Build the board popover — title widget, rename, styling, git slot
The window-title widget arrives as a leading titlebar accessory — a quiet chevron on board windows only, installed and removed by the window controller's own attach lifecycle — anchoring the one board-level surface as a transient popover (the board window deliberately grows no toolbar item for it). Inside: board rename editing frontmatter title only (the folder is never renamed; an empty commit removes the key and the window title falls back to the folder name), the embedded shared style editor permanently targeting the board, and the labeled Git section that this milestone only reserves — a mode-none explanation and a disabled stub where m7's add-git, branch, remote, and authentication controls land. Cmd-I (File > Board Info) toggles it per window through a focused scene value, kept apart from board-scoped transient state since a titlebar popover belongs to one window, not to the board. Escape reverts a dirty rename field and falls through to dismiss otherwise; a foreign rename resyncs the field only while unfocused. 12 new tests. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -979,6 +979,49 @@ public final class BoardStore {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Board rename
|
||||
|
||||
/// Writes the board's own `title` — the board popover's rename field (03-board-ui.md § Board
|
||||
/// popover), and the one rename in the app with no item to aim at.
|
||||
///
|
||||
/// **It edits frontmatter, never the folder**: "Rename edits the board's frontmatter `title`
|
||||
/// only — the folder is never renamed by the app; the Finder document name is Finder's to
|
||||
/// change" (§ Board popover, 01-storage-format.md § Board naming). The app's display name and
|
||||
/// the Finder document name may therefore diverge, which is accepted rather than reconciled.
|
||||
///
|
||||
/// The three commit rules are `commitRename`'s, deliberately identical — one rename vocabulary
|
||||
/// whatever level it is aimed at:
|
||||
///
|
||||
/// - **Trimmed**, so a title of three spaces is a slip rather than a name.
|
||||
/// - **An empty commit removes the key.** A board with no `title` falls back to its *folder
|
||||
/// name* (§ Board naming) — never the "Untitled" placeholder cards and lanes show, and never
|
||||
/// `title: ""`, which would be a real if blank title with nothing to fall back to.
|
||||
/// - **An unchanged title writes nothing**, so a popover opened and dismissed with Return
|
||||
/// neither stamps `modified` nor mints a commit.
|
||||
///
|
||||
/// There is no vanished-target guard, because a board cannot tombstone itself out of its own
|
||||
/// window (01-storage-format.md § Deletion): the only way this target goes away is the root
|
||||
/// itself vanishing, which is the read-only lock's story, and `performWrite` refuses under it
|
||||
/// before anything touches disk.
|
||||
public func renameBoard(_ title: String?) {
|
||||
let typed = (title ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let newTitle: String? = typed.isEmpty ? nil : typed
|
||||
guard newTitle != snapshot.title.value else { return }
|
||||
|
||||
let folder = rootURL
|
||||
try? performWrite { () throws(BoardWriteError) -> Void in
|
||||
// `.rename(title: nil)`: `updateIndex` enriches it off the document it reads, so a
|
||||
// refusal names the board by the title it still has (see `WriteOperation.rename`).
|
||||
try BoardWriter.updateIndex(inItemFolder: folder, operation: .rename(title: nil)) { document in
|
||||
if let newTitle {
|
||||
document.set(FrontmatterKeys.title, to: .string(newTitle))
|
||||
} else {
|
||||
document.remove(FrontmatterKeys.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Lane reorder
|
||||
|
||||
/// Commits a lane drag: `id` lands at display position `index` among the board's live lanes,
|
||||
|
||||
Reference in New Issue
Block a user