Skip to content

feat: side-panel layout on wide screens (#24)#32

Merged
DocGerd merged 4 commits into
mainfrom
feat/24-wide-screen-side-panel
Jul 16, 2026
Merged

feat: side-panel layout on wide screens (#24)#32
DocGerd merged 4 commits into
mainfrom
feat/24-wide-screen-side-panel

Conversation

@DocGerd

@DocGerd DocGerd commented Jul 16, 2026

Copy link
Copy Markdown
Owner

At ≥ 1024 px the app shell becomes a two-column CSS grid: the panel (header, banners, tabs, content) sits as a ~1/3-width column on the left (grid-template-columns: minmax(320px, 1fr) 2fr), and the map fills the remaining ~2/3 at full viewport height. Below the breakpoint the existing bottom-sheet layout is byte-for-byte unchanged — phone / cockpit-portrait remains the primary on-boat mode.

Closes #24

What changed

  • app/src/app.css — all new rules live inside a single @media (min-width: 1024px) block: the shell's four absolutely-positioned overlay children become grid items via grid-template-areas (map spans all rows); panel inputs/selects capped at 22rem; the lone motor checkbox rendered inline (:has()); the Live readout becomes a compact bottom-left card over the map.
  • app/src/components/MapView.tsx — comment only: MapLibre v5's built-in trackResize container ResizeObserver already handles breakpoint crossings (verified in the installed 5.24.0 dist: _setupResizeObserver() observes this._container), so no second observer is added — one would double-fire resize().
  • app/e2e/layout.spec.ts — new spec asserting side-panel geometry at 1280×800, bottom-sheet geometry at 375×667, and a wide→narrow→wide round-trip proving the canvas tracks its container across the breakpoint.
  • Rides along (per plan): CLAUDE.md updates (pipeline icons cmd, agent-topology working-style bullet, deploy section now records the protect-main ruleset implemented for Public readiness: branch protection / rulesets for main #15) and the two .claude/agents/ definitions used by that topology.

Decisions

  • Breakpoint 1024 px (issue allowed ~900–1024): landscape tablets get the side panel; portrait tablets/phones keep the bottom sheet.
  • Panel left, per the issue's primary sketch; kept stable.
  • No JS resize plumbing: MapLibre's own container ResizeObserver covers the requirement; the e2e round-trip exercises it.
  • Known trade-off (reviewed, deferred): on wide screens the Live tab leaves the panel column empty — the readout floats over the map because LiveView must render inside MapView's subtree (useMapInstance()). Relocating it is Wide layout: move the Live readout into the side panel column #31.

Verification

  • typecheck / lint clean; test -- App 39 passed; e2e -- layout.spec.ts 1 passed (1.2 s — wide CI margin); pree2e fixture churn restored.
  • Real-browser pass (dev server + Playwright): at 1440×900 the panel measures exactly 480 px (1/3) full height, map 960 px, canvas drawing buffer 959×900 (no letterboxing); at 375×667 the bottom sheet is unchanged and the canvas resized down — proving the ResizeObserver fires on the crossing.
  • Per-PR reviewer (persistent sail-reviewer): round 1 Approve (0 Blocker / 0 Major / 3 Minor); round 2 Approve on the fix commit (re-ran the spec independently, confirmed the y > 100 threshold separates the layouts — wide panel sits at y ≈ 60, bottom sheet at y ≥ 300 — and that 0440a41 introduces nothing new). Minor dispositions: settle-guard fixed (0440a41); Live-tab placement → Wide layout: move the Live readout into the side panel column #31; prettier noise waved through.

🤖 Generated with Claude Code

Patrick Kuhn and others added 3 commits July 16, 2026 13:22
- CLAUDE.md: pipeline cmd list gains 'icons'; working-style bullet for the
  hybrid agent topology (fresh sail-implementer per task, persistent
  sail-reviewer per PR); deploy section now records the protect-main
  ruleset (PR-only merges, required app+e2e checks) implemented for #15.
- .claude/agents/: sail-implementer and sail-reviewer definitions used by
  that topology.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
At >=1024px the shell becomes a two-column CSS grid: the panel (header,
banners, tabs, content) is a ~1/3-width column on the left and the map fills
the remaining ~2/3 at full viewport height, instead of a full-width bottom
sheet eating the map's vertical space and stretching form controls to absurd
widths. Below the breakpoint the existing bottom-sheet layout is unchanged
(phone / cockpit-portrait remains the primary on-boat mode).

Form inputs in the side panel are capped at 22rem and the lone motor-enabled
checkbox goes inline. The Live readout (which must live in MapView's subtree
for its map context) becomes a compact bottom-left card on the map rather
than a full-width sheet, since the tab strip now lives in the panel column.

MapLibre's canvas already tracks the container-size change across the
breakpoint via its built-in ResizeObserver (trackResize, default on in v5) —
verified in-browser (canvas 959->375 px on a wide<->narrow round-trip); no
extra observer added. New e2e spec asserts the geometry at both viewports.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review round 1, Minor 2: the narrow-transition guard polled panel width
> 337.5px, which the ~426px wide-layout panel already satisfies — the
poll could pass before the bottom-sheet reflow. Only the bottom sheet
docks the panel low (y > 100), so poll that instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Comment thread app/e2e/layout.spec.ts
Comment thread app/e2e/layout.spec.ts
Comment thread app/e2e/layout.spec.ts
Comment thread app/e2e/layout.spec.ts
Comment thread app/e2e/layout.spec.ts
Comment thread app/e2e/layout.spec.ts Outdated
Comment thread app/e2e/layout.spec.ts
Comment thread app/src/app.css
Comment thread app/src/app.css
Comment thread app/src/app.css
Comment thread CLAUDE.md
Comment thread app/src/app.css Outdated
Apply accepted self-review findings for PR #32 (wide-screen side panel, #24):

- app.css (@media min-width:1024px): give the floating live-view card a
  downward box-shadow (the base 0 -2px is for the docked bottom sheet);
  offset .route-layer-controls to top:0.75rem so they sit at the map's
  now-clear top edge instead of behind a dead 3.5rem header gap; correct the
  stale .map-area comment — the overlays' containing block is MapView's own
  position:relative wrapper, not .map-area, in both layouts.
- layout.spec: assert the panel is bottom-flush (edge, not a height fraction);
  add wide-layout coverage for the floating live card, the tap-pick banner,
  and the form-control width cap; poll that the narrow canvas actually shrank
  (closes a round-trip blind spot); add a 1024px boundary phase.
- plan.spec: pin a 375x667 phone viewport so the full flow exercises the
  bottom-sheet layout (the former 1280x720 default is now the wide layout);
  collapse the always-expanded map attribution before the plan click, which
  otherwise overlaps the full-width button at any sub-1024px width.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@DocGerd
DocGerd merged commit 8700ecb into main Jul 16, 2026
2 checks passed
@DocGerd
DocGerd deleted the feat/24-wide-screen-side-panel branch July 17, 2026 14:21
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.

Responsive layout: side panel (~1/3 width) on wide screens instead of bottom sheet

1 participant