The board's symbol takes a tint — a 4×2 colour row under the picker's glyphs, and the glyph itself moves into the titlebar

iconColor stops being hand-written-only (user-ruled, superseding 03's
"schema yes, control no"): it rides StyleCommand.apply → applyStyle as
the third styled dimension — per-dimension no-op skip, one bracket, one
history step, ExpectedField.iconColor for staleness. The SymbolPicker
grows an opt-in colour row (leading None plus seven Palette.foregrounds
hues, None removes the key); the board popover is its one caller. The
window-title widget now draws the board's resolved glyph in that tint
beside the name. Doc realignment filed on the Redesign board (Minor).

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-08-07 18:36:49 -04:00
parent 3d231d6454
commit 7ac34651a2
12 changed files with 342 additions and 23 deletions
+10 -3
View File
@@ -367,8 +367,10 @@ extension BoardStore {
///
/// `.remove` is spelled as `nil`, which is the after-value the None well leaves: the key is gone,
/// and the item renders the level's default (03-board-ui.md § Styling Controls).
static func styledFields(background: StyleChange, icon: StyleChange) -> [ExpectedField] {
field(background, as: ExpectedField.background) + field(icon, as: ExpectedField.icon)
static func styledFields(background: StyleChange, icon: StyleChange, iconColor: StyleChange) -> [ExpectedField] {
field(background, as: ExpectedField.background)
+ field(icon, as: ExpectedField.icon)
+ field(iconColor, as: ExpectedField.iconColor)
}
/// The same dimensions, holding the values the *inverse* restores what the redo half validates
@@ -381,7 +383,9 @@ extension BoardStore {
background: StyleChange,
priorBackground: FieldValue<String>,
icon: StyleChange,
priorIcon: FieldValue<String>
priorIcon: FieldValue<String>,
iconColor: StyleChange,
priorIconColor: FieldValue<String>
) -> [ExpectedField] {
var fields: [ExpectedField] = []
if background != .keep {
@@ -390,6 +394,9 @@ extension BoardStore {
if icon != .keep {
fields.append(.icon(priorIcon.value))
}
if iconColor != .keep {
fields.append(.iconColor(priorIconColor.value))
}
return fields
}
+1 -1
View File
@@ -272,7 +272,7 @@ public final class CardWindowUndo {
}
private static let fieldOrder: [ExpectedField.Kind] = [
.title, .order, .width, .background, .backgroundImage, .icon, .body,
.title, .order, .width, .background, .backgroundImage, .icon, .iconColor, .body,
]
}
}
+8
View File
@@ -42,6 +42,11 @@ public enum ExpectedField: Sendable, Equatable {
/// `icon` the styling gesture's symbol dimension.
case icon(String?)
/// `iconColor` the symbol's tint, the styling gesture's third dimension since the board
/// popover's symbol picker grew its colour row (2026-08-07; previously "schema yes, control
/// no"). `nil` is the removed key the None well exactly as everywhere else here.
case iconColor(String?)
/// The body span, **byte for byte** the Edit session's step, and the one inverse in the app
/// whose fidelity is not field-level (13: "body steps compare bytes").
case body(String)
@@ -57,6 +62,7 @@ public enum ExpectedField: Sendable, Equatable {
case .background: .background
case .backgroundImage: .backgroundImage
case .icon: .icon
case .iconColor: .iconColor
case .body: .body
}
}
@@ -70,6 +76,7 @@ public enum ExpectedField: Sendable, Equatable {
case background
case backgroundImage
case icon
case iconColor
case body
}
}
@@ -332,6 +339,7 @@ public enum HistoryStaleness {
case let .background(expected): equal(document.background, expected)
case let .backgroundImage(expected): equal(document.backgroundImage, expected)
case let .icon(expected): equal(document.icon, expected)
case let .iconColor(expected): equal(document.iconColor, expected)
case let .body(expected): document.body == expected
}
}