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:
@@ -79,6 +79,32 @@ enum CardWindowMetrics {
|
||||
columnWidth(characters: bodyMinimumCharacters, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
// MARK: - The rendered body
|
||||
|
||||
/// One step of structural indent in Preview — a list level, a quote level. One and a half ems,
|
||||
/// which is wide enough for a bullet plus its space and narrow enough that four nested levels
|
||||
/// still leave a measure worth reading.
|
||||
static func previewIndent(bodyPointSize: CGFloat) -> CGFloat {
|
||||
(bodyPointSize * 1.5).rounded()
|
||||
}
|
||||
|
||||
/// The inside padding of a table cell and the inset of a code block — half a gutter, so the
|
||||
/// rendered body's rhythm is the column's rhythm halved rather than a second, unrelated one.
|
||||
static func previewPadding(bodyPointSize: CGFloat) -> CGFloat {
|
||||
(gutter(bodyPointSize: bodyPointSize) / 2).rounded()
|
||||
}
|
||||
|
||||
/// The widest an inline image is drawn at.
|
||||
///
|
||||
/// A number rather than "the text container's width" on purpose: a `NSTextAttachment`'s bounds
|
||||
/// are fixed at build time, so an image sized to the window would have to be rebuilt on every
|
||||
/// resize — and the body column is resizable by contract. A generous cap keeps a screenshot
|
||||
/// legible without letting a 4000-pixel-wide one push the measure around, and an image narrower
|
||||
/// than the cap is never enlarged.
|
||||
static func previewImageMaximumWidth(bodyPointSize: CGFloat) -> CGFloat {
|
||||
columnWidth(characters: 56, bodyPointSize: bodyPointSize)
|
||||
}
|
||||
|
||||
// MARK: - The window
|
||||
|
||||
/// The window's minimum size: the sidebar's fixed width plus the body's floor, and tall enough
|
||||
|
||||
Reference in New Issue
Block a user