feat: increase button size while driving
This commit is contained in:
10
bun.lock
10
bun.lock
@ -38,7 +38,7 @@
|
|||||||
"@types/libsodium-wrappers": "^0.7.14",
|
"@types/libsodium-wrappers": "^0.7.14",
|
||||||
"@types/node": "^22.15.24",
|
"@types/node": "^22.15.24",
|
||||||
"@types/pako": "^2.0.3",
|
"@types/pako": "^2.0.3",
|
||||||
"bits-ui": "^2.8.6",
|
"bits-ui": "^2.11.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"git-format-staged": "^3.1.1",
|
"git-format-staged": "^3.1.1",
|
||||||
@ -441,7 +441,7 @@
|
|||||||
|
|
||||||
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
|
||||||
|
|
||||||
"bits-ui": ["bits-ui@2.9.2", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.29.1", "svelte-toolbelt": "^0.9.3", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-GGbyr4oVKtHin//Q0AhlygkasmfWt328VjsnmB3sP+h8Sh+Eyghm+1AQ8o+xQMDCYbdL35JZ9UZGTZYTMar4Uw=="],
|
"bits-ui": ["bits-ui@2.11.5", "", { "dependencies": { "@floating-ui/core": "^1.7.1", "@floating-ui/dom": "^1.7.1", "esm-env": "^1.1.2", "runed": "^0.31.1", "svelte-toolbelt": "^0.10.4", "tabbable": "^6.2.0" }, "peerDependencies": { "@internationalized/date": "^3.8.1", "svelte": "^5.33.0" } }, "sha512-d7b6HrrCUeK261c777agFz0G5lx13RMA0DT022e4SRuIjI3bZ8ci53YxIZ2/jpXTmeAeqeShyC+Mgibh9OeW9A=="],
|
||||||
|
|
||||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||||
|
|
||||||
@ -801,7 +801,7 @@
|
|||||||
|
|
||||||
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
||||||
|
|
||||||
"runed": ["runed@0.29.2", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA=="],
|
"runed": ["runed@0.31.1", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-v3czcTnO+EJjiPvD4dwIqfTdHLZ8oH0zJheKqAHh9QMViY7Qb29UlAMRpX7ZtHh7AFqV60KmfxaJ9QMy+L1igQ=="],
|
||||||
|
|
||||||
"rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
|
"rw": ["rw@1.3.3", "", {}, "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ=="],
|
||||||
|
|
||||||
@ -839,7 +839,7 @@
|
|||||||
|
|
||||||
"svelte-maplibre-gl": ["svelte-maplibre-gl@0.1.8", "", { "peerDependencies": { "@deck.gl/core": "^9.1.0", "@deck.gl/layers": "^9.1.0", "@deck.gl/mapbox": "^9.1.0", "maplibre-contour": ">=0.1.0", "maplibre-gl": "^5.0.0 || ^4.0.0", "pmtiles": "^4.0.0", "svelte": ">=5.0.0", "terra-draw": "^1.0.0", "terra-draw-maplibre-gl-adapter": "^1.0.3" } }, "sha512-YvMo25q/rpNDNE4iBvOuYYt+E+6jT+PBLxX7vR20LE5ZD2K3cLV9cR34S4SX7w81E00lP7InD2+CvFr7T0vBxg=="],
|
"svelte-maplibre-gl": ["svelte-maplibre-gl@0.1.8", "", { "peerDependencies": { "@deck.gl/core": "^9.1.0", "@deck.gl/layers": "^9.1.0", "@deck.gl/mapbox": "^9.1.0", "maplibre-contour": ">=0.1.0", "maplibre-gl": "^5.0.0 || ^4.0.0", "pmtiles": "^4.0.0", "svelte": ">=5.0.0", "terra-draw": "^1.0.0", "terra-draw-maplibre-gl-adapter": "^1.0.3" } }, "sha512-YvMo25q/rpNDNE4iBvOuYYt+E+6jT+PBLxX7vR20LE5ZD2K3cLV9cR34S4SX7w81E00lP7InD2+CvFr7T0vBxg=="],
|
||||||
|
|
||||||
"svelte-toolbelt": ["svelte-toolbelt@0.9.3", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.29.0", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw=="],
|
"svelte-toolbelt": ["svelte-toolbelt@0.10.5", "", { "dependencies": { "clsx": "^2.1.1", "runed": "^0.29.0", "style-to-object": "^1.0.8" }, "peerDependencies": { "svelte": "^5.30.2" } }, "sha512-8e+eWTgxw1aiLxhDE8Rb1X6AoLitqpJz+WhAul2W7W58C8KoLoJQf1TgQdFPBiCPJ0Jg5y0Zi1uyua9em4VS0w=="],
|
||||||
|
|
||||||
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
|
"tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="],
|
||||||
|
|
||||||
@ -949,6 +949,8 @@
|
|||||||
|
|
||||||
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||||
|
|
||||||
|
"svelte-toolbelt/runed": ["runed@0.29.2", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA=="],
|
||||||
|
|
||||||
"tailwind-variants/tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="],
|
"tailwind-variants/tailwind-merge": ["tailwind-merge@3.0.2", "", {}, "sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw=="],
|
||||||
|
|
||||||
"vaul-svelte/runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
|
"vaul-svelte/runed": ["runed@0.23.4", "", { "dependencies": { "esm-env": "^1.0.0" }, "peerDependencies": { "svelte": "^5.7.0" } }, "sha512-9q8oUiBYeXIDLWNK5DfCWlkL0EW3oGbk845VdKlPeia28l751VpfesaB/+7pI6rnbx1I6rqoZ2fZxptOJLxILA=="],
|
||||||
|
|||||||
@ -157,6 +157,10 @@
|
|||||||
"probing-server": "Probing server...",
|
"probing-server": "Probing server...",
|
||||||
"discovering-calendars": "Discovering calendars...",
|
"discovering-calendars": "Discovering calendars...",
|
||||||
"choose": "Choose calendars to add:"
|
"choose": "Choose calendars to add:"
|
||||||
|
},
|
||||||
|
"appearance": {
|
||||||
|
"header": "Appearance",
|
||||||
|
"bigger-buttons-in-drive": "Bigger Buttons while Driving"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"unsave": "Unsave",
|
"unsave": "Unsave",
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
"@types/libsodium-wrappers": "^0.7.14",
|
"@types/libsodium-wrappers": "^0.7.14",
|
||||||
"@types/node": "^22.15.24",
|
"@types/node": "^22.15.24",
|
||||||
"@types/pako": "^2.0.3",
|
"@types/pako": "^2.0.3",
|
||||||
"bits-ui": "^2.8.6",
|
"bits-ui": "^2.11.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"eslint-config-prettier": "^10.1.5",
|
"eslint-config-prettier": "^10.1.5",
|
||||||
"git-format-staged": "^3.1.1",
|
"git-format-staged": "^3.1.1",
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
import Input from "../ui/input/input.svelte";
|
import Input from "../ui/input/input.svelte";
|
||||||
import EvConnectorSelect from "./EVConnectorSelect.svelte";
|
import EvConnectorSelect from "./EVConnectorSelect.svelte";
|
||||||
import { m } from "$lang/messages";
|
import { m } from "$lang/messages";
|
||||||
|
import { localStore } from "$lib/services/localStore.svelte";
|
||||||
|
import { isDriving } from "./location.svelte";
|
||||||
|
|
||||||
let open = $state(false);
|
let open = $state(false);
|
||||||
|
|
||||||
@ -52,11 +54,14 @@
|
|||||||
fuelType: "diesel",
|
fuelType: "diesel",
|
||||||
preferredFuel: "Diesel",
|
preferredFuel: "Diesel",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const biggerButtonsInDrive = localStore<boolean>("bigger-buttons-in-drive", false);
|
||||||
|
const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Drawer.Root bind:open>
|
<Drawer.Root bind:open>
|
||||||
<Drawer.Trigger
|
<Drawer.Trigger
|
||||||
class={buttonVariants({ variant: "secondary", class: "w-full p-5" })}
|
class={buttonVariants({ variant: "secondary", class: "w-full", size: shouldUseLargeSize ? "drive" : "default" })}
|
||||||
>
|
>
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</Drawer.Trigger>
|
</Drawer.Trigger>
|
||||||
|
|||||||
@ -45,6 +45,7 @@
|
|||||||
"nearby-poi": "NearbyPOISidebar",
|
"nearby-poi": "NearbyPOISidebar",
|
||||||
licenses: "settings/LicensesSidebar",
|
licenses: "settings/LicensesSidebar",
|
||||||
calendar: "settings/CalendarSidebar",
|
calendar: "settings/CalendarSidebar",
|
||||||
|
appearance: "settings/AppearanceSidebar",
|
||||||
};
|
};
|
||||||
|
|
||||||
const fullscreen: Record<string, boolean> = {
|
const fullscreen: Record<string, boolean> = {
|
||||||
@ -64,6 +65,7 @@
|
|||||||
"nearby-poi": false,
|
"nearby-poi": false,
|
||||||
licenses: true,
|
licenses: true,
|
||||||
calendar: true,
|
calendar: true,
|
||||||
|
appearance: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let isDragging = false;
|
let isDragging = false;
|
||||||
|
|||||||
@ -19,6 +19,8 @@
|
|||||||
import AddVehicleDrawer from "./AddVehicleDrawer.svelte";
|
import AddVehicleDrawer from "./AddVehicleDrawer.svelte";
|
||||||
import { m } from "$lang/messages";
|
import { m } from "$lang/messages";
|
||||||
import { updateStore } from "$lib/services/stores.svelte";
|
import { updateStore } from "$lib/services/stores.svelte";
|
||||||
|
import { localStore } from "$lib/services/localStore.svelte";
|
||||||
|
import { isDriving } from "./location.svelte";
|
||||||
|
|
||||||
let open = $state(false);
|
let open = $state(false);
|
||||||
|
|
||||||
@ -38,11 +40,14 @@
|
|||||||
return TractorIcon; // Default icon if no match
|
return TractorIcon; // Default icon if no match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const biggerButtonsInDrive = localStore<boolean>("bigger-buttons-in-drive", false);
|
||||||
|
const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Drawer.Root bind:open>
|
<Drawer.Root bind:open>
|
||||||
<Drawer.Trigger
|
<Drawer.Trigger
|
||||||
class={buttonVariants({ variant: "secondary", class: "w-full p-5" })}
|
class={buttonVariants({ variant: "secondary", class: "w-full", size: shouldUseLargeSize ? "drive" : "default" })}
|
||||||
>
|
>
|
||||||
{@const vehicle = selectedVehicle()?.data ?? DefaultVehicle}
|
{@const vehicle = selectedVehicle()?.data ?? DefaultVehicle}
|
||||||
{@const Icon = getVehicleIcon(vehicle.type)}
|
{@const Icon = getVehicleIcon(vehicle.type)}
|
||||||
@ -63,7 +68,7 @@
|
|||||||
variant={selectedVehicle()?.data === vehicle.data
|
variant={selectedVehicle()?.data === vehicle.data
|
||||||
? "default"
|
? "default"
|
||||||
: "secondary"}
|
: "secondary"}
|
||||||
class="w-[calc(100%-48px-8px)] p-5"
|
class="w-[calc(100%-48px-8px)]"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
selectVehicle(vehicle.data);
|
selectVehicle(vehicle.data);
|
||||||
open = false;
|
open = false;
|
||||||
@ -92,10 +97,8 @@
|
|||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<AddVehicleDrawer>
|
<AddVehicleDrawer>
|
||||||
<Button variant="secondary" class="w-full p-5">
|
|
||||||
<PlusCircleIcon />
|
<PlusCircleIcon />
|
||||||
{m["vehicles.selector.add"]()}
|
{m["vehicles.selector.add"]()}
|
||||||
</Button>
|
|
||||||
</AddVehicleDrawer>
|
</AddVehicleDrawer>
|
||||||
</div>
|
</div>
|
||||||
</Drawer.Content>
|
</Drawer.Content>
|
||||||
|
|||||||
@ -33,6 +33,12 @@ export const location = $state({
|
|||||||
lastUpdate: null as Date | null,
|
lastUpdate: null as Date | null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const _isDriving = $derived(location.speed > (7 / 3.6));
|
||||||
|
|
||||||
|
export function isDriving() {
|
||||||
|
return _isDriving;
|
||||||
|
}
|
||||||
|
|
||||||
export function watchLocation() {
|
export function watchLocation() {
|
||||||
if (navigator.geolocation) {
|
if (navigator.geolocation) {
|
||||||
navigator.geolocation.watchPosition(
|
navigator.geolocation.watchPosition(
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="lg"
|
|
||||||
style="flex: 1;"
|
style="flex: 1;"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
view.switch("nearby-poi", {
|
view.switch("nearby-poi", {
|
||||||
@ -36,7 +35,6 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="lg"
|
|
||||||
style="flex: 1;"
|
style="flex: 1;"
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
view.switch("nearby-poi", {
|
view.switch("nearby-poi", {
|
||||||
|
|||||||
@ -12,10 +12,8 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<AddVehicleDrawer>
|
<AddVehicleDrawer>
|
||||||
<Button variant="secondary" class="w-full p-5">
|
|
||||||
<PlusCircleIcon />
|
<PlusCircleIcon />
|
||||||
{m["vehicles.selector.add"]()}
|
{m["vehicles.selector.add"]()}
|
||||||
</Button>
|
|
||||||
</AddVehicleDrawer>
|
</AddVehicleDrawer>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -0,0 +1,11 @@
|
|||||||
|
<script>
|
||||||
|
import { m } from "$lang/messages";
|
||||||
|
import SidebarHeader from "../SidebarHeader.svelte";
|
||||||
|
import SettingsToggle from "./SettingsToggle.svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SidebarHeader>
|
||||||
|
{m["sidebar.appearance.header"]()}
|
||||||
|
</SidebarHeader>
|
||||||
|
|
||||||
|
<SettingsToggle text={m["sidebar.appearance.bigger-buttons-in-drive"]()} localStorageKey="bigger-buttons-in-drive" />
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
style="width: 100%; height: 40px;"
|
style="width: 100%;"
|
||||||
{disabled}
|
{disabled}
|
||||||
onclick={() => {
|
onclick={() => {
|
||||||
if (viewName) view.switch(viewName);
|
if (viewName) view.switch(viewName);
|
||||||
|
|||||||
@ -25,6 +25,11 @@
|
|||||||
text={m["sidebar.language.header"]()}
|
text={m["sidebar.language.header"]()}
|
||||||
view="language"
|
view="language"
|
||||||
/>
|
/>
|
||||||
|
<SettingsButton
|
||||||
|
icon={PaintbrushIcon}
|
||||||
|
text={m["sidebar.appearance.header"]()}
|
||||||
|
view="appearance"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { IconProps } from "@lucide/svelte";
|
||||||
|
import type { Component } from "svelte";
|
||||||
|
import Switch from "$lib/components/ui/switch/switch.svelte";
|
||||||
|
import { Label } from "$lib/components/ui/label";
|
||||||
|
import { eventTarget } from "$lib/services/localStore.svelte";
|
||||||
|
|
||||||
|
let {
|
||||||
|
icon: Icon,
|
||||||
|
text,
|
||||||
|
onchange,
|
||||||
|
disabled,
|
||||||
|
localStorageKey,
|
||||||
|
value = $bindable(localStorageKey ? localStorage.getItem(localStorageKey) === "true" : false),
|
||||||
|
}: {
|
||||||
|
icon?: Component<IconProps>;
|
||||||
|
text: string;
|
||||||
|
onchange?: () => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
value?: boolean;
|
||||||
|
localStorageKey?: string;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<Label
|
||||||
|
style="width: 100%;"
|
||||||
|
for="settings-toggle"
|
||||||
|
>
|
||||||
|
{#if Icon}
|
||||||
|
<Icon />
|
||||||
|
{/if}
|
||||||
|
{text}
|
||||||
|
</Label>
|
||||||
|
<Switch {disabled} bind:checked={value} onCheckedChange={() => {
|
||||||
|
if (onchange) onchange();
|
||||||
|
if (localStorageKey) {
|
||||||
|
localStorage.setItem(localStorageKey, value ? "true" : "false");
|
||||||
|
eventTarget.dispatchEvent(new CustomEvent("localStorageChanged", { detail: { key: localStorageKey, value } }));
|
||||||
|
}
|
||||||
|
}} id="settings-toggle" />
|
||||||
|
</div>
|
||||||
@ -1,4 +1,6 @@
|
|||||||
<script lang="ts" module>
|
<script lang="ts" module>
|
||||||
|
import { isDriving } from "$lib/components/lnv/location.svelte";
|
||||||
|
import { localStore } from "$lib/services/localStore.svelte";
|
||||||
import { cn, type WithElementRef } from "$lib/utils.js";
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
import type {
|
import type {
|
||||||
HTMLAnchorAttributes,
|
HTMLAnchorAttributes,
|
||||||
@ -6,6 +8,9 @@
|
|||||||
} from "svelte/elements";
|
} from "svelte/elements";
|
||||||
import { type VariantProps, tv } from "tailwind-variants";
|
import { type VariantProps, tv } from "tailwind-variants";
|
||||||
|
|
||||||
|
const biggerButtonsInDrive = localStore<boolean>("bigger-buttons-in-drive", false);
|
||||||
|
const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false);
|
||||||
|
|
||||||
export const buttonVariants = tv({
|
export const buttonVariants = tv({
|
||||||
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
base: "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium outline-none transition-all focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
||||||
variants: {
|
variants: {
|
||||||
@ -27,6 +32,7 @@
|
|||||||
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
|
||||||
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
|
||||||
icon: "size-9",
|
icon: "size-9",
|
||||||
|
drive: "h-12 rounded-md px-8 has-[>svg]:px-6"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
@ -63,7 +69,7 @@
|
|||||||
<a
|
<a
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="button"
|
data-slot="button"
|
||||||
class={cn(buttonVariants({ variant, size }), className)}
|
class={cn(buttonVariants({ variant, size: shouldUseLargeSize ? "drive" : size }), className)}
|
||||||
href={disabled ? undefined : href}
|
href={disabled ? undefined : href}
|
||||||
aria-disabled={disabled}
|
aria-disabled={disabled}
|
||||||
role={disabled ? "link" : undefined}
|
role={disabled ? "link" : undefined}
|
||||||
@ -76,7 +82,7 @@
|
|||||||
<button
|
<button
|
||||||
bind:this={ref}
|
bind:this={ref}
|
||||||
data-slot="button"
|
data-slot="button"
|
||||||
class={cn(buttonVariants({ variant, size }), className)}
|
class={cn(buttonVariants({ variant, size: shouldUseLargeSize ? "drive" : size }), className)}
|
||||||
{type}
|
{type}
|
||||||
{disabled}
|
{disabled}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
|||||||
7
src/lib/components/ui/label/index.ts
Normal file
7
src/lib/components/ui/label/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Root from "./label.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Label,
|
||||||
|
};
|
||||||
20
src/lib/components/ui/label/label.svelte
Normal file
20
src/lib/components/ui/label/label.svelte
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Label as LabelPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
...restProps
|
||||||
|
}: LabelPrimitive.RootProps = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<LabelPrimitive.Root
|
||||||
|
bind:ref
|
||||||
|
data-slot="label"
|
||||||
|
class={cn(
|
||||||
|
"flex select-none items-center gap-2 text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-50 group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
7
src/lib/components/ui/switch/index.ts
Normal file
7
src/lib/components/ui/switch/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Root from "./switch.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
//
|
||||||
|
Root as Switch,
|
||||||
|
};
|
||||||
29
src/lib/components/ui/switch/switch.svelte
Normal file
29
src/lib/components/ui/switch/switch.svelte
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Switch as SwitchPrimitive } from "bits-ui";
|
||||||
|
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
checked = $bindable(false),
|
||||||
|
...restProps
|
||||||
|
}: WithoutChildrenOrChild<SwitchPrimitive.RootProps> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SwitchPrimitive.Root
|
||||||
|
bind:ref
|
||||||
|
bind:checked
|
||||||
|
data-slot="switch"
|
||||||
|
class={cn(
|
||||||
|
"data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 shadow-xs peer inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent outline-none transition-all focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
<SwitchPrimitive.Thumb
|
||||||
|
data-slot="switch-thumb"
|
||||||
|
class={cn(
|
||||||
|
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SwitchPrimitive.Root>
|
||||||
29
src/lib/services/localStore.svelte.ts
Normal file
29
src/lib/services/localStore.svelte.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import type { WrappedValue } from "$lib/services/stores.svelte";
|
||||||
|
|
||||||
|
export const eventTarget = new EventTarget();
|
||||||
|
|
||||||
|
export function localStore<T>(key: string, defaultValue: T): WrappedValue<T> {
|
||||||
|
const storedValue = localStorage.getItem(key);
|
||||||
|
const initialValue = storedValue !== null ? JSON.parse(storedValue) : defaultValue;
|
||||||
|
const state = $state<WrappedValue<T>>({ current: initialValue });
|
||||||
|
eventTarget.addEventListener("localStorageChanged", (event) => {
|
||||||
|
const customEvent = event as CustomEvent;
|
||||||
|
console.log("localStorageChanged event received", customEvent.detail);
|
||||||
|
if(customEvent.detail.key === key) {
|
||||||
|
const newValue = customEvent.detail.value as T;
|
||||||
|
console.log(`localStore: ${key} updated from another tab`, newValue);
|
||||||
|
if(JSON.stringify(state.current) === JSON.stringify(newValue)) return;
|
||||||
|
state.current = newValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
get current() {
|
||||||
|
return state.current;
|
||||||
|
},
|
||||||
|
set current(newValue: T) {
|
||||||
|
state.current = newValue;
|
||||||
|
eventTarget.dispatchEvent(new CustomEvent("localStorageChanged", { detail: { key, value: newValue } }));
|
||||||
|
localStorage.setItem(key, JSON.stringify(newValue));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user