From aa47bdd0b873f761c814ba6e5cad6b37d85bd7c1 Mon Sep 17 00:00:00 2001 From: Developer Date: Sun, 13 Sep 2026 22:06:59 +0200 Subject: [PATCH] Tabs: what does not fit goes behind a menu (#84) Concepts gains the tab row; Architecture loses the 90 px floor, which is gone, and names TabStrip/tabRow in the file tree. Counter 790. Co-Authored-By: Claude Opus 5 --- Architecture.md | 11 ++++++++--- Concepts.md | 7 +++++++ Development.md | 4 ++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Architecture.md b/Architecture.md index 730be67..6a6e9b2 100644 --- a/Architecture.md +++ b/Architecture.md @@ -23,8 +23,12 @@ measures from it — only what is drawn is shortened — and a subclass that puts something else inside the control takes its room off `labelSlot()`, so a long value is cut rather than run underneath the chevron. Given a `width`, a button is exactly that wide and truncates instead: - the Behavior, Texture, Animation and Container pickers keep their size whatever they show; the tab - bar uses 90 px as a floor. A button that can draw its label bold — on an accent fill: primary, + the Behavior, Texture, Animation and Container pickers keep their size whatever they show. The + tab row has no floor at all: it is label-wide at half the theme padding, and `TabStrip` drops + what does not fit into an overflow menu rather than letting it spill (the rule is + `tabRowLayout` in `editor/tabRow.ts`, so it is checkable without a browser; `__gm.tabRow()` + reports what is in the row and what went away). + A button that can draw its label bold — on an accent fill: primary, danger, a toggled tab — is measured bold, or a dialog's `Delete` comes out as `Del…`. The padding is an inset rather than a claim, so a 24 px icon button spends it on the glyph instead of truncating it away; a button that switches between label forms (`↺` and `↺ ▾`) asks @@ -56,7 +60,8 @@ src/viewport/ view (transforms), items (what to draw), symbols (how to src/editor/ App → Editor (layout + ticker), PlaySession (the run), ProjectSession (load/create), EditorRun (run in editor), state, actions, shortcuts, debugHook, autosave, fileImport (drop/paste) → textureImport / fontImport, - framing (fit/marquee/snap maths), AssetTabEditor (the shared shell of the asset tabs) + framing (fit/marquee/snap maths), AssetTabEditor (the shared shell of the asset tabs), + TabStrip + tabRow (the tab row and what it does when the tabs outgrow it) src/editor/viewport/ WorldViewport base + SceneViewport/GameViewport — editing tools, hence not in src/viewport/ src/editor/inspector/ Inspector panel, host (what a section builds into), field factory, previewHandlers (scrub → preview → command), valueSpecs (where a value lives — shared with the List tab), diff --git a/Concepts.md b/Concepts.md index a01f854..50b3cf9 100644 --- a/Concepts.md +++ b/Concepts.md @@ -43,6 +43,13 @@ from texture* and *Delete…*. In **Scene objects** it offers *Select asset*, *Add collider*, *Create container*, *Unpack container*, *Unparent*, *Expand all* / *Collapse all* and *Remove*. +**The tab row.** The centre column carries one button per tab. When the column is too narrow to +hold them all — a small window, or the side panels dragged wide — the ones that do not fit move +behind a `»` button at the end of the row, which lists them by name; picking one opens it and +brings it into the row. The tab you are editing is always in the row: if it has to, the row gives +up every other tab to keep it there. Nothing is ever drawn past the column's edge, where it would +sit under the inspector and take clicks meant for it. + **The console.** Under whichever centre tab is showing sits the **Console** panel, always visible and resized by the divider above it — dragged all the way shut it keeps its own header to be dragged open by. It mirrors everything that reaches the browser console: a `Log` node's diff --git a/Development.md b/Development.md index 5dd147d..f8e9883 100644 --- a/Development.md +++ b/Development.md @@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs # code is lost (tail's is reported), so a red run reads as green npm run build # writes dist/ and regenerates index.html ./build.sh # the same under `set -o pipefail`, for callers that pipe the output -node tools/seed-e2e.mjs && node tools/e2e.mjs # 785 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 790 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result @@ -151,4 +151,4 @@ widths to find click points. The **render device is not in this repo** — `/dev and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`, -WebGL 2.0, and the same 785 checks as here. +WebGL 2.0, and the same 790 checks as here.