the new-commander pane scrolls, because the panel it lives in zooms

Setup card, start button and guide were three `shrink-0` siblings, so they took
whatever height they wanted and nothing could scroll past them. The guide carried
its own `overflow-y-auto`, which never once engaged — `shrink-0` had already given
it its full natural height, so there was nothing to overflow.

Fine at 100%, and the panel system is zoomable. At 120% the setup ran off the
bottom of the panel with no way to reach it, which is the zoom somebody uses
precisely because they want to read it.

So the scroller moves up to where the height is actually constrained, and the
composer keeps `shrink-0` before the first message so it stays pinned at the
bottom whatever the zoom.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 00:02:25 +00:00
co-authored by Claude Opus 5
parent 3551a3af71
commit 383df51a99
@@ -44,7 +44,7 @@ function EmptyState() {
* which matters because this ships on every deploy whether the copy is ready or not.
*/
const NewCommanderGuide = () => (
<div className="shrink-0 overflow-y-auto border-b border-border px-5 py-4">
<div className="shrink-0 border-b border-border px-5 py-4">
<div className="mx-auto flex max-w-2xl flex-col gap-4">
{NEW_COMMANDER_GUIDE.map((section) => (
<section key={section.title}>
@@ -302,8 +302,19 @@ function NewCommander({
and not to the component left that radio hidden inside a commander — the one place it exists for. */}
{/* Before the first message, the pane explains itself. `EmbeddableChat`'s own empty state is "Send a
message to start", which is true and tells a first-time user nothing about what to send. */}
{/*
One scroll region for the whole pre-start pane, rather than three `shrink-0` siblings.
They stacked to whatever height they wanted and nothing could scroll: the guide carried its own
`overflow-y-auto`, which never engaged, because `shrink-0` had already given it its full natural
height. Fine at 100%, and the panel system is zoomable — at 120% the setup ran off the bottom of
the panel with no way to reach it.
So the scroller is here, where the height is actually constrained, and the composer below keeps
`shrink-0` so it stays reachable at the bottom whatever the zoom.
*/}
{chat.messages.length === 0 && (
<>
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
<CommanderSetup name={name} onName={setName} cwd={cwd} onPickDirectory={() => setPickerOpen(true)} />
<StartCommanderButton
ready={ready}
@@ -324,7 +335,7 @@ function NewCommander({
}
/>
<NewCommanderGuide />
</>
</div>
)}
{/* Disabled until both are chosen. The composer is where somebody would otherwise type first and
discover the requirement afterwards, having already written what they meant to say. */}
@@ -338,7 +349,7 @@ function NewCommander({
? { reason: !name.trim() ? 'Name it first…' : 'Choose a working directory first…' }
: false
}
className="min-h-0 flex-1"
className={chat.messages.length === 0 ? 'shrink-0' : 'min-h-0 flex-1'}
/>
<DirPickerModal open={pickerOpen} onClose={() => setPickerOpen(false)} onSelect={setCwd} />
</div>