mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:41:09 +02:00
feat(places): show reverse-geocoded location label during tracking
When tracking is active the workbench ListView used to show only raw
coordinates ("47.6630, 9.1750"). Now a human-readable location label
appears above the coords ("Münster Café" or "Konstanz, Germany"),
fed from the shared reverse-geocoding endpoint.
To avoid hammering the geocoding service while the user is stationary
and their GPS jitters by a few metres, the effect debounces to 1.5 s
and rounds coordinates to 4 decimal places (~10 m) before checking
whether a new reverse lookup is needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
286e273b18
commit
0c1eb623bb
1 changed files with 76 additions and 7 deletions
|
|
@ -7,7 +7,13 @@
|
|||
import { useAllPlaces } from './queries';
|
||||
import { placesStore } from './stores/places.svelte';
|
||||
import { trackingStore } from './stores/tracking.svelte';
|
||||
import { searchAddress, formatAddress, type GeocodingResult } from '$lib/geocoding';
|
||||
import {
|
||||
searchAddress,
|
||||
reverseGeocode,
|
||||
formatAddress,
|
||||
formatLocality,
|
||||
type GeocodingResult,
|
||||
} from '$lib/geocoding';
|
||||
import { Star, MapPin, Plus, PencilSimple, Trash, MagnifyingGlass } from '@mana/shared-icons';
|
||||
import type { ViewProps } from '$lib/app-registry';
|
||||
import { ContextMenu, type ContextMenuItem } from '@mana/shared-ui';
|
||||
|
|
@ -55,6 +61,40 @@
|
|||
other: 'Sonstiges',
|
||||
};
|
||||
|
||||
// --- Reverse geocode of current tracking position ---
|
||||
// When tracking is active we have fresh coordinates every few seconds, but
|
||||
// the GeolocationPosition object is replaced on every update. We debounce
|
||||
// by ~1.5 s and round to ~10 m precision so we only hit the geocoding
|
||||
// service when the user has actually moved, not on every micro-jitter.
|
||||
let currentLocationLabel = $state<string | null>(null);
|
||||
let lastReverseKey = '';
|
||||
let reverseDebounce: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
$effect(() => {
|
||||
const pos = trackingStore.currentPosition;
|
||||
if (!pos) {
|
||||
currentLocationLabel = null;
|
||||
lastReverseKey = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// Round to ~10 m precision (4 decimal places) so we don't re-fetch
|
||||
// on every tiny coordinate drift while standing still.
|
||||
const lat = pos.coords.latitude.toFixed(4);
|
||||
const lon = pos.coords.longitude.toFixed(4);
|
||||
const key = `${lat},${lon}`;
|
||||
if (key === lastReverseKey) return;
|
||||
lastReverseKey = key;
|
||||
|
||||
clearTimeout(reverseDebounce);
|
||||
reverseDebounce = setTimeout(async () => {
|
||||
const result = await reverseGeocode(pos.coords.latitude, pos.coords.longitude);
|
||||
if (result) {
|
||||
currentLocationLabel = formatLocality(result);
|
||||
}
|
||||
}, 1500);
|
||||
});
|
||||
|
||||
// --- Address autocomplete ---
|
||||
let addressQuery = $state('');
|
||||
let suggestions = $state<GeocodingResult[]>([]);
|
||||
|
|
@ -191,12 +231,20 @@
|
|||
{trackingStore.isTracking ? 'Tracking aktiv' : 'Tracking starten'}
|
||||
</button>
|
||||
{#if trackingStore.currentPosition}
|
||||
<span class="tracking-coords">
|
||||
{formatCoords(
|
||||
trackingStore.currentPosition.coords.latitude,
|
||||
trackingStore.currentPosition.coords.longitude
|
||||
)}
|
||||
</span>
|
||||
<div class="tracking-location">
|
||||
{#if currentLocationLabel}
|
||||
<span class="tracking-label">
|
||||
<MapPin size={10} />
|
||||
{currentLocationLabel}
|
||||
</span>
|
||||
{/if}
|
||||
<span class="tracking-coords">
|
||||
{formatCoords(
|
||||
trackingStore.currentPosition.coords.latitude,
|
||||
trackingStore.currentPosition.coords.longitude
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if trackingStore.error}
|
||||
|
|
@ -400,6 +448,27 @@
|
|||
animation: dot-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.tracking-location {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
gap: 0.0625rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.tracking-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.1875rem;
|
||||
font-size: 0.75rem;
|
||||
color: #0ea5e9;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 220px;
|
||||
}
|
||||
|
||||
.tracking-coords {
|
||||
font-size: 0.6875rem;
|
||||
color: hsl(var(--color-muted-foreground));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue