mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-01 08:12:32 +00:00
store settings
This commit is contained in:
@@ -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 @@
|
||||
<Tooltip side="left">
|
||||
<Zap slot="data" size="16" />
|
||||
<span slot="tooltip"
|
||||
>{$settings.velocityUnits === 'speed'
|
||||
? $_('chart.show_speed')
|
||||
: $_('chart.show_pace')}</span
|
||||
>{$velocityUnits === 'speed' ? $_('chart.show_speed') : $_('chart.show_pace')}</span
|
||||
>
|
||||
</Tooltip>
|
||||
</ToggleGroup.Item>
|
||||
|
@@ -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;
|
||||
</script>
|
||||
|
||||
<Card.Root class="h-full overflow-hidden border-none shadow-none min-w-48 pl-4">
|
||||
@@ -36,7 +39,7 @@
|
||||
<WithUnits value={$gpxStatistics.global.speed.moving} type="speed" />
|
||||
</span>
|
||||
<span slot="tooltip"
|
||||
>{$settings.velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')} ({$_(
|
||||
>{$velocityUnits === 'speed' ? $_('quantities.speed') : $_('quantities.pace')} ({$_(
|
||||
'quantities.total'
|
||||
)} / {$_('quantities.moving')})</span
|
||||
>
|
||||
|
@@ -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);
|
||||
}
|
||||
</script>
|
||||
|
||||
|
@@ -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 @@
|
||||
><Menubar.Sub>
|
||||
<Menubar.SubTrigger inset>{$_('menu.distance_units')}</Menubar.SubTrigger>
|
||||
<Menubar.SubContent>
|
||||
<Menubar.RadioGroup bind:value={$settings.distanceUnits}>
|
||||
<Menubar.RadioGroup bind:value={$distanceUnits}>
|
||||
<Menubar.RadioItem value="metric">{$_('menu.metric')}</Menubar.RadioItem>
|
||||
<Menubar.RadioItem value="imperial">{$_('menu.imperial')}</Menubar.RadioItem>
|
||||
</Menubar.RadioGroup>
|
||||
@@ -141,7 +131,7 @@
|
||||
<Menubar.Sub>
|
||||
<Menubar.SubTrigger inset>{$_('menu.velocity_units')}</Menubar.SubTrigger>
|
||||
<Menubar.SubContent>
|
||||
<Menubar.RadioGroup bind:value={$settings.velocityUnits}>
|
||||
<Menubar.RadioGroup bind:value={$velocityUnits}>
|
||||
<Menubar.RadioItem value="speed">{$_('quantities.speed')}</Menubar.RadioItem>
|
||||
<Menubar.RadioItem value="pace">{$_('quantities.pace')}</Menubar.RadioItem>
|
||||
</Menubar.RadioGroup>
|
||||
@@ -150,7 +140,7 @@
|
||||
<Menubar.Sub>
|
||||
<Menubar.SubTrigger inset>{$_('menu.temperature_units')}</Menubar.SubTrigger>
|
||||
<Menubar.SubContent>
|
||||
<Menubar.RadioGroup bind:value={$settings.temperatureUnits}>
|
||||
<Menubar.RadioGroup bind:value={$temperatureUnits}>
|
||||
<Menubar.RadioItem value="celsius">{$_('menu.celsius')}</Menubar.RadioItem>
|
||||
<Menubar.RadioItem value="fahrenheit">{$_('menu.fahrenheit')}</Menubar.RadioItem>
|
||||
</Menubar.RadioGroup>
|
||||
@@ -160,7 +150,7 @@
|
||||
<Menubar.Sub>
|
||||
<Menubar.SubTrigger inset>{$_('menu.mode')}</Menubar.SubTrigger>
|
||||
<Menubar.SubContent>
|
||||
<Menubar.RadioGroup bind:value={$settings.mode}>
|
||||
<Menubar.RadioGroup bind:value={$mode}>
|
||||
<Menubar.RadioItem value="light">{$_('menu.light')}</Menubar.RadioItem>
|
||||
<Menubar.RadioItem value="dark">{$_('menu.dark')}</Menubar.RadioItem>
|
||||
<Menubar.RadioItem value="system">{$_('menu.system')}</Menubar.RadioItem>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { settings } from '$lib/stores';
|
||||
import { settings } from '$lib/db';
|
||||
import {
|
||||
celsiusToFahrenheit,
|
||||
distancePerHourToSecondsPerDistance,
|
||||
@@ -13,36 +13,38 @@
|
||||
export let value: number;
|
||||
export let type: 'distance' | 'elevation' | 'speed' | 'temperature' | 'time';
|
||||
export let showUnits: boolean = true;
|
||||
|
||||
const { distanceUnits, velocityUnits, temperatureUnits } = settings;
|
||||
</script>
|
||||
|
||||
{#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') : ''}
|
||||
|
@@ -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 @@
|
||||
<ToolbarItemMenu tool={Tool.ROUTING} bind:active>
|
||||
<div class="w-full flex flex-row justify-between items-center gap-2">
|
||||
<Label>{$_('toolbar.routing.activity')}</Label>
|
||||
<Select.Root bind:selected={$routingProfile}>
|
||||
<Select.Root bind:selected={$routingProfileSelectItem}>
|
||||
<Select.Trigger class="h-8 w-40">
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
|
@@ -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<TrackPoint[]> {
|
||||
if (get(routing)) {
|
||||
|
@@ -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 {
|
||||
|
||||
@@ -260,3 +261,36 @@ export const dbUtils = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dexieSettingStore(setting: string, initial: any): Writable<any> {
|
||||
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),
|
||||
};
|
@@ -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<Map<string, GPXLayer>> = writable(new Map());
|
||||
|
||||
export enum Tool {
|
||||
|
@@ -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);
|
||||
}
|
Reference in New Issue
Block a user