@@ -11,6 +11,7 @@ import {
1111 createMemo ,
1212 createEffect ,
1313 createComputed ,
14+ createSignal ,
1415 on ,
1516 onMount ,
1617 type ParentProps ,
@@ -69,6 +70,11 @@ import { createTimelineModel } from "@/pages/session/timeline/model"
6970import { type DiffStyle , SessionReviewTab , type SessionReviewTabProps } from "@/pages/session/review-tab"
7071import { useSessionLayout } from "@/pages/session/session-layout"
7172import { syncSessionModel } from "@/pages/session/session-model-helpers"
73+ import {
74+ clampSessionPanelWidth ,
75+ SESSION_PANEL_WIDTH_MIN ,
76+ sessionPanelWidthMax ,
77+ } from "@/pages/session/session-panel-width"
7278import { SessionSidePanel } from "@/pages/session/session-side-panel"
7379import { sessionPanelLayout } from "@/pages/session/session-panel-layout"
7480import { SessionReviewEmptyChangesV2 } from "@opencode-ai/session-ui/v2/session-review-empty-changes-v2"
@@ -442,9 +448,39 @@ export default function Page() {
442448 newSessionDesign ( ) ? desktopV2ReviewOpen ( ) || desktopTerminalOpen ( ) : desktopReviewOpen ( ) ,
443449 )
444450 const desktopSidePanelOpen = createMemo ( ( ) => desktopSessionResizeOpen ( ) || desktopFileTreeOpen ( ) )
451+ let panelRow : HTMLDivElement | undefined
452+ const [ panelRowWidth , setPanelRowWidth ] = createSignal < number > ( )
453+ createResizeObserver (
454+ ( ) => panelRow ,
455+ ( { width } ) => setPanelRowWidth ( width ) ,
456+ )
457+ const splitReview = createMemo (
458+ ( ) => ( newSessionDesign ( ) ? desktopV2ReviewOpen ( ) : desktopReviewOpen ( ) ) && layout . review . diffStyle ( ) === "split" ,
459+ )
460+ // The observer reports the content-box width, which already excludes the row
461+ // padding; only the flex gap between the panels remains to subtract.
462+ const sessionPanelAvailable = createMemo ( ( ) => {
463+ const width = panelRowWidth ( )
464+ if ( width === undefined ) return undefined
465+ return width - ( settings . general . newLayoutDesigns ( ) ? 8 : 0 )
466+ } )
467+ const sessionPanelMax = createMemo ( ( ) => {
468+ const available = sessionPanelAvailable ( )
469+ if ( available === undefined ) return 1000
470+ return sessionPanelWidthMax ( { available, split : splitReview ( ) } )
471+ } )
472+ // Clamp at render time so window or sidebar resizes squeeze the chat panel
473+ // instead of the review pane, without overwriting the persisted width.
474+ const sessionPanelResizedWidth = createMemo ( ( ) =>
475+ clampSessionPanelWidth ( {
476+ width : layout . session . width ( ) ,
477+ available : sessionPanelAvailable ( ) ,
478+ split : splitReview ( ) ,
479+ } ) ,
480+ )
445481 const sessionPanelWidth = createMemo ( ( ) => {
446482 if ( ! desktopSidePanelOpen ( ) ) return "100%"
447- if ( desktopSessionResizeOpen ( ) ) return `${ layout . session . width ( ) } px`
483+ if ( desktopSessionResizeOpen ( ) ) return `${ sessionPanelResizedWidth ( ) } px`
448484 return `calc(100% - ${ layout . fileTree . width ( ) } px)`
449485 } )
450486 const centered = createMemo ( ( ) => isDesktop ( ) && ! desktopReviewOpen ( ) )
@@ -2148,6 +2184,7 @@ export default function Page() {
21482184 < SessionRouteFrame >
21492185 < SessionHeader />
21502186 < div
2187+ ref = { panelRow }
21512188 class = "flex-1 min-h-0 flex flex-col md:flex-row"
21522189 classList = { {
21532190 "gap-2 p-2" : settings . general . newLayoutDesigns ( ) ,
@@ -2186,9 +2223,9 @@ export default function Page() {
21862223 "-right-1" : settings . general . newLayoutDesigns ( ) ,
21872224 } }
21882225 direction = "horizontal"
2189- size = { layout . session . width ( ) }
2190- min = { 450 }
2191- max = { typeof window === "undefined" ? 1000 : window . innerWidth * 0.45 }
2226+ size = { sessionPanelResizedWidth ( ) }
2227+ min = { SESSION_PANEL_WIDTH_MIN }
2228+ max = { sessionPanelMax ( ) }
21922229 onResize = { ( width ) => {
21932230 size . touch ( )
21942231 layout . session . resize ( width )
0 commit comments