new setting: begin drawing a new trail from current location (#592)

* new setting: begin drawing a new trail from  current location

* apply only when drawing

* fix application when editing an existing route

* documentation

* ignore pointer events on location circles

* fix i18n

---------

Co-authored-by: Flomp <Flomp@users.noreply.github.com>
Co-authored-by: Christian Beutel <>
This commit is contained in:
slothful-vassal
2026-02-28 10:15:43 +01:00
committed by GitHub
parent 230f42d639
commit bd293e6739
19 changed files with 151 additions and 19 deletions

View File

@@ -5,7 +5,6 @@
import type { Trail } from "$lib/models/trail";
import type { Waypoint } from "$lib/models/waypoint";
import { theme } from "$lib/stores/theme_store";
import { fetchGPX } from "$lib/stores/trail_store";
import { findStartAndEndPoints } from "$lib/util/geojson_util";
import {
createMarkerFromWaypoint,
@@ -69,6 +68,7 @@
trail: Trail,
) => void;
oninit?: (map: M.Map) => void;
autoGeolocateOnDrawing?: boolean;
}
let {
@@ -99,6 +99,7 @@
onclick,
onUnclusteredClick,
oninit,
autoGeolocateOnDrawing = false,
}: Props = $props();
let mapContainer: HTMLDivElement;
@@ -592,6 +593,10 @@
if (trails[activeTrail]) {
removeStartEndMarkers(trails[activeTrail].id);
}
if (autoGeolocateOnDrawing) {
geolocate();
}
}
function stopDrawing() {
@@ -731,6 +736,8 @@
}
}
let geolocateControl : M.GeolocateControl;
onMount(async () => {
const initialState = {
lng: 0,
@@ -800,8 +807,7 @@
"top-left",
);
map.addControl(
new M.GeolocateControl({
geolocateControl = new M.GeolocateControl({
positionOptions: {
enableHighAccuracy: true,
},
@@ -809,7 +815,8 @@
animate: fitBounds == "animate",
},
trackUserLocation: true,
}));
});
map.addControl(geolocateControl);
if (showStyleSwitcher) {
map.addControl(switcherControl);
@@ -901,6 +908,17 @@
showWaypoints();
});
function geolocate() {
if (!page.data.settings?.behavior) return;
if (page.data.settings.behavior.allowAutoGeolocate === true) {
if (geolocateControl._watchState === 'OFF') {
geolocateControl.options.trackUserLocation = true;
geolocateControl.trigger();
}
}
}
onDestroy(() => {
map?.remove();
});
@@ -982,4 +1000,8 @@
padding-bottom: 2.5px;
@apply bg-menu-item-background-focus w-3 aspect-square rounded-full;
}
:global(.maplibregl-user-location-accuracy-circle, .maplibregl-user-location-dot) {
pointer-events: none;
}
</style>

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Routen hinzugefügt zu",
"after": "Nach",
"all-activities": "Alle Aktivitäten",
"allow-auto-geolocate": "Beginne das Zeichnen einer neuen Route am aktuellen Standort",
"alphabetical": "Alphabetisch",
"already-account": "Du hast bereits ein Konto?",
"altitude": "Höhe",
@@ -35,6 +36,7 @@
"basic-info": "Basisinformation",
"basque": "Baskisch",
"before": "Vor",
"behavior": "Verhalten",
"bicycle-parking": "Fahrrad-Parkplatz",
"bicycle-rental": "Fahrradverleih",
"bicycle-shop": "Fahrrad-Reparatur",
@@ -215,8 +217,8 @@
"invalid-username": "Ungültiger Nutzername",
"italian": "Italienisch",
"joined": "Beigetreten",
"keep-private": "Ohne Veröffentlichung fortfahren",
"keep-original": "",
"keep-private": "Ohne Veröffentlichung fortfahren",
"language": "Sprache",
"latitude": "Breitengrad",
"layer": "{n, plural, =1 {Ebene} other {Ebenen}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Added trails to",
"after": "After",
"all-activities": "All activities",
"allow-auto-geolocate": "Begin drawing a new trail from your current location",
"alphabetical": "Alphabetical",
"already-account": "Already have an account?",
"altitude": "Altitude",
@@ -35,6 +36,7 @@
"basic-info": "Basic Info",
"basque": "Basque",
"before": "Before",
"behavior": "Behavior",
"bicycle-parking": "Bicycle Parking",
"bicycle-rental": "Bicycle Rental",
"bicycle-shop": "Bicycle Shop",
@@ -215,8 +217,8 @@
"invalid-username": "Invalid username",
"italian": "Italian",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "Keep original",
"keep-private": "Keep private",
"language": "Language",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Rutas añadidas a",
"after": "Después",
"all-activities": "Todas las actividades",
"allow-auto-geolocate": "",
"alphabetical": "Alfabético",
"already-account": "¿Ya tienes una cuenta?",
"altitude": "Altitud",
@@ -213,9 +214,9 @@
"invalid-date": "Fecha no válida",
"invalid-username": "Usuario no válido",
"italian": "Italiano",
"keep-private": "Keep private",
"joined": "Afiliado",
"keep-original": "",
"keep-private": "Keep private",
"language": "Idioma",
"latitude": "Latitud",
"layer": "{n, plural, one {}=1 {Lista} other {Listas}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Ibilbideak hona gehitu dira",
"after": "Ondoren",
"all-activities": "Ekintza guztiak",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetikoa",
"already-account": "Baduzu kontua lehendik?",
"altitude": "Altuera",
@@ -215,8 +216,8 @@
"invalid-username": "Erabiltzailea ez da zuzena",
"italian": "Italiera",
"joined": "Sartu da",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Hizkuntza",
"latitude": "Latitudea",
"layer": "{n, plural, one {}=1 {geruza} other {geruza}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Ajouter les itinéraires à",
"after": "Après",
"all-activities": "Toutes les activités",
"allow-auto-geolocate": "",
"alphabetical": "Alphabétique",
"already-account": "Déjà un compte ?",
"altitude": "Altitude",
@@ -215,8 +216,8 @@
"invalid-username": "Nom d'utilisateur invalide",
"italian": "Italien",
"joined": "Rejoint",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Langue",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Calque} other {Calques}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Hozzáadott nyomvonalak a",
"after": "After",
"all-activities": "All activities",
"allow-auto-geolocate": "",
"alphabetical": "Betűrendben",
"already-account": "Már rendelkezik fiókkal?",
"altitude": "Magasság",
@@ -215,8 +216,8 @@
"invalid-username": "Érvénytelen felhasználó",
"italian": "Olasz",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Nyelf",
"latitude": "Szélesség",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Percorsi aggiunto a",
"after": "Dopo",
"all-activities": "Tutte le Attività",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetico",
"already-account": "Hai già un account?",
"altitude": "Altitudine",
@@ -215,8 +216,8 @@
"invalid-username": "Nome utente non valido",
"italian": "Italiano",
"joined": "Aggiunto",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Lingua",
"latitude": "Latitudine",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Route toegevoegd aan",
"after": "Na",
"all-activities": "Alle activiteiten",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetisch",
"already-account": "Heb je al een account?",
"altitude": "Hoogte",
@@ -216,8 +217,8 @@
"invalid-username": "Ongeldige gebruikersnaam",
"italian": "Italiaans",
"joined": "Aangesloten",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Taal",
"latitude": "Breedtegraad",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Dodaj szlaki do",
"after": "Po",
"all-activities": "Wszystkie aktywności",
"allow-auto-geolocate": "",
"alphabetical": "Alfabetyczne",
"already-account": "Czy masz już konto?",
"altitude": "Wysokość",
@@ -215,8 +216,8 @@
"invalid-username": "Błędna nazwa użytkownika",
"italian": "Włoski",
"joined": "Dołączono",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Język",
"latitude": "Szerokość",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "trilhas adicionada para",
"after": "Depois",
"all-activities": "Todas as atividades",
"allow-auto-geolocate": "",
"alphabetical": "Alfabético",
"already-account": "Já tem uma conta?",
"altitude": "Altitude",
@@ -215,8 +216,8 @@
"invalid-username": "Nome de usuário inválido",
"italian": "Italiano",
"joined": "Joined",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Língua",
"latitude": "Latitude",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "Added trails to",
"after": "После",
"all-activities": "Все активности",
"allow-auto-geolocate": "",
"alphabetical": "По алфавиту",
"already-account": "Уже есть аккаунт?",
"altitude": "Высота",
@@ -215,8 +216,8 @@
"invalid-username": "Некорректное имя пользователя",
"italian": "Итальянский",
"joined": "Зарегистрирован",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "Язык",
"latitude": "Широта",
"layer": "{n, plural, =1 {Layer} other {Layers}}",

View File

@@ -17,6 +17,7 @@
"added-trails-to": "添加路线到",
"after": "之后",
"all-activities": "所有活动",
"allow-auto-geolocate": "",
"alphabetical": "字母",
"already-account": "已注册账户?",
"altitude": "海拔",
@@ -215,8 +216,8 @@
"invalid-username": "无效用户名",
"italian": "意大利语",
"joined": "已加入",
"keep-private": "Keep private",
"keep-original": "",
"keep-private": "Keep private",
"language": "语言",
"latitude": "纬度",
"layer": "{n, plural, =1 {层} other {层}}",

View File

@@ -21,8 +21,8 @@ const SettingsCreateSchema = z.object({
trails: z.enum(["public", "private"]),
lists: z.enum(["public", "private"])
}).optional().nullable(),
notifications: z.record(z.enum(Object.values(NotificationType) as [string, ...string[]]), z.object({ web: z.boolean(), email: z.boolean() })).optional().nullable()
notifications: z.record(z.enum(Object.values(NotificationType) as [string, ...string[]]), z.object({ web: z.boolean(), email: z.boolean() })).optional().nullable(),
behavior: z.object({ allowAutoGeolocate: z.boolean() }).optional().nullable(),
}) satisfies ZodType<Settings>
ZodType<Partial<Comment>>

View File

@@ -30,6 +30,7 @@ class Settings {
user?: string;
privacy?: { account: "public" | "private", trails: "public" | "private", lists: "public" | "private" } | null
notifications?: Record<NotificationType, { web: boolean, email: boolean }> | null
behavior?: Behavior | null;
constructor(
unit: "metric" | "imperial",
@@ -54,5 +55,9 @@ class Settings {
}
}
export type Behavior = {
allowAutoGeolocate: boolean;
}
export { Settings };

View File

@@ -14,13 +14,41 @@
} from "$lib/stores/search_store";
import { settings_update } from "$lib/stores/settings_store";
import { currentUser } from "$lib/stores/user_store";
import { country_codes } from "$lib/util/country_code_util";
import { getIconForLocation } from "$lib/util/icon_util";
import { onMount } from "svelte";
import { _ } from "svelte-i18n";
import Toggle from "$lib/components/base/toggle.svelte";
import { show_toast } from "$lib/stores/toast_store.svelte.js";
let settings = $derived(page.data.settings);
let allowAutoGeolocate = $state(
page.data.settings.behavior?.allowAutoGeolocate ?? false,
);
async function handleAllowAutoGeolocateChange() {
if (!settings) {
return;
}
try {
if (!settings.behavior) {
settings.behavior = { allowAutoGeolocate: allowAutoGeolocate };
} else {
settings.behavior.allowAutoGeolocate = allowAutoGeolocate;
}
await settings_update(settings);
} catch (e) {
show_toast({
type: "error",
icon: "close",
text: "Error updating behavior settings",
});
console.error(e);
}
}
const mapFocus: SelectItem[] = [
{ text: $_("trail", { values: { n: 2 } }), value: "trails" },
{ text: $_("location"), value: "location" },
@@ -138,6 +166,18 @@
></Search>
</div>
{/if}
<div
class="mt-4 grid gap-4"
style="grid-template-columns: 1fr min-content ;"
>
<p>{$_("allow-auto-geolocate")}</p>
<div>
<Toggle
bind:value={allowAutoGeolocate}
onchange={handleAllowAutoGeolocateChange}
></Toggle>
</div>
</div>
</div>
<div>
<h4 class="text-xl font-medium mb-2">{$_("tilesets")}</h4>

View File

@@ -1504,6 +1504,7 @@
waypoints={$formData.expand?.waypoints_via_trail}
drawing={drawingActive}
showTerrain={true}
autoGeolocateOnDrawing={page.params.id === "new"}
onmarkerdragend={moveMarker}
activeTrail={0}
bind:map