diff --git a/website/src/lib/components/ElevationProfile.svelte b/website/src/lib/components/ElevationProfile.svelte index 08c6b48f..8e050a70 100644 --- a/website/src/lib/components/ElevationProfile.svelte +++ b/website/src/lib/components/ElevationProfile.svelte @@ -6,7 +6,8 @@ import Chart from 'chart.js/auto'; import mapboxgl from 'mapbox-gl'; - import { map, settings, gpxStatistics } from '$lib/stores'; + import { map, gpxStatistics } from '$lib/stores'; + import { settings } from '$lib/db'; import { onDestroy, onMount } from 'svelte'; import { @@ -53,6 +54,8 @@ let marker: mapboxgl.Marker | null = null; + let { distanceUnits, velocityUnits, temperatureUnits } = settings; + let options = { animation: false, parsing: false, @@ -111,7 +114,7 @@ } return `${$_('quantities.elevation')}: ${getElevationWithUnits(point.y, false)}`; } else if (context.datasetIndex === 1) { - return `${$settings.velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')}: ${getVelocityWithUnits(point.y, false)}`; + return `${$velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')}: ${getVelocityWithUnits(point.y, false)}`; } else if (context.datasetIndex === 2) { return `${$_('quantities.heartrate')}: ${getHeartRateWithUnits(point.y)}`; } else if (context.datasetIndex === 3) { @@ -150,8 +153,7 @@ } = { speed: { id: 'speed', - getLabel: () => - $settings.velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace'), + getLabel: () => ($velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')), getUnits: () => getVelocityUnits() }, hr: { @@ -196,7 +198,7 @@ } options.scales.yspeed['ticks'] = { callback: function (value: number) { - if ($settings.velocityUnits === 'speed') { + if ($velocityUnits === 'speed') { return value; } else { return secondsToHHMMSS(value); @@ -232,7 +234,7 @@ }); }); - $: if (chart && $settings) { + $: if (chart && $distanceUnits && $velocityUnits && $temperatureUnits) { let data = $gpxStatistics; // update data @@ -432,9 +434,7 @@ {$settings.velocityUnits === 'speed' - ? $_('chart.show_speed') - : $_('chart.show_pace')}{$velocityUnits === 'speed' ? $_('chart.show_speed') : $_('chart.show_pace')} diff --git a/website/src/lib/components/GPXStatistics.svelte b/website/src/lib/components/GPXStatistics.svelte index 92a3a7c3..3febeeb2 100644 --- a/website/src/lib/components/GPXStatistics.svelte +++ b/website/src/lib/components/GPXStatistics.svelte @@ -3,11 +3,14 @@ import Tooltip from '$lib/components/Tooltip.svelte'; import WithUnits from '$lib/components/WithUnits.svelte'; - import { gpxStatistics, settings } from '$lib/stores'; + import { gpxStatistics } from '$lib/stores'; + import { settings } from '$lib/db'; import { MoveDownRight, MoveUpRight, Ruler, Timer, Zap } from 'lucide-svelte'; import { _ } from 'svelte-i18n'; + + const { velocityUnits } = settings; @@ -36,7 +39,7 @@ {$settings.velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')} ({$_( + >{$velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')} ({$_( 'quantities.total' )} / {$_('quantities.moving')}) diff --git a/website/src/lib/components/Map.svelte b/website/src/lib/components/Map.svelte index aa369e2d..45395358 100644 --- a/website/src/lib/components/Map.svelte +++ b/website/src/lib/components/Map.svelte @@ -7,7 +7,8 @@ import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder'; import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'; - import { map, settings } from '$lib/stores'; + import { map } from '$lib/stores'; + import { settings } from '$lib/db'; import { locale } from 'svelte-i18n'; import { get } from 'svelte/store'; @@ -20,8 +21,9 @@ easing: () => 1 }; + const { distanceUnits } = settings; let scaleControl = new mapboxgl.ScaleControl({ - unit: $settings.distanceUnits + unit: $distanceUnits }); function toggleTerrain() { @@ -98,7 +100,7 @@ }); $: if ($map) { - scaleControl.setUnit($settings.distanceUnits); + scaleControl.setUnit($distanceUnits); } diff --git a/website/src/lib/components/Menu.svelte b/website/src/lib/components/Menu.svelte index 50505d4c..ef00029b 100644 --- a/website/src/lib/components/Menu.svelte +++ b/website/src/lib/components/Menu.svelte @@ -11,33 +11,23 @@ exportSelectedFiles, triggerFileInput, selectFiles, - settings, createFile } from '$lib/stores'; + import { derived } from 'svelte/store'; + import { canUndo, canRedo, dbUtils, fileObservers, settings } from '$lib/db'; - import { mode, resetMode, setMode } from 'mode-watcher'; + import { resetMode, setMode } from 'mode-watcher'; import { _ } from 'svelte-i18n'; - import { derived, get } from 'svelte/store'; - import { canUndo, canRedo, dbUtils, fileObservers } from '$lib/db'; let showDistanceMarkers = false; let showDirectionMarkers = false; - let currentMode = derived(mode, ($mode) => { - if (!$mode) { - return 'system'; - } else { - return $mode; - } - }); - - $: if ($settings.mode !== get(currentMode)) { - if ($settings.mode === 'system') { - resetMode(); - } else { - setMode($settings.mode); - } + const { distanceUnits, velocityUnits, temperatureUnits, mode } = settings; + $: if ($mode === 'system') { + resetMode(); + } else { + setMode($mode); } let undoDisabled = derived(canUndo, ($canUndo) => !$canUndo); @@ -132,7 +122,7 @@ > {$_('menu.distance_units')} - + {$_('menu.metric')} {$_('menu.imperial')} @@ -141,7 +131,7 @@ {$_('menu.velocity_units')} - + {$_('quantities.speed')} {$_('quantities.pace')} @@ -150,7 +140,7 @@ {$_('menu.temperature_units')} - + {$_('menu.celsius')} {$_('menu.fahrenheit')} @@ -160,7 +150,7 @@ {$_('menu.mode')} - + {$_('menu.light')} {$_('menu.dark')} {$_('menu.system')} diff --git a/website/src/lib/components/WithUnits.svelte b/website/src/lib/components/WithUnits.svelte index 339ff30c..28973374 100644 --- a/website/src/lib/components/WithUnits.svelte +++ b/website/src/lib/components/WithUnits.svelte @@ -1,5 +1,5 @@ {#if type === 'distance'} - {#if $settings.distanceUnits === 'metric'} + {#if $distanceUnits === 'metric'} {value.toFixed(2)} {showUnits ? $_('units.kilometers') : ''} {:else} {kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles') : ''} {/if} {:else if type === 'elevation'} - {#if $settings.distanceUnits === 'metric'} + {#if $distanceUnits === 'metric'} {value.toFixed(0)} {showUnits ? $_('units.meters') : ''} {:else} {metersToFeet(value).toFixed(0)} {showUnits ? $_('units.feet') : ''} {/if} {:else if type === 'speed'} - {#if $settings.distanceUnits === 'metric'} - {#if $settings.velocityUnits === 'speed'} + {#if $distanceUnits === 'metric'} + {#if $velocityUnits === 'speed'} {value.toFixed(2)} {showUnits ? $_('units.kilometers_per_hour') : ''} {:else} {secondsToHHMMSS(distancePerHourToSecondsPerDistance(value))} {showUnits ? $_('units.minutes_per_kilometer') : ''} {/if} - {:else if $settings.velocityUnits === 'speed'} + {:else if $velocityUnits === 'speed'} {kilometersToMiles(value).toFixed(2)} {showUnits ? $_('units.miles_per_hour') : ''} {:else} {secondsToHHMMSS(distancePerHourToSecondsPerDistance(kilometersToMiles(value)))} {showUnits ? $_('units.minutes_per_mile') : ''} {/if} {:else if type === 'temperature'} - {#if $settings.temperatureUnits === 'celsius'} + {#if $temperatureUnits === 'celsius'} {value} {showUnits ? $_('units.celsius') : ''} {:else} {celsiusToFahrenheit(value)} {showUnits ? $_('units.fahrenheit') : ''} diff --git a/website/src/lib/components/toolbar/tools/routing/Routing.svelte b/website/src/lib/components/toolbar/tools/routing/Routing.svelte index cf8011ac..0d4dcd58 100644 --- a/website/src/lib/components/toolbar/tools/routing/Routing.svelte +++ b/website/src/lib/components/toolbar/tools/routing/Routing.svelte @@ -7,7 +7,8 @@ import { CircleHelp } from 'lucide-svelte'; import { map, selectedFiles, Tool } from '$lib/stores'; - import { brouterProfiles, privateRoads, routing, routingProfile } from './Routing'; + import { settings } from '$lib/db'; + import { brouterProfiles, routingProfileSelectItem } from './Routing'; import { _ } from 'svelte-i18n'; import { get } from 'svelte/store'; @@ -23,6 +24,8 @@ let selectedId: string | null = null; let active = false; + const { privateRoads, routing } = settings; + $: if ($map) { // remove controls for deleted files routingControls.forEach((controls, fileId) => { @@ -82,7 +85,7 @@
- + diff --git a/website/src/lib/components/toolbar/tools/routing/Routing.ts b/website/src/lib/components/toolbar/tools/routing/Routing.ts index 9477af57..752a706a 100644 --- a/website/src/lib/components/toolbar/tools/routing/Routing.ts +++ b/website/src/lib/components/toolbar/tools/routing/Routing.ts @@ -1,8 +1,11 @@ import type { Coordinates } from "gpx"; import { TrackPoint } from "gpx"; import { get, writable } from "svelte/store"; +import { settings } from "$lib/db"; import { _ } from "svelte-i18n"; +const { routing, routingProfile, privateRoads } = settings; + export const brouterProfiles: { [key: string]: string } = { bike: 'Trekking-dry', racing_bike: 'fastbike', @@ -12,12 +15,24 @@ export const brouterProfiles: { [key: string]: string } = { water: 'river', railway: 'rail' }; -export const routingProfile = writable({ +export const routingProfileSelectItem = writable({ value: 'bike', label: get(_)('toolbar.routing.activities.bike') }); -export const routing = writable(true); -export const privateRoads = writable(false); +routingProfile.subscribe((value) => { + if (value !== get(routingProfileSelectItem).value) { + routingProfileSelectItem.update((item) => { + item.value = value; + item.label = get(_)(`toolbar.routing.activities.${value}`); + return item; + }); + } +}); +routingProfileSelectItem.subscribe((item) => { + if (item.value !== get(routingProfile)) { + routingProfile.set(item.value); + } +}); export function route(points: Coordinates[]): Promise { if (get(routing)) { diff --git a/website/src/lib/db.ts b/website/src/lib/db.ts index 5c70f42f..7cd417dc 100644 --- a/website/src/lib/db.ts +++ b/website/src/lib/db.ts @@ -3,6 +3,7 @@ import { GPXFile } from 'gpx'; import { type FreezedObject, type Patch, produceWithPatches, applyPatches } from 'structurajs'; import { writable, get, derived, type Readable, type Writable } from 'svelte/store'; import { fileOrder, selectedFiles } from './stores'; +import { mode } from 'mode-watcher'; class Database extends Dexie { @@ -259,4 +260,37 @@ export const dbUtils = { }); } } -} \ No newline at end of file +} + +function dexieSettingStore(setting: string, initial: any): Writable { + let store = writable(initial); + liveQuery(() => db.settings.get(setting)).subscribe(value => { + if (value !== undefined) { + store.set(value); + } + }); + return { + subscribe: store.subscribe, + set: (value: any) => db.settings.put(value, setting), + update: (callback: (value: any) => any) => { + let newValue = callback(get(store)); + db.settings.put(newValue, setting); + } + }; +} + +export const settings = { + distanceUnits: dexieSettingStore('distanceUnits', 'metric'), + velocityUnits: dexieSettingStore('velocityUnits', 'speed'), + temperatureUnits: dexieSettingStore('temperatureUnits', 'celsius'), + mode: dexieSettingStore('mode', (() => { + let currentMode: string | undefined = get(mode); + if (currentMode === undefined) { + currentMode = 'system'; + } + return currentMode; + })()), + routing: dexieSettingStore('routing', true), + routingProfile: dexieSettingStore('routingProfile', 'bike'), + privateRoads: dexieSettingStore('privateRoads', false), +}; \ No newline at end of file diff --git a/website/src/lib/stores.ts b/website/src/lib/stores.ts index 03ce7086..19e23e4c 100644 --- a/website/src/lib/stores.ts +++ b/website/src/lib/stores.ts @@ -57,12 +57,6 @@ selectedFiles.subscribe((selectedFiles) => { updateGPXData(); }); -export const settings = writable<{ [key: string]: any }>({ - distanceUnits: 'metric', - velocityUnits: 'speed', - temperatureUnits: 'celsius', - mode: 'system' -}); export const gpxLayers: Writable> = writable(new Map()); export enum Tool { diff --git a/website/src/lib/units.ts b/website/src/lib/units.ts index 64f1d1bd..8bc3eadc 100644 --- a/website/src/lib/units.ts +++ b/website/src/lib/units.ts @@ -1,7 +1,9 @@ import { get } from 'svelte/store'; -import { settings } from './stores'; +import { settings } from '$lib/db'; import { _ } from 'svelte-i18n'; +const { distanceUnits, velocityUnits, temperatureUnits } = settings; + export function kilometersToMiles(value: number) { return value * 0.621371; } @@ -39,9 +41,7 @@ export function getDistanceWithUnits(value: number, convert: boolean = true) { } export function getVelocityWithUnits(value: number, convert: boolean = true) { - const velocityUnits = get(settings).velocityUnits; - const distanceUnits = get(settings).distanceUnits; - if (velocityUnits === 'speed') { + if (get(velocityUnits) === 'speed') { if (convert) { return getConvertedVelocity(value).toFixed(2) + ' ' + getVelocityUnits(); } else { @@ -86,22 +86,20 @@ export function getTemperatureWithUnits(value: number, convert: boolean = true) // Get the units export function getDistanceUnits() { - return get(settings).distanceUnits === 'metric' ? get(_)('units.kilometers') : get(_)('units.miles'); + return get(distanceUnits) === 'metric' ? get(_)('units.kilometers') : get(_)('units.miles'); } export function getVelocityUnits() { - const velocityUnits = get(settings).velocityUnits; - const distanceUnits = get(settings).distanceUnits; - if (velocityUnits === 'speed') { - return distanceUnits === 'metric' ? get(_)('units.kilometers_per_hour') : get(_)('units.miles_per_hour'); + if (get(velocityUnits) === 'speed') { + return get(distanceUnits) === 'metric' ? get(_)('units.kilometers_per_hour') : get(_)('units.miles_per_hour'); } else { - return distanceUnits === 'metric' ? get(_)('units.minutes_per_kilometer') : get(_)('units.minutes_per_mile'); + return get(distanceUnits) === 'metric' ? get(_)('units.minutes_per_kilometer') : get(_)('units.minutes_per_mile'); } } export function getElevationUnits() { - return get(settings).distanceUnits === 'metric' ? get(_)('units.meters') : get(_)('units.feet'); + return get(distanceUnits) === 'metric' ? get(_)('units.meters') : get(_)('units.feet'); } export function getHeartRateUnits() { @@ -117,28 +115,26 @@ export function getPowerUnits() { } export function getTemperatureUnits() { - return get(settings).temperatureUnits === 'celsius' ? get(_)('units.celsius') : get(_)('units.fahrenheit'); + return get(temperatureUnits) === 'celsius' ? get(_)('units.celsius') : get(_)('units.fahrenheit'); } // Convert only the value export function getConvertedDistance(value: number) { - return get(settings).distanceUnits === 'metric' ? value : kilometersToMiles(value); + return get(distanceUnits) === 'metric' ? value : kilometersToMiles(value); } export function getConvertedElevation(value: number) { - return get(settings).distanceUnits === 'metric' ? value : metersToFeet(value); + return get(distanceUnits) === 'metric' ? value : metersToFeet(value); } export function getConvertedVelocity(value: number) { - const velocityUnits = get(settings).velocityUnits; - const distanceUnits = get(settings).distanceUnits; - if (velocityUnits === 'speed') { - return distanceUnits === 'metric' ? value : kilometersToMiles(value); + if (get(velocityUnits) === 'speed') { + return get(distanceUnits) === 'metric' ? value : kilometersToMiles(value); } else { - return distanceUnits === 'metric' ? distancePerHourToSecondsPerDistance(value) : distancePerHourToSecondsPerDistance(kilometersToMiles(value)); + return get(distanceUnits) === 'metric' ? distancePerHourToSecondsPerDistance(value) : distancePerHourToSecondsPerDistance(kilometersToMiles(value)); } } export function getConvertedTemperature(value: number) { - return get(settings).temperatureUnits === 'celsius' ? value : celsiusToFahrenheit(value); + return get(temperatureUnits) === 'celsius' ? value : celsiusToFahrenheit(value); } \ No newline at end of file