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:
@@ -6,7 +6,7 @@ import Testing
|
||||
/// the tree as sentences:
|
||||
///
|
||||
/// > A lane container is labeled "⟨title⟩, lane, N cards" — the count reads the search filter like
|
||||
/// > the visible badge. The lane header's new-card button is a labeled child ("New card in ⟨lane⟩").
|
||||
/// > the visible badge. The lane header's collapse chevron is a labeled child ("Collapse ⟨lane⟩").
|
||||
/// > A card is one flattened element: label = title (or the untitled placeholder), value carries the
|
||||
/// > attachment count when present, selected state via trait … cut cards expose their dimmed pending
|
||||
/// > state in the value ("cut, pending paste").
|
||||
@@ -69,18 +69,6 @@ struct AccessibilityPhrasesTests {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - The new-card button
|
||||
|
||||
@Test("The header button names its lane")
|
||||
func newCardLabel() {
|
||||
#expect(AccessibilityPhrases.newCardLabel(lane: "Doing") == "New card in Doing")
|
||||
}
|
||||
|
||||
@Test("The header button of an untitled lane names the placeholder")
|
||||
func newCardLabelUntitled() {
|
||||
#expect(AccessibilityPhrases.newCardLabel(lane: nil) == "New card in Untitled")
|
||||
}
|
||||
|
||||
// MARK: - Card elements
|
||||
|
||||
@Test("A card's label is its title")
|
||||
|
||||
@@ -203,7 +203,6 @@ struct BoardZoomMetricsTests {
|
||||
("laneStackSpacing", { BoardMetrics.laneStackSpacing(bodyPointSize: $0) }),
|
||||
("laneHeaderSpacing", { BoardMetrics.laneHeaderSpacing(bodyPointSize: $0) }),
|
||||
("laneAccentBandHeight", { BoardMetrics.laneAccentBandHeight(bodyPointSize: $0) }),
|
||||
("newCardButtonReserve", { BoardMetrics.newCardButtonReserve(bodyPointSize: $0) }),
|
||||
("collapsedLaneWidth", { BoardMetrics.collapsedLaneWidth(bodyPointSize: $0) }),
|
||||
("laneCollapseButtonReserve", { BoardMetrics.laneCollapseButtonReserve(bodyPointSize: $0) }),
|
||||
("cardCornerRadius", { BoardMetrics.cardCornerRadius(bodyPointSize: $0) }),
|
||||
|
||||
@@ -432,8 +432,8 @@ struct CreateCardsFromFilesTests {
|
||||
}
|
||||
|
||||
/// **The create half is a user-initiated creation, so it clears the query** (04-interactions.md
|
||||
/// § Search, stated by mechanism: "⌘N, Return-creation, the header button, empty-space
|
||||
/// double-click, paste, and Finder file drops alike"). The card is titled `shot`, which the
|
||||
/// § Search, stated by mechanism: "⌘N, Return-creation, empty-space double-click, paste, and
|
||||
/// Finder file drops alike"). The card is titled `shot`, which the
|
||||
/// standing query would hide — the whole point of the carve-out.
|
||||
@Test("A file drop that creates cards clears the search — the same rule ⌘N obeys")
|
||||
func creatingFromFilesClearsTheSearch() throws {
|
||||
|
||||
@@ -359,8 +359,8 @@ struct PasteFromTrashTests {
|
||||
/// Two rules that meet at the same guard.
|
||||
///
|
||||
/// **A paste is a user-initiated creation, so it clears the destination's query**
|
||||
/// (04-interactions.md § Search, stated by mechanism: "⌘N, Return-creation, the header button,
|
||||
/// empty-space double-click, paste, and Finder file drops alike") — cards and lanes alike, since the
|
||||
/// (04-interactions.md § Search, stated by mechanism: "⌘N, Return-creation, empty-space
|
||||
/// double-click, paste, and Finder file drops alike") — cards and lanes alike, since the
|
||||
/// clipboard holds one or the other and both mint items on arrival.
|
||||
///
|
||||
/// **The pasteboard is re-read lazily, and a stale paste no-ops** (04 ▸ Clipboard, settled):
|
||||
|
||||
@@ -39,12 +39,12 @@ struct BoardMetricsSettledFiguresTests {
|
||||
#expect(BoardMetrics.laneStackSpacing(bodyPointSize: size) == 8)
|
||||
#expect(BoardMetrics.laneHeaderSpacing(bodyPointSize: size) == 6)
|
||||
#expect(BoardMetrics.laneAccentBandHeight(bodyPointSize: size) == 5)
|
||||
#expect(BoardMetrics.newCardButtonReserve(bodyPointSize: size) == 22)
|
||||
// The fold's two figures (03-board-ui.md § Lane ▸ Collapsed lanes): the strip is the ruling's
|
||||
// ~44pt, and the chevron's reserve is 18 — together the header's 40pt trailing budget.
|
||||
// The fold's own figure (03-board-ui.md § Lane ▸ Collapsed lanes): the strip is the ruling's
|
||||
// ~44pt, and the chevron's reserve is 18 — which is also the header's whole trailing budget
|
||||
// now that the new-card button that once shared it is gone (m-remove-header-add).
|
||||
#expect(BoardMetrics.collapsedLaneWidth(bodyPointSize: size) == 44)
|
||||
#expect(BoardMetrics.laneCollapseButtonReserve(bodyPointSize: size) == 18)
|
||||
#expect(BoardMetrics.laneHeaderTrailingReserve(bodyPointSize: size) == 40)
|
||||
#expect(BoardMetrics.laneHeaderTrailingReserve(bodyPointSize: size) == 18)
|
||||
#expect(BoardMetrics.cardCornerRadius(bodyPointSize: size) == 8)
|
||||
#expect(BoardMetrics.cardStripeWidth(bodyPointSize: size) == 4)
|
||||
#expect(BoardMetrics.cardContentPadding(bodyPointSize: size) == 10)
|
||||
@@ -95,7 +95,6 @@ struct BoardMetricsScalingTests {
|
||||
("laneHeaderSpacing", { BoardMetrics.laneHeaderSpacing(bodyPointSize: $0) }),
|
||||
("laneHeaderInset", { BoardMetrics.laneHeaderInset(bodyPointSize: $0) }),
|
||||
("laneAccentBandHeight", { BoardMetrics.laneAccentBandHeight(bodyPointSize: $0) }),
|
||||
("newCardButtonReserve", { BoardMetrics.newCardButtonReserve(bodyPointSize: $0) }),
|
||||
("collapsedLaneWidth", { BoardMetrics.collapsedLaneWidth(bodyPointSize: $0) }),
|
||||
("laneCollapseButtonReserve", { BoardMetrics.laneCollapseButtonReserve(bodyPointSize: $0) }),
|
||||
("laneHeaderTrailingReserve", { BoardMetrics.laneHeaderTrailingReserve(bodyPointSize: $0) }),
|
||||
@@ -122,19 +121,21 @@ struct BoardMetricsScalingTests {
|
||||
}
|
||||
}
|
||||
|
||||
/// **The new-card button's reserve stays ahead of the header's own furniture.**
|
||||
/// **The header's trailing reserve stays ahead of the header's own furniture.**
|
||||
///
|
||||
/// 03-board-ui.md's graceful-truncation rule says a long lane title truncates rather than
|
||||
/// colliding with the button, and the reserve is what makes that true. It has to stay wider than
|
||||
/// a glyph-and-margin at every size, which is the fixed-22pt failure this conversion exists to
|
||||
/// remove: at 24pt the glyph alone approaches the old reserve.
|
||||
@Test("The header's button reserve stays wider than the glyph it reserves for")
|
||||
func theButtonReserveOutgrowsItsGlyph() {
|
||||
/// colliding with the collapse chevron, and the reserve is what makes that true. It has to stay
|
||||
/// wider than a glyph-and-margin at every size, which is the fixed-point-size failure this
|
||||
/// conversion exists to remove: at 24pt the glyph alone approaches a stale fixed reserve. (Once
|
||||
/// the sum of two glyphs' room — the new-card button and the chevron — this is now the chevron's
|
||||
/// alone, the button having been removed.)
|
||||
@Test("The header's trailing reserve stays wider than the glyph it reserves for")
|
||||
func theTrailingReserveOutgrowsItsGlyph() {
|
||||
for size in Self.sizes {
|
||||
#expect(BoardMetrics.newCardButtonReserve(bodyPointSize: size) > size,
|
||||
#expect(BoardMetrics.laneHeaderTrailingReserve(bodyPointSize: size) > size,
|
||||
"the reserve is narrower than one em at \(size)pt")
|
||||
#expect(
|
||||
BoardMetrics.newCardButtonReserve(bodyPointSize: size)
|
||||
BoardMetrics.laneHeaderTrailingReserve(bodyPointSize: size)
|
||||
> BoardMetrics.laneHeaderSpacing(bodyPointSize: size),
|
||||
"the reserve is narrower than the header's own spacing at \(size)pt"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user