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:
2026-08-09 09:14:51 -04:00
parent 55663e855a
commit d905e73960
11 changed files with 301 additions and 28 deletions
+8 -2
View File
@@ -258,6 +258,11 @@ enum CardWindowMetrics {
/// The window's minimum size: the sidebar's fixed width plus the body's floor, and tall enough
/// for a title, its date line and a few lines of body.
///
/// - Parameter sidebar: whether the attributes sidebar is currently shown View Show Sidebar
/// (05-card-window.md Composition, extended for the toggle). Hidden, it costs the window no
/// width at all, the comments column's own "the pane costs the window no width while it is not
/// mounted" rule applied to the sidebar's own visibility. Defaulted to `true` so every caller
/// that predates the toggle still asks the same question it always did.
/// - Parameter commentsColumn: whether the comments pane is currently mounted **beside** the body
/// "the window's minimum width grows only while the column is shown side-by-side"
/// (05-card-window.md Composition). Stacked, or hidden, the pane costs the window no width at
@@ -267,10 +272,11 @@ enum CardWindowMetrics {
///
/// Defaulted to `false` so every caller that predates the comments pane still asks the same
/// question it always did.
static func minimumSize(bodyPointSize: CGFloat, commentsColumn: Bool = false) -> CGSize {
static func minimumSize(bodyPointSize: CGFloat, sidebar: Bool = true, commentsColumn: Bool = false) -> CGSize {
let sidebarComponent = sidebar ? sidebarWidth(bodyPointSize: bodyPointSize) : 0
let comments = commentsColumn ? commentsMinimumWidth(bodyPointSize: bodyPointSize) : 0
return CGSize(
width: sidebarWidth(bodyPointSize: bodyPointSize)
width: sidebarComponent
+ bodyMinimumWidth(bodyPointSize: bodyPointSize)
+ comments,
height: (lineHeight(bodyPointSize: bodyPointSize) * 16).rounded()