sonner on routing error, and dark mode

This commit is contained in:
vcoppe
2024-04-27 11:16:59 +02:00
parent 2ad0e9125e
commit ca7d85b421
13 changed files with 135 additions and 16 deletions

View File

@@ -15,8 +15,10 @@
"gpx": "file:../gpx",
"lucide-svelte": "^0.365.0",
"mapbox-gl": "^3.2.0",
"mode-watcher": "^0.3.0",
"sortablejs": "^1.15.2",
"svelte-i18n": "^4.0.0",
"svelte-sonner": "^0.3.22",
"tailwind-merge": "^2.2.2",
"tailwind-variants": "^0.2.1"
},
@@ -3939,6 +3941,14 @@
"mkdirp": "bin/cmd.js"
}
},
"node_modules/mode-watcher": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/mode-watcher/-/mode-watcher-0.3.0.tgz",
"integrity": "sha512-k8jjuTx94HaaRKWO6JDf8wL761hFatrTIHJKl+E+3JWcnv+GnMBH062zcLsy0lbCI3n7RZxxHaWi66auFnUO4g==",
"peerDependencies": {
"svelte": "^4.0.0"
}
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
@@ -5745,6 +5755,14 @@
}
}
},
"node_modules/svelte-sonner": {
"version": "0.3.22",
"resolved": "https://registry.npmjs.org/svelte-sonner/-/svelte-sonner-0.3.22.tgz",
"integrity": "sha512-1AEBl7rTP4oeMAmBmkcvoHNOwB8gPzz73RYApcY8pyDwbjBewU8ATnXV8N42omV1sQvtSX/X0o5A1nfkN3T6cg==",
"peerDependencies": {
"svelte": ">=3 <5"
}
},
"node_modules/tabbable": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",

View File

@@ -48,8 +48,10 @@
"gpx": "file:../gpx",
"lucide-svelte": "^0.365.0",
"mapbox-gl": "^3.2.0",
"mode-watcher": "^0.3.0",
"sortablejs": "^1.15.2",
"svelte-i18n": "^4.0.0",
"svelte-sonner": "^0.3.22",
"tailwind-merge": "^2.2.2",
"tailwind-variants": "^0.2.1"
}

View File

@@ -7,6 +7,7 @@
import Menu from '$lib/components/Menu.svelte';
import Toolbar from '$lib/components/toolbar/Toolbar.svelte';
import LayerControl from '$lib/components/layer-control/LayerControl.svelte';
import { Toaster } from '$lib/components/ui/sonner';
</script>
<div class="flex flex-col w-screen h-screen">
@@ -17,9 +18,18 @@
<LayerControl />
<GPXLayers />
<FileList />
<Toaster richColors />
</div>
<div class="h-48 flex flex-row gap-2 overflow-hidden">
<GPXData />
<ElevationProfile />
</div>
</div>
<style lang="postcss">
div :global(.toaster.group) {
@apply absolute;
@apply right-2;
--offset: 50px !important;
}
</style>

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { fileOrder, files, getFileIndex, selectedFiles, selectFiles } from '$lib/stores';
import { Button } from '$lib/components/ui/button';
import { ScrollArea } from '$lib/components/ui/scroll-area/index';
import Sortable from 'sortablejs/Sortable';
@@ -9,8 +10,8 @@
import { afterUpdate, onMount } from 'svelte';
import { get } from 'svelte/store';
let tabs: HTMLDivElement;
let buttons: HTMLButtonElement[] = [];
let container: HTMLDivElement;
let buttons: HTMLDivElement[] = [];
let sortable: Sortable;
function selectFile(file: GPXFile) {
@@ -60,7 +61,7 @@
}
onMount(() => {
sortable = Sortable.create(tabs, {
sortable = Sortable.create(container, {
forceAutoScrollFallback: true,
multiDrag: true,
multiDragKey: 'shift',
@@ -125,22 +126,29 @@
<div class="h-10 -translate-y-10 w-full pointer-events-none">
<ScrollArea orientation="horizontal" class="w-full h-full" scrollbarXClasses="h-2">
<div bind:this={tabs} class="flex flex-row gap-1">
<div bind:this={container} class="flex flex-row gap-1">
{#each $files as file, index}
<button
<div
bind:this={buttons[index]}
data-id={index}
class="my-1 px-1.5 py-1 rounded bg-secondary hover:bg-gray-200 shadow-none first:ml-1 last:mr-1 pointer-events-auto"
class="pointer-events-auto first:ml-1 last:mr-1 mb-1 bg-transparent"
>
{get(file).metadata.name}
</button>
<Button variant="outline" class="h-9 px-1.5 py-1 border-none shadow-md">
{get(file).metadata.name}
</Button>
</div>
{/each}
</div>
</ScrollArea>
</div>
<style lang="postcss">
div :global(.sortable-selected) {
@apply bg-background shadow;
div :global(button) {
@apply bg-accent;
@apply hover:bg-background;
}
div :global(.sortable-selected > button) {
@apply bg-background;
}
</style>

View File

@@ -162,11 +162,11 @@
}
div :global(.mapboxgl-ctrl-bottom-left) {
@apply bottom-9;
@apply bottom-[42px];
}
div :global(.mapboxgl-ctrl-bottom-right) {
@apply bottom-9;
@apply bottom-[42px];
}
div :global(.mapboxgl-popup) {

View File

@@ -17,10 +17,29 @@
settings
} from '$lib/stores';
import { mode, resetMode, setMode } from 'mode-watcher';
import { _ } from 'svelte-i18n';
import { derived, get } from 'svelte/store';
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);
}
}
</script>
<div class="absolute top-2 left-0 right-0 z-20 flex flex-row justify-center pointer-events-none">
@@ -126,6 +145,17 @@
</Menubar.SubContent>
</Menubar.Sub>
<Menubar.Separator />
<Menubar.Sub>
<Menubar.SubTrigger inset>{$_('menu.mode')}</Menubar.SubTrigger>
<Menubar.SubContent>
<Menubar.RadioGroup bind:value={$settings.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>
</Menubar.RadioGroup>
</Menubar.SubContent>
</Menubar.Sub>
<Menubar.Separator />
<Menubar.CheckboxItem bind:checked={showDistanceMarkers}>
{$_('menu.distance_markers')}
</Menubar.CheckboxItem>

View File

@@ -38,6 +38,12 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
let url = `https://routing.gpx.studio?lonlats=${points.map(point => `${point.lon.toFixed(8)},${point.lat.toFixed(8)}`).join('|')}&profile=${brouterProfile + (privateRoads ? '-private' : '')}&format=geojson&alternativeidx=0`;
let response = await fetch(url);
// Check if the response is ok
if (!response.ok) {
throw new Error(`${await response.text()}`);
}
let geojson = await response.json();
let route: TrackPoint[] = [];
@@ -66,7 +72,7 @@ async function getRoute(points: Coordinates[], brouterProfile: string, privateRo
coordinates[i][1] == Number(messages[messageIdx][latIdx]) / 1000000) {
messageIdx++;
if (messageIdx == messages.length) surface = "missing";
if (messageIdx == messages.length) surface = "unknown";
else surface = getSurface(messages[messageIdx][tagIdx]);
}
}

View File

@@ -3,7 +3,11 @@ import { get, type Writable } from "svelte/store";
import { computeAnchorPoints, type SimplifiedTrackPoint } from "./Simplify";
import mapboxgl from "mapbox-gl";
import { route } from "./Routing";
import { applyToFileElement, applyToFileStore } from "$lib/stores";
import { applyToFileElement } from "$lib/stores";
import { toast } from "svelte-sonner";
import { _ } from "svelte-i18n";
export class RoutingControls {
map: mapboxgl.Map;
@@ -100,7 +104,7 @@ export class RoutingControls {
createMarker(anchor: SimplifiedTrackPoint) {
let element = document.createElement('div');
element.className = `h-3 w-3 rounded-full bg-background border-2 border-black cursor-pointer`;
element.className = `h-3 w-3 rounded-full bg-white border-2 border-black cursor-pointer`;
let marker = new mapboxgl.Marker({
draggable: true,
@@ -380,7 +384,14 @@ export class RoutingControls {
try {
response = await route(targetCoordinates);
} catch (e) {
console.error(e);
console.log(e);
if (e.message.includes('from-position not mapped in existing datafile')) {
toast.error(get(_)("toolbar.routing.error.from"));
} else if (e.message.includes('to-position not mapped in existing datafile')) {
toast.error(get(_)("toolbar.routing.error.to"));
} else {
toast.error(e.message);
}
return false;
}

View File

@@ -0,0 +1 @@
export { default as Toaster } from "./sonner.svelte";

View File

@@ -0,0 +1,20 @@
<script lang="ts">
import { Toaster as Sonner, type ToasterProps as SonnerProps } from "svelte-sonner";
import { mode } from "mode-watcher";
type $$Props = SonnerProps;
</script>
<Sonner
theme={$mode}
class="toaster group"
toastOptions={{
classes: {
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton: "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton: "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...$$restProps}
/>

View File

@@ -12,6 +12,7 @@ export const settings = writable<{ [key: string]: any }>({
distanceUnits: 'metric',
velocityUnits: 'speed',
temperatureUnits: 'celsius',
mode: 'system'
});
export enum Tool {
ROUTING

View File

@@ -20,6 +20,10 @@
"temperature_units": "Temperature units",
"celsius": "Celsius",
"fahrenheit": "Fahrenheit",
"mode": "Mode",
"light": "Light",
"dark": "Dark",
"system": "System",
"distance_markers": "Show distance markers",
"direction_markers": "Show direction markers",
"about": "About",
@@ -42,6 +46,10 @@
"motorcycle": "Motorcycle",
"water": "Water",
"railway": "Railway"
},
"error": {
"from": "The start point is too far from the nearest road",
"to": "The end point is too far from the nearest road"
}
},
"time_tooltip": "Change the time and speed data",

View File

@@ -1,5 +1,9 @@
<script>
import '../app.pcss';
import { ModeWatcher } from 'mode-watcher';
</script>
<ModeWatcher />
<slot />