Three curated symbol vocabularies — boards, lanes, and cards each pick from their own shelf
`CuratedSymbols` was one flat ~65-glyph list serving every style-editor target alike. It is now three level-specific sets — `boards` (project/container/identity), `lanes` (workflow/stage/status), `cards` (work-item/content) — each ~30-40 entries, seeded from the original list and `SymbolPickerCatalog.defaultSet`, reorganized by which level a glyph actually reads as being about. Overlap is kept where a glyph genuinely fits everywhere (`flag`, `star`). Wiring: - `BoardInfoPopover`'s board-glyph `SymbolPicker` now passes `CuratedSymbols.availableBoards` instead of the picker's domain-agnostic default. - The card sidebar's `SymbolPicker` (`CardSidebarSections`) now passes `CuratedSymbols.availableCards` instead of the old flat `available`. - The style editor's own curated grid (`StyleEditorView`, the Style… popover's only remaining anchor) reads `CuratedSymbols.availableForStyleEditor(level:spansLevels:)`: a homogeneous target reads its own level's set, and a target that somehow spans more than one level (today unreachable — 04-interactions.md's cards-XOR-lanes rule keeps a live selection homogeneous) reads the three combined, via a new `BoardStore.styleTargetSpansLevels` seam that asks the question `styleLevel(of:)` deliberately collapses. - `CuratedSymbols.combined` (the three sets' stable-order union) also replaces the old `.all` in `SymbolPickerCatalog`'s full-catalog fallback. - `SymbolPickerCatalog.defaultSet` is kept as the fallback for a caller naming no level (a future saved-search picker, say) rather than retired. DESIGN/03-board-ui.md and DESIGN/05-card-window.md's Styling/sidebar prose amended minimally where they named "the curated set" as a single list. Tests: three new/rewritten suites in KanbanTests/StyleModelTests.swift (set shape, availability, overlap, `combined`, the style-editor level/span decision, the board-anchor width tripwire), one new test in KanbanTests/StyleWriteTests.swift (`styleTargetSpansLevels`), and the old single-list-pinning tests in KanbanTests/SymbolPickerTests.swift and KanbanTests/CardSidebarTests.swift updated to the new set names. 2834 tests, 487 suites green (KanbanTests, arm64); one unrelated flaky failure (RootRecoveryTests.vanishAndReturn under full-suite load) passed clean in isolation. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -13,10 +13,13 @@ import SwiftUI
|
||||
///
|
||||
/// ### Why the curated set differs from `CuratedSymbols`
|
||||
///
|
||||
/// `CuratedSymbols.all` is grouped by what a *board item* is (status/flow, containers, people…) —
|
||||
/// this control has no board item in mind, so `SymbolPickerCatalog.defaultSet` is a smaller,
|
||||
/// ungrouped 36 chosen for the general "boards and projects" case instead. The two lists are free to
|
||||
/// diverge; nothing here reads the other.
|
||||
/// `CuratedSymbols` is three sets grouped by *level* — boards, lanes, cards (2026-08-09) — because a
|
||||
/// board's identity, a lane's stage and a card's content want different glyphs. This control has no
|
||||
/// level built in; a caller aimed at one names it explicitly (`BoardInfoPopover` passes
|
||||
/// `CuratedSymbols.availableBoards`, the card sidebar `CuratedSymbols.availableCards`), and a caller
|
||||
/// with no level in mind — a saved search, a smart filter — falls back to `SymbolPickerCatalog.defaultSet`,
|
||||
/// a smaller, ungrouped 36 chosen for the general "boards and projects" case instead. The lists are
|
||||
/// free to diverge; nothing here reads the others beyond the merge below.
|
||||
///
|
||||
/// ### The one thing `CuratedSymbols` never needed
|
||||
///
|
||||
@@ -32,11 +35,11 @@ import SwiftUI
|
||||
/// inventory it searches into once the grid alone isn't enough.
|
||||
enum SymbolPickerCatalog {
|
||||
|
||||
/// The picker's curated grid, in order — a general "boards and projects" set rather than the
|
||||
/// style editor's kanban-item groupings, chosen so a first-run picker with no caller-supplied
|
||||
/// `symbols` still shows something broadly useful. A stored constant, not a computed property,
|
||||
/// for `CuratedSymbols.all`'s own reason: the list is the design decision, and `available` is the
|
||||
/// only thing the OS gets a say in.
|
||||
/// The picker's curated grid, in order — a general "boards and projects" set rather than one of
|
||||
/// the style editor's level-specific groupings, chosen so a first-run picker with no
|
||||
/// caller-supplied `symbols` still shows something broadly useful. A stored constant, not a
|
||||
/// computed property, for `CuratedSymbols`' own reason: the list is the design decision, and
|
||||
/// `available` is the only thing the OS gets a say in.
|
||||
static let defaultSet: [String] = [
|
||||
"star", "flag", "heart", "bolt", "flame", "leaf", "drop", "sun.max", "moon", "sparkles",
|
||||
"tag", "bookmark", "pin", "bell", "paperplane", "tray", "folder", "archivebox", "doc.text",
|
||||
@@ -45,8 +48,8 @@ enum SymbolPickerCatalog {
|
||||
"airplane", "gamecontroller", "globe",
|
||||
]
|
||||
|
||||
/// The set this Mac can actually draw — `CuratedSymbols.available`'s rule, mirrored: a curated
|
||||
/// list is a convenience, never a claim about the running system.
|
||||
/// The set this Mac can actually draw — `CuratedSymbols.available(for:)`'s rule, mirrored: a
|
||||
/// curated list is a convenience, never a claim about the running system.
|
||||
static var available: [String] { defaultSet.filter(ItemSymbol.exists) }
|
||||
|
||||
/// The colour row's seven tints — `Palette.foregrounds`' hues, minus the four grayscale steps
|
||||
@@ -98,7 +101,7 @@ enum SymbolPickerCatalog {
|
||||
let root = plist as? [String: Any],
|
||||
let symbols = root["symbols"] as? [String: Any]
|
||||
else {
|
||||
return Set(defaultSet + CuratedSymbols.all).sorted()
|
||||
return Set(defaultSet + CuratedSymbols.combined).sorted()
|
||||
}
|
||||
return symbols.keys.sorted()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user