The comments column gets a handle — the beside-mount divider is now user-draggable

Kanban.xcodeproj must be regenerated (xcodegen generate) before building.

CardWindowMetrics.commentsColumnWidth was a fixed figure between the body
column and the comments pane in the side-by-side layout; it is now only the
resting default. A new CommentsColumnDivider replaces the plain Divider()
between the two panes with a real HStack element carrying a resize-left-right
cursor and a drag gesture, clamped through a new pure seam,
CardWindowMetrics.clampedCommentsColumnWidth — never narrower than the
existing commentsMinimumWidth floor, never wide enough to push the body under
its own bodyMinimumWidth. The drag tracks live in memory
(commentsColumnWidthOverride) and writes AppPreferences.commentsColumnWidthKey
exactly once, on release, mirroring LaneResizeSession's live-track/write-once
split rather than hammering UserDefaults per tick.

Persistence is app-wide via @AppStorage, matching showComments and
commentsBesideBody — the pane's other two layout bits — rather than the
per-card BoardRegistry.cardWindowFrames: this is "how the pane is arranged,"
the same kind of fact those two already are, not a per-card window geometry.
Flagged on the card thread as a call worth owner review.

Six new unit tests cover the clamp's two floors, the degenerate case where a
container is too narrow for both, and its agreement with
CardWindowMetrics.minimumSize at the window's own floor.

Claude-Session: https://claude.ai/code/session_014PtZdPwqZuqEDLc6wZMtEy
This commit is contained in:
2026-08-09 08:38:07 -04:00
parent b0c134a896
commit 0a01405ced
5 changed files with 351 additions and 16 deletions
+20
View File
@@ -107,6 +107,26 @@ public enum AppPreferences {
UserDefaults.standard.bool(forKey: commentsNewestFirstKey)
}
// MARK: The comments column's user width
/// **The comments column's width, once the beside-mount divider has been dragged** the drag's
/// memory (05-card-window.md The comments column, extended 2026-08-09: "the divider between
/// the body and the comments column is user-resizable app-wide, persisted, the same home as
/// the pane's other two bits").
///
/// App-wide for the neighbours' reason exactly: every open card window's divider answers to one
/// figure, so a window that took it as a parameter would need something above it keeping every
/// window in step with a value that has exactly one instance which is also what makes
/// `@AppStorage` the right binding for it, as it is for `commentsBesideBody`.
///
/// Stored as a `Double` in points what a drag actually produces rather than in characters:
/// re-deriving characters from it on every launch would round-trip through the body font for a
/// number that is no longer a character count once someone has dragged it away from the default.
/// **`0` reads as "never dragged"**: `CardWindowMetrics.clampedCommentsColumnWidth`'s floor is
/// always positive, so a real drag can never land on zero, which makes the plain
/// `double(forKey:)` reading safe here in a way `boardZoomLevel`'s note warns it usually is not.
public static let commentsColumnWidthKey = "commentsColumnWidth"
/// The quick-style row's recently-used backgrounds an array of palette names / hex strings,
/// most-recent-first (03-board-ui.md § Styling Controls: "Recents are app-wide and persist
/// app-side (user preference, never board data)"; 11-command-nexus.md files it under the