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:
@@ -115,6 +115,18 @@ struct BoardInfoWidget: View {
|
||||
presentation.toggle()
|
||||
} label: {
|
||||
HStack(spacing: 4) {
|
||||
// The board's own glyph beside its name — the identity pair the popover header
|
||||
// states, restated where the board is named all day (2026-08-07). Read inside
|
||||
// `body` for `summary`'s reason: `icon`/`iconColor` are `@Observable` fields, so a
|
||||
// restyle from the popover repaints this widget without reinstalling it. Lenient on
|
||||
// both dimensions — an unresolvable glyph draws the board default, an unresolvable
|
||||
// tint draws the standard secondary.
|
||||
Image(systemName: ItemSymbol.name(store.snapshot.icon, fallback: ItemSymbol.board))
|
||||
.imageScale(.small)
|
||||
.foregroundStyle(iconTint)
|
||||
// Decorative beside the name it repeats — the button's own label already says
|
||||
// everything VoiceOver needs (`accessibilityLabel` below).
|
||||
.accessibilityHidden(true)
|
||||
Text(summary.title)
|
||||
// Styled like a titlebar title, because that is what it now stands in for
|
||||
// (`BoardWindowHost` hides the system title display in favor of this widget).
|
||||
@@ -172,6 +184,15 @@ struct BoardInfoWidget: View {
|
||||
guard let branch = summary.branch else { return summary.title }
|
||||
return "\(summary.title), branch \(branch)"
|
||||
}
|
||||
|
||||
/// The widget glyph's tint: the board's `iconColor` where it resolves, the quiet secondary
|
||||
/// otherwise — `CardFaceView`'s `iconTint` rule at the board's own level.
|
||||
private var iconTint: AnyShapeStyle {
|
||||
if let color = Palette.color(for: store.snapshot.iconColor) {
|
||||
return AnyShapeStyle(color)
|
||||
}
|
||||
return AnyShapeStyle(.secondary)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - The widget's strings
|
||||
@@ -352,6 +373,18 @@ struct BoardInfoView: View {
|
||||
in: store,
|
||||
recents: recents
|
||||
)
|
||||
},
|
||||
// The colour row — the picker's 4×2 tint grid, writing `iconColor` through
|
||||
// the same funnel the glyph writes `icon`: None removes the key, a well
|
||||
// writes the palette name (2026-08-07).
|
||||
currentColor: store.snapshot.iconColor.value,
|
||||
onSelectColor: { name in
|
||||
StyleCommand.apply(
|
||||
iconColor: name.map { StyleChange.set($0) } ?? .remove,
|
||||
to: .board,
|
||||
in: store,
|
||||
recents: recents
|
||||
)
|
||||
}
|
||||
)
|
||||
.disabled(!store.acceptsBoardMutations)
|
||||
|
||||
Reference in New Issue
Block a user