From 3934cbc0f8a3a549e9cfb6fc769a1f1c19b6ac63 Mon Sep 17 00:00:00 2001 From: David Montero Date: Fri, 3 Jul 2026 07:32:14 +0200 Subject: [PATCH] fix(editor): stop unified toolbar controls overlapping on a narrow bar The top bar packs three zones onto one row: the view-mode toggle, the editor actions (Compile/Run/Stop/...), and the canvas controls (board selector, Serial, Scope, zoom, Add) portaled in from SimulatorCanvas. The editor zone was flex:1 min-width:0 while the canvas zone was fixed-width, so when the bar narrowed - mainly when the right-docked AI chat opens - the editor zone shrank below its own buttons and painted them over the board selector / Serial / Scope. The existing collapse logic was keyed to the viewport (@media 768px), so it never fired on a wide screen with the chat open. Make the shared bar a container-query context and collapse every zone by the bar's own width instead of the viewport: view-mode labels drop to icons first, then Serial/Scope/Add labels and the board selector ellipsizes, then the component count and finally the zoom buttons (wheel-zoom still works). Floor the editor zone at its collapsed content width so it can never underflow and overlap; past that the lower-priority canvas controls yield toward the right edge instead. Verified across bar widths 660-1140px with the AI chat open: overlap eliminated, dropdown menus still render un-clipped. --- frontend/src/App.css | 23 ++++++++- .../components/simulator/SimulatorCanvas.css | 47 +++++++++++++++++++ frontend/src/pages/EditorPage.tsx | 2 +- 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index 16b1f25f..47df9d9c 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -169,6 +169,23 @@ body { background: #252526; border-bottom: 1px solid #333; min-height: 38px; + /* Query container so every zone (view-mode toggle, editor toolbar, canvas + controls) can collapse based on the *shared bar's own width* — which is + what shrinks when the right-docked AI chat opens — instead of the viewport + width. Prevents the canvas controls (board selector, Serial, Scope) from + overlapping the editor Run/Compile buttons on a narrow bar. `layout` + containment (implied) does not clip: the overflow/run dropdowns still + render below the bar. */ + container-type: inline-size; + container-name: unified-toolbar; +} + +/* Collapse the Code/Both/Circuit labels to icon-only first (biggest fixed + block in the bar) as the shared bar narrows. */ +@container unified-toolbar (max-width: 1140px) { + .view-mode-toggle .vm-label { + display: none; + } } .unified-toolbar-explorer-toggle { @@ -177,7 +194,11 @@ body { .unified-toolbar-editor { flex: 1 1 auto; - min-width: 0; + /* Floor the editor zone at its fully-collapsed content width so it can never + shrink *under* its own buttons and paint them over the adjacent canvas + controls. Below this floor the (lower-priority) canvas controls get pushed + toward the right edge instead of overlapping — never the other way. */ + min-width: 280px; display: flex; } diff --git a/frontend/src/components/simulator/SimulatorCanvas.css b/frontend/src/components/simulator/SimulatorCanvas.css index e8ffdef8..53c52e67 100644 --- a/frontend/src/components/simulator/SimulatorCanvas.css +++ b/frontend/src/components/simulator/SimulatorCanvas.css @@ -398,6 +398,53 @@ } } +/* ── Narrow shared toolbar (desktop, AI chat open) ──────────────────────── + When the canvas header is portaled into the unified top toolbar, it shares + one row with the editor actions. As that *bar* narrows (mainly when the + right-docked AI chat opens), collapse the canvas controls the same way the + mobile block does — but keyed to the bar's own width via a container query, + not the viewport, so it triggers on a wide screen with the chat open too. + Priority: labels -> icons, then drop the non-interactive count, then the + zoom buttons (mouse-wheel zoom still works). Mirrors the thresholds the + editor toolbar and view-mode toggle collapse at, so the whole bar degrades + together and nothing overlaps. */ +@container unified-toolbar (max-width: 1010px) { + .canvas-serial-btn { + padding: 0 8px; + font-size: 0; /* hide "Serial" / "Scope" text, keep the icon */ + } + .canvas-serial-btn svg { + width: 18px; + height: 18px; + } + .add-component-btn { + padding: 0 9px; + font-size: 0; /* hide "Add" text, keep the icon */ + } + .add-component-btn svg { + width: 18px; + height: 18px; + } + .board-selector { + max-width: 120px; + text-overflow: ellipsis; + overflow: hidden; + } +} +@container unified-toolbar (max-width: 905px) { + .component-count { + display: none; + } + .board-selector { + max-width: 96px; + } +} +@container unified-toolbar (max-width: 835px) { + .zoom-controls { + display: none; /* mouse-wheel / trackpad zoom still available */ + } +} + /* ── WiFi / BLE status badges ─────────────────────────────────────────── */ .canvas-wifi-badge, .canvas-ble-badge { diff --git a/frontend/src/pages/EditorPage.tsx b/frontend/src/pages/EditorPage.tsx index 13b3bffe..106f03c9 100644 --- a/frontend/src/pages/EditorPage.tsx +++ b/frontend/src/pages/EditorPage.tsx @@ -480,7 +480,7 @@ export const EditorPage: React.FC = () => { > - {m.label} + {m.label} ))}