A reserved key comes to life — the card window's sidebar grows a Labels section, and labels stops being somebody else's
`labels` has been a reserved tracker key since the rewrite: preserved verbatim, never interpreted, drawn only as an anonymous row in the Details section beside `assignees` and `due`. The owner's cards claim it for first-party use, so it joins the schema — read leniently (a list of names, a bare scalar coercing to one, a mapping malformed and preserved), written canonically (a quoted flow list in the order the user arranged, no auto-sort), and removed outright when the last label goes, the way an expanded lane drops `collapsed`. Identity is case-insensitive and display is case-preserving, so a card carries `bug` once however many ways the board spells it, and entries the reading cannot name ride through the write untouched at the tail. The section sits second, above Details — which is the point rather than a layout preference: Details is where keys the app does *not* own are shown, and this key just stopped being one. Rows rather than chips, because the sidebar is twenty-six characters wide. The add field autocompletes against the board's own used-labels universe, derived from every live and trashed card with no store beside the files, and says out loud when Return would mint a word the board has never used. Writes ride a `.relabel` operation of their own, because the commit composer has said "Relabel card 'X'" since long before there was a control to press — and now the undo row says it too. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -84,6 +84,10 @@ struct CardWindowView: View {
|
||||
/// Controls) — app state, not board state, which is why it arrives beside the store rather than
|
||||
/// on it.
|
||||
let recents: StyleRecents
|
||||
/// The app-wide recently-applied labels the Labels section feeds (`LabelRecents`;
|
||||
/// `FrontmatterKeys.labels`) — `recents`' neighbour in every respect, app state rather than board
|
||||
/// state, arriving beside the store for that field's reason exactly.
|
||||
let labelRecents: LabelRecents
|
||||
/// The card's folder on disk — what relative images and links in the body resolve against
|
||||
/// (05 ▸ Preview). `nil` only where a caller has no board root to build it from.
|
||||
let cardFolder: URL?
|
||||
@@ -449,8 +453,8 @@ struct CardWindowView: View {
|
||||
|
||||
// MARK: - Attributes sidebar
|
||||
|
||||
/// The sidebar's sections: **Style, Details, Attachments** — Attachments at the bottom of the
|
||||
/// stack (reordered 2026-08-09, Pipeline card 8f26b029), Actions gone entirely (retired the same
|
||||
/// The sidebar's sections: **Style, Labels, Details, Attachments** — Attachments at the bottom of
|
||||
/// the stack (reordered 2026-08-09, Pipeline card 8f26b029), Actions gone entirely (retired the same
|
||||
/// day, Pipeline card bcd3b323): its Delete and Reveal in Finder are now the card window's own
|
||||
/// toolbar items (`CardToolbar`), reachable from Customize and, for Delete, on by default. This
|
||||
/// is exactly the `VStack`'s child order, so keyboard Tab order and VoiceOver's reading order
|
||||
@@ -462,10 +466,15 @@ struct CardWindowView: View {
|
||||
/// with Actions at the bottom — an owed amendment, tracked on the two cards' own threads rather
|
||||
/// than made here.
|
||||
///
|
||||
/// One of the two remaining sections is conditional, and the condition is the section's own
|
||||
/// rather than a rule restated here: **Details** renders nothing when the card carries no unknown
|
||||
/// frontmatter keys ("shown only when any exist"). Style and Attachments are unconditional, so
|
||||
/// the composition a user learns on one card is the composition they get on the next.
|
||||
/// One of the four sections is conditional, and the condition is the section's own rather than a
|
||||
/// rule restated here: **Details** renders nothing when the card carries no unknown frontmatter
|
||||
/// keys ("shown only when any exist"). Style, Labels and Attachments are unconditional, so the
|
||||
/// composition a user learns on one card is the composition they get on the next.
|
||||
///
|
||||
/// **Labels joined 2026-08-09** (Pipeline card a4462d28), sitting second — see
|
||||
/// `CardLabelsSection`'s own doc comment for why it goes after Style and, load-bearingly, *above*
|
||||
/// Details: `labels` stopped being an unknown key that day, and Details is the section for keys the
|
||||
/// app does not own.
|
||||
///
|
||||
/// The History section that once sat between Details and Actions left with app-managed git
|
||||
/// (strategy/01-git-excision.md, 2026-08-08); View ▸ History (`FutureCommands.swift`) is the only
|
||||
@@ -475,6 +484,16 @@ struct CardWindowView: View {
|
||||
VStack(alignment: .leading, spacing: bodyPointSize * 1.25) {
|
||||
CardStyleSection(store: store, recents: recents, cardID: card.id, undo: undo)
|
||||
|
||||
// The snapshot's own reading, not a store lookup: this window's `Card` is the value
|
||||
// the last reload produced, and every other section here renders off it.
|
||||
CardLabelsSection(
|
||||
store: store,
|
||||
recents: labelRecents,
|
||||
cardID: card.id,
|
||||
labels: card.labels.value ?? [],
|
||||
undo: undo
|
||||
)
|
||||
|
||||
// The snapshot's own document, not a re-read: the loader parsed this file, unknown
|
||||
// keys and their order included, and `Card` has carried it since (`BoardModel`).
|
||||
CardDetailsSection(rows: CardDetails.rows(of: card.document))
|
||||
|
||||
Reference in New Issue
Block a user