Commit graph

9 commits

Author SHA1 Message Date
Ullrich Schäfer
08070cdd90
Sync notes through GPX, Journal, and Planner roundtrip
Full notes lifecycle:
- GPX: description field in GpxData, <metadata><desc> in generate/parse
- Export: Plan GPX and Save to Journal include notes as description
- Journal: updateRoute extracts description from GPX, stores on route
- Reimport: Edit in Planner passes notes via URL params → Yjs Y.Text
- Drop import: GPX with <desc> restores notes in session

Spec updated: session-notes gains GPX export, Journal sync, and
reimport requirements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 03:35:40 +02:00
Ullrich Schäfer
efdb3c1973
Add multi-day data model, computeDays, and GPX roundtrip
- overnight.ts: Yjs helpers to set/clear/check overnight flag on waypoints
- compute-days.ts: Pure function splitting routes into DayStage[] at day breaks
- use-days.ts: Reactive hook mapping Yjs state into computeDays() input
- GPX generate: emit <type>overnight</type> for isDayBreak waypoints
- GPX parse: recognize <type>overnight</type> and set isDayBreak on waypoints

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:51:31 +02:00
Ullrich Schäfer
6ccf7af7b1
Fix no-go area parsing for namespaced XML elements
querySelectorAll('nogo') doesn't match <trails:nogo>. Now matches
both unprefixed and prefixed element names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 12:26:54 +01:00
Ullrich Schäfer
4b711abaec
Add split export: Export Route vs Export Plan
Split button with default "Export GPX" (track only) and dropdown:
- Export Route: clean track for use in any app
- Export Plan: track + waypoints + no-go areas in GPX extensions
  (trails:planning namespace) for reimporting into the planner

Also:
- Add no-go area serialization to generateGpx (GPX extensions)
- Parse no-go areas from GPX extensions on import
- Initialize no-go areas in Yjs session from imported GPX
- Save to Journal now exports track only (consistent with Export Route)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 10:52:39 +01:00
Ullrich Schäfer
5f3d4ae846
Remove sync parseGpx, use parseGpxAsync everywhere
parseGpx (sync) needs browser DOMParser which doesn't exist on the
server — it silently failed in every server-side caller. Removed the
export and migrated all callers to parseGpxAsync. Updated tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:32:48 +01:00
Ullrich Schäfer
d5bcecb345
Fix distance calculation for GPX files without elevation data
Distance was only stored in the elevation profile array, which was
empty when track points had no <ele> elements. Now computed via
haversine independently and exposed as gpxData.distance.

Tested: berlin-dresden-radweg-2021.gpx (5660 points, no elevation)
now correctly reports 248.8 km.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 20:32:47 +01:00
Ullrich Schäfer
62b5fb998e
Fix planner production server + use .ts extensions everywhere
- Fix createRequestHandler → createRequestListener (@react-router/node
  removed the old API)
- Move noEmit + allowImportingTsExtensions to tsconfig.base.json so all
  packages and apps inherit them consistently
- Add explicit .ts extensions to all remaining relative imports across
  packages and apps

Verified locally: node --experimental-strip-types server.ts starts and
responds 200.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:41:33 +01:00
Ullrich Schäfer
14b179bb0c Fix waypoint loading in Edit in Planner flow
Three issues fixed:

1. GPX parser used browser DOMParser which doesn't exist in Node/Vite SSR.
   Added async parseGpxAsync() using linkedom for server-side parsing.

2. Server-side session initialization stored waypoints in a Yjs doc
   instance separate from the Vite WebSocket plugin's doc store.
   Moved waypoint initialization to client-side: API returns parsed
   waypoints, client adds them to Yjs after sync.

3. GPX was encoded in URL params causing HTTP 431. Now the Journal
   creates a Planner session via API (POST body), and only passes
   compact waypoint coordinates in URL params.

Verified: Journal route → Edit in Planner → 4 waypoints loaded,
route computed (79.3km), elevation profile, Save to Journal ready.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:22:58 +00:00
Ullrich Schäfer
2cfa5e54e7
Implement shared packages (tasks 2.1-2.6)
- @trails-cool/types: Route, Activity, Waypoint, RouteVersion, RouteMetadata
- @trails-cool/gpx: GPX parser (XML→waypoints/tracks/elevation) and generator
  with round-trip test, haversine distance, elevation gain/loss computation
- @trails-cool/map: MapView (Leaflet + OSM/OpenTopoMap/CyclOSM layer switcher),
  RouteLayer (GeoJSON polyline rendering)
- @trails-cool/ui: Button (primary/secondary/ghost), Input (with label/error),
  Card components with Tailwind styling
- @trails-cool/i18n: react-i18next config with English + German translations,
  browser language detection, fallback to English

All 13 unit tests pass. Both apps build successfully.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:09:35 +01:00