From 36fdfb2758f47800fe50a9f0b902e039e6d9b289 Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 8 Nov 2026 21:40:57 -0500 Subject: [PATCH] map: mount without waiting on the 500-call window; legend collapsible, hidden under open layers list The Live map was held behind useCalls(500), measured at ~9.2s to first map paint on prod; it now mounts as soon as the saved view is known (nodes are awaited only when there is no view). The legend painted over the expanded Leaflet layers list (z-1001 vs the map's z-0 stacking context): it is now a
that hides while the list is open and starts folded on short viewports. Co-Authored-By: Claude Opus 5.5 --- drb-frontend/app/globals.css | 7 +++++++ drb-frontend/components/LiveView.tsx | 6 +++++- drb-frontend/components/MapView.tsx | 15 +++++++++++++-- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/drb-frontend/app/globals.css b/drb-frontend/app/globals.css index 5d35c6f..187e312 100644 --- a/drb-frontend/app/globals.css +++ b/drb-frontend/app/globals.css @@ -193,6 +193,13 @@ html:not(.dark) .border-indigo-800 { border-color: #c8ccf6 !important; } z-index: 0; } +/* The legend floats above the map's stacking context, so it would cover the + * expanded layers list (both live in the right-hand column). Hide it while the + * list is open. */ +.relative:has(.leaflet-control-layers-expanded) > .drb-legend { + visibility: hidden; +} + /* "Dark" base layer (#136): the prod tile URL is bright OSM, so dark-theme * overlay cards sat on a bright, busy map. Inverting the raster keeps the * keyless OSM source (CARTO's dark_all CDN proved flaky, #117) while giving diff --git a/drb-frontend/components/LiveView.tsx b/drb-frontend/components/LiveView.tsx index 194a73d..e986a1d 100644 --- a/drb-frontend/components/LiveView.tsx +++ b/drb-frontend/components/LiveView.tsx @@ -560,7 +560,11 @@ export function LiveView() { {/* Degraded → grey the map and its incident rail (the rail lives inside MapView, so it is wrapped here rather than edited). */}
- {nodesLoading || callsLoading || !mapState ? ( + {/* Mount the map as soon as its starting view is known. The 500-call + window took ~9s on prod and used to hold the whole map back; + calls and paths now stream in once it lands. Nodes are only + awaited when there's no saved view, since they pick the centre. */} + {!mapState || (!mapState.view && nodesLoading) ? (
Loading map…
) : ( startLayers.has("wx")); const [radarLoop, setRadarLoop] = useState(false); // off by default (#237); not persisted const loopClock = useMemo(createLoopClock, []); + // Short viewports (laptops, the 352px incident-page map) start with the + // legend folded to a chip so it doesn't cover the right side of the map. + const [legendOpenAtStart] = useState(() => typeof window === "undefined" || window.innerHeight >= 760); // The altitude key only belongs in the legend while the opt-in Aircraft // overlay is actually on (server-26#185); same for the outage key (#184). @@ -1931,7 +1934,14 @@ function MapView({
{/* ── Legend — shape-first, both themes. Never a bare colour swatch. ──── */} -
+ {/* Collapsible (one click to a "Legend" chip) and hidden while the Leaflet + layers list is expanded: the map sits in a z-0 stacking context, so the + legend at z-1001 used to paint over the bottom of that list. */} +
+ + ▸▾ Legend + +

Severity

{(["major", "moderate", "minor", "routine"] as Severity[]).map((sev) => ( @@ -2070,7 +2080,8 @@ function MapView({
))}
-
+ +
{/* ── Incident overlay panel ───────────────────────────────────────────── */} {incidents.length > 0 && (