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
82 lines
4.0 KiB
Swift
82 lines
4.0 KiB
Swift
import SwiftUI
|
|
|
|
// MARK: - The window's card-level actions, as a handle
|
|
|
|
/// One card window's card-level actions, reduced to what things *outside* it need — today, exactly
|
|
/// one: the write that used to be the sidebar's Actions ▸ Delete (05-card-window.md ▸ Actions, retired
|
|
/// with the Actions section — Pipeline card bcd3b323), now the card window's own toolbar item
|
|
/// (`CardToolbar`) and its required menu twin (`DeleteCardCommand`).
|
|
///
|
|
/// `CardAttachments`'s shape and for its own reason: published through the focus system so a menu
|
|
/// item and a toolbar item can reach the frontmost card window without a which-window-is-key
|
|
/// register, `@State` in the host so it dies with the window it belongs to.
|
|
///
|
|
/// **Deliberately not folded into `CardAttachments`.** That type is "reduced to what things outside
|
|
/// it need" about the *attachments section* specifically — reused elsewhere only as the "a card
|
|
/// window is frontmost" presence signal (`ShowSidebarCommand`'s own note) — and a delete has nothing
|
|
/// to do with attachments. Folding it in would leave `CardAttachments`'s own doc comment wrong about
|
|
/// what the type is for.
|
|
@MainActor
|
|
@Observable
|
|
public final class CardWindowActions {
|
|
|
|
/// Whether the delete write is offered at all — `!store.isReadOnly`, the read-only lock applied
|
|
/// to the one mutation this handle starts (02-architecture.md's every-entry-point predicate,
|
|
/// `CardActionsSection`'s own posture before it retired).
|
|
public var isDeletable = false
|
|
|
|
/// Moves this window's card to the trash — filled by the host with `BoardStore.deleteCard(_:)`,
|
|
/// the same write ⌫ and the trash column's own drop already make (`CardActionsSection`'s former
|
|
/// doc comment, carried over verbatim: "the ⌫ delete exactly — same write op, same bracket, same
|
|
/// stamps"). It does not dismiss the window; the window's fate is re-derived from every snapshot,
|
|
/// exactly as it was when this lived in the sidebar.
|
|
public var deleteCard: (() -> Void)?
|
|
|
|
public init() {}
|
|
}
|
|
|
|
/// The focused card window's actions handle — `FocusedCardAttachmentsKey`'s own shape, one type over.
|
|
struct FocusedCardWindowActionsKey: FocusedValueKey {
|
|
typealias Value = CardWindowActions
|
|
}
|
|
|
|
extension FocusedValues {
|
|
var cardWindowActions: CardWindowActions? {
|
|
get { self[FocusedCardWindowActionsKey.self] }
|
|
set { self[FocusedCardWindowActionsKey.self] = newValue }
|
|
}
|
|
}
|
|
|
|
// MARK: - File ▸ Delete Card
|
|
|
|
/// The card window's delete, as a menu row — the required twin `CardToolbar`'s own item needs
|
|
/// ("toolbars are pure enhancement: every function they host already has a menu item + shortcut",
|
|
/// 03-board-ui.md ▸ Toolbar) now that the sidebar's Actions ▸ Delete button has retired.
|
|
///
|
|
/// **Deliberately titled "Delete Card", not "Delete"** — 11-command-nexus.md's File ▸ Delete row is
|
|
/// explicit that the chord's title is a singleton ("the chord's only owner — no twin menu items, no
|
|
/// shared-equivalent routing"), and that row is unchanged: it still validates against the board
|
|
/// window's own focused store and still carries ⌘⌫. This is a second, distinctly named row, scoped to
|
|
/// the card window alone, so the two can never be mistaken for one another in the File menu.
|
|
///
|
|
/// **No default chord, on purpose** — the reason the sidebar button existed in the first place and
|
|
/// the reason `TrashCommands`' own ⌘⌫ was "deliberately not extended to the card window": an enabled
|
|
/// delete-key equivalent here would steal delete-to-line-start from this window's text surfaces (the
|
|
/// body editor, the title field). `View ▸ History`'s own "no default chord" is the precedent for a
|
|
/// menu row that means something without owning a key.
|
|
struct DeleteCardCommand: View {
|
|
|
|
@FocusedValue(\.cardWindowActions) private var actions
|
|
|
|
static func isEnabled(_ actions: CardWindowActions?) -> Bool {
|
|
actions?.isDeletable == true
|
|
}
|
|
|
|
var body: some View {
|
|
Button("Delete Card") {
|
|
actions?.deleteCard?()
|
|
}
|
|
.disabled(!Self.isEnabled(actions))
|
|
}
|
|
}
|