Build the styling system and shared style editor
One style-editor component, anchor-agnostic: a background grid (None well plus the 12 palette colors) and a curated symbol grid (the pathfinder's five-dozen set, leading well removing the icon key for the level default), selection-aware across cards, lanes, and the board itself. Batch edits compute per-dimension state — uniform, mixed (no well selected), or an off-palette value labeled verbatim outside the grids — and choosing a well applies to the whole target set as one write bracket, skipping no-ops per field. The popover tracks its target set live per the freshly ratified rule: targets re-resolve by UUID on every reload, a vanished target leaves the set, an emptied set dismisses the editor, and nothing ever silently retargets to the board. Anchors landing now: Board > Style (Opt-Cmd-S) and the card/lane context menus, which also carry the quick-style recents row (app-wide, persisted, capped at six, None never recorded) and the lane's width control twinning the menu chords. The styling system's other two renders arrive with it: a lane's background paints the C7 top-edge band, the board's paints the window content background — malformed values paint nothing and stay byte-identical on disk. 31 new tests. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
+40
-3
@@ -63,9 +63,46 @@ enum Palette {
|
||||
}
|
||||
|
||||
// The pathfinder's panel round-trip helpers (`NSColor.paletteHexString`, `Palette.name(forHex:)`)
|
||||
// and its swatch drawing are deliberately not ported yet: nothing writes a colour until the style
|
||||
// editor lands, and an unused writer is a claim about a surface that doesn't exist. The styling
|
||||
// card brings them back when the editor needs them.
|
||||
// stay unported: they exist to turn a colour the *system picker* returned back into a palette name,
|
||||
// and this app has no colour picker — "custom hex is not pickable in-app" (03 § Styling ▸ Controls)
|
||||
// makes the whole round trip a surface that doesn't exist. Its swatch drawing, on the other hand, is
|
||||
// below: a menu can only render `Image`/`Text`, so the quick-style row's dots have to be pictures.
|
||||
|
||||
// MARK: - Menu swatches
|
||||
|
||||
/// A colour value drawn as a picture, for the one surface that cannot take a SwiftUI shape: **menu
|
||||
/// items**. AppKit renders a menu row from its label's image and text, so the quick-style recents row
|
||||
/// (03-board-ui.md § Styling ▸ Controls) needs an `NSImage` per dot where the editor's own wells are
|
||||
/// ordinary views.
|
||||
enum PaletteSwatch {
|
||||
|
||||
/// A filled dot for `value` (a palette name or `#RRGGBB[AA]` hex), hairline-bordered.
|
||||
///
|
||||
/// The border is not decoration: the background palette contains `chalk` (`#FFFFFF`), and an
|
||||
/// unbordered white dot on a light menu is an invisible menu item — the same reason the editor's
|
||||
/// wells are stroked (10-accessibility.md's contrast stance applied to the app's own chrome).
|
||||
///
|
||||
/// A value that resolves to nothing draws the border alone rather than a guessed colour, matching
|
||||
/// every other lenient rendering here: there is no colour, so show none.
|
||||
static func circleImage(for value: String, diameter: CGFloat = 14) -> NSImage {
|
||||
let color = Palette.nsColor(for: value)
|
||||
return NSImage(size: NSSize(width: diameter, height: diameter), flipped: false) { rect in
|
||||
let inset = rect.insetBy(dx: 0.5, dy: 0.5)
|
||||
let path = NSBezierPath(ovalIn: inset)
|
||||
// Under a translucent colour the menu's own backdrop would show through unevenly across
|
||||
// appearances; filling the standard control backdrop first makes the dot composite the
|
||||
// same way in light and dark. An opaque colour covers it completely.
|
||||
NSColor.textBackgroundColor.setFill()
|
||||
path.fill()
|
||||
color?.setFill()
|
||||
path.fill()
|
||||
NSColor.separatorColor.setStroke()
|
||||
path.lineWidth = 1
|
||||
path.stroke()
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Palette {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user