Copy Link — a card context-menu row that puts the card folder on the pasteboard
Card 737a949f: "Add an option to card context menu to copy a link to the card folder." Implements the design ruling verbatim. - New context-menu row "Copy Link" (CardFaceView.boardMenu, board side only — trash cards are excluded, matching "sole selected live card"). Writes the clicked card's folder in one pasteboard item carrying two representations: the file:// URL under .fileURL and the plain absolute path under .string (FolderLinkPasteboard.swift). Enabled on a sole selected live card; disabled on a multi-selection and wherever edit-shaped actions already disable, per the ruling. Also exposed as a VoiceOver custom action alongside its siblings. - Menu-bar twin: Board ▸ Copy Link (BoardCommands.swift, CopyLinkCommand), no default chord — the every-function-a-menu-item contract in DESIGN/11-command-nexus.md is still current, so this is the twin that contract calls for, homed the way Open Card/Rename/ Style… already are. - DESIGN/11-command-nexus.md: new Board-menu row and an updated Card context-menu row. - Tests (KanbanTests/CopyLinkTests.swift): the target predicate's enablement (sole card / multi-selection / lane / trash / empty / inline-editing), the pasteboard write's exact bytes via a fake pasteboard (both representations, exact folder URL), and a disabled-target no-op. Caught and fixed during self-review: an early version read the context menu's widened-selection helper (targetIDs) inside the Copy Link row's .disabled(...), which reads store.selection. Since .contextMenu's content closure is evaluated on every ordinary body pass (not only when the menu opens), that resubscribed every card face on the board to every selection change — the exact O(board) regression RENDER-INSTRUMENTATION.md's isSelected/selectedCount split exists to prevent, caught by BoardRenderPerformanceTests and MarqueeRenderCostTests. Fixed by reading the already-hoisted, non-Observable `selectedCount` parameter instead, which answers the same "how many ride along" question at zero extra subscription cost. xcodegen generate, the Kanban scheme build, and the full KanbanTests suite (2816 tests) are clean. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -272,9 +272,9 @@ struct KanbanApp: App {
|
||||
}
|
||||
|
||||
// The Board menu (11-command-nexus.md), complete and in its inventoried row order — Open
|
||||
// Card, Rename, Style…, the card moves, the lane moves, the width pair. Its items act on
|
||||
// the frontmost board window, which they reach through the focus system rather than through
|
||||
// the app model — see `BoardCommands.swift`, which also owns their validation.
|
||||
// Card, Copy Link, Rename, Style…, the card moves, the lane moves, the width pair. Its items
|
||||
// act on the frontmost board window, which they reach through the focus system rather than
|
||||
// through the app model — see `BoardCommands.swift`, which also owns their validation.
|
||||
//
|
||||
// **Board Settings… came out 2026-08-07** with the sheet it opened (03 ▸ Board settings
|
||||
// sheet, marked retired; the 2026-07-31 popover/sheet split reversed): a board is configured
|
||||
@@ -283,8 +283,13 @@ struct KanbanApp: App {
|
||||
//
|
||||
// **The Board ▸ Pull/Push row (`RemoteCommands`) came out 2026-08-08** with app-managed git
|
||||
// itself (strategy/01-git-excision.md): the width pair is now the menu's last row.
|
||||
//
|
||||
// **Copy Link joined 2026-08-09** (design ruling, card 737a949f) right beside Open Card: the
|
||||
// two read-only rows — nothing here mutates the board — grouped ahead of the edit-shaped
|
||||
// block below (Rename, Style…), which is where the context menu puts the same two.
|
||||
CommandMenu("Board") {
|
||||
OpenCardCommand()
|
||||
CopyLinkCommand()
|
||||
BoardRenameCommand()
|
||||
BoardStyleCommand()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user