From 13388776e1cd982bc739a67f26d68fa42caef942 Mon Sep 17 00:00:00 2001 From: rzen Date: Thu, 6 Aug 2026 21:00:23 -0400 Subject: [PATCH] =?UTF-8?q?The=20squeezed=20search=20field's=20two=20answe?= =?UTF-8?q?rs=20blessed=20=E2=80=94=20expand=20in=20place,=20and=20the=20p?= =?UTF-8?q?latform's=20own=20row?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Minors ruled into 03 ▸ Toolbar: a space-constrained search item collapses to a button still in the window and ⌘F expands and focuses it — the strip fires only for a truly windowless field; and AppKit's overflow row that widens the window is the platform's own second answer, unsuppressable without destroying honest overflow — two gestures, two honest resolutions, no contradiction. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy --- DESIGN/03-board-ui.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESIGN/03-board-ui.md b/DESIGN/03-board-ui.md index 527a883..763c9db 100644 --- a/DESIGN/03-board-ui.md +++ b/DESIGN/03-board-ui.md @@ -6,13 +6,14 @@ The board window: layout, lanes, cards, and styling. Interaction mechanics (sele - **Every lane is always on screen.** The window width divides across the lanes' width units — no horizontal scroll, no enforced minimum lane width. Resizing the window is the width control. (Settled emphatically in the old app: horizontal scroll strays from what kanban is for.) The degenerate case is accepted, not floored: enough lanes/units in a small window compress every lane, titles and cards truncate gracefully, and the remedy is the user's (fewer units, bigger window). A minimum-width setting that reintroduces scroll was considered in the pathfinder and deliberately rejected. **Lane-count changes re-divide, never resize**: new lane (⇧⌘N), lane paste or cross-board lane drop, lane delete (and its undo), and Show/Hide Trash (the trash lane's fixed unit joins and leaves the division — Trash below) all re-divide the existing window width across the new unit total — window-growing behavior belongs to the right-edge drag alone (Lane below). - A lane spans a **whole number of width units** (`width` frontmatter, ≥ 1, no cap). Cards stay standard width; a wide lane flows them into as many interior masonry columns as it has units. +- **Zoom scales the ruler, never the strip** (settled 2026-08-02 — View ▸ Zoom In / Zoom Out / Actual Size, 11-command-nexus.md). The board's whole geometry is already derived from the body font's point size (10-accessibility.md ▸ Full relative scaling — every figure an em multiple, no fixed point sizes), and macOS supplies no text-size control to move it, so the zoom commands *are* that control: a rung on the level ladder raises the effective body size, and type, card chrome, lane chrome and card heights grow together off it. **Full visibility above is untouched, and that is the whole design constraint**: a canvas magnification would have to widen the strip and reintroduce the horizontal scroll this section rejects, so zoom does not do that — lane *width* stays the window's division at every rung. Zoom does move the inter-lane gap (an em multiple like everything else), so lanes narrow by a few percent across the ladder's whole range; the felt effect is the intended one — zoom in for bigger, more legible cards and fewer per screen, out for a denser board. **The level is app-wide, persisted, and never a property of a board**: it lives beside Show Comments in the app's preferences, not in any lane's or board's frontmatter, because it describes how a user likes to read rather than what a board is. **Zoom never moves the window** — the minimum content size stays pinned to the *system* body size, since window-growing behavior belongs to the right-edge drag alone (Lane below). - New lanes are created via a **File-menu item** (the one committed surface; ⇧⌘N — 11-command-nexus.md); new cards from the lane (see 04-interactions.md for creation flows). **The created lane becomes the sole selection** (settled): ⇧⌘N → Board ▸ Rename is a pure keyboard path — the create-then-act texture (Return-creation re-selects its lane, ⌫ picks a successor). ## Toolbar (board + card windows) Toolbars are **pure enhancement**: every function they host already has a menu item + shortcut (04-interactions.md's contract), so nothing below is anyone's only path. Both windows' toolbars are **user-customizable, macOS-native** (right-click ▸ Customize Toolbar…, drag to rearrange, system overflow and icon/text display options) — the sets below are shipped defaults, not verdicts. Toolbar item labels match their menu-item titles exactly (Show Trash, Edit Body, Raw Source, …), minus any trailing ellipsis (macOS convention: "Add Attachment…" labels as Add Attachment) — one vocabulary everywhere, and the customize palette self-documents against the menus. One exception: the Undo/Redo toolbar items keep static labels — NSUndoManager rewrites their menu titles dynamically ("Undo Move Card…", 04-interactions.md ▸ Configurable bindings), which a toolbar label doesn't track. -- **Board window default: the search field, nothing else** — trailing, the one default item; the titlebar stays clean. ⌘F always summons search: with the field removed from the toolbar, invoking it surfaces the field transiently until the search clears. **The field is the platform's own search toolbar item and grows on focus** (2026-08-01): the em-derived width is the *focused* width — applied when the field takes the keyboard, expanding via the item's own animation — and the resting width is AppKit's natural one, not the app's to set. **The two-homes width rule is focused-width parity** (ruled 2026-08-01): the width the user *types in* is the same em-derived figure whichever home the field is in — the toolbar item focused, or the transient strip; the toolbar field's resting width is outside the invariant (the strip never rests — it exists only while a search is live or focused, so it has no collapsed state to mirror). **Catalog** (available via Customize): New Card, New Lane, Undo, Redo (the pair disabled only under locks and on empty stacks — re-ruled 2026-07-31, twice: the provider follows the board, so boards without app-managed git — repo-nested included — bind 13-native-undo.md's native stack in **every** tier and Pro git boards bind the git provider — 06-history-undo.md), Show Trash (toggle state matching the View menu checkmark). The board popover deliberately has **no toolbar item** — the window-title widget is its committed home (below), and a second entry would muddy it. +- **Board window default: the search field, nothing else** — trailing, the one default item; the titlebar stays clean. ⌘F always summons search: with the field removed from the toolbar, invoking it surfaces the field transiently until the search clears. **A squeezed field expands in place; the strip answers only genuine unreachability** (blessed 2026-08-06): a space-constrained `NSSearchToolbarItem` collapses to a magnifying-glass button still in the window, and ⌘F expands and focuses it — the toolbar's own field, a better surface than the fallback — so the transient strip fires only for a truly windowless field (true overflow, or the item removed from the toolbar). **The item's overflow row is the platform's own second answer, and the duality is blessed** (2026-08-06): AppKit's overflow menu row carries a live action that widens the window until the field is usable, and suppressing it would destroy the honest overflow presentation — so a squeezed toolbar reaches search two ways with two honest resolutions: ⌘F expands the item or surfaces the strip (ours), the overflow row grows the window (the platform's) — different gestures, reasonable respective outcomes, no contradiction to resolve. **The field is the platform's own search toolbar item and grows on focus** (2026-08-01): the em-derived width is the *focused* width — applied when the field takes the keyboard, expanding via the item's own animation — and the resting width is AppKit's natural one, not the app's to set. **The two-homes width rule is focused-width parity** (ruled 2026-08-01): the width the user *types in* is the same em-derived figure whichever home the field is in — the toolbar item focused, or the transient strip; the toolbar field's resting width is outside the invariant (the strip never rests — it exists only while a search is live or focused, so it has no collapsed state to mirror). **Catalog** (available via Customize): New Card, New Lane, Zoom In, Zoom Out (the zoom pair is catalog-only by the same logic as everything else here — the titlebar's default stays the search field alone; each disables at its end of the ladder, and both disable mid-drag like their menu rows — Layout ▸ zoom above), Undo, Redo (the pair disabled only under locks and on empty stacks — re-ruled 2026-07-31, twice: the provider follows the board, so boards without app-managed git — repo-nested included — bind 13-native-undo.md's native stack in **every** tier and Pro git boards bind the git provider — 06-history-undo.md), Show Trash (toggle state matching the View menu checkmark). The board popover deliberately has **no toolbar item** — the window-title widget is its committed home (below), and a second entry would muddy it. - **Card window default: Edit Body · Raw Source · Add Attachment** — the window's three committed functions, all discoverable from its toolbar; the catalog is the same trio. Edit Body is a **single toggle button** (on-state in Edit — mirroring the View ▸ Edit Body checkmark and the ⌘E/Return/Escape grammar; the pathfinder's segmented Preview|Edit is retired). Raw Source is likewise a toggle showing on-state; while source mode is active, Edit Body disables (Cancel/Apply own the exits — 05-card-window.md). Add Attachment stays enabled in every mode — attachment operations never touch `index.md`, so they're safe alongside a raw edit (the sidebar's feedback returns on exit). ## Lane