Commit graph

1520 commits

Author SHA1 Message Date
Ullrich Schäfer
23882dae68
Merge pull request #610 from trails-cool/feat/planner-map-markers
feat(planner): restyle map markers + route on tokens
2026-07-16 07:24:39 +02:00
Ullrich Schäfer
7b15ba609f
feat(planner): restyle map markers + route on tokens
Bring the map surface on-brand (visual-redesign group 4):

- Waypoint markers: sage accent numbered circles (was blue #2563eb);
  overnight stops keep the warm stop tone; note indicator uses the
  eg-mid gold token.
- Plain route line + ghost (insert) marker: sage accent (was blue).
- Map highlight dot (synced with the chart hover): sage accent (was
  red), so map and chart hovers match.
- Day labels: bg-raised surface + text-hi.
- No-go areas: danger token (#a03c3c) instead of bright red.
- GPX drag-over overlay: accent tokens.

Per-mode route coloring (surface/grade/…) is unchanged (data-viz);
coordinating the elevation-mode gradient with the route line is task 1.5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 07:20:17 +02:00
Ullrich Schäfer
92821e6e8b
Merge pull request #609 from trails-cool/feat/planner-elevation-collapsible
feat(planner): collapsible elevation chart with summary bar
2026-07-16 07:11:16 +02:00
Ullrich Schäfer
a520668dc0
Merge pull request #607 from trails-cool/feat/planner-elevation-canvas
feat(planner): restyle elevation chart canvas on tokens
2026-07-16 01:44:50 +02:00
Ullrich Schäfer
a5162fcc90
Merge branch 'main' into feat/planner-elevation-canvas 2026-07-16 01:40:27 +02:00
Ullrich Schäfer
8cbaceb356
feat(planner): collapsible elevation chart with summary bar
Docked-but-collapsible placement (the chosen direction):

- A collapse toggle (chevron) in the chart header; state persists to
  localStorage.
- Collapsed = a thin summary bar: a mini sage sparkline + distance and
  ascent/descent + an expand toggle. Reclaims map space on demand.
- Summary figures come from the same authoritative routeStats the
  sidebar uses (distance, elevationGain, elevationLoss), so the numbers
  match the sidebar exactly — not recomputed from the raw elevation
  points (which over-counted ascent ~2x from noise).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:39:01 +02:00
Ullrich Schäfer
87c06ead2d
Merge pull request #608 from trails-cool/fix/planner-elevation-interaction
fix(planner): elevation chart drag survives leaving the canvas; move reset-zoom button
2026-07-16 01:32:24 +02:00
Ullrich Schäfer
97ddf36621
fix(planner): elevation chart drag survives leaving the canvas; move reset-zoom
- Drag-to-zoom on the chart now tracks via window mousemove/mouseup, so
  it keeps going when the pointer leaves the chart and still completes if
  released outside it (previously mouseleave aborted the drag and an
  outside release was lost). Listeners are detached on mouseup/unmount.
- Move the "reset zoom" button from top-right (which overlapped the
  color-mode dropdown) to the bottom-right of the chart, and restyle it
  on tokens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:27:45 +02:00
stigi
0b157ce96e chore: update visual snapshots [skip ci] 2026-07-15 23:22:05 +00:00
Ullrich Schäfer
c38e054088
feat(planner): restyle elevation chart canvas on tokens
Bring the chart's chrome onto the design system (spec task 5.1):

- Plain mode: sage accent line + soft accent→transparent gradient fill
  (was off-palette blue).
- Hover: calm near-black crosshair + accent dot with a light ring, mono
  label (was red).
- Axis + day-divider labels: token colors, Geist Mono; dividers use the
  border-md token.
- Drag-select: accent tint (was blue).

Per-mode data-viz palettes (grade, surface, …) are unchanged. Darwin
visual-regression baselines regenerated; linux baselines to follow via
the update-snapshots workflow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:20:36 +02:00
Ullrich Schäfer
6d905c152f
Merge pull request #606 from trails-cool/feat/planner-computing-overlay
feat(planner): move "computing route" indicator from topbar to a map overlay
2026-07-16 01:16:09 +02:00
Ullrich Schäfer
d2d2d057cd
Merge pull request #604 from trails-cool/feat/planner-colormode-select
feat(planner): restyle color-mode selector + chart header on tokens
2026-07-16 01:07:11 +02:00
Ullrich Schäfer
24913b9f3e
Merge branch 'main' into feat/planner-colormode-select 2026-07-16 01:03:09 +02:00
Ullrich Schäfer
46018c9f89
feat(planner): move "computing route" from topbar to a map overlay
The topbar's "Route wird berechnet…" text appeared/disappeared with
routing, shifting the topbar layout. Move it onto the map as a floating
status pill (spinner + label, top-center, pointer-events-none) that
appears temporarily without affecting the topbar. Restyle the ambient
top-edge progress bar to accent tokens. Drop the now-unused `computing`
prop from Topbar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:01:08 +02:00
Ullrich Schäfer
d17d4bc3a4
Merge pull request #602 from trails-cool/feat/topbar-button-restyle
feat(planner): restyle Export + SaveToJournal buttons on tokens
2026-07-16 00:49:09 +02:00
Ullrich Schäfer
079ce5aba2
Merge branch 'main' into feat/planner-colormode-select 2026-07-16 00:44:42 +02:00
Ullrich Schäfer
c504d6e34b
Merge branch 'main' into feat/topbar-button-restyle 2026-07-16 00:44:25 +02:00
Ullrich Schäfer
8eae92b8a2
Merge pull request #605 from trails-cool/feat/planner-sidebar
feat(planner): restyle sidebar on tokens (waypoints, notes, days)
2026-07-16 00:43:34 +02:00
Ullrich Schäfer
3603624b70
fix(planner): distinct aria-label for export dropdown toggle
The restyled Export split-button's dropdown toggle got aria-label
"Export GPX", colliding with the main button's text and breaking the
E2E selector that clicked the old "▾" glyph. Give it a dedicated
exportOptions label (en + de) and target it in the E2E test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:43:30 +02:00
Ullrich Schäfer
1d3ba956cb
feat(planner): restyle Export + SaveToJournal buttons on tokens
Bring the two slotted topbar actions onto the design system so the bar
reads as one cohesive surface:

- SaveToJournalButton: primary Button primitive; "saved" uses the
  accent, error uses a new --color-danger token, and the return link
  gets secondary token styling.
- ExportButton: token split-button (secondary look, chevron icon,
  single divider) and a token dropdown menu (raised surface, soft
  shadow, muted descriptions).
- New --color-danger token (#a03c3c, the no-go hue at full strength)
  for error text.

Behavior and i18n unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:42:37 +02:00
Ullrich Schäfer
b09d810301
feat(planner): restyle sidebar on tokens (waypoints, notes, days)
Migrate the whole sidebar surface onto the design system:

- SidebarTabs: token tab bar, sage active indicator.
- WaypointSidebar: token surfaces/text; sage number badges; overnight
  marker uses the Badge (stop tone) primitive; route summary + stats
  footer in Geist Mono; destructive delete signalled via bg-nogo.
- NotesPanel + DayBreakdown headers/rows on tokens.
- i18n the previously-hardcoded empty-state string (en + de).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:39:12 +02:00
Ullrich Schäfer
28f92d0d8f
feat(planner): restyle color-mode selector + chart header on tokens
The elevation chart's 10-mode color selector now uses the Select
primitive (token-styled, consistent with ProfileSelector). Chart-header
chrome (top border, title link, legend text) moved onto tokens too.

Kept as a dropdown rather than a segmented control — 10 modes don't fit
a segmented toggle. Canvas/legend data-viz colors are unchanged (task
1.5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:32:05 +02:00
Ullrich Schäfer
2bc6afcf4f
Merge pull request #603 from trails-cool/feat/planner-profile-selector
feat(ui): Select primitive; restyle ProfileSelector on tokens
2026-07-16 00:16:40 +02:00
Ullrich Schäfer
a56445daf3
feat(ui): Select primitive; restyle ProfileSelector on tokens
- New Select primitive in @trails-cool/ui: token-styled native <select>
  (appearance-none + overlaid chevron for a consistent closed control),
  sm/md sizes, sibling of Input. Unit-tested + added to /dev/ui.
- ProfileSelector uses Select (size sm) with token label; the profile
  label now hides on small screens. Completes the topbar's migration
  onto the design system.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:12:23 +02:00
Ullrich Schäfer
bf73feb75a
Merge pull request #601 from trails-cool/fix/dev-ui-scroll
fix(planner): make the /dev/ui gallery scrollable
2026-07-16 00:01:47 +02:00
Ullrich Schäfer
723cd8069b
fix(planner): make the /dev/ui gallery scrollable
The app body is h-screen overflow-hidden (for the full-screen map
editor), which clipped the taller gallery so it couldn't scroll. Give
the gallery route its own full-height scroll container.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:57:44 +02:00
Ullrich Schäfer
5e75894372
Merge pull request #600 from trails-cool/feat/planner-topbar
feat(planner): redesign topbar with tokens + primitives
2026-07-15 23:55:59 +02:00
Ullrich Schäfer
4f0d4a34b3
feat(planner): redesign topbar with tokens + primitives, presentational
Extract a presentational Topbar driven by plain props, so SessionView
is the container (reads Yjs/awareness) and the topbar can render in the
/dev/ui gallery without a live session.

- New useParticipants(yjs) hook: awareness -> sorted Participant[] +
  renameLocal. Replaces ParticipantList's inline logic.
- New presentational ParticipantAvatars (Avatar + Host Badge + inline
  rename) and Topbar (token-styled shell; undo/redo via IconButton;
  connection status with a live dot). ProfileSelector/Export/Save are
  passed in as slots (their own restyle is separate).
- SessionView composes <Topbar> from real data; delete ParticipantList.
- /dev/ui gains a "Topbar - configurations" section (solo, multiplayer
  + computing, guest/connecting). Surfaced a narrow-width overflow, now
  fixed by making the participant strip the shrink/clip element.

Connection status text ("Connected"/"Verbunden") and behavior are
unchanged, so existing planner E2E selectors still match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:51:27 +02:00
Ullrich Schäfer
9463c5b1e5
Merge pull request #599 from trails-cool/feat/ui-primitives-2
feat(ui): topbar primitives — IconButton, SegmentedControl, Avatar
2026-07-15 23:47:48 +02:00
Ullrich Schäfer
1bd5f18a33
feat(ui): topbar primitives — IconButton, SegmentedControl, Avatar
Adds the shared primitives the planner topbar redesign needs, on the
design-system tokens:

- IconButton — icon-only button (undo/redo), ghost/secondary variants,
  requires an accessible label.
- SegmentedControl — generic single-select toggle (color mode
  Plain/Elevation/Surface), radiogroup semantics.
- Avatar — colored initial circle for participants, per-user color with
  an accent fallback.

Co-located jsdom unit tests for each (roles, aria-checked, onChange,
disabled, color fallback). Extends the dev-only /dev/ui gallery with
sections for all three.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:43:14 +02:00
Ullrich Schäfer
c9ad475e59
Merge pull request #598 from trails-cool/feat/ui-primitives
feat(ui): shared primitives (Button, Badge, Card, Input) on the tokens
2026-07-15 23:37:09 +02:00
Ullrich Schäfer
6344a513ce
feat(ui): shared primitives (Button, Badge, Card, Input) on the tokens
Second step of the visual-redesign (tokens -> primitives -> surfaces):
a small set of shared, token-driven primitives in @trails-cool/ui so
both apps compose from one styled vocabulary instead of hand-rolling
bg-white/text-gray-* per screen.

- @trails-cool/ui now ships React components (Button variants+sizes,
  Badge tones, Card raised/subtle, Input) plus a tiny cn() helper.
  React is a peer dep; package builds with no bundling step.
- Co-located jsdom unit tests (@testing-library/react) assert roles,
  token classes, variant switching, and behavior — run in the existing
  Unit Tests gate, cross-platform, no snapshot baseline needed.
- Tailwind @source directive in both apps' styles.css so the package's
  token utility classes get generated.
- Dev-only /dev/ui gallery route in the planner renders every primitive
  in all states — a zero-dependency stand-in for Storybook. Excluded
  from production builds (NODE_ENV guard in routes.ts).

No app surfaces are refactored yet; adopting the primitives in the
topbar/sidebar/etc. is the surface task groups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:32:28 +02:00
Ullrich Schäfer
546d1d61d6
Merge pull request #597 from trails-cool/fix/dockerfile-ui-package
fix(docker): copy packages/ui/package.json in both Dockerfiles
2026-07-15 23:21:30 +02:00
Ullrich Schäfer
91fb764556
Merge branch 'main' into fix/dockerfile-ui-package 2026-07-15 23:17:29 +02:00
Ullrich Schäfer
df6df023e0
fix(docker): copy packages/ui/package.json in both Dockerfiles
New @trails-cool/ui workspace package needs its package.json in the
deps stage so pnpm install --frozen-lockfile can resolve the
workspace:* dependency. Fixes the Dockerfile Package Check and the
journal image build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:11:50 +02:00
Ullrich Schäfer
834536308d
Merge pull request #596 from trails-cool/feat/design-system-foundation
feat(ui): design-system foundation — shared token layer + fonts
2026-07-15 23:05:04 +02:00
Ullrich Schäfer
34c3a31e73
feat(ui): design-system foundation — shared token layer + fonts
Establish the visual-redesign foundation (task group 1): a single
shared source of design tokens both apps consume, so Planner and
Journal read from one palette/typography layer instead of drifting
per-app.

- New @trails-cool/ui package exporting theme.css: Tailwind v4 @theme
  tokens (warm off-white surfaces, one sage accent, earthy overnight
  tones, elevation-gradient colors, shadows) extracted from the
  visual-redesign mockup.
- Self-hosted Outfit (body) + Geist Mono (stats) via @fontsource-variable
  — privacy-first, no Google Fonts CDN.
- Both apps import the theme and set the base canvas to the warm
  off-white token + Outfit as the default font.

Foundation only: tokens are now available as Tailwind utilities
(bg-bg-raised, text-accent, font-mono, …) and raw CSS vars. Wiring
them into specific surfaces (topbar, sidebar, markers, elevation
chart) is later task groups.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:00:28 +02:00
Ullrich Schäfer
ad9a633ae0
Merge pull request #595 from trails-cool/fix/planner-note-tooltip-adaptive-width
fix(planner): note tooltip sizes to content (max-content, cap 280)
2026-07-15 21:48:22 +02:00
Ullrich Schäfer
eb1ab7d9e4
fix(planner): note tooltip sizes to content (width max-content, cap 280)
Refines #594: a fixed width made short notes an oversized box and wrapped
long notes early. Use `width: max-content` capped at `max-width: 280` so
the tooltip hugs short notes on one line and grows to 280px before wrapping
long ones (instead of collapsing to the longest word, the pre-#593 bug).
Keeps the centered text.

Verified in local dev with both a short ("Zug zurück?") and a long note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:44:05 +02:00
Ullrich Schäfer
f751f5057d
Merge pull request #594 from trails-cool/fix/planner-note-tooltip-width-align
fix(planner): note tooltip fixed width + centered text
2026-07-15 21:38:11 +02:00
Ullrich Schäfer
64d770ebea
fix(planner): give the note tooltip a fixed width + centered text
Follow-up to #593. With a long note the tooltip still squeezed to ~1 word
wide: an inline-block with only max-width, inside Leaflet's auto-width
tooltip, shrinks to its longest word rather than filling max-width.

Give it an explicit `width: 200` (a consistent, comfortably wide box that
wraps long notes cleanly) and `text-align: center`. Verified live in the
browser against a long repeated note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 21:33:43 +02:00
Ullrich Schäfer
b660b1582c
Merge pull request #593 from trails-cool/fix/planner-note-tooltip-width
fix(planner): waypoint-note tooltip collapses to one char per line
2026-07-15 17:52:18 +02:00
Ullrich Schäfer
8cf483a4ee
fix(planner): waypoint-note tooltip no longer collapses to one char per line
The note tooltip's inner span was `display: block` with
`word-break: break-word` and no width, so the Leaflet tooltip sized itself
to the block's *min-content* — which under break-word is ~1 character —
and every character wrapped onto its own line (a tall vertical strip).

Switch to `display: inline-block` (sizes to content up to maxWidth, so it
stays one line when short and wraps at 220px when long) and the standard
`overflow-wrap: break-word`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:48:33 +02:00
Ullrich Schäfer
9ecce6a219
Merge pull request #592 from trails-cool/chore/archive-planner-route-encoding
chore(openspec): archive planner-route-encoding
2026-07-15 17:17:37 +02:00
Ullrich Schäfer
6fcd1e21cd
chore(openspec): archive planner-route-encoding
All 12 tasks complete (shipped in #590 codec + #591 wiring). Archive via
`openspec archive`:
- Creates openspec/specs/planner-route-encoding/spec.md — new capability
  (5 requirements: compact single-source geometry, RLE road metadata,
  backward-compatible reads, preserved compute-once model, bounded doc
  size). Purpose filled in (CLI leaves TBD).
- Moves the change to openspec/changes/archive/2026-07-15-planner-route-encoding/.

Spec passes `openspec validate --strict`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:13:19 +02:00
Ullrich Schäfer
86fc596e50
Merge pull request #591 from trails-cool/feat/planner-route-encoding-wire
feat(planner): store computed route compact-encoded
2026-07-15 17:12:00 +02:00
Ullrich Schäfer
c33a413395
feat(planner): store computed route compact-encoded (groups 2–4)
Wire the map-core codec into route-data.ts so the Yjs session doc stores
the computed route compactly, without changing the routing-host
compute-once-and-share model.

- Codec: add encodeElevations/decodeElevations (delta+varint) so geometry
  = encoded [lon,lat] polyline + elevation channel; precision bumped to
  1e6 (~0.11 m) to preserve the router's 6-decimal output.
- writeComputedRoute: geometry stored once (encoded polyline + elevations,
  no redundant geojson), road metadata run-length encoded.
- Dual-format reads: getCoordinates / readRoadMetadata / new readGeojson
  transparently handle the new encoding AND legacy JSON docs (+ oldest
  geojson-only) — no migration, no flag day; legacy docs re-encode on the
  next recompute. use-elevation-data reads readGeojson (assembled for new
  docs).
- Spec correction: a lossy compact codec can't be byte-identical to legacy
  (generateGpx emits raw precision), so "GPX byte-compatible" is corrected
  to "coordinates preserved within the router's ~0.1 m precision".

Tests: legacy-format read, size assertion (>4x smaller / round-trips),
elevation round-trip. map-core + planner typecheck/lint clean; full
pnpm test 11/11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:07:28 +02:00
Ullrich Schäfer
84744567bc
Merge pull request #590 from trails-cool/feat/planner-route-encoding-codec
feat(map-core): compact route codec (polyline + RLE)
2026-07-15 17:00:00 +02:00
Ullrich Schäfer
b81108b10b
feat(map-core): compact route codec (polyline + RLE) for planner doc
Task group 1 of planner-route-encoding. Framework-free `route-codec.ts`:
- encodePolyline/decodePolyline — fixed-precision (1e5) delta + zig-zag
  varint + base64; lossless to ~1 m, version-tagged ("p1:").
- encodeRuns/decodeRuns — run-length codec for the per-coordinate
  road-metadata channels, tagged ("r1:").
- isEncodedPolyline/isEncodedRuns — so the read path (group 3) tells the
  new encoding apart from legacy JSON.

Not yet wired into route-data.ts (groups 2–3). Verified: map-core
typecheck + lint clean, 52/52 tests (round-trip within 1 m, empty/single,
RLE collapse, >3x smaller than JSON).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 16:55:34 +02:00
Ullrich Schäfer
e92591b3ff
Merge pull request #589 from trails-cool/chore/propose-planner-route-encoding
docs(openspec): propose planner-route-encoding
2026-07-14 15:27:20 +02:00