import AppKit /// The `icon` field's rendering rule: **a name that resolves is drawn, anything else falls back to /// the level's default** (03-board-ui.md § Styling ▸ Capabilities, "`icon`: SF Symbol per item with /// per-level defaults"). /// /// ### Lenient, never an error /// /// `icon` is a lenient field (01-storage-format.md § Frontmatter): a typo in a hand-written name is /// not a load failure, not a warning, and not an empty box — it renders as the default and the /// author's bytes are left exactly as written until they change them. That mirrors the read side's /// treatment of `width`, and it is what makes "any other SF Symbol name works written by hand" /// (03 § Controls) safe to promise: the app's curated grid is a convenience, the file is the escape /// hatch, and a name the running OS does not happen to have simply degrades. /// /// `NSImage(systemSymbolName:)` is the only honest test — the symbol set is the *OS's*, and it grows /// between releases, so a hard-coded allow-list would be wrong the day after it was written. enum ItemSymbol { /// The per-level defaults, verbatim from 03-board-ui.md § Styling ▸ Capabilities. static let board = "rectangle.split.3x1" static let lane = "square.stack" static let card = "doc.text" /// `field`'s symbol name if it names a symbol this system can draw, `fallback` otherwise. /// /// Handles all three `FieldValue` shapes the same way, which is the point: a missing key, a /// malformed one (a sequence where a scalar belongs), and a valid-but-unknown name are one /// case to the renderer — *there is no symbol to draw, so draw the default*. static func name(_ field: FieldValue, fallback: String) -> String { guard let name = field.value, exists(name) else { return fallback } return name } /// Whether the running system can draw `name` as an SF Symbol. /// /// Uncached deliberately. The lookup is a bundle-backed symbol resolution that AppKit itself /// caches, it runs once per lane per render pass, and a cache here would be one more piece of /// main-actor state to keep honest across the OS's own symbol availability. If a profile ever /// says otherwise, this one function is where the memo goes. static func exists(_ name: String) -> Bool { !name.isEmpty && NSImage(systemSymbolName: name, accessibilityDescription: nil) != nil } }