feat: task 2.8 camera control trio + follow toggle
- src/map/core/map-pref-store.ts: mapFollow boolean (default true) +
setter. Persisted via trm-map-prefs.
- src/map/core/camera/default-camera.tsx: <MapDefaultCamera /> fits
the snapshot's bounds once per activeEventId change. Uses a
fittedFor ref; resets to null when activeEventId becomes null.
Single-point events centre+zoom 12; multi-point fitBounds with
padding capped at min(canvas*0.1, 80).
- src/map/core/camera/selected-device.tsx: <MapSelectedDevice />
pans+zooms on selection change, smooth pans on subsequent position
updates with mapFollow on. Separate effect listens for user-gesture
movestart (originalEvent truthy) and flips mapFollow off.
- src/map/core/camera/map-camera.tsx: <MapCamera coordinates> imperative
one-shot. Phase 2 doesn't use it; primitive for replay (Phase 4) and
future "fit to all" UI.
- src/map/core/follow-toggle.tsx: <FollowToggle /> icon-button using
Lucide Locate/LocateOff. Sits below the trails toggle.
- src/routes/_authed/monitor.tsx: renders FollowToggle, MapDefaultCamera,
MapSelectedDevice.
Deviations:
- Manual-pan listener uses an inline { originalEvent?: unknown } type
instead of MapLibre's MapMouseEvent|MapTouchEvent union (typing
friction across version bumps).
- MapDefaultCamera clears fittedFor on activeEventId === null so
re-selecting the same event later re-fits.
Bundle: main 395KB / 120KB gz, no measurable change.
This commit is contained in:
@@ -188,8 +188,8 @@ Three new files plus orchestration in the monitor route:
|
||||
3. `subscribe('event:<new>')`.
|
||||
4. On success → `applySnapshot(eventId, snapshot)` + persist to `localStorage`.
|
||||
5. On failure → `console.warn` and leave previous state alone.
|
||||
Out-of-order safety via per-call version counter; `null` clears the active event.
|
||||
Plus `readSavedActiveEventId()` for callers that want to know what the persisted choice is.
|
||||
Out-of-order safety via per-call version counter; `null` clears the active event.
|
||||
Plus `readSavedActiveEventId()` for callers that want to know what the persisted choice is.
|
||||
- **`src/ui/components/event-picker.tsx`** — `<EventPicker activeEventId, onChange>`. Click-to-open dropdown with click-outside-to-close. Shows the events list sorted most-recent-first; each row displays name + date + discipline. Disabled state when loading / errored / empty.
|
||||
- **`src/live/index.ts`** — re-exports `useActiveEventOrchestration` + `readSavedActiveEventId`.
|
||||
- **`src/routes/_authed/monitor.tsx`** — orchestration:
|
||||
@@ -204,6 +204,7 @@ Three new files plus orchestration in the monitor route:
|
||||
3. Logout-clears-saved-event-id: documented as a Phase 1 follow-up in this task's risks section. Not implemented here — `performLogout` (Phase 1.8) doesn't currently clear localStorage. A small follow-up patch will pull `localStorage.removeItem('trm-active-event-id')` into the logout flow.
|
||||
|
||||
**Smoke check (local `pnpm dev`):**
|
||||
|
||||
- `/monitor` shows the event picker top-left. Clicking it opens the dropdown with the seeded events.
|
||||
- On a fresh page load (with stage Directus reachable + a connected WS): the dogfood event auto-selects within ~1s; the snapshot of seeded positions appears as map markers.
|
||||
- Switching events: previous event's markers disappear, new event's markers appear, no leftover state.
|
||||
|
||||
Reference in New Issue
Block a user