From 8536ba422c6835d22367e5372ec96ab2ab596612 Mon Sep 17 00:00:00 2001 From: Christian Beutel <> Date: Sun, 12 Jan 2025 15:29:51 +0100 Subject: [PATCH] adds search to trail edit --- web/src/css/components.css | 19 ++++ web/src/lib/i18n/locales/de.json | 3 + web/src/lib/i18n/locales/en.json | 3 + web/src/lib/i18n/locales/es.json | 3 + web/src/lib/i18n/locales/fr.json | 3 + web/src/lib/i18n/locales/hu.json | 3 + web/src/lib/i18n/locales/it.json | 3 + web/src/lib/i18n/locales/nl.json | 3 + web/src/lib/i18n/locales/pl.json | 3 + web/src/lib/i18n/locales/pt.json | 3 + web/src/lib/i18n/locales/zh.json | 3 + web/src/routes/trail/edit/[id]/+page.svelte | 104 ++++++++++++++++++-- 12 files changed, 144 insertions(+), 9 deletions(-) diff --git a/web/src/css/components.css b/web/src/css/components.css index 3c35d235..7c4af374 100644 --- a/web/src/css/components.css +++ b/web/src/css/components.css @@ -94,6 +94,25 @@ border-color: rgba(var(--primary)) transparent rgba(var(--primary)) transparent; } +.spinner-light:after { + border: 6px solid #fff; + border-color: #fff transparent #fff transparent; +} + +.spinner-small { + width: 24px; + height: 24px; + display: grid; + align-content: center; + justify-content: center; +} + +.spinner-small:after { + border-width: 2px; + width: 16px; + height: 16px; +} + @keyframes spinner { 0% { transform: rotate(0deg); diff --git a/web/src/lib/i18n/locales/de.json b/web/src/lib/i18n/locales/de.json index c308fb3f..543db179 100644 --- a/web/src/lib/i18n/locales/de.json +++ b/web/src/lib/i18n/locales/de.json @@ -80,6 +80,7 @@ "edit": "Bearbeiten", "edit-entry": "Eintrag bearbeiten", "edit-list": "Liste bearbeiten", + "edit-route": "", "edit-waypoint": "Wegpunkt bearbeiten", "edited": "bearbeitet", "elevation-gain": "Höhenunterschied (aufw.)", @@ -259,6 +260,7 @@ "speed": "Geschwindigkeit", "statistics": "Statistiken", "stop-drawing": "Zeichnen beenden", + "stop-editing": "", "summit-book": "Gipfelbuch", "table": "Tabelle", "text": "Text", @@ -270,6 +272,7 @@ "units": "Einheiten", "upload-file": "Datei hochladen", "upload-gpx": "GPX hochladen", + "upload-new-file": "", "uploaded": "hochgeladen", "username": "Nutzername", "view": "Ansehen", diff --git a/web/src/lib/i18n/locales/en.json b/web/src/lib/i18n/locales/en.json index e245d22a..071a62cf 100644 --- a/web/src/lib/i18n/locales/en.json +++ b/web/src/lib/i18n/locales/en.json @@ -80,6 +80,7 @@ "edit": "Edit", "edit-entry": "Edit Entry", "edit-list": "Edit List", + "edit-route": "Edit route", "edit-waypoint": "Edit Waypoint", "edited": "edited", "elevation-gain": "Elevation Gain", @@ -259,6 +260,7 @@ "speed": "Speed", "statistics": "Statistics", "stop-drawing": "Stop drawing", + "stop-editing": "Stop editing", "summit-book": "Summit Book", "table": "Table", "text": "Text", @@ -270,6 +272,7 @@ "units": "Units", "upload-file": "Upload file", "upload-gpx": "Upload GPX", + "upload-new-file": "Upload new file", "uploaded": "uploaded", "username": "Username", "view": "View", diff --git a/web/src/lib/i18n/locales/es.json b/web/src/lib/i18n/locales/es.json index 74c7df75..e9eff65c 100644 --- a/web/src/lib/i18n/locales/es.json +++ b/web/src/lib/i18n/locales/es.json @@ -80,6 +80,7 @@ "edit": "Editar", "edit-entry": "Editar entrada", "edit-list": "Editar Lista", + "edit-route": "", "edit-waypoint": "Editar Punto de Interés", "edited": "editado", "elevation-gain": "Ascenso", @@ -259,6 +260,7 @@ "speed": "Velocidad", "statistics": "Estadísticas", "stop-drawing": "Parar de diseñar", + "stop-editing": "", "summit-book": "Libro de ascensos", "table": "Tabla", "text": "Texto", @@ -270,6 +272,7 @@ "units": "Unidades", "upload-file": "Cargar archivo", "upload-gpx": "Cargar GPX", + "upload-new-file": "", "uploaded": "cargado", "username": "Nombre de usuario", "view": "Ver", diff --git a/web/src/lib/i18n/locales/fr.json b/web/src/lib/i18n/locales/fr.json index 74da3927..c84bd3d3 100644 --- a/web/src/lib/i18n/locales/fr.json +++ b/web/src/lib/i18n/locales/fr.json @@ -80,6 +80,7 @@ "edit": "Editer", "edit-entry": "Éditer une entrée", "edit-list": "Éditer la liste", + "edit-route": "", "edit-waypoint": "Éditer le point de repère", "edited": "edited", "elevation-gain": "Dénivelé positif", @@ -259,6 +260,7 @@ "speed": "Vitesse", "statistics": "Statistics", "stop-drawing": "Arrêter de tracer", + "stop-editing": "", "summit-book": "Liste des ascensions", "table": "Tableau", "text": "Texte", @@ -270,6 +272,7 @@ "units": "Unités", "upload-file": "Importer un fichier", "upload-gpx": "Envoyer un GPX", + "upload-new-file": "", "uploaded": "téléchargé", "username": "Nom d'utilisateur", "view": "Afficher", diff --git a/web/src/lib/i18n/locales/hu.json b/web/src/lib/i18n/locales/hu.json index f2bcc1ac..dbfea04d 100644 --- a/web/src/lib/i18n/locales/hu.json +++ b/web/src/lib/i18n/locales/hu.json @@ -80,6 +80,7 @@ "edit": "Szerkesztés", "edit-entry": "Bejegyzés szerkesztése", "edit-list": "Lista szerkesztése", + "edit-route": "", "edit-waypoint": "Útvonalpont szerkesztése", "edited": "edited", "elevation-gain": "Magasságnövekedés", @@ -259,6 +260,7 @@ "speed": "Speed", "statistics": "Statistics", "stop-drawing": "Stop drawing", + "stop-editing": "", "summit-book": "Csúcspont könyv", "table": "Táblázat", "text": "Szöveg", @@ -270,6 +272,7 @@ "units": "Mértékegységek", "upload-file": "Fájl feltöltése", "upload-gpx": "GPX feltöltése", + "upload-new-file": "", "uploaded": "uploaded", "username": "Felhasználónév", "view": "View", diff --git a/web/src/lib/i18n/locales/it.json b/web/src/lib/i18n/locales/it.json index 06c41681..6cd216f4 100644 --- a/web/src/lib/i18n/locales/it.json +++ b/web/src/lib/i18n/locales/it.json @@ -80,6 +80,7 @@ "edit": "Modifica", "edit-entry": "Modifica voce", "edit-list": "Modifica lista", + "edit-route": "", "edit-waypoint": "Modifica waypoint", "edited": "modificato", "elevation-gain": "Guadagno di quota", @@ -259,6 +260,7 @@ "speed": "Velocità", "statistics": "Statistiche", "stop-drawing": "Smettere di disegnare", + "stop-editing": "", "summit-book": "Libro di vetta", "table": "Tavolo", "text": "Testo", @@ -270,6 +272,7 @@ "units": "Unità", "upload-file": "Carica file", "upload-gpx": "Carica file GPX", + "upload-new-file": "", "uploaded": "caricato", "username": "Nome utente", "view": "Visualizza", diff --git a/web/src/lib/i18n/locales/nl.json b/web/src/lib/i18n/locales/nl.json index e506db9e..80985e65 100644 --- a/web/src/lib/i18n/locales/nl.json +++ b/web/src/lib/i18n/locales/nl.json @@ -80,6 +80,7 @@ "edit": "Bewerken", "edit-entry": "Item bewerken", "edit-list": "Lijst aanpassen", + "edit-route": "", "edit-waypoint": "Routepunt aanpassen", "edited": "edited", "elevation-gain": "Hoogteverschil", @@ -259,6 +260,7 @@ "speed": "Speed", "statistics": "Statistics", "stop-drawing": "Stop drawing", + "stop-editing": "", "summit-book": "Bergtopboek", "table": "Tabel", "text": "Tekst", @@ -270,6 +272,7 @@ "units": "Eenheden", "upload-file": "Bestand uploaden", "upload-gpx": "GPX-bestand uploaden", + "upload-new-file": "", "uploaded": "uploaded", "username": "Gebruikersnaam", "view": "View", diff --git a/web/src/lib/i18n/locales/pl.json b/web/src/lib/i18n/locales/pl.json index 92c8183a..261b10dd 100644 --- a/web/src/lib/i18n/locales/pl.json +++ b/web/src/lib/i18n/locales/pl.json @@ -80,6 +80,7 @@ "edit": "Edytuj", "edit-entry": "Edytuj pozycję", "edit-list": "Edytuj Listę", + "edit-route": "", "edit-waypoint": "Edytuj Punkt", "edited": "edited", "elevation-gain": "Przyrost wysokości", @@ -259,6 +260,7 @@ "speed": "Prędkość", "statistics": "Statystyki", "stop-drawing": "Przestań rysować", + "stop-editing": "", "summit-book": "Logbook", "table": "Tabela", "text": "Tekst", @@ -270,6 +272,7 @@ "units": "Jednostki", "upload-file": "Przesyłanie pliku", "upload-gpx": "Importuj GPX", + "upload-new-file": "", "uploaded": "wgrany", "username": "Nazwa Użytkownika", "view": "Widok", diff --git a/web/src/lib/i18n/locales/pt.json b/web/src/lib/i18n/locales/pt.json index adba37cb..749072f1 100644 --- a/web/src/lib/i18n/locales/pt.json +++ b/web/src/lib/i18n/locales/pt.json @@ -80,6 +80,7 @@ "edit": "Editar", "edit-entry": "Editar entrada", "edit-list": "Editar lista", + "edit-route": "", "edit-waypoint": "Editar ponto de passagem", "edited": "edited", "elevation-gain": "Ganho de elevação", @@ -259,6 +260,7 @@ "speed": "Velocidade", "statistics": "Statistics", "stop-drawing": "Parar desenho", + "stop-editing": "", "summit-book": "Livro da cimeira", "table": "Tabela", "text": "Texto", @@ -270,6 +272,7 @@ "units": "Unidades", "upload-file": "Subir arquivo", "upload-gpx": "Carregar GPX", + "upload-new-file": "", "uploaded": "carregado", "username": "Nome de utilizador", "view": "Ver", diff --git a/web/src/lib/i18n/locales/zh.json b/web/src/lib/i18n/locales/zh.json index 30ad7d7b..d92f092a 100644 --- a/web/src/lib/i18n/locales/zh.json +++ b/web/src/lib/i18n/locales/zh.json @@ -80,6 +80,7 @@ "edit": "编辑", "edit-entry": "编辑日程", "edit-list": "编辑列表", + "edit-route": "", "edit-waypoint": "编辑坐标", "edited": "edited", "elevation-gain": "上升海拔", @@ -259,6 +260,7 @@ "speed": "速度", "statistics": "Statistics", "stop-drawing": "停止绘制", + "stop-editing": "", "summit-book": "详细日程", "table": "表格", "text": "文本", @@ -270,6 +272,7 @@ "units": "单位", "upload-file": "上传文件", "upload-gpx": "上传 GPX", + "upload-new-file": "", "uploaded": "已上传", "username": "用户名", "view": "查看", diff --git a/web/src/routes/trail/edit/[id]/+page.svelte b/web/src/routes/trail/edit/[id]/+page.svelte index 5a01753b..ae4b2900 100644 --- a/web/src/routes/trail/edit/[id]/+page.svelte +++ b/web/src/routes/trail/edit/[id]/+page.svelte @@ -70,6 +70,10 @@ import { backInOut } from "svelte/easing"; import { scale } from "svelte/transition"; import { z } from "zod"; + import Search, { + type SearchItem, + } from "$lib/components/base/search.svelte"; + import { country_codes } from "$lib/util/country_code_util.js"; export let data; @@ -96,6 +100,8 @@ let overwriteGPX = false; let draggingMarker = false; + let searchDropdownItems: SearchItem[] = []; + const ClientTrailCreateSchema = TrailCreateSchema.extend({ expand: z .object({ @@ -523,6 +529,12 @@ addAnchor(e.lngLat.lat, e.lngLat.lng, anchors.length); } else { const previousAnchor = anchors[anchorCount - 1]; + const anchor = addAnchor( + e.lngLat.lat, + e.lngLat.lng, + anchors.length, + ); + const markerText = startAnchorLoading(anchor); try { const routeWaypoints = await calculateRouteBetween( previousAnchor.lat, @@ -533,7 +545,6 @@ autoRouting, ); insertIntoRoute(routeWaypoints); - addAnchor(e.lngLat.lat, e.lngLat.lng, anchors.length); updateTrailWithRouteData(); } catch (e) { console.error(e); @@ -542,6 +553,8 @@ icon: "close", type: "error", }); + } finally { + stopAnchorLoading(anchor, markerText); } } } @@ -567,14 +580,16 @@ (e) => { draggingMarker = true; }, - (_) => { + async (_) => { if (!drawingActive) { return; } const position = marker.getLngLat(); anchor.lat = position.lat; anchor.lon = position.lng; - recalculateRoute(anchors.findIndex((a) => a.id == anchor.id)); + await recalculateRoute( + anchors.findIndex((a) => a.id == anchor.id), + ); draggingMarker = false; }, ); @@ -587,7 +602,32 @@ return anchor; } - function removeAnchor(anchorIndex: number) { + function startAnchorLoading(anchor: ValhallaAnchor) { + const markerIcon = anchor.marker?.getElement(); + if (!markerIcon) { + return null; + } + markerIcon.classList.add("spinner", "spinner-light", "spinner-small"); + const savedMarkerNumber = markerIcon.textContent; + markerIcon.textContent = ""; + + return savedMarkerNumber; + } + + function stopAnchorLoading(anchor: ValhallaAnchor, index: string | null) { + const markerIcon = anchor.marker?.getElement(); + if (!markerIcon || !index) { + return; + } + markerIcon.classList.remove( + "spinner", + "spinner-light", + "spinner-small", + ); + markerIcon.textContent = index; + } + + async function removeAnchor(anchorIndex: number) { if (!drawingActive) { return; } @@ -610,11 +650,13 @@ updateTrailWithRouteData(); } else { deleteFromRoute(anchorIndex - 1); - recalculateRoute(anchorIndex); + await recalculateRoute(anchorIndex); } } async function recalculateRoute(anchorIndex: number) { + const markerText = startAnchorLoading(anchors[anchorIndex]); + const anchor = anchors[anchorIndex]; if (!anchor) { return; @@ -661,6 +703,8 @@ icon: "close", type: "error", }); + } finally { + stopAnchorLoading(anchors[anchorIndex], markerText); } } @@ -676,6 +720,8 @@ data.event.lngLat.lng, data.segment + 1, ); + const markerText = startAnchorLoading(anchor); + for (let i = data.segment + 2; i < anchors.length; i++) { const anchor = anchors[i]; const markerIcon = anchor.marker?.getElement(); @@ -716,6 +762,8 @@ icon: "close", type: "error", }); + } finally { + stopAnchorLoading(anchor, markerText); } } @@ -735,6 +783,30 @@ function updateTrailOnMap() { mapTrail = [$formData as Trail]; } + + function handleSearchClick(item: SearchItem) { + map.flyTo({ + center: [item.value._geo.lng, item.value._geo.lat], + zoom: 13, + animate: false, + }); + } + + async function searchCities(q: string) { + const r = await fetch("/api/v1/search/cities500", { + method: "POST", + body: JSON.stringify({ q: q, options: { limit: 5 } }), + }); + const result = await r.json(); + searchDropdownItems = result.hits.map((h: Record) => ({ + text: h.name, + description: `${h.division ? `${h.division} | ` : ""}${ + country_codes[h["country code"] as keyof typeof country_codes] + }`, + value: h, + icon: "city", + })); + } @@ -750,12 +822,22 @@ class="overflow-y-auto overflow-x-hidden flex flex-col gap-4 px-8 order-1 md:order-none mt-8 md:mt-0" use:form > + searchCities(e.detail)} + on:click={(e) => handleSearchClick(e.detail)} + placeholder="{$_('search-cities')}..." + items={searchDropdownItems} + > +

{$_("pick-a-trail")}

{$formData.expand?.gpx_data + ? $_("upload-new-file") + : $_("upload-file")} {#if PUBLIC_VALHALLA_URL}
@@ -768,9 +850,13 @@ type="button" on:click={drawingActive ? stopDrawing : startDrawing} > - {drawingActive - ? $_("stop-drawing") - : $_("draw-a-route")} {/if}