Skip to content

feat(web): spatial platform picker (map + walk-sorted list)#16

Draft
i11v wants to merge 7 commits into
mainfrom
claude/refine-local-plan-x4ndy8
Draft

feat(web): spatial platform picker (map + walk-sorted list)#16
i11v wants to merge 7 commits into
mainfrom
claude/refine-local-plan-x4ndy8

Conversation

@i11v

@i11v i11v commented Jun 13, 2026

Copy link
Copy Markdown
Owner

What & why

Prague interchanges (Anděl = 9 platforms around one junction) are the product's hard case. Today a stop card offers an "All / nást. A / nást. B…" chip filter — it names a platform but never says where to stand. This replaces it (where wired) with a shared map + walk-sorted platform list picker: one tappable pin per platform beside a list sorted by walk time, kept in sync, surfaced on both surfaces — the stop card and inline in each search result.

How it's built

GTFS stops.txt (lat/lon per platform row)
   │  scripts/lib/build.ts — keep per-platform coords
   ▼
contract: StopPlatform { code, stop, lat, lon }
   ▼
lib/platforms.ts  buildPlatformPicks(platforms, origin, departures?)
   • join index platform.code === departure.platform (raw → metro matches)
   • walk via haversineMetres / metresToWalkMinutes; sort by walk, then code
   ▼
PlatformPicker (variant "sheet" | "inline")
   │  React.lazy → <Suspense>
   ▼
RealMap (Leaflet, dark CARTO tiles, divIcon pins)
   ├─ StopCard  (sheet, live countdowns)   ← App.tsx threads platforms/origin/onPick
   └─ search.tsx ResultCard (inline, no countdowns)
  • Data layer: StopPlatform gains lat/lon; build.ts keeps each platform's own GTFS coords instead of averaging them into the node centroid. The index is a gitignored build artifact, regenerated at deploy — no committed-data change.
  • lib/platforms.ts: pure buildPlatformPicks joining index geo with the live board (raw platform === code so per-line metro codes match), sorted nearest-first. Reuses existing haversineMetres/metresToWalkMinutes/reachTier/Origin.
  • RealMap.tsx: static dark Leaflet map, divIcon pins (no broken default-marker PNGs), "you" marker, dashed line to the selected pin, two-way onSelect. Default-exported and React.lazy'd — lands in its own chunk.
  • PlatformPicker.tsx: map + walk-sorted list reusing RouteChip/VehicleIcon/Count. sheet adds a confirm bar; inline adds per-row "Add" + "Add whole stop".
  • Integration: MapIcon; StopCard gains optional platforms/origin/onPick/onWholeStop (chip filter stays as the fallback when absent, e.g. preview.tsx); App.tsx threads them and re-scopes a card in place; search.tsx ResultCard gets an expandable inline picker.

Behaviour notes

  • No geo: map still renders, rows fall back to code order, walk shows "—".
  • Search results aren't subscribed → inline picker shows code + walk only (no countdowns). Accepted caveat.
  • Single-platform stops: no map button, unchanged.

Verification

  • bun run typecheck — clean (the TS11 messages are pre-existing Effect-LS info diagnostics in the untouched worker package).
  • bun run test — 74 passing, incl. updated build.test.ts (per-platform coords) and a new platforms.test.ts (sort order, metro raw-code join, null-origin).
  • bun run build:web — succeeds; Leaflet is a separate chunk (RealMap-*.js ~152 kB + RealMap-*.css ~15 kB) loaded only when a picker opens.
  • ⚠️ bun run build:index and interactive bun dev smoke could not run here — outbound fetch to data.pid.cz is blocked by the environment network policy (HTTP 403) and there's no cached GTFS. The index regenerates at deploy; the build logic + schema-decode are exercised by build.test.ts. Manual smoke (map button → pick narrows card → re-open switches; search expand → add a platform; geo-off degrade) is still worth a pass in a networked env.

Generated by Claude Code

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown

🚀 Preview deployed: https://tablo-pr-16.i11v.workers.dev

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants