Remove the lane header's "+" new-card control

The lane header no longer draws a new-card button. Every other
creation path is untouched: File > New Card (Cmd-N), Return on a
selected lane, and double-click on lane empty space.

- LaneView: drop the button and its overlay slot, leaving the
  collapse chevron as the header's one piece of trailing chrome.
- NewCardTarget: drop the button's click-names-target carve-out over
  the Cmd-N target rule (Return on a selected lane is now the only
  direct-target path left).
- AccessibilityPhrases: drop the button's spoken label.
- BoardMetrics: drop its width reserve; laneHeaderTrailingReserve now
  reduces to the collapse chevron's own reserve.
- DESIGN/03, 04, 10, 11: update the lane title-bar inventory, the
  Cmd-N override clause and search-clearing mechanism list, the
  accessibility tree-shape sentence, and the pointer-grammar row that
  described the button.
- Tests: drop the two pinned accessibility-label tests and the
  newCardButtonReserve assertions; retarget the truncation-headroom
  test at the now-solo laneHeaderTrailingReserve; fix stale doc-quote
  comments and the manual accessibility-verification checklist.

Full KanbanTests suite: 2807 tests, 482 suites, all passing.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-08 23:28:05 -04:00
parent b09c4bd5c0
commit eb950ee881
16 changed files with 76 additions and 126 deletions
+15 -23
View File
@@ -115,35 +115,27 @@ enum BoardMetrics {
em(0.4, bodyPointSize: bodyPointSize)
}
/// The trailing room the header reserves for the new-card button, so **a long title truncates
/// before it collides with the button** rather than running under it.
/// The room the header reserves for the **collapse chevron**, its one piece of trailing chrome
/// (03-board-ui.md § Lane Collapsed lanes). A new-card button once shared this edge and had its
/// own matching reserve (`newCardButtonReserve`, retired with the button this milestone); the
/// chevron kept its own figure rather than folding into a since-widowed combined one.
///
/// This is the one figure that is not decoration: the button is an `Image` at
/// `.imageScale(.small)`, which *is* a relative size, so a reserve fixed at 22pt would be
/// overrun by the glyph itself at a large system text size and the truncation rule would stop
/// being true. 1.7 em is the button plus its breathing room, measured in the same unit the glyph
/// grows in.
static func newCardButtonReserve(bodyPointSize: CGFloat) -> CGFloat {
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.
/// This is the one figure that is not decoration: the chevron is an `Image` at
/// `.imageScale(.small)`, which *is* a relative size, so a reserve fixed at 18pt would be overrun
/// by the glyph itself at a large system text size and the truncation rule would stop being true.
/// 1.4 em 18pt at the standard 13pt body is the glyph plus its breathing room, measured in the
/// same unit it grows in.
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.
/// Everything the lane header's trailing chrome takes the collapse chevron alone now that the
/// new-card button beside it is gone (this milestone narrowed this from a two-term sum to one).
/// Kept as its own figure rather than inlined at the call site: the one thing the header pads by,
/// so "a long title truncates before it collides" stays one rule however many controls end up
/// living there again.
static func laneHeaderTrailingReserve(bodyPointSize: CGFloat) -> CGFloat {
newCardButtonReserve(bodyPointSize: bodyPointSize)
+ laneCollapseButtonReserve(bodyPointSize: bodyPointSize)
laneCollapseButtonReserve(bodyPointSize: bodyPointSize)
}
/// The count badge's capsule inset horizontal and vertical, which are deliberately different: