From e6322857022f72880e7085acbe04173ed53b0b41 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Tue, 29 Sep 2026 17:38:01 +0700 Subject: [PATCH] ui: compact route summary, map-first route dialog, clearer crews filter toggle - Directions: the Distance/Time/Arrive tiles are now a compact one-line strip (StatTile removed), and the dialog's DOM order matches its visual order (header, map, vehicle row, From row, details, pinned Start) with redundant order-* so a dev CSS-timing hiccup can't scramble it. - Crews: the filter expand toggle now has a divider and always shows its More/Less label, so it no longer reads as another crew category. --- AGENTS.md | 24 ++--- src/components/RouteDialog.tsx | 171 +++++++++++++++++---------------- src/pages/CrewsPage.tsx | 9 +- 3 files changed, 106 insertions(+), 98 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6479233..292e9c4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -296,18 +296,18 @@ session with **no other memory of this project**. So: screen-off/background navigation needs a native foreground service — the app must stay foregrounded to guide. - **Dialog layout (2026-09-29):** app-like flex column — - `flex max-h-[calc(100dvh-2rem)] flex-col overflow-hidden`. **Visual order is - set with flex `order-*` utilities, not DOM order** (avoids moving JSX): the - **map** is `order-2` (directly under the header — it's the point of the - screen), the **mode/vehicle row** `order-3` and **"From" row** `order-4` sit - *below* the map, the details are `order-5`, and the **Start/Stop bar** is - `order-6`, pinned at the bottom so it's always reachable. The map is - `shrink-0` at `h-[50vh] min-h-[300px] sm:h-[440px]` (was `38vh`), or - `h-[60vh]`/`sm:h-[62vh]` while following. ⚠️ Don't go back to a single - `overflow-hidden` content box: - that made everything below the fold **unreachable** once the map grew. The - summary is three `StatTile`s (distance / time / arrive) + a detail line - (steps, driving-roads note, avg speed) and the map carries a metric + `flex max-h-[calc(100dvh-2rem)] flex-col overflow-hidden`. **DOM order now + matches the visual order** (and `order-*` is set redundantly, so a dev-mode + CSS-timing hiccup can't scramble it): header, then the **map directly under + it** (it's the point of the screen), then the **mode/vehicle row**, then the + **"From" row**, then the scrolling details, with the **Start/Stop bar + pinned** at the bottom. The map is `shrink-0` at + `h-[50vh] min-h-[300px] sm:h-[440px]` (was `38vh`), or `h-[60vh]`/`sm:h-[62vh]` + while following. The **summary is a compact one-line strip** + (distance · time · arrive) — `StatTile` was **removed**; the three ~90px + tiles were eating the map's space. ⚠️ Don't go back to a single + `overflow-hidden` content box: that made everything below the fold + **unreachable** once the map grew. The map carries a metric `L.control.scale`. **Transit** mode uses **Transitous** (`api.transitous.org`, MOTIS 2, open CORS) — note origin/destination go to that service, unlike road modes. **No external map-app handoff anywhere** (product decision) and no diff --git a/src/components/RouteDialog.tsx b/src/components/RouteDialog.tsx index d770bc6..deddd55 100644 --- a/src/components/RouteDialog.tsx +++ b/src/components/RouteDialog.tsx @@ -96,18 +96,6 @@ interface RouteDialogProps { * is drawn here. See src/lib/routing.ts for the honest scope notes. */ /** Big number + label tile used in the route summary. */ -function StatTile({ label, value, sub }: { label: string; value: string; sub?: string }) { - return ( -
-

{value}

-

- {label} -

- {sub &&

{sub}

} -
- ); -} - /** The average speed the routing engine assumed for this mode, e.g. "21 km/h avg". */ function speedLabel(distanceM: number, durationS: number): string | undefined { if (!(distanceM > 0) || !(durationS > 0)) return undefined; @@ -685,62 +673,6 @@ export function RouteDialog({ - {/* Mode toggle (vehicles) — sits BELOW the map via order-3. */} -
- {TRAVEL_MODES.map((m) => ( - - ))} -
- - {/* Start point — default is where you are; you can pick another on the map */} -
- - From - - - -
- {/* Map. The height lives on the WRAPPER: the global `.leaflet-container { height: 100% }` override beats a `h-64` on the map element itself, and against a height-less parent that resolved to @@ -842,11 +774,67 @@ export function RouteDialog({ )} + {/* Mode toggle (vehicles) — sits BELOW the map (order-3). */} +
+ {TRAVEL_MODES.map((m) => ( + + ))} +
+ + {/* Start point — default is where you are; you can pick another on the map */} +
+ + From + + + +
+ {/* Scrollable details */}
{/* Summary bar */} -
+
{error ? (
@@ -887,22 +875,34 @@ export function RouteDialog({

{TRANSIT_ATTRIBUTION}

) : route ? ( -
-
- - - +
+ {/* Compact summary — a single line instead of three ~90px tiles, + so the map above keeps the vertical space. */} +
+ + {formatDistance(route.distanceM / 1000)} + + + + + {formatDuration(route.durationS)} + + + ride + + + + + + arrive + + + {etaClock(route.durationS)} + +

- + {TRAVEL_MODES.find((m) => m.mode === mode)?.emoji} @@ -910,6 +910,11 @@ export function RouteDialog({ ? `${route.steps.length} steps` : 'direct'} + {mode === 'foot' + ? · {skateTime(route.distanceM / 1000)} on a board + : speedLabel(route.distanceM, route.durationS) && ( + · {speedLabel(route.distanceM, route.durationS)} + )} {TRAVEL_MODES.find((m) => m.mode === mode)?.approximate && ( · uses driving roads )} diff --git a/src/pages/CrewsPage.tsx b/src/pages/CrewsPage.tsx index 7aa24a7..37280f1 100644 --- a/src/pages/CrewsPage.tsx +++ b/src/pages/CrewsPage.tsx @@ -310,16 +310,19 @@ export default function CrewsPage() {

- {/* Expand/collapse the full filter names (remembered across visits) */} + {/* Expand/collapse the filter names (remembered across visits). + A divider + a labelled button keep it from reading as just another + crew category sitting next to the chips. */} + {/* Near me — mobile only; on desktop it was just clutter in this bar. */}