The whole board-name area opens the popover — the chevron alone was the trigger

The titlebar widget grows from a 20×18 chevron into one button saying
the board's name and, on a git-mode Pro board, its branch — click
anywhere across it and the popover opens as before, anchored to the
widget. BoardInfoTitlebarSummary is the pure seam for both strings
(title falls back to the folder name per 01's naming rule; branch only
under pro + git mode, live off the observable HistoryStore.branch).
Board windows now hide the system title display through the same
hideTitle slot card windows adopted — the widget says the name, so the
chrome would only repeat it — while navigationTitle keeps feeding
window.title to the Window menu, Exposé, VoiceOver and restoration.

The widget also refreshes the branch eagerly at appearance: it used to
populate only once the popover had been opened, which would have left
the new branch line empty on a freshly opened board.

Claude-Session: https://claude.ai/code/session_01CqjXB7ASoWtbyoGod68k97
This commit is contained in:
2026-08-01 08:28:53 -04:00
parent 6f2e0d15da
commit 94e60cd444
6 changed files with 253 additions and 34 deletions
+69
View File
@@ -77,3 +77,72 @@ struct BoardGitSectionTests {
#expect(resolved == Set(BoardGitSection.allCases))
}
}
/// **The window-title widget's two strings** (03-board-ui.md Board popover, the card that widened
/// the widget from a chevron to the whole board-name area): `BoardInfoTitlebarSummary` is the pure
/// function this pins, exactly as `BoardGitSectionTests` above pins the section it shares its
/// tier/mode inputs with. No disk I/O the title half of this seam takes a raw `URL`, not a
/// `BoardStore`, so a plain `/tmp/...` path is enough.
@Suite("Board popover ▸ the widget's strings")
struct BoardInfoTitlebarSummaryTests {
private let root = URL(fileURLWithPath: "/tmp/My Board.board")
@Test("The title is the on-disk title, falling back to the folder name sans extension")
func titleFallsBackToTheFolderName() {
let named = BoardInfoTitlebarSummary(
snapshotTitle: "Sprint 12", rootURL: root, tier: .free, mode: .none, branch: nil
)
#expect(named.title == "Sprint 12")
let untitled = BoardInfoTitlebarSummary(
snapshotTitle: nil, rootURL: root, tier: .free, mode: .none, branch: nil
)
#expect(untitled.title == "My Board")
let emptyTitled = BoardInfoTitlebarSummary(
snapshotTitle: "", rootURL: root, tier: .free, mode: .none, branch: nil
)
#expect(
emptyTitled.title == "My Board",
"an empty title reads the same as no title at all — the window-title rule this seam restates"
)
}
@Test("The branch shows under Pro, in git mode, once it has been read")
func branchShowsForProGitMode() {
let summary = BoardInfoTitlebarSummary(
snapshotTitle: nil, rootURL: root, tier: .pro, mode: .git, branch: "main"
)
#expect(summary.branch == "main")
}
@Test("The free tier never shows a branch, whatever the mode or the git state hands it")
func theFreeTierNeverShowsABranch() {
for mode in BoardGitMode.allCases {
let summary = BoardInfoTitlebarSummary(
snapshotTitle: nil, rootURL: root, tier: .free, mode: mode, branch: "main"
)
#expect(summary.branch == nil, "detection never runs under the free tier, so a stray branch value must never surface")
}
}
@Test("An inert .git under Pro — mode none or repo-nested — never shows a branch")
func inertGitNeverShowsABranch() {
#expect(
BoardInfoTitlebarSummary(snapshotTitle: nil, rootURL: root, tier: .pro, mode: .none, branch: "main").branch == nil
)
#expect(
BoardInfoTitlebarSummary(snapshotTitle: nil, rootURL: root, tier: .pro, mode: .repoNested, branch: "main").branch
== nil
)
}
@Test("A git-mode board whose branch has not been read yet shows none, honestly")
func unreadBranchShowsNone() {
let summary = BoardInfoTitlebarSummary(
snapshotTitle: nil, rootURL: root, tier: .pro, mode: .git, branch: nil
)
#expect(summary.branch == nil)
}
}