Space in Finder opens the board — a Quick Look preview extension that outlines a .kanban package

A board is a folder, and a folder previews as a folder. `KanbanQuickLook.appex` gives it a
document's preview instead: the board's name, its tint and its symbol, then its lanes in display
order with each one's card count and its first few card titles.

The reading is `BoardOutline` (Kanban/Storage), deliberately not `BoardLoader.load`. The loader
throws on a half-broken board — right for opening one, wrong for pressing Space, where the honest
answer is the part that reads; it visits every card and lists `attachments/` and counts `comments/`
inside each; and it carries trash, tombstone migration and the defect stream, none of which renders.
This walk never throws and is capped at every level (`BoardOutlineLimits`): 12 lanes shown of at
most 100 considered, 6 card titles per lane of at most 200 parsed, counts by readdir-plus-stat up to
2000 per lane and never a parse. It re-derives nothing that decides *what* the answer is —
`FrontmatterDocument` parses, `IntegrityRules.isIdentityShaped` says what a lane or a card is,
`BoardLoader.directoryCandidates` supplies the stray tolerance, `Ranks` supplies display order,
`Palette` resolves colours — only *how far to look*.

The reply is HTML, the one data-based reply that reflows: a Quick Look panel is resized by the
user and a board outline is a wrapping row of columns, so a drawing block baked at a fixed
`contentSize` would be the wrong size a moment later. It gets vector text, its own scrolling and
light/dark for free. The board tint is a wash under the title and a lane's edge accent — never
under text, because a preview has none of `ContrastMath`'s ink-picking machinery and should not
grow one.

The extension compiles `Kanban/Storage` whole, the `KanbanMobile` arrangement — the directory is
one unit in practice, so a narrower list is not on offer. `STORAGE_ONLY` is new: EchoLedger's
consumer sections speak the live store's vocabulary, and the phone's `#if os(macOS)` cannot exclude
them from a target that *is* macOS. Platform, and layer. Nothing else defines it.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-09 02:37:10 -04:00
parent da5d310673
commit b18f7ca609
8 changed files with 1260 additions and 2 deletions
+60
View File
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Lanework Board Preview</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Lanework Board Preview</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>© 2026 rzen</string>
<!-- The classic app-extension shape, matching Xcode's own "Quick Look Preview Extension"
template: Quick Look's preview point is an NSExtension point, not an ExtensionKit one.
`QLIsDataBasedPreview` is what selects the data-based half of the API — the principal
class is a `QLPreviewProvider` answering with content (`QLPreviewReply`) rather than an
NSViewController putting a view on screen. See BoardPreviewProvider.swift for why.
`QLSupportedContentTypes` names the board type the *host app* exports (Kanban/Info.plist ▸
UTExportedTypeDeclarations, `LSHandlerRank: Owner`). The extension deliberately re-declares
nothing: it ships inside that app's bundle, so LaunchServices already knows the type, and a
second declaration of one identifier is how two bundles end up disagreeing about it.
`QLSupportsSearchableItems` is false — this previews files, and there is no Spotlight
searchable-item vocabulary behind a board. -->
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.quicklook.preview</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).BoardPreviewProvider</string>
<key>NSExtensionAttributes</key>
<dict>
<key>QLSupportedContentTypes</key>
<array>
<string>dev.rzen.indie.kanban-board</string>
</array>
<key>QLSupportsSearchableItems</key>
<false/>
<key>QLIsDataBasedPreview</key>
<true/>
</dict>
</dict>
</dict>
</plist>