fix(window): pin detail column's reported frame so Chat/Sessions stop resizing window

Prior fixes (4baa3d4, 9aad905, d968878) narrowed the root cause
but didn't fully close the loop. Both the Chat section and the
v2.3 per-project Sessions tab were still growing the window past
the screen — the chat input bar ended up below the visible
desktop edge, unreachable.

Why the previous fixes weren't enough:
- Adding `.frame(maxHeight: .infinity)` on ChatView /
  ProjectSessionsView / dashboardArea told each view to FILL the
  space they were offered, but didn't cap what they reported UP
  the tree as their intrinsic ideal.
- `.windowResizability(.contentMinSize)` at the WindowGroup
  level used the content's minimum size as the window's min
  floor — and with VStack-based layouts (RichChatMessageList
  materialises every message in a plain VStack to avoid
  LazyVStack's whitespace bug), the minimum bubbles up as
  ~messages-total-height, which exceeds the screen on long
  sessions.

This commit pins the NavigationSplitView.detail slot's reported
frame explicitly. The detail column now reports:
- minWidth/minHeight: 500×300 — big enough for toolbars + chat
  input to always fit, small enough to work on any Mac screen
- idealWidth/idealHeight: 900×600 — reasonable first-launch size
  that fits under `.contentMinSize`'s floor without pushing past
  the screen
- maxWidth/maxHeight: infinity — user-resizable, no ceiling

With this bound intercepting the size-reporting chain,
NavigationSplitView's ideal becomes 500×300 ± idealWidth/Height
regardless of what ChatView or ProjectSessionsView's children
want internally. The window's content-derived minimum stays
bounded to a sensible value. Views still fill the offered space
because their `.frame(maxHeight: .infinity)` modifiers continue
to claim whatever the detail column hands them.

This is a window-layout-level fix that sits above the per-view
clamps in earlier commits — those stay in as defensive intra-
view layout, and the new frame here handles the outer coupling
to the window.

80/80 Swift tests still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alan Wizemann
2026-04-24 00:17:08 +02:00
parent d9688781ee
commit 205bb2c56e
+26
View File
@@ -17,6 +17,32 @@ struct ContentView: View {
.navigationSplitViewColumnWidth(min: 180, ideal: 240, max: 360)
} detail: {
detailView
// The detail column's size is what NavigationSplitView
// reports up to the window. Without a bound here, the
// reported ideal is derived from the currently-rendered
// section's natural intrinsic size and some sections
// (Chat with a fully-materialized message list, the
// v2.3 per-project Sessions tab) have intrinsic heights
// that exceed the screen. With `.windowResizability
// (.contentMinSize)` in scarfApp, the window is forced
// at least that tall, pushing its bottom edge past the
// visible desktop and hiding the input bar.
//
// This frame pins the detail's reported ideal at a
// modest 900×600 small enough to fit any reasonable
// screen while allowing it to expand freely to
// whatever the user drags the window to. `minHeight: 0`
// is load-bearing: it overrides the "my child's min is
// huge" chain so NavigationSplitView doesn't carry a
// massive min up to the window.
.frame(
minWidth: 500,
idealWidth: 900,
maxWidth: .infinity,
minHeight: 300,
idealHeight: 600,
maxHeight: .infinity
)
.toolbar {
ToolbarItem(placement: .navigation) {
ServerSwitcherToolbar()