The board wears a picture — background becomes a mapping, and the window chrome follows it under a thin frost
background is {color:, image:} and only a mapping at every level; the board's image paints the full window under a transparent title bar, with a thin-material frost strip keeping the chrome legible and the standard accommodations intact.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -51,9 +51,9 @@ private func makeBoard() throws -> WriterFixture {
|
||||
let fixture = try WriterFixture()
|
||||
try fixture.item("", boardIndex)
|
||||
try fixture.item(Ident.lane1, styled(order: "1024", title: "Todo"))
|
||||
try fixture.item("\(Ident.lane1)/\(Ident.card1)", styled(order: "1024", title: "First", keys: ["background: fern", "iconColor: chalk"]))
|
||||
try fixture.item("\(Ident.lane1)/\(Ident.card1)", styled(order: "1024", title: "First", keys: ["background: {color: fern}", "iconColor: chalk"]))
|
||||
try fixture.item("\(Ident.lane1)/\(Ident.card2)", styled(order: "2048", title: "Second"))
|
||||
try fixture.item(Ident.lane2, styled(order: "2048", title: "Doing", keys: ["background: chalk", "icon: tray"]))
|
||||
try fixture.item(Ident.lane2, styled(order: "2048", title: "Doing", keys: ["background: {color: chalk}", "icon: tray"]))
|
||||
try fixture.item("\(Ident.lane2)/\(Ident.card3)", styled(order: "1024", title: "Third"))
|
||||
try fixture.item(Ident.lane3, Item.uneditable)
|
||||
try fixture.item(Ident.lane4, styled(order: "4096", title: "Gone"))
|
||||
@@ -120,7 +120,7 @@ struct StyleWriteTests {
|
||||
store.applyStyle(to: .items([card2]), background: .set("smokey-ocean"))
|
||||
|
||||
let after = try fixture.indexText("\(Ident.lane1)/\(Ident.card2)")
|
||||
#expect(after.contains("background: smokey-ocean"))
|
||||
#expect(after.contains("background: {color: \"smokey-ocean\"}"))
|
||||
#expect(!after.contains("icon:"), "the untouched dimension writes no key at all")
|
||||
#expect(!after.contains("modified-by"), "an app-mediated write clears an external writer's attribution")
|
||||
#expect(untouchedLines(after) == untouchedLines(before))
|
||||
@@ -141,13 +141,13 @@ struct StyleWriteTests {
|
||||
store.applyStyle(to: .items([card1]), background: .set("dark-teal"), icon: .set("flag"))
|
||||
|
||||
let after = try fixture.indexText("\(Ident.lane1)/\(Ident.card1)")
|
||||
#expect(after.contains("background: dark-teal"))
|
||||
#expect(after.contains("background: {color: \"dark-teal\"}"))
|
||||
#expect(after.contains("icon: flag"))
|
||||
// "iconColor: resolved — schema yes, control no" (03 § Styling ▸ Capabilities): the field
|
||||
// renders when hand-written and the app offers no control for it, so a style write must
|
||||
// carry it through untouched like any unknown key.
|
||||
#expect(after.contains("iconColor: chalk"))
|
||||
#expect(!after.contains("background: fern"), "the old value is replaced, not duplicated")
|
||||
#expect(!after.contains("fern"), "the old value is replaced, not duplicated")
|
||||
}
|
||||
|
||||
@Test("The None and default wells remove their key rather than writing a blank value")
|
||||
@@ -182,8 +182,8 @@ struct StyleWriteTests {
|
||||
|
||||
#expect(log.begins == 1)
|
||||
#expect(log.ends == 1)
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card1)").contains("background: light-cayenne"))
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card2)").contains("background: light-cayenne"))
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card1)").contains("background: {color: \"light-cayenne\"}"))
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card2)").contains("background: {color: \"light-cayenne\"}"))
|
||||
}
|
||||
|
||||
@Test("A value a target already carries writes nothing — per target and per dimension")
|
||||
@@ -195,13 +195,13 @@ struct StyleWriteTests {
|
||||
log.attach(to: store)
|
||||
let untouchedCard = try fixture.indexData("\(Ident.lane1)/\(Ident.card1)")
|
||||
|
||||
// `card1` is already `fern` and `card2` has no background at all: only the second file may
|
||||
// `card1` is already `{color: fern}` and `card2` has no background at all: only the second file may
|
||||
// move. A well clicked twice must not stamp `modified` or mint a commit on what was already
|
||||
// right (`setLaneWidth`'s rule).
|
||||
store.applyStyle(to: .items([card1, card2]), background: .set("fern"))
|
||||
|
||||
#expect(try fixture.indexData("\(Ident.lane1)/\(Ident.card1)") == untouchedCard)
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card2)").contains("background: fern"))
|
||||
#expect(try fixture.indexText("\(Ident.lane1)/\(Ident.card2)").contains("background: {color: \"fern\"}"))
|
||||
#expect(log.begins == 1, "the batch still opens exactly one bracket for the target that moved")
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ struct StyleWriteTests {
|
||||
log.attach(to: store)
|
||||
let before = try fixture.indexData("\(Ident.lane1)/\(Ident.card1)")
|
||||
|
||||
// Both dimensions already read this way: `background: fern` is set and `icon` is absent, so
|
||||
// Both dimensions already read this way: the colour is already `fern` and `icon` is absent, so
|
||||
// the removal is a no-op too.
|
||||
store.applyStyle(to: .items([card1]), background: .set("fern"), icon: .remove)
|
||||
|
||||
@@ -234,7 +234,7 @@ struct StyleWriteTests {
|
||||
store.applyStyle(to: .items([card2]), background: .set("shale"))
|
||||
|
||||
let after = try fixture.indexText("\(Ident.lane1)/\(Ident.card2)")
|
||||
#expect(after.contains("background: shale"))
|
||||
#expect(after.contains("background: {color: \"shale\"}"))
|
||||
#expect(!after.contains("[a, b]"))
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ struct StyleWriteTests {
|
||||
store.applyStyle(to: .board, background: .set("intense-cool-shale"), icon: .set("square.stack"))
|
||||
|
||||
let after = try fixture.indexText("")
|
||||
#expect(after.contains("background: intense-cool-shale"))
|
||||
#expect(after.contains("background: {color: \"intense-cool-shale\"}"))
|
||||
#expect(after.contains("icon: square.stack"))
|
||||
#expect(after.contains("iconColor: carnation"))
|
||||
#expect(after.contains("Board description."))
|
||||
@@ -258,6 +258,38 @@ struct StyleWriteTests {
|
||||
#expect(lane(lane1, in: model)?.background.isMissing == true)
|
||||
}
|
||||
|
||||
/// **The mapping form, through the real writer** (03-board-ui.md § Styling ▸ Capabilities; the
|
||||
/// unit-level claims are `BackgroundWriteTests`'). The app has a control for the colour and none
|
||||
/// for the image, so the whole gesture — well, then None — has to leave the image standing.
|
||||
@Test("A colour change on a board carrying an image preserves the image, and None drops only the colour")
|
||||
func preservesABackgroundImage() throws {
|
||||
let fixture = try WriterFixture()
|
||||
defer { fixture.tearDown() }
|
||||
try fixture.item("", """
|
||||
---
|
||||
schema: 1
|
||||
title: Board
|
||||
background: {color: fern, image: art/sunset.jpg}
|
||||
---
|
||||
Board description.
|
||||
|
||||
""")
|
||||
let store = try BoardStore(rootURL: fixture.root)
|
||||
|
||||
store.applyStyle(to: .board, background: .set("dark-teal"))
|
||||
|
||||
var model = try load(fixture)
|
||||
#expect(model.background == .valid("dark-teal"))
|
||||
#expect(model.backgroundImage == .valid("art/sunset.jpg"))
|
||||
#expect(try fixture.indexText("").contains("Board description."))
|
||||
|
||||
store.applyStyle(to: .board, background: .remove)
|
||||
|
||||
model = try load(fixture)
|
||||
#expect(model.background.isMissing)
|
||||
#expect(model.backgroundImage == .valid("art/sunset.jpg"), "the None well removes the colour, not the picture")
|
||||
}
|
||||
|
||||
@Test("Vanished and trashed targets are skipped silently")
|
||||
func skipsTargetsThatRenderNowhere() throws {
|
||||
let fixture = try makeBoard()
|
||||
|
||||
Reference in New Issue
Block a user