Files
lanework/Kanban/App/FutureCommands.swift
T
rzen 40322247e0 Build the style, details, and actions sidebar sections
The sidebar completes: the shared style editor gains a second anchor —
StyleEditorLayout carries the geometry (the popover keeps its settled
268/14/7/8 untouched as the default; the sidebar packs columns to its
width with no inner scroller) while every well, the batch display, the
arrow grammar, and the one applyStyle bracket stay the shared
component's. The card anchor is fixed, not tracking: the target is
this card, and the fate walk retires the window when the card goes.
Details renders every unknown frontmatter key read-only in file order —
Card.document already carried them — showing the author's own bytes
where the raw span is a value and the engine's rendering for block
scalars and empties; reserved enhanced-schema keys are ordinary
unknowns, and no keys means no section. Actions: Delete rides the same
tombstone bytes as Backspace and drop-on-trash through a one-line
seam, says nothing about selection, and lets the fate walk dismiss;
Reveal in Finder resolves through the attachment scope so the two
paths cannot disagree. History reserves its m7 slot without drawing a
header no base board can honor.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
2026-07-28 12:22:04 -04:00

115 lines
5.8 KiB
Swift

import SwiftUI
// MARK: - The shared shape
/// The shape behind every menu row this milestone ships **before** the window that answers it.
///
/// 11-command-nexus.md's own contract runs both directions: "a command absent here doesn't exist, and
/// adding one means adding a row here first" — so once a row *is* in the Nexus, shipping the window
/// behind it is a validation-and-action change, not a menu change. `FutureCommand` below is that
/// reading, applied: the row exists now, stably titled and stably chorded — `NSUserKeyEquivalents`
/// already resolves it, so a user can remap it today — with validation pinned to `false` and the
/// action a no-op until the milestone named at the call site fills both in. That milestone's whole
/// diff then reads as "flip `.disabled`, fill the closure" rather than "add a menu item", which is
/// also why every call site below carries the codebase's `mN-` marker for a component still owed.
///
/// **The title never moves once a row ships**, disabled or not: a command wired live later must not
/// gain a second spelling on the way (04-interactions.md ▸ Configurable bindings — "toggles keep one
/// stable title, checkmark state only" — which applies to a row that has not started ticking yet
/// exactly as it does to one that has).
///
/// There was a `FutureToggleCommand` beside this — a disabled `Toggle` for a checkmark row — and it
/// went with the last of its call sites (Raw Source, `RawSourceCommand`). Every row still owed is a
/// plain command; a future checkmark row brings its scaffold back with it rather than keeping an
/// unused one warm.
struct FutureCommand: View {
let title: String
var key: KeyEquivalent?
var modifiers: EventModifiers = .command
var body: some View {
Button(title) {
// No-op: the milestone named at the call site wires this in.
}
.keyboardShortcut(key.map { KeyboardShortcut($0, modifiers: modifiers) })
.disabled(true)
}
}
// MARK: - File ▸ Save as Template
/// File ▸ Save as Template — no default chord (11-command-nexus.md; 09-templates.md).
///
// m9-templates: copies the open board into the user templates store, close-flushed first exactly as
// Duplicate is (09 ▸ Save as Template: "The copy is preceded by the close flush"), `.git` stripped,
// tombstones dropped, a `template:` key stamped. Validation will be `acceptsBoardMutations` plus 09's
// one carve-out from the read-only lock — live under the unwritable-location state unless an open
// Edit/raw-source session holds unsaved content — so it cannot simply borrow
// `DuplicateBoardCommand`'s predicate outright.
struct SaveAsTemplateCommand: View {
var body: some View {
FutureCommand(title: "Save as Template")
}
}
// File ▸ Add Attachment… (⇧⌘A) was the scaffold here and is now live, beside the focused value it
// reads (`AddAttachmentCommand`, in `CardAttachments.swift`) — the diff this file predicts: the
// title and the chord did not move, the validation and the action filled in. The attachment row's
// context menu (Open / Remove / Reveal in Finder) shipped with it, on the row view that now exists.
// MARK: - Edit ▸ Find Next / Find Previous
/// Edit ▸ Find Next / Find Previous (⌘G / ⇧⌘G) — the card window's find bar stepping,
/// "disabled in the board window — board search is a live filter, not a cursor"
/// (11-command-nexus.md).
///
// m6-card-window: joins `FindCommand` in the Edit menu once the card window's find-in-text exists
// (05-card-window.md). Both rows are unconditionally disabled here rather than reading `boardStore`
// to prove "board window" disables them: there is no card-window find session anywhere yet for
// either validation branch to check.
struct FindSteppingCommands: View {
var body: some View {
FutureCommand(title: "Find Next", key: "g", modifiers: .command)
FutureCommand(title: "Find Previous", key: "g", modifiers: [.shift, .command])
}
}
// MARK: - View ▸ Edit Body / Raw Source / History
/// View ▸ Edit Body (⌘E) / Raw Source (⌥⌘E) / History — the card window's three view-state rows
/// (11-command-nexus.md).
///
/// **Edit Body and Raw Source are both live** (`EditBodyCommand`, `RawSourceCommand`, each beside the
/// focused value it reads): the body column's Preview/Edit toggle, and the window-level outlet whose
/// toggling-off *applies*. Each diff was the one `FutureCommand` promises — the title and the chord
/// did not move, the validation and the action filled in — and the pair also carries the clause that
/// joins them, "Edit Body disables while Raw Source is active" (05-card-window.md).
///
// m7-git: History is a plain command that focuses the sidebar's History section, and disables
// outright on mode `none` / repo-nested boards once that section exists (05-card-window.md,
// 07-sync-collab.md). It remains unconditionally disabled here — the sidebar reserves the section's
// place (`CardWindowView.historySlot`) but draws nothing, so there is still no surface to focus.
struct CardViewCommands: View {
var body: some View {
EditBodyCommand()
RawSourceCommand()
FutureCommand(title: "History")
}
}
// MARK: - Board ▸ Pull / Push
/// Board ▸ Pull / Push — no default chord, remote-backed boards only (11-command-nexus.md;
/// 07-sync-collab.md: "also Board-menu items").
///
// m7-git: menu-bar twins of the board popover's own Pull/Push buttons (07-sync-collab.md).
// Validation will be remote-mode plus 06's abnormal-state pause ("disabled during 06's
// abnormal-state pause ... and on an unresolvable remote" — 11-command-nexus.md). Unconditionally
// disabled here: there is no remote model, no popover twin, and no git mode to validate against yet.
struct RemoteCommands: View {
var body: some View {
FutureCommand(title: "Pull")
FutureCommand(title: "Push")
}
}