fix: Karte lazy-loaded, formatKm bei 0, Enter im Dialog
- TrailMap: IntersectionObserver für WebGL-Kontexte (max 8-16 gleichzeitig) → Karte erst laden, wenn sichtbar, rootMargin 200px für frühes Laden - Trail-Liste: formatKm zeigt 0 m als "0,0 km" statt "–" - Trail-Anlegen: Enter im Namensfeld triggert save(), saving-Guard hinzugefügt Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
60d5891bc9
commit
7bc128601a
2 changed files with 67 additions and 37 deletions
|
|
@ -62,6 +62,9 @@
|
|||
let highlightMarker: Marker | null = null
|
||||
|
||||
onMount(() => {
|
||||
let cleanupMap: (() => void) | null = null
|
||||
|
||||
function build() {
|
||||
const instance = new maplibregl.Map({
|
||||
container,
|
||||
style: {
|
||||
|
|
@ -92,7 +95,7 @@
|
|||
if (placing) onplace?.({ lat: e.lngLat.lat, lng: e.lngLat.lng })
|
||||
})
|
||||
|
||||
return () => {
|
||||
cleanupMap = () => {
|
||||
// Map.remove() räumt Controls auf, aber keine Marker — die tragen
|
||||
// eigene move-Listener auf der Karte und werden hier zuerst entfernt.
|
||||
for (const m of markerObjects) m.remove()
|
||||
|
|
@ -102,6 +105,26 @@
|
|||
|
||||
instance.remove()
|
||||
map = null
|
||||
ready = false
|
||||
}
|
||||
}
|
||||
|
||||
// Browser begrenzen WebGL-Kontexte auf rund 8 bis 16. In einer Liste
|
||||
// mit vielen Trails wären das zu viele — deshalb entsteht die Karte
|
||||
// erst, wenn ihre Kachel in den Sichtbereich scrollt.
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
for (const entry of entries) {
|
||||
if (entry.isIntersecting && !map) build()
|
||||
}
|
||||
},
|
||||
{ rootMargin: '200px' },
|
||||
)
|
||||
observer.observe(container)
|
||||
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
cleanupMap?.()
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -52,11 +52,13 @@
|
|||
}
|
||||
|
||||
function formatKm(m: number | undefined) {
|
||||
if (!m) return '–'
|
||||
// Nur fehlende Werte zeigen "–"; 0 ist eine gültige Länge.
|
||||
if (m == null) return '–'
|
||||
return `${(m / 1000).toFixed(1)} km`
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (saving) return
|
||||
if (!form.name.trim()) {
|
||||
error = 'Bitte einen Namen angeben.'
|
||||
return
|
||||
|
|
@ -169,7 +171,12 @@
|
|||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="trail-name">Name</Label>
|
||||
<Input id="trail-name" bind:value={form.name} placeholder="z. B. Steinberg-Abfahrt" />
|
||||
<Input
|
||||
id="trail-name"
|
||||
bind:value={form.name}
|
||||
placeholder="z. B. Steinberg-Abfahrt"
|
||||
onkeydown={(e) => e.key === 'Enter' && save()}
|
||||
/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="trail-desc">Beschreibung</Label>
|
||||
|
|
|
|||
Loading…
Reference in a new issue