diff --git a/src/lib/components/lnv/AddVehicleDrawer.svelte b/src/lib/components/lnv/AddVehicleDrawer.svelte index 412889b..9eced4d 100644 --- a/src/lib/components/lnv/AddVehicleDrawer.svelte +++ b/src/lib/components/lnv/AddVehicleDrawer.svelte @@ -55,13 +55,22 @@ preferredFuel: "Diesel", }); - const biggerButtonsInDrive = localStore("bigger-buttons-in-drive", false); - const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false); + const biggerButtonsInDrive = localStore( + "bigger-buttons-in-drive", + false, + ); + const shouldUseLargeSize = $derived( + biggerButtonsInDrive.current ? isDriving() : false, + ); {@render children()} diff --git a/src/lib/components/lnv/Sidebar.svelte b/src/lib/components/lnv/Sidebar.svelte index 1f2f184..148a0d6 100644 --- a/src/lib/components/lnv/Sidebar.svelte +++ b/src/lib/components/lnv/Sidebar.svelte @@ -178,8 +178,13 @@ {/if} {#if !hideSearch && !!location.speed != false} -
- {(location.speed * 3.6 | 0).toFixed(0)} +
+ {((location.speed * 3.6) | 0).toFixed(0)}
{/if} {#if getRoadMetadata().current} @@ -187,7 +192,12 @@ {#if meta.maxspeed} {@const maxspeed = getSpeed(meta.maxspeed)} {#if maxspeed && maxspeed < 100} -
+
{meta.maxspeed}
{/if} diff --git a/src/lib/components/lnv/VehicleSelector.svelte b/src/lib/components/lnv/VehicleSelector.svelte index 6203db3..5f8526d 100644 --- a/src/lib/components/lnv/VehicleSelector.svelte +++ b/src/lib/components/lnv/VehicleSelector.svelte @@ -41,13 +41,22 @@ } } - const biggerButtonsInDrive = localStore("bigger-buttons-in-drive", false); - const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false); + const biggerButtonsInDrive = localStore( + "bigger-buttons-in-drive", + false, + ); + const shouldUseLargeSize = $derived( + biggerButtonsInDrive.current ? isDriving() : false, + ); {@const vehicle = selectedVehicle()?.data ?? DefaultVehicle} {@const Icon = getVehicleIcon(vehicle.type)} diff --git a/src/lib/components/lnv/location.svelte.ts b/src/lib/components/lnv/location.svelte.ts index 3e9417e..e9fb25b 100644 --- a/src/lib/components/lnv/location.svelte.ts +++ b/src/lib/components/lnv/location.svelte.ts @@ -35,13 +35,15 @@ export const location = $state({ lastUpdate: null as Date | null, }); -const _isDriving = $derived(location.speed > (7 / 3.6)); +const _isDriving = $derived(location.speed > 7 / 3.6); export function isDriving() { return _isDriving; } -const roadMetadata: WrappedValue = $state({ current: null }); +const roadMetadata: WrappedValue = $state({ + current: null, +}); export function getRoadMetadata() { return roadMetadata; @@ -60,8 +62,11 @@ export function watchLocation() { location.available = true; location.heading = pos.coords.heading; location.lastUpdate = new Date(); - - getMeta({ lat: location.lat, lon: location.lng }, "transportation").then((meta) => { + + getMeta( + { lat: location.lat, lon: location.lng }, + "transportation", + ).then((meta) => { roadMetadata.current = meta; }); diff --git a/src/lib/components/lnv/main/Calendar.svelte b/src/lib/components/lnv/main/Calendar.svelte index c57de5b..82e2fd4 100644 --- a/src/lib/components/lnv/main/Calendar.svelte +++ b/src/lib/components/lnv/main/Calendar.svelte @@ -1,7 +1,12 @@
@@ -31,35 +37,40 @@

- {m["calendar.start"]()}: {event.start?.toLocaleString("de-DE") || m["calendar.no-start"]()} + {m["calendar.start"]()}: + {event.start?.toLocaleString("de-DE") || m["calendar.no-start"]()}

- {m["calendar.end"]()}: {event.end?.toLocaleString("de-DE") || m["calendar.no-end"]()} + {m["calendar.end"]()}: + {event.end?.toLocaleString("de-DE") || m["calendar.no-end"]()}

{#if event.location} {m["calendar.location"]()}: {event.location} {:else} - {m["calendar.location"]()}: {m["calendar.no-location"]()} + {m["calendar.location"]()}: + {m["calendar.no-location"]()} {/if}

- + {/each} diff --git a/src/lib/components/lnv/sidebar/RouteSidebar.svelte b/src/lib/components/lnv/sidebar/RouteSidebar.svelte index ff92615..d06ff58 100644 --- a/src/lib/components/lnv/sidebar/RouteSidebar.svelte +++ b/src/lib/components/lnv/sidebar/RouteSidebar.svelte @@ -74,11 +74,13 @@ const FROM: WorldLocation = fromLocation == "current" ? { lat: location.lat, lon: location.lng } - : savedLocations.current.find(s => s.name == fromLocation) + : savedLocations.current.find((s) => s.name == fromLocation) ? { - lat: savedLocations.current.find(s => s.name == fromLocation)!.data.lat, - lon: savedLocations.current.find(s => s.name == fromLocation)!.data.lng, - } + lat: savedLocations.current.find((s) => s.name == fromLocation)! + .data.lat, + lon: savedLocations.current.find((s) => s.name == fromLocation)! + .data.lng, + } : { lat: parseFloat(fromLocation.split(",")[0]), lon: parseFloat(fromLocation.split(",")[1]), @@ -86,11 +88,13 @@ const TO: WorldLocation = toLocation == "current" ? { lat: location.lat, lon: location.lng } - : savedLocations.current.find(s => s.name == toLocation) + : savedLocations.current.find((s) => s.name == toLocation) ? { - lat: savedLocations.current.find(s => s.name == fromLocation)!.data.lat, - lon: savedLocations.current.find(s => s.name == fromLocation)!.data.lng, - } + lat: savedLocations.current.find((s) => s.name == fromLocation)! + .data.lat, + lon: savedLocations.current.find((s) => s.name == fromLocation)! + .data.lng, + } : { lat: parseFloat(toLocation.split(",")[0]), lon: parseFloat(toLocation.split(",")[1]), diff --git a/src/lib/components/lnv/sidebar/settings/AppearanceSidebar.svelte b/src/lib/components/lnv/sidebar/settings/AppearanceSidebar.svelte index ec27c35..b05accb 100644 --- a/src/lib/components/lnv/sidebar/settings/AppearanceSidebar.svelte +++ b/src/lib/components/lnv/sidebar/settings/AppearanceSidebar.svelte @@ -8,4 +8,7 @@ {m["sidebar.appearance.header"]()} - + diff --git a/src/lib/components/lnv/sidebar/settings/CalendarSidebar.svelte b/src/lib/components/lnv/sidebar/settings/CalendarSidebar.svelte index b58e112..d338e4c 100644 --- a/src/lib/components/lnv/sidebar/settings/CalendarSidebar.svelte +++ b/src/lib/components/lnv/sidebar/settings/CalendarSidebar.svelte @@ -6,10 +6,16 @@ import * as Drawer from "$lib/components/ui/drawer"; import { Button } from "$lib/components/ui/button"; import Input from "$lib/components/ui/input/input.svelte"; - import { fetchCalendars, findScheme, type AuthScheme, type DAVCalendar, type DAVCredentials } from "$lib/services/CalDAV"; + import { + fetchCalendars, + findScheme, + type AuthScheme, + type DAVCalendar, + type DAVCredentials, + } from "$lib/services/CalDAV"; import { onMount } from "svelte"; - - let calendars: (DAVCalendar & {credentials: DAVCredentials})[] = $state([]); + + let calendars: (DAVCalendar & { credentials: DAVCredentials })[] = $state([]); let calDavDrawerOpen = $state(false); let calDavLoading = $state(false); @@ -25,15 +31,19 @@ calDavState = m["sidebar.calendar.probing-server"](); calDavScheme = await findScheme(calDavUrl); calDavState = m["sidebar.calendar.discovering-calendars"](); - calDavCalendars = await fetchCalendars(calDavUrl, { scheme: calDavScheme, username: calDavUsername, password: calDavPassword }); + calDavCalendars = await fetchCalendars(calDavUrl, { + scheme: calDavScheme, + username: calDavUsername, + password: calDavPassword, + }); calDavState = ""; } onMount(() => { - if(localStorage.getItem("calendars")) { + if (localStorage.getItem("calendars")) { calendars = JSON.parse(localStorage.getItem("calendars")!); } - }) + }); @@ -41,15 +51,30 @@ - - - {m["sidebar.calendar.connect"]()} - + + + {m["sidebar.calendar.connect"]()} +
{#if calDavCalendars} - - - + + + {#if calDavState} {calDavState} {/if} @@ -59,40 +84,51 @@
    {#each calDavCalendars as calendar (calendar.url)}
  • -
  • @@ -100,33 +136,44 @@
{/if}
- + {#if calDavCalendars.length === 0} - + {/if} - + {calDavCalendars.length === 0 ? m.done() : m.cancel()} - -
+ +
{#each calendars as calendar (calendar.url)}

{calendar.name}

- +
{/each} - { - calDavDrawerOpen = true; -}} /> \ No newline at end of file + { + calDavDrawerOpen = true; + }} +/> diff --git a/src/lib/components/lnv/sidebar/settings/DeveloperSidebar.svelte b/src/lib/components/lnv/sidebar/settings/DeveloperSidebar.svelte index d327e26..05e26e0 100644 --- a/src/lib/components/lnv/sidebar/settings/DeveloperSidebar.svelte +++ b/src/lib/components/lnv/sidebar/settings/DeveloperSidebar.svelte @@ -1,6 +1,6 @@
-
diff --git a/src/lib/components/ui/button/button.svelte b/src/lib/components/ui/button/button.svelte index 71c5602..27b0e40 100644 --- a/src/lib/components/ui/button/button.svelte +++ b/src/lib/components/ui/button/button.svelte @@ -8,8 +8,13 @@ } from "svelte/elements"; import { type VariantProps, tv } from "tailwind-variants"; - const biggerButtonsInDrive = localStore("bigger-buttons-in-drive", false); - const shouldUseLargeSize = $derived(biggerButtonsInDrive.current ? isDriving() : false); + const biggerButtonsInDrive = localStore( + "bigger-buttons-in-drive", + false, + ); + const shouldUseLargeSize = $derived( + biggerButtonsInDrive.current ? isDriving() : false, + ); 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", @@ -32,7 +37,7 @@ 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", icon: "size-9", - drive: "h-12 rounded-md px-8 has-[>svg]:px-6" + drive: "h-12 rounded-md px-8 has-[>svg]:px-6", }, }, defaultVariants: { @@ -69,7 +74,10 @@ diff --git a/src/lib/components/ui/switch/switch.svelte b/src/lib/components/ui/switch/switch.svelte index 78477dd..49df85f 100644 --- a/src/lib/components/ui/switch/switch.svelte +++ b/src/lib/components/ui/switch/switch.svelte @@ -16,14 +16,14 @@ 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 + className, )} {...restProps} > diff --git a/src/lib/services/CalDAV.ts b/src/lib/services/CalDAV.ts index 6bde4b1..216b9eb 100644 --- a/src/lib/services/CalDAV.ts +++ b/src/lib/services/CalDAV.ts @@ -22,18 +22,24 @@ export interface DAVEvent { } export async function findScheme(url: string): Promise { - const scheme = await invoke("dav_find_scheme", { url }); + const scheme = await invoke("dav_find_scheme", { url }); return scheme as AuthScheme; } -export async function fetchCalendars(url: string, credentials: DAVCredentials): Promise { +export async function fetchCalendars( + url: string, + credentials: DAVCredentials, +): Promise { const calendars = await invoke("dav_fetch_calendars", { url, credentials }); return calendars as DAVCalendar[]; } -export async function fetchEvents(calendar: DAVCalendar, credentials: DAVCredentials): Promise { +export async function fetchEvents( + calendar: DAVCalendar, + credentials: DAVCredentials, +): Promise { const events = await invoke("dav_fetch_events", { calendar, credentials }); - return (events as DAVEvent[]).map(e => { + return (events as DAVEvent[]).map((e) => { if (e.start) e.start = new Date(e.start); if (e.end) e.end = new Date(e.end); return e; diff --git a/src/lib/services/TileMeta.ts b/src/lib/services/TileMeta.ts index a55f26f..f8b59ae 100644 --- a/src/lib/services/TileMeta.ts +++ b/src/lib/services/TileMeta.ts @@ -11,8 +11,8 @@ function getFeatureDistance(f: GeoJSON.Feature, point: [number, number]) { // Compute the min distance across all parts return Math.min( ...f.geometry.coordinates.map((coords) => - pointToLineDistance(point, lineString(coords)) - ) + pointToLineDistance(point, lineString(coords)), + ), ); } else { return Infinity; @@ -30,8 +30,11 @@ export async function getMeta(coord: WorldLocation, layer: string) { const feature = layerData.feature(i); features.push(feature.toGeoJSON(zxy.x, zxy.y, zxy.z)); } - const filtered = features.filter((f) => f.geometry.type === "LineString" || f.geometry.type == "MultiLineString"); - if(filtered.length === 0) return null; + const filtered = features.filter( + (f) => + f.geometry.type === "LineString" || f.geometry.type == "MultiLineString", + ); + if (filtered.length === 0) return null; const nearest = filtered.reduce((a, b) => { const distA = getFeatureDistance(a, [coord.lon, coord.lat]); const distB = getFeatureDistance(b, [coord.lon, coord.lat]); @@ -44,16 +47,16 @@ const IMPLICIT_SPEEDS: Record = { "DE:urban": 50, "DE:rural": 100, // TODO: 80 (hgv weight > 3.5t, or trailer), 60 (weight > 7.5t) "DE:living_street": 7, - "DE:bicycle_road": 30 -} + "DE:bicycle_road": 30, +}; export function getSpeed(maxspeed: string): number | null { - if(!isNaN(parseInt(maxspeed))) return parseInt(maxspeed); - if(maxspeed.endsWith(" mph")) { + if (!isNaN(parseInt(maxspeed))) return parseInt(maxspeed); + if (maxspeed.endsWith(" mph")) { const val = parseInt(maxspeed.replace(" mph", "")); - if(!isNaN(val)) return Math.round(val * 1.60934); // Convert to km/h + if (!isNaN(val)) return Math.round(val * 1.60934); // Convert to km/h } - if(maxspeed === "walk") return 7; // https://wiki.openstreetmap.org/wiki/Proposed_features/maxspeed_walk + if (maxspeed === "walk") return 7; // https://wiki.openstreetmap.org/wiki/Proposed_features/maxspeed_walk return IMPLICIT_SPEEDS[maxspeed as keyof typeof IMPLICIT_SPEEDS] || null; } @@ -64,11 +67,11 @@ function coordToTile(coord: WorldLocation, zoom: number) { ((1 - Math.log( Math.tan((coord.lat * Math.PI) / 180) + - 1 / Math.cos((coord.lat * Math.PI) / 180) + 1 / Math.cos((coord.lat * Math.PI) / 180), ) / Math.PI) / 2) * - Math.pow(2, z) + Math.pow(2, z), ); return { z, x, y }; } @@ -117,7 +120,7 @@ export async function fetchTile(z: number, x: number, y: number) { const pmtiles = (await hasPMTiles("tiles")) ? new PMTiles(new FSSource("tiles")) : new PMTiles("https://trafficcue-tiles.picoscratch.de/germany.pmtiles"); - const tile = (await pmtiles.getZxy(z, x, y)); + const tile = await pmtiles.getZxy(z, x, y); if (!tile) { console.log(tile); throw new Error(`Tile not found: z${z} x${x} y${y}`); diff --git a/src/lib/services/localStore.svelte.ts b/src/lib/services/localStore.svelte.ts index 9131678..71c7f83 100644 --- a/src/lib/services/localStore.svelte.ts +++ b/src/lib/services/localStore.svelte.ts @@ -4,15 +4,16 @@ export const eventTarget = new EventTarget(); export function localStore(key: string, defaultValue: T): WrappedValue { const storedValue = localStorage.getItem(key); - const initialValue = storedValue !== null ? JSON.parse(storedValue) : defaultValue; + const initialValue = + storedValue !== null ? JSON.parse(storedValue) : defaultValue; const state = $state>({ current: initialValue }); eventTarget.addEventListener("localStorageChanged", (event) => { const customEvent = event as CustomEvent; console.log("localStorageChanged event received", customEvent.detail); - if(customEvent.detail.key === key) { + 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; + if (JSON.stringify(state.current) === JSON.stringify(newValue)) return; state.current = newValue; } }); @@ -22,8 +23,12 @@ export function localStore(key: string, defaultValue: T): WrappedValue { }, set current(newValue: T) { state.current = newValue; - eventTarget.dispatchEvent(new CustomEvent("localStorageChanged", { detail: { key, value: newValue } })); + eventTarget.dispatchEvent( + new CustomEvent("localStorageChanged", { + detail: { key, value: newValue }, + }), + ); localStorage.setItem(key, JSON.stringify(newValue)); }, }; -} \ No newline at end of file +}