The sidebar's Actions section retires — Delete and Reveal in Finder move to the card window's toolbar
Actions is gone from the trailing sidebar. Its two rows land on the card
window's toolbar instead: Delete Card is a new default item (trash SF
Symbol), and Reveal in Finder joins the customizable catalog. The sidebar's
final order is now Style, Details, Attachments — no fourth section.
Delete Card is a push button gated by the same read-only predicate the
sidebar button carried, and it fires the identical write
(BoardStore.deleteCard(_:)) — same bracket, same stamps, no confirmation,
matching the delete flow exactly: recovery is the board's trash lane, so
there is nothing here for an alert to guard. It sits behind a trailing
flexibleSpace in the default set, apart from the four creation/view items
ahead of it, the HIG separation Mail.app's own toolbar Delete models —
one-click, no-confirm, recoverable by trash.
Reveal in Finder is catalog-only: it already had a menu-bar twin with no
default chord (File ▸ Reveal in Finder / RevealInFinderCommand), so nothing
was unreachable before this — the toolbar item is Customize's shortcut to
the same computation (CardAttachments.revealURLs), not a new path.
Delete Card needed a menu-row twin of its own before it could sit on the
toolbar at all ("toolbars are pure enhancement: every function they host
already has a menu item + shortcut" — 03-board-ui.md ▸ Toolbar). File ▸
Delete Card is that row: distinctly titled from the board-scope File ▸
Delete (whose title 11-command-nexus.md calls out as the ⌘⌫ chord's
singleton), and deliberately chord-less — an enabled delete-key equivalent
in the card window would steal delete-to-line-start from its text surfaces,
the same reason the board's own ⌘⌫ was never extended here in the first
place. A new small handle, CardWindowActions, carries the wiring through the
focus system the way CardAttachments and CardPrintSubject already do for
their own single-purpose seams — kept separate from CardAttachments on
purpose, since a delete has nothing to do with the attachments section that
type is scoped to.
CardToolbarTests grows the BoardToolbarTests split (defaults vs. catalog,
now that they differ) plus two new suites: Delete Card firing the wired
write under the lock, and Reveal in Finder's enablement mirroring the menu
row's own card-window computation.
05-card-window.md's Actions section and 11-command-nexus.md's File-menu
inventory are now stale; both amendments are owed and tracked on the card's
own thread rather than made here.
Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -289,6 +289,11 @@ struct CardWindowHost: View {
|
||||
/// needs them (`CardPrintSubject`). Window-scoped for `CardBodyPresentation`'s reason: two card
|
||||
/// windows are two documents, and the menu bar reaches the frontmost one through the focus system.
|
||||
@State private var cardPrint = CardPrintSubject()
|
||||
/// This window's card-level actions — today, just Delete Card, promoted off the sidebar's former
|
||||
/// Actions section to the toolbar (`CardWindowActions`, `CardToolbar`). Window-scoped for
|
||||
/// `CardBodyPresentation`'s reason: File ▸ Delete Card (`DeleteCardCommand`) reaches the
|
||||
/// frontmost card window through the focus system exactly as Add Attachment… does.
|
||||
@State private var cardActions = CardWindowActions()
|
||||
/// This window's thumbnail memory. Held here rather than in the section so it survives every
|
||||
/// snapshot the store applies — a cache that died with the view would regenerate every thumbnail
|
||||
/// on every reload (`AttachmentThumbnailCache`).
|
||||
@@ -394,6 +399,10 @@ struct CardWindowHost: View {
|
||||
// File ▸ Print… (⌘P) reaches the frontmost card window the same way — the card-window scope
|
||||
// of a row the board window answers with its whole board (11-command-nexus.md).
|
||||
.focusedSceneValue(\.cardPrint, cardPrint)
|
||||
// File ▸ Delete Card reaches the frontmost card window the same way — the toolbar's own
|
||||
// Delete Card item reads this same handle directly, wired at install time rather than
|
||||
// through the focus system (`configureWindow`).
|
||||
.focusedSceneValue(\.cardWindowActions, cardActions)
|
||||
// The raw-source outlet's detailed alert, presented over this window — a validation
|
||||
// refusal on Apply, or a file that could not be opened as source. It hangs *here* rather
|
||||
// than inside the editor because the second of those fires while source mode is still
|
||||
@@ -536,6 +545,9 @@ struct CardWindowHost: View {
|
||||
.onChange(of: store.isReadOnly, initial: true) { _, locked in
|
||||
attachments.isEditable = !locked
|
||||
session.comments.isEditable = !locked
|
||||
// Delete Card's own read-only gate — the sidebar Actions button's `.disabled(store
|
||||
// .isReadOnly)`, carried over verbatim to its toolbar and menu-row twins.
|
||||
cardActions.isDeletable = !locked
|
||||
}
|
||||
// **The thread re-reads on every landed reload** (05 ▸ The comments column: "the pane
|
||||
// reloads its thread from the same FSEvents stream").
|
||||
@@ -729,6 +741,24 @@ struct CardWindowHost: View {
|
||||
attachments, store: store, cardID: cardID, undo: session.undo, clipboard: appModel.clipboard
|
||||
)
|
||||
Self.configureComments(session.comments, store: store, cardID: cardID, on: session.undo)
|
||||
Self.configureActions(cardActions, store: store, cardID: cardID)
|
||||
}
|
||||
|
||||
/// Points this window's card-level actions at its card — **the one place File ▸ Delete Card and
|
||||
/// the toolbar's Delete Card item learn which card they act on**, `configureAttachments`'s pattern
|
||||
/// applied to the seam Actions ▸ Delete left behind when the sidebar section retired.
|
||||
///
|
||||
/// The store is captured **weakly**, `configureAttachments`'s own reason: a toolbar click or menu
|
||||
/// row still firing after the board window has gone should write nothing rather than resurrect a
|
||||
/// released store.
|
||||
///
|
||||
/// `static`, and taking every collaborator as a parameter, for `configureAttachments`'s reason:
|
||||
/// which card a gesture lands on is invisible in a running window until it is wrong, and this
|
||||
/// shape is what lets a test drive the real wiring rather than a re-typed copy of it.
|
||||
static func configureActions(_ actions: CardWindowActions, store: BoardStore, cardID: ItemID) {
|
||||
actions.deleteCard = { [weak store] in
|
||||
store?.deleteCard(cardID)
|
||||
}
|
||||
}
|
||||
|
||||
/// Points this window's session at **its own undo stack** — the three seams the two-level model
|
||||
@@ -951,13 +981,19 @@ struct CardWindowHost: View {
|
||||
|
||||
// The window's customizable toolbar — Edit Body · Raw Source · Add Attachment, "the
|
||||
// window's three committed functions" (03-board-ui.md ▸ Toolbar; 05-card-window.md ▸
|
||||
// Window), joined by Show Sidebar (below). It carries the three window-scoped handles above
|
||||
// rather than a store, which is why it is installed here and not at attach: those are this
|
||||
// window's, and so is it. Show Sidebar needs none of them — its read and write default to
|
||||
// Window), joined by Show Sidebar and, since the sidebar's Actions section retired, Delete
|
||||
// Card and Reveal in Finder (below). It carries the four window-scoped handles above rather
|
||||
// than a store, which is why it is installed here and not at attach: those are this window's,
|
||||
// and so is it. Show Sidebar needs none of them — its read and write default to
|
||||
// `AppPreferences.showCardSidebar` / `.setShowCardSidebar`, the same app-wide bit every card
|
||||
// window answers to, so this call leaves the two injectable parameters unnamed.
|
||||
windowController.installToolbar(
|
||||
CardToolbar.controller(body: bodyPresentation, rawSource: rawSource, attachments: attachments)
|
||||
CardToolbar.controller(
|
||||
body: bodyPresentation,
|
||||
rawSource: rawSource,
|
||||
attachments: attachments,
|
||||
actions: cardActions
|
||||
)
|
||||
)
|
||||
|
||||
// **No title in the title bar** — the card's name is shown as part of the card's body
|
||||
|
||||
Reference in New Issue
Block a user