From 1d7449e49aac61913f1aa3805f8fdec12cb061bc Mon Sep 17 00:00:00 2001 From: rzen Date: Sun, 26 Jul 2026 20:45:10 -0400 Subject: [PATCH] =?UTF-8?q?Give=20lane=20selection=20its=20keyboard=20entr?= =?UTF-8?q?y=20=E2=80=94=20=E2=8C=A5=E2=86=91=20escalates;=20header=20clic?= =?UTF-8?q?ks=20select?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every lane command keyed off "a selected lane" with no drag-free way to create one. Settled: ⌥↑ with the lane's first card selected selects the lane (↓/⌥↓ descend back; ⌥↑ then inert), an empty selection seeds at the first lane's first card, and a plain click on the lane title bar selects with the drag surface engaging only on movement. Claude-Session: https://claude.ai/code/session_01HJ7PhFNmQ19bvy9RMD6GSb --- DESIGN/03-board-ui.md | 2 +- DESIGN/04-interactions.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/DESIGN/03-board-ui.md b/DESIGN/03-board-ui.md index 530e09e..ba6f44f 100644 --- a/DESIGN/03-board-ui.md +++ b/DESIGN/03-board-ui.md @@ -17,7 +17,7 @@ Toolbars are **pure enhancement**: every function they host already has a menu i ## Lane -- Title bar: leading SF Symbol (the lane's `icon`), title, **card-count badge** (quiet, secondary styling), new-card button. The whole title bar is the lane's drag surface — no separate grip. The count reads the search filter like every other surface (04-interactions.md): during a search it shows the visible count, not the total. +- Title bar: leading SF Symbol (the lane's `icon`), title, **card-count badge** (quiet, secondary styling), new-card button. The whole title bar is the lane's drag surface — no separate grip; a plain click (no movement) on it selects the lane (04-interactions.md ▸ Selection). The count reads the search filter like every other surface (04-interactions.md): during a search it shows the visible count, not the total. - Body: vertical card stack (masonry grid when wide — settled, the pathfinder's masonry works), scrolls vertically. - Right-edge **drag-to-resize** between integer widths (1×, 2×, 3×, … — no cap): shadow snaps at the inter-column gap with 10pt release hysteresis; the window grows/shrinks by one standard width per snap so other lanes keep their exact size. **Growth hard-stops at the screen's visible frame, with rubber-band feedback** (the dragged edge gives a fraction of the overshoot and snaps back, signalling the bound — pathfinder behavior, proven): the drag never compresses siblings and the window never overflows the screen. The header context menu's Width control (stepper, uncapped) is the precise control — and deliberately the opposite mechanism: it never touches the window, it **re-divides** the existing width across the new unit total (siblings compress). Widths beyond the screen's capacity stay reachable through it. The **Increase/Decrease Lane Width menu items (⌥⌘→/⌥⌘← — 11-command-nexus.md) are this stepper's keyboard face** — same re-divide semantics, never the window's size; window-growing behavior belongs to the drag alone. diff --git a/DESIGN/04-interactions.md b/DESIGN/04-interactions.md index ca6c6bb..23f28f6 100644 --- a/DESIGN/04-interactions.md +++ b/DESIGN/04-interactions.md @@ -6,7 +6,7 @@ Selection, drag & drop, keyboard, clipboard, search. This is where the old app s - Cards: click selects; ⌘-click toggles; ⇧-click range-extends; click-drag rubber-bands across lanes. Lanes: ⌘/⇧-click multi-select. - Selection is **homogeneous**: cards XOR lanes. -- Lane empty-space: single click selects the lane (click again to unselect); double click creates a card at the bottom, title editor focused. +- Lane empty-space: single click selects the lane (click again to unselect); double click creates a card at the bottom, title editor focused. **The lane header is click-to-select too** (settled — a full lane has no empty space left): a plain click on the title bar selects the lane; the drag surface (03-board-ui.md ▸ Lane) engages only on movement — the click-vs-drag split cards already have. - **Clicking never edits** (pivot from the pathfinder's Finder-rename two-stage click): one click selects, and that is all a single click ever does — no slow-second-click rename, no timers, no accidental edit on a hesitant click. Inline rename is **Return** on a sole selected card, or Board ▸ Rename — the menu item is a lane's only rename path, since Return on a lane creates a card (Grammar below). A fast double-click opens the card window (⌘↩'s pointer twin). Committing an empty rename on an existing item removes its `title` key (titles are optional; the face shows the untitled placeholder). ## Drag & drop @@ -35,7 +35,7 @@ Selection, drag & drop, keyboard, clipboard, search. This is where the old app s ### Grammar (fixed keys — deliberately not remappable) - **Arrows**: spatial card navigation (nearest card in the direction, across interior grid columns and lanes); with a lane selected, ←/→ move lane selection; ⇧-arrow extends; selection scrolls into view; all grammar keys inert while a title editor is focused, and menu dispatch narrows to the text domain (focused-editor rule below). -- **⌥-arrows jump**: ⌥↑/⌥↓ to the current lane's first/last card; ⌥←/⌥→ to the first/last lane. +- **⌥-arrows jump**: ⌥↑/⌥↓ to the current lane's first/last card; ⌥←/⌥→ to the first/last lane. **⌥↑ escalates into the lane domain** (settled — the keyboard's one entry to lane selection): with the lane's first card already selected, ⌥↑ selects the *lane* itself — up in the hierarchy sense, the same key one press deeper; with a lane selected, ↓ (or ⌥↓) descends back into its cards at the first (last) card, and ⌥↑ is inert. **An empty selection seeds at the first lane's first card** on any plain arrow (deterministic origin; the ⌥-jumps behave as specified regardless) — two ⌥↑ presses from nothing reach the lane domain. - **Return** on a selected lane: creates a card at its bottom, editor focused; Return commits and re-selects the lane (next Return = next card); ⌘↩ commits and opens the card window. Abandoned placeholders (Escape, empty commit, click-away) are discarded — creating-then-abandoning never leaves an empty card behind (untitled cards exist only when made deliberately, e.g. by an external writer or by clearing an existing title). The placeholder is store-transient overlay state — the named exception to 02-architecture.md's one-way flow; nothing exists on disk until the title commits. - **Inline rename tracks its target by UUID, and vanishing discards it** (the placeholder and card-window kin rules — 02-architecture.md — applied to the third inline editor): a foreign *move* mid-rename is invisible — the editor follows the UUID and the commit writes the title wherever the card now lives; a target that is tombstoned, deleted, or gone at commit time discards the editor and its keystrokes silently (a liveness flip is a vanish; nothing is ever written into a vanished folder, and no partial `index.md` can resurrect deleted data). A write that fails *after* a valid commit is the ordinary one-shot write-failure banner. VoiceOver announces the vanished target per 10-accessibility.md's recovery rule. - **Return** on a sole selected **card**: inline rename. Return disambiguates on card selection — sole card = rename, lane = create (above) — and is **inert on a multi-card selection**; a lane's rename path is Board ▸ Rename. **Escape** steps outward one layer per press: abandons an open editor; else clears search, returning focus to the board (Search below); else **clears the selection** — the keyboard deselect.