Build Preview mode rendering
The card body's resting state: swift-markdown (pinned 0.8.0, smart typography off — Preview renders the bytes on disk) parsed into a pure BodyMarkup model with UTF-8 source offsets, rendered on one hosted TextKit 1 NSTextView — chosen because find-in-text is NSTextFinder, checkbox clicks reuse AppKit character hit-testing, links are .link attributes, and NSTextTable's automatic layout is exactly the columns-sized-to-contents rule. The GFM subset renders per 05; HTML stays verbatim code-styled text; relative images resolve against the card folder while remote URLs are never fetched, drawing a quiet chip instead. Task checkboxes are live: a click flips exactly one byte through a fresh-read, refuse-uneditable, stamp, atomic-replace write — the app's only offset-addressed write, so a moved target refuses as staleTarget and what the user saw decides the direction, netting one toggle on a double-click. Empty bodies open in Edit per CardBodyMode's opening rule, applied once; the Edit surface itself stays an honest read-only stub until its card. FindCommand prefers the card body's find over board search when a card window is focused. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -641,6 +641,11 @@ public final class BannerCenter {
|
||||
// failure the user did not provoke is exactly the one they have no other way to learn
|
||||
// about.
|
||||
"Couldn't move '\(filename)' into attachments"
|
||||
case let .toggleTask(title):
|
||||
// The user's word for it, not the file's: they ticked a box. The card is named where
|
||||
// the read that preceded the flip learned its title, so a body write that refused says
|
||||
// *which* card refused it — a card window is not always the frontmost thing on screen.
|
||||
if let title { "Couldn't tick the checkbox in '\(title)'" } else { "Couldn't tick the checkbox" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,6 +660,8 @@ public final class BannerCenter {
|
||||
"this file's frontmatter can't be edited in place (\(shape.description))"
|
||||
case let .io(message):
|
||||
message
|
||||
case let .staleTarget(message):
|
||||
message
|
||||
}
|
||||
return trimmed(text)
|
||||
}
|
||||
|
||||
@@ -1127,6 +1127,36 @@ public final class BoardStore {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Task checkboxes
|
||||
|
||||
/// Ticks or unticks a Preview task-list checkbox — **the app's one write into a card's body**
|
||||
/// (05-card-window.md ▸ Preview), and otherwise an entirely ordinary one: the same
|
||||
/// `performWrite` bracket, the same banner on failure, the same one-way flow back through the
|
||||
/// watcher. "A toggle is an ordinary user edit — the standard atomic write, auto-committed and
|
||||
/// undoable on git boards."
|
||||
///
|
||||
/// `bodyOffset` is the UTF-8 byte offset the parse handed the renderer (`BodyTask
|
||||
/// .markerOffset`) and `checked` is the state the user was looking at; both travel to
|
||||
/// `BoardWriter.toggleTaskMarker`, which re-verifies them against the file it reads and refuses
|
||||
/// rather than write blind. Nothing here inspects the body: the store never re-parses to
|
||||
/// second-guess the click, because its own snapshot is exactly as stale as the render was.
|
||||
///
|
||||
/// **A checkbox in a card that has gone writes nothing** — the vanished-target guard every
|
||||
/// gesture in this file makes, ancestor-walked through `liveItem`: the card window would be
|
||||
/// dismissing itself in the same breath, and the reload that removed the card is the authority.
|
||||
/// The read-only lock is `performWrite`'s refusal, which is also why the controls disable in
|
||||
/// place on the Preview side rather than failing here (02-architecture.md § the lock's scope).
|
||||
public func toggleTaskMarker(inCard cardID: ItemID, bodyOffset: Int, checked: Bool) {
|
||||
guard let target = Self.liveItem(cardID, in: snapshot), let card = target.cardID else { return }
|
||||
let folder = rootURL
|
||||
.appendingPathComponent(target.laneID.rawValue, isDirectory: true)
|
||||
.appendingPathComponent(card.rawValue, isDirectory: true)
|
||||
|
||||
try? performWrite { () throws(BoardWriteError) -> Void in
|
||||
try BoardWriter.toggleTaskMarker(inItemFolder: folder, bodyOffset: bodyOffset, checked: checked)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Board rename
|
||||
|
||||
/// Writes the board's own `title` — the board popover's rename field (03-board-ui.md § Board
|
||||
|
||||
Reference in New Issue
Block a user