Generated and pasted board backgrounds move into .backgrounds/ — the board root stops collecting the app's own pictures
New app-written background images (Theme tab ▸ Pattern, and Edit ▸ Paste as Board Background) now land in a hidden `.backgrounds/` folder at board root instead of beside index.md, matching the `.trash/` app-managed pattern. `background.image` stores the qualified relative reference (`.backgrounds/facets.png`); the resolver needed no change at all, since it already accepted any relative path inside the board root — the same mechanism that already resolved `art/backdrops/sunset.png` resolves the new location for free. `BoardWriter.writeBoardImage` now creates its destination folder if missing, since `.backgrounds/` won't exist until a board's first generated or pasted background. The Finder collision-ladder (`BoardStore.boardImageName`) is rescoped to `.backgrounds/`'s own contents, and its overwrite-in-place check now recognizes only the qualified form as "ours" — a legacy bare `background.image: facets.png` from before this change is read as a foreign reference rather than migrated, so a regeneration writes a fresh `.backgrounds/` file and orphans the old one in place, per the no-migration ruling. The Theme tab's Pattern/Solid mode-detection was updated to recognize both the legacy and current spellings as the generator's own output. The board loader needed no change: `.backgrounds/` is a hidden, non-UUID-shaped name, and `.skipsHiddenFiles` already keeps every hidden entry off the lane walk before any name-based exclusion is consulted — pinned with a new loader test. Deliberately did not add `.backgrounds` to IntegrityRules' claimed-name/squatter-displacement table: that table mirrors a specific existing DESIGN ruling this card doesn't amend. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -665,7 +665,7 @@ struct PasteBoardBackgroundTests {
|
||||
try FrontmatterDocument.parse(fixture.indexText(""))
|
||||
}
|
||||
|
||||
@Test("The picture lands in the board folder and `background.image` names it")
|
||||
@Test("The picture lands in .backgrounds/ and `background.image` names it")
|
||||
func thePictureLands() throws {
|
||||
let harness = try makeClipboardHarness()
|
||||
defer { harness.tearDown() }
|
||||
@@ -674,8 +674,8 @@ struct PasteBoardBackgroundTests {
|
||||
|
||||
#expect(harness.clipboard.pasteBoardBackground(into: harness.store))
|
||||
|
||||
#expect(try harness.fixture.data("Pasted Background.png") == png)
|
||||
#expect(try background(harness.fixture).backgroundImage.value == "Pasted Background.png")
|
||||
#expect(try harness.fixture.data(".backgrounds/Pasted Background.png") == png)
|
||||
#expect(try background(harness.fixture).backgroundImage.value == ".backgrounds/Pasted Background.png")
|
||||
#expect(harness.store.banners.oneShots.isEmpty)
|
||||
}
|
||||
|
||||
@@ -693,7 +693,7 @@ struct PasteBoardBackgroundTests {
|
||||
|
||||
let document = try background(harness.fixture)
|
||||
#expect(document.background.value == "#112233")
|
||||
#expect(document.backgroundImage.value == "Pasted Background.png")
|
||||
#expect(document.backgroundImage.value == ".backgrounds/Pasted Background.png")
|
||||
}
|
||||
|
||||
/// The generator's overwrite-in-place rule, inherited: re-pasting must not leave a folder full of
|
||||
@@ -710,24 +710,25 @@ struct PasteBoardBackgroundTests {
|
||||
harness.pasteboard.seed([(UTType.png.identifier, second)])
|
||||
#expect(harness.clipboard.pasteBoardBackground(into: harness.store))
|
||||
|
||||
#expect(try harness.fixture.data("Pasted Background.png") == second)
|
||||
#expect(!harness.fixture.exists("Pasted Background 2.png"))
|
||||
#expect(try harness.fixture.data(".backgrounds/Pasted Background.png") == second)
|
||||
#expect(!harness.fixture.exists(".backgrounds/Pasted Background 2.png"))
|
||||
}
|
||||
|
||||
/// A hand-placed file of that name is the user's, and is never written through — the ladder's
|
||||
/// rule, the same one the generator follows.
|
||||
/// A hand-placed file of that name **inside `.backgrounds/`** is the user's, and is never written
|
||||
/// through — the ladder's rule, the same one the generator follows. A file of that name at board
|
||||
/// root would not collide at all any more: it simply is not where this write ever looks.
|
||||
@Test("A file already holding the name is stepped around")
|
||||
func anExistingNameIsRespected() throws {
|
||||
let harness = try makeClipboardHarness()
|
||||
defer { harness.tearDown() }
|
||||
let mine = Data("hand placed".utf8)
|
||||
try harness.fixture.file("Pasted Background.png", mine)
|
||||
try harness.fixture.file(".backgrounds/Pasted Background.png", mine)
|
||||
harness.pasteboard.seed([(UTType.png.identifier, encodedImage(.png))])
|
||||
|
||||
#expect(harness.clipboard.pasteBoardBackground(into: harness.store))
|
||||
|
||||
#expect(try harness.fixture.data("Pasted Background.png") == mine)
|
||||
#expect(try background(harness.fixture).backgroundImage.value == "Pasted Background 2.png")
|
||||
#expect(try harness.fixture.data(".backgrounds/Pasted Background.png") == mine)
|
||||
#expect(try background(harness.fixture).backgroundImage.value == ".backgrounds/Pasted Background 2.png")
|
||||
}
|
||||
|
||||
/// The two producers must not read each other's echo: a paste landing inside the reroll's window
|
||||
@@ -743,8 +744,8 @@ struct PasteBoardBackgroundTests {
|
||||
|
||||
#expect(harness.clipboard.pasteBoardBackground(into: harness.store))
|
||||
|
||||
#expect(try harness.fixture.data(FacetsGenerator.fileName) == generated, "untouched")
|
||||
#expect(try background(harness.fixture).backgroundImage.value == "Pasted Background.png")
|
||||
#expect(try harness.fixture.data(".backgrounds/\(FacetsGenerator.fileName)") == generated, "untouched")
|
||||
#expect(try background(harness.fixture).backgroundImage.value == ".backgrounds/Pasted Background.png")
|
||||
}
|
||||
|
||||
@Test("⌘Z puts the image subkey back and leaves the colour alone")
|
||||
@@ -757,17 +758,17 @@ struct PasteBoardBackgroundTests {
|
||||
|
||||
#expect(store.applyPastedBackground(data: encodedImage(.png), fileExtension: "png"))
|
||||
#expect(try FrontmatterDocument.parse(fixture.indexText("")).backgroundImage.value
|
||||
== "Pasted Background.png")
|
||||
== ".backgrounds/Pasted Background.png")
|
||||
#expect(history.undoActionName == "Restyle Board")
|
||||
|
||||
history.undo()
|
||||
#expect(try FrontmatterDocument.parse(fixture.indexText("")).backgroundImage.isMissing)
|
||||
// The file survives the undo — "the undo restores the field, not the bytes".
|
||||
#expect(fixture.exists("Pasted Background.png"))
|
||||
#expect(fixture.exists(".backgrounds/Pasted Background.png"))
|
||||
|
||||
history.redo()
|
||||
#expect(try FrontmatterDocument.parse(fixture.indexText("")).backgroundImage.value
|
||||
== "Pasted Background.png")
|
||||
== ".backgrounds/Pasted Background.png")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user