Build card faces with edge-accent styling
The card face becomes real: leading SF Symbol (card default doc.text, tinted by a valid hand-written iconColor — schema yes, control no), title or the quiet untitled placeholder, and a quiet paperclip when the card has attachments — title-only by design, no body excerpt. Color is the settled K1 edge accent, not a fill: background paints a 4pt stripe down the left edge, resolved through the ported pathfinder palette (12 icon tints + 12 backgrounds carried over verbatim, plus raw #RRGGBB[AA]); anything unresolvable paints nothing and stays on disk exactly as written. The snapshot now carries each card's flat attachment names — the loader's one read inside a card folder, shared with the Writer's listing so the m5 carousel and m6 sidebar can never disagree on order (Finder order, the Writer's existing comparator). The face keeps its top-aligned structure so the sole-selection carousel can expand inside the card without moving masonry neighbors. 18 new tests. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -1002,26 +1002,17 @@ public enum BoardWriter: Sendable {
|
||||
/// directory, *is* `.unreadable` — that is a caller asking about a card that isn't there,
|
||||
/// not an empty listing. Purely a read: nothing here ever creates `attachments/` or
|
||||
/// disturbs anything inside it, subfolders included.
|
||||
///
|
||||
/// The listing itself is `BoardLoader.attachmentNames(in:)`, which is also what fills
|
||||
/// `Card.attachments` for the board window's face indicator and carousel. **One function, so
|
||||
/// the sidebar and the face can never disagree** about a card's attachments or their order.
|
||||
/// What this call adds over that one is the card-folder guard and this API's error
|
||||
/// vocabulary — the difference between a surface that *acts* on the files and two that
|
||||
/// merely show them.
|
||||
public static func listAttachments(ofCard cardFolder: URL) throws(BoardWriteError) -> [String] {
|
||||
let operation = WriteOperation.listAttachments
|
||||
try checkIsDirectory(cardFolder, describedAs: "card folder", operation: operation)
|
||||
|
||||
let attachmentsFolder = cardFolder.appendingPathComponent(attachmentsFolderName, isDirectory: true)
|
||||
guard let entries = try? FileManager.default.contentsOfDirectory(
|
||||
at: attachmentsFolder,
|
||||
includingPropertiesForKeys: [.isRegularFileKey, .isSymbolicLinkKey],
|
||||
options: [.skipsHiddenFiles]
|
||||
) else {
|
||||
return []
|
||||
}
|
||||
|
||||
let files = entries.filter { url in
|
||||
guard let values = try? url.resourceValues(forKeys: [.isRegularFileKey, .isSymbolicLinkKey]) else {
|
||||
return false
|
||||
}
|
||||
return values.isRegularFile == true && values.isSymbolicLink != true
|
||||
}
|
||||
return files.map(\.lastPathComponent).sorted { $0.localizedStandardCompare($1) == .orderedAscending }
|
||||
return BoardLoader.attachmentNames(in: cardFolder)
|
||||
}
|
||||
|
||||
// MARK: - Move/copy pre-flight
|
||||
|
||||
Reference in New Issue
Block a user