diff --git a/packages/app-bundle/manifest.json b/packages/app-bundle/manifest.json index 8e65c7f3..c635e624 100644 --- a/packages/app-bundle/manifest.json +++ b/packages/app-bundle/manifest.json @@ -216,7 +216,7 @@ "packages/app/src/pages/new-session-landing.ts": "528d27cd5d441b521674328fb7812fb2acf77233e9e436d081c98ce611e8b268", "packages/app/src/pages/new-session.tsx": "c060bbb15569b6da2f67146e6af0879ccb5444345df03dbc2f9b39cb98b9db78", "packages/app/src/pages/overlay-content-hash.test.ts": "aa208098213522dcde42434408afe9c8641fad663f44a58c316922dbd0da2f5c", - "packages/app/src/pages/session.tsx": "e502d2274c351612aacbed4dbee49e8692da1fb6b3411fbd1491499737772a39", + "packages/app/src/pages/session.tsx": "a76358b41641c2568b0904b4260f9d0e0b5747424751859e48957a5b32c46d67", "packages/app/src/utils/amicode-bridge.ts": "5104a04c7822f80dc0c564619e7dd2d850ba50035dbc86ea875604ecd97df05f", "packages/app/src/utils/amicode-bug-report.test.ts": "b1bbf49230ff3aa6d1a43ffa9165ba5a84ca4ee18a6d49f52ee5cd887c3e6444", "packages/app/src/utils/amicode-bug-report.ts": "d55d9cecfe17719c0d4a0ca498345c7eff6fca1de6b645e4bc3fecb40f2f4645", @@ -692,7 +692,7 @@ "packages/app/src/pages/session/helpers.ts": "0311f52b7cc34c2c38950512c01397e9672c89a9e61fdfa0e4696192da114f34", "packages/app/src/pages/session/review-tab.tsx": "3c90e6b11fad40ea19a258966c374ee12c05bd0e7891fcea561ba0b965ddc9f5", "packages/app/src/pages/session/session-panel-width.test.ts": "9482afba7fbce254cbbd21ef885e9e9620b981616681635376f466478f611155", - "packages/app/src/pages/session/session-panel-width.ts": "02ee3a02ed78db2eac47c2528055cf78aef95f389641e929ddc56c17471dcbe2", + "packages/app/src/pages/session/session-panel-width.ts": "654f84b2b43d9e2b0d5f021a1f859d69fe9ee579c88039a492dd3c645d087bea", "packages/app/src/pages/session/session-side-panel-structure.test.ts": "b2d1d007d9200d0ac4a0889e45c2dbe57a324a10cb26ae9ab8f420d3c890402b", "packages/app/src/pages/session/session-side-panel.tsx": "b295340d9a39ba37c9e025d6360669d2a879284c4e60df795b7902c5a4cef3fc", "packages/app/src/pages/session/terminal-panel-v2.tsx": "68dad9307f1d2abf3ff9248e451bd08005acf01ddc46b30a6d01b58f4a90dce0", @@ -873,7 +873,7 @@ "packages/ui/src/v2/components/text-shimmer-v2.tsx" ], "exceptions": [], - "extracted_at": "2026-09-24T04:46:38.771Z", + "extracted_at": "2026-09-24T20:34:57.925Z", "per_package": { "packages/app": { "A": 186, diff --git a/packages/app-bundle/overlay/packages/app/src/pages/session.tsx b/packages/app-bundle/overlay/packages/app/src/pages/session.tsx index f4b2c138..559615ae 100644 --- a/packages/app-bundle/overlay/packages/app/src/pages/session.tsx +++ b/packages/app-bundle/overlay/packages/app/src/pages/session.tsx @@ -78,6 +78,7 @@ import { restorePromptModel, syncPromptModel, syncSessionModel } from "@/pages/s import { clampSessionPanelWidth, clampWorkColumnWidth, + CHAT_COLLAPSE_THRESHOLD, SESSION_PANEL_WIDTH_MIN, sessionChatTakesRemainder, sessionPanelWidthMax, @@ -707,9 +708,54 @@ export default function Page() { const chatTakesRemainder = createMemo(() => sessionChatTakesRemainder({ newDesign: newSessionDesign(), columnVisible: isDesktop() && desktopV2PanelLayout().visible }), ) - const workColumnWidth = createMemo(() => - clampWorkColumnWidth({ width: layout.panelColumn.width(), available: sessionPanelAvailable() }), - ) + const workColumnWidth = createMemo(() => { + // #1434: when Chat is collapsed, the Work Column fills the full row + if (chatCollapsed()) return sessionPanelAvailable() ?? 900 + return clampWorkColumnWidth({ width: layout.panelColumn.width(), available: sessionPanelAvailable() }) + }) + + // #1434: Work Column maximize — collapse the Chat panel to give Preview + // full width. The pre-maximize column width is remembered for restore. + const [chatCollapsed, setChatCollapsed] = createSignal(false) + const [preMaximizeWidth, setPreMaximizeWidth] = createSignal(undefined) + + const chatEffectivelyCollapsed = createMemo(() => { + if (chatCollapsed()) return true + // Also collapse when the user drags the column so wide the chat is squeezed + // below the threshold. + const available = sessionPanelAvailable() + if (available === undefined) return false + return available - workColumnWidth() < CHAT_COLLAPSE_THRESHOLD + }) + + function toggleMaximize() { + if (chatCollapsed()) { + // Restore: set column back to pre-maximize width + setChatCollapsed(false) + const restoreWidth = preMaximizeWidth() ?? WORK_COLUMN_WIDTH_MIN + layout.panelColumn.resize(restoreWidth) + } else { + // Maximize: remember current width, then expand column to fill + setPreMaximizeWidth(workColumnWidth()) + setChatCollapsed(true) + const available = sessionPanelAvailable() ?? 900 + layout.panelColumn.resize(available) + } + } + + // Cmd+Shift+M (Ctrl+Shift+M on Linux/Windows) toggles maximize + createEffect(() => { + if (!newSessionDesign()) return + function onKeyDown(e: KeyboardEvent) { + if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === "m") { + e.preventDefault() + toggleMaximize() + } + } + window.addEventListener("keydown", onKeyDown) + onCleanup(() => window.removeEventListener("keydown", onKeyDown)) + }) + const sessionPanelWidth = createMemo(() => { if (chatTakesRemainder()) return undefined if (!desktopSidePanelOpen()) return "100%" @@ -2739,6 +2785,17 @@ export default function Page() { > {mobileTabs()} + {/* #1434: restore chevron when Chat is collapsed */} + + + +
-
size.start()}> +
size.start()} onDblClick={(e) => { + e.preventDefault() + // #1434: double-click cycles: 50/50 → full Preview → default + const available = sessionPanelAvailable() ?? 900 + const current = workColumnWidth() + const half = Math.floor(available * 0.5) + const full = available + const def = WORK_COLUMN_WIDTH_MIN + // Determine which snap to go to next + if (Math.abs(current - half) < 20) { + // Currently ~50/50 → go to full + setChatCollapsed(true) + setPreMaximizeWidth(half) + layout.panelColumn.resize(full) + } else if (current > available - CHAT_COLLAPSE_THRESHOLD) { + // Currently full → go to default + setChatCollapsed(false) + layout.panelColumn.resize(def) + } else { + // Currently at some other width → go to 50/50 + setChatCollapsed(false) + layout.panelColumn.resize(half) + } + }}> { size.touch() layout.panelColumn.resize(width) + // #1434: if dragging pushes chat below collapse threshold, + // auto-collapse it + const available = sessionPanelAvailable() ?? 900 + if (available - width < CHAT_COLLAPSE_THRESHOLD && !chatCollapsed()) { + setChatCollapsed(true) + setPreMaximizeWidth(width) + } else if (available - width >= CHAT_COLLAPSE_THRESHOLD && chatCollapsed()) { + setChatCollapsed(false) + } }} />
+ {/* #1434: Maximize/restore toggle button */} +
diff --git a/packages/app-bundle/overlay/packages/app/src/pages/session/session-panel-width.ts b/packages/app-bundle/overlay/packages/app/src/pages/session/session-panel-width.ts index 43191381..cce66b48 100644 --- a/packages/app-bundle/overlay/packages/app/src/pages/session/session-panel-width.ts +++ b/packages/app-bundle/overlay/packages/app/src/pages/session/session-panel-width.ts @@ -19,15 +19,19 @@ export function clampSessionPanelWidth(input: { width: number; available: number } // amicode#105: the Work Column owns a bounded width of its own. The pre-fix -// philosophy (above) let the review pane take everything the chat left behind +// philosophy (above) let the review pane take whatever the chat left behind // — a wide monitor squished the chat into the left margin. Now the column is // fixed-width (default 320 — DEFAULT_PANEL_COLUMN_WIDTH — user-resizable // within these bounds) and the CHAT is the flex remainder. export const WORK_COLUMN_WIDTH_MIN = 330 -/** The column may never take more than 60% of the measured row. */ +/** Minimum chat width before it collapses entirely (#1434). */ +export const CHAT_COLLAPSE_THRESHOLD = 200 + +/** The column may expand to fill the full row — the chat collapses when + * squeezed below CHAT_COLLAPSE_THRESHOLD (#1434). */ export function workColumnWidthMax(available: number) { - return Math.max(WORK_COLUMN_WIDTH_MIN, Math.floor(available * 0.6)) + return Math.max(WORK_COLUMN_WIDTH_MIN, available) } /** `available` is undefined until the layout row is first measured; render the