A card window toolbar control shows and hides the trailing sidebar — View ▸ Show Sidebar joins Edit Body, Raw Source and Add Attachment
The card window's trailing attributes sidebar has always been unconditional since m6; this adds View ▸ Show Sidebar (a checkmark toggle, ShowComments' shape) and a matching toolbar item on the customizable card toolbar (NSToolbar/WindowToolbarController), a fourth default beside Edit Body, Raw Source and Add Attachment. sidebar.right for the trailing pane; one shared animated write path (AppPreferences.setShowCardSidebar) both faces call, structural-voice reflow with a trailing slide-and-fade transition (Motion.cardSidebarTransition), Reduce Motion respected throughout. CardWindowMetrics.minimumSize gains a sidebar: Bool = true parameter so a hidden sidebar shrinks the window's floor, composing with the existing commentsColumn parameter. The toolbar item's read/write are injectable closures (defaulted to the real UserDefaults-backed pair) so its plumbing is testable without touching the developer's own preferences domain. WindowToolbarController's observation tracking only sees @Observable reads, so a small HostedWindowController.revalidateToolbar() plus an onChange nudge keeps the toolbar button's on-state in step with the View-menu row's write. Scope held narrowly to visibility, per the card: no sidebar section reordering, no action-moving. Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
@@ -6,6 +6,7 @@ extension NSToolbarItem.Identifier {
|
||||
static let cardEditBody = Self("card.editBody")
|
||||
static let cardRawSource = Self("card.rawSource")
|
||||
static let cardAddAttachment = Self("card.addAttachment")
|
||||
static let cardShowSidebar = Self("card.showSidebar")
|
||||
}
|
||||
|
||||
// MARK: - The card window's toolbar
|
||||
@@ -15,9 +16,12 @@ extension NSToolbarItem.Identifier {
|
||||
/// "**Card window default: Edit Body · Raw Source · Add Attachment** — the window's three committed
|
||||
/// functions, all discoverable from its toolbar; the catalog is the same trio." So the default set
|
||||
/// *is* the catalog here, and Customize offers rearrangement and removal rather than a choice of
|
||||
/// items — which is exactly what a window with three functions should offer.
|
||||
/// items — which is exactly what a window with three functions should offer. **Show Sidebar joined
|
||||
/// them** (05-card-window.md ▸ Composition, the toggle added beside the toolbar-customization work):
|
||||
/// a fourth default item, the trailing sidebar's own show/hide control, the `Show Trash` precedent
|
||||
/// applied to the card window's one collapsible pane.
|
||||
///
|
||||
/// ### The three items are the three menu rows, predicates included
|
||||
/// ### The four items are the four menu rows, predicates included
|
||||
///
|
||||
/// - **Edit Body** is "a single toggle button (on-state in Edit — mirroring the View ▸ Edit Body
|
||||
/// checkmark)", and it disables while source mode is active. That clause is not restated here: the
|
||||
@@ -31,6 +35,12 @@ extension NSToolbarItem.Identifier {
|
||||
/// `index.md`, so they're safe alongside a raw edit". Its predicate is likewise the row's own
|
||||
/// (`AddAttachmentCommand.isEnabled`), which is scope plus the read-only lock and says nothing
|
||||
/// about the body's mode.
|
||||
/// - **Show Sidebar** is a toggle showing on-state too, mirroring the View ▸ Show Sidebar checkmark
|
||||
/// (`ShowSidebarCommand`) — and it is the one item here with no window-scoped handle behind it:
|
||||
/// its predicate reads `AppPreferences.showCardSidebar` straight off `UserDefaults`, the same
|
||||
/// app-wide, persisted bit `CardWindowView` renders from and every card window's toolbar answers
|
||||
/// to alike. Always enabled, `ShowCommentsCommand`'s own posture: showing or hiding a pane is not a
|
||||
/// mutation, so the read-only lock has no say in it.
|
||||
///
|
||||
/// Labels are the menu titles minus a trailing ellipsis, so File ▸ Add Attachment… labels as **Add
|
||||
/// Attachment** (03's own example).
|
||||
@@ -39,17 +49,28 @@ enum CardToolbar {
|
||||
|
||||
static let identifier = "dev.rzen.indie.Kanban.card"
|
||||
|
||||
/// "The catalog is the same trio" — so the defaults are the catalog, in 03's order.
|
||||
/// "The catalog is the same trio" plus Show Sidebar — so the defaults are the whole catalog, in
|
||||
/// this file's order.
|
||||
static let defaultItems: [NSToolbarItem.Identifier] = [
|
||||
.cardEditBody,
|
||||
.cardRawSource,
|
||||
.cardAddAttachment,
|
||||
.cardShowSidebar,
|
||||
]
|
||||
|
||||
/// - Parameters:
|
||||
/// - isSidebarShown: Show Sidebar's read, defaulted to the real bit
|
||||
/// (`AppPreferences.showCardSidebar`). Injectable so a test can drive the item without
|
||||
/// touching the developer's own `UserDefaults.standard` domain — `StyleRecents`' own caution,
|
||||
/// applied to the one item here with no window-scoped handle to hold a scratch value instead.
|
||||
/// - setSidebarShown: Show Sidebar's write, defaulted to the real setter
|
||||
/// (`AppPreferences.setShowCardSidebar`), for the same reason.
|
||||
static func specs(
|
||||
body: CardBodyPresentation,
|
||||
rawSource: CardRawSourceSession,
|
||||
attachments: CardAttachments
|
||||
attachments: CardAttachments,
|
||||
isSidebarShown: @escaping () -> Bool = { AppPreferences.showCardSidebar },
|
||||
setSidebarShown: @escaping (Bool) -> Void = { AppPreferences.setShowCardSidebar($0) }
|
||||
) -> [ToolbarItemSpec] {
|
||||
[
|
||||
.mirroring(
|
||||
@@ -90,17 +111,38 @@ enum CardToolbar {
|
||||
perform: { [weak attachments] in attachments?.add() }
|
||||
)
|
||||
),
|
||||
// **The one item here with no window-scoped handle** — its read and write are the two
|
||||
// injected closures above, defaulted to `AppPreferences.showCardSidebar` /
|
||||
// `.setShowCardSidebar`, the plain `UserDefaults`-backed bit every card window's sidebar
|
||||
// (`CardWindowView`) and View ▸ Show Sidebar row (`ShowSidebarCommand`) already read and
|
||||
// write the same way. `sidebar.right` is the trailing variant: the sidebar this toggles
|
||||
// sits on the window's trailing edge (05-card-window.md ▸ Composition), never the leading
|
||||
// one the plain `sidebar.left` glyph would imply.
|
||||
.mirroring(
|
||||
menuTitle: "Show Sidebar",
|
||||
identifier: .cardShowSidebar,
|
||||
symbol: "sidebar.right",
|
||||
behavior: .toggle(isEnabled: { true }, isOn: isSidebarShown, setOn: setSidebarShown)
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
static func controller(
|
||||
body: CardBodyPresentation,
|
||||
rawSource: CardRawSourceSession,
|
||||
attachments: CardAttachments
|
||||
attachments: CardAttachments,
|
||||
isSidebarShown: @escaping () -> Bool = { AppPreferences.showCardSidebar },
|
||||
setSidebarShown: @escaping (Bool) -> Void = { AppPreferences.setShowCardSidebar($0) }
|
||||
) -> WindowToolbarController {
|
||||
WindowToolbarController(
|
||||
identifier: identifier,
|
||||
specs: specs(body: body, rawSource: rawSource, attachments: attachments),
|
||||
specs: specs(
|
||||
body: body,
|
||||
rawSource: rawSource,
|
||||
attachments: attachments,
|
||||
isSidebarShown: isSidebarShown,
|
||||
setSidebarShown: setSidebarShown
|
||||
),
|
||||
defaults: defaultItems
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user