Collapsible lanes — frontmatter-backed slim strips outside the width division
A lane folds to a fixed slim vertical strip carrying its glyph, its card-count badge and its title turned on its side, and the strip is deliberately not part of the window's division: the expanded lanes' units divide what is left once each folded strip's fixed width has come off the top, so folding a lane is a re-divide trigger of the Show/Hide Trash family — the window never moves and the siblings grow into what the lane gave up. The state is a first-class lane frontmatter key, `collapsed: true`, and document state exactly as `width` is: the files are the board, so an agent folds a lane by writing one key. Absent means expanded, expanding removes the key rather than writing `false` (the remove-at-default family beside a one-unit `width`, the empty rename's `title` and the None well's `background`), and the lane's `width` rides along untouched so expanding restores the lane the user had. The read is `width`'s leniency one type over — a boolean scalar or a quoted boolean word reads as itself, everything else has no reading at all and renders as expanded, bytes preserved either way. Toggling is the header's always-visible collapse chevron, the lane context menu's single Collapse Lane / Expand Lane row, and a plain click anywhere on the strip; a modified click on the strip stays the ordinary selection grammar, so a folded lane is still selectable by pointer. The title reads bottom-up and is justified to the top of the room below the strip's chrome (owner ruling 2026-08-08), truncating against the strip's own height. While folded the lane draws no cards at all, which is what makes every exclusion true by construction rather than by a guard per gesture: no card face means no marquee target and no navigation frame, and no registered grid means the masonry's drop zones have nothing to resolve against. What did need code is the half that names absolute destinations — the option-arrow jumps and the arrow seed scan past a folded lane, the lane domain's down-arrow is inert on one, and New Card skips it (a selection inside one falls through to the last-active lane, the stale selection's rule). A drop on the strip appends at the lane's end, cards and Finder files alike, with an accent edge standing in for the shadow the strip has no masonry to open; there is no hover-to-auto- expand yet. Lane reorder works on the strip, and a dragged folded lane carries its fold, so its shadow and its replica are the strip rather than its units. The write is `writeLaneWidths` clause for clause — one `updateIndex` bracket, the same stamp behaviour, the same three do-nothing paths — with two new `WriteOperation` cases and two new undo verbs rather than one of each, because a banner or an Edit-menu row that said "resize" after Collapse Lane would name a control the user never touched. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -92,6 +92,23 @@ enum BoardMetrics {
|
||||
em(0.3, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
/// **A collapsed lane's slim strip** (03-board-ui.md § Lane ▸ Collapsed lanes) — the one lane
|
||||
/// width in the app that is *not* the window's division: a collapsed lane takes this and nothing
|
||||
/// more, and `LaneLayoutMath.standardWidth` divides what is left among the expanded lanes.
|
||||
///
|
||||
/// 3.4 em — 44pt at the standard 13pt body, which is the figure the ruling asked for (roughly
|
||||
/// 40–48pt) and the same multiple `nominalCardHeight` uses, so the strip is about as wide as a
|
||||
/// default card is tall. Wide enough for the lane's glyph, a rotated title and the count badge
|
||||
/// stacked in a column; narrow enough that a folded lane reads as a spine rather than as a lane.
|
||||
///
|
||||
/// **Font-derived like everything else here**, and it has to be: the strip's whole content is
|
||||
/// type and a badge, so a figure fixed at 44pt would clip its own glyph at a large system text
|
||||
/// size, and 10-accessibility.md's full-relative-scaling rule would quietly stop holding. It moves
|
||||
/// with the board's zoom for the same reason every other figure does.
|
||||
static func collapsedLaneWidth(bodyPointSize: CGFloat) -> CGFloat {
|
||||
em(3.4, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
/// C7 · full-column top edge (03-board-ui.md § Styling ▸ Capabilities) — the lane accent band's
|
||||
/// height.
|
||||
static func laneAccentBandHeight(bodyPointSize: CGFloat) -> CGFloat {
|
||||
@@ -110,6 +127,25 @@ enum BoardMetrics {
|
||||
em(1.7, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
/// The room the header reserves for the **collapse chevron** beside the new-card button
|
||||
/// (03-board-ui.md § Lane ▸ Collapsed lanes) — `newCardButtonReserve`'s twin, and it exists for
|
||||
/// exactly that figure's reason: two glyphs now share the header's trailing edge, and a title has
|
||||
/// to truncate before it reaches either.
|
||||
///
|
||||
/// 1.4 em — 18pt at the standard 13pt body: the chevron is a smaller glyph than the plus and sits
|
||||
/// closer to it than to the title, so it asks for less breathing room than the button it precedes.
|
||||
static func laneCollapseButtonReserve(bodyPointSize: CGFloat) -> CGFloat {
|
||||
em(1.4, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
/// Everything the lane header's trailing chrome takes — the chevron plus the new-card button. The
|
||||
/// one figure the header pads by, so "a long title truncates before it collides" stays one rule
|
||||
/// however many controls end up living there.
|
||||
static func laneHeaderTrailingReserve(bodyPointSize: CGFloat) -> CGFloat {
|
||||
newCardButtonReserve(bodyPointSize: bodyPointSize)
|
||||
+ laneCollapseButtonReserve(bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
/// The count badge's capsule inset — horizontal and vertical, which are deliberately different:
|
||||
/// a capsule around a single digit wants width, not height.
|
||||
static func badgeHorizontalPadding(bodyPointSize: CGFloat) -> CGFloat {
|
||||
|
||||
Reference in New Issue
Block a user