The Background tab becomes Theme — solid colors or patterns, presets only, chevron-paged
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -2050,6 +2050,81 @@ public final class BoardStore: HealHost {
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Solid background
|
||||
|
||||
/// **Applies a solid colour background to this board** — the `background.color` subkey set and
|
||||
/// the `background.image` subkey removed, in one bracket (03-board-ui.md § Styling ▸ Theme tab;
|
||||
/// the Solid color half of `BoardThemeTabView`'s picker).
|
||||
///
|
||||
/// Modeled line-for-line on `applyGeneratedBackground` **minus the file write**: there is no
|
||||
/// picture to land, so the bracket holds a single `updateIndex` rather than an image write ahead
|
||||
/// of one. Everything else is that gesture's, restated here rather than shared because the two
|
||||
/// brackets differ in exactly the one place that matters (one write versus two): the same
|
||||
/// undo-restores-both-fields shape, the same `WriteOperation.setBoardBackground`, the same
|
||||
/// swallowed failure.
|
||||
///
|
||||
/// ### `facets.png` survives on disk
|
||||
///
|
||||
/// Choosing a solid colour over a generated background does **not** delete the picture the
|
||||
/// generator wrote. Undo restores the `image` *field*, and a field cannot point an undo back at
|
||||
/// bytes this gesture just erased — so the file has to survive for the same reason
|
||||
/// `applyGeneratedBackground`'s own overwrite-in-place does. A board that regenerates after
|
||||
/// choosing solid still finds `facets.png` free to overwrite in place; the file becomes an orphan
|
||||
/// only when nothing in the frontmatter ever points at it again, which is the same quiet leftover
|
||||
/// a hand-deleted `image:` line already leaves.
|
||||
///
|
||||
/// - Parameter colorHex: the solid colour to write, `#RRGGBB` — one of the Theme tab's Solid color
|
||||
/// swatches, which read `FacetsRecipe.primaryColorHex` at the filters' tone/saturation level.
|
||||
/// - Returns: whether bytes reached disk (`applyGeneratedBackground`'s same rule). Discardable:
|
||||
/// the picker has nothing to do with the answer.
|
||||
@discardableResult
|
||||
public func applySolidBackground(colorHex: String) -> Bool {
|
||||
let root = rootURL
|
||||
let priorImage = snapshot.backgroundImage
|
||||
let priorColor = snapshot.background
|
||||
|
||||
let landed: Void? = try? performWrite { () throws(BoardWriteError) -> Void in
|
||||
try BoardWriter.updateIndex(
|
||||
inItemFolder: root, kind: .board, operation: .setBoardBackground
|
||||
) { document in
|
||||
Self.pointSolidBackground(color: colorHex, in: &document)
|
||||
}
|
||||
}
|
||||
guard landed != nil else { return false }
|
||||
|
||||
// restyle → prior style (13-native-undo.md ▸ Rules). The board's own stack, never a window's:
|
||||
// there is no card here to have a session.
|
||||
registerStep(
|
||||
HistoryPhrase.name(.restyle, kind: .board),
|
||||
undoExpects: [.present(root, .background(colorHex), .backgroundImage(nil))],
|
||||
redoExpects: [.present(root, .background(priorColor.value), .backgroundImage(priorImage.value))]
|
||||
) { _ in
|
||||
try BoardWriter.updateIndex(
|
||||
inItemFolder: root, kind: .board, operation: .setBoardBackground
|
||||
) { document in
|
||||
// A malformed prior reads as a removal on both subkeys, `restore(_:to:in:)`'s own
|
||||
// rule and the one the redo expectation above is written against.
|
||||
document.setBackgroundImage(priorImage.value)
|
||||
Self.restore(priorColor, to: FrontmatterKeys.background, in: &document)
|
||||
}
|
||||
} redo: { _ in
|
||||
try BoardWriter.updateIndex(
|
||||
inItemFolder: root, kind: .board, operation: .setBoardBackground
|
||||
) { document in
|
||||
Self.pointSolidBackground(color: colorHex, in: &document)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/// The one subkey write and the one subkey removal, spelled once so the gesture and its redo
|
||||
/// cannot drift apart on the order they land in — `pointBackground(at:color:in:)`'s sibling, one
|
||||
/// image write short.
|
||||
private static func pointSolidBackground(color: String, in document: inout FrontmatterDocument) {
|
||||
document.setStyleValue(color, for: FrontmatterKeys.background)
|
||||
document.setBackgroundImage(nil)
|
||||
}
|
||||
|
||||
/// The name a generated background is written under: **ours to overwrite**, or the next free one.
|
||||
///
|
||||
/// `current` is what `background.image` says now. When that is already the generated name the
|
||||
|
||||
Reference in New Issue
Block a user