Skip to content

Give the bottom panels one row, and let the rail be stowed - #41

Merged
takashi-matsuyama merged 1 commit into
mainfrom
feat/workspace-bottom-row-and-rail-fold
Aug 10, 2026
Merged

takashi-matsuyama merged 1 commit into
mainfrom
feat/workspace-bottom-row-and-rail-fold

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

The last two items of the layout work (decision_01KZ8JJTWW), both about width and height the workspace was spending on things nobody had asked to see. Sits on top of #38.

One row for the bottom panels

Enum types, Functions and Drafts each collapsed themselves, so all three shut cost three rows below the pane row the rest of this work spent its time giving a definite height to — measured in the built app at 1280x840, a shut panel is 34px of that. They now share one row that names whichever of them this database has something for, and the row is 23px whether it holds one name or two.

Opening one gives it the workspace and collapses the pane row — the same switch the Data tab makes rather than a division of the row — and the control that shuts it stays on screen below. The pane row goes out of the flow entirely, floor and all: hidden while keeping its 460px, the body comes out at 7px of visible area, a scroll box with nothing in view, which the workspace absorbs by squeezing rather than spilling. That is the shape of defect the rail's own floor comment was written about, and it is what the height assertion in the e2e is for — toBeVisible() and a page-overflow check both accept 7px.

Releasing that floor is also what left the open body with nothing under it, found by the review of this commit and fixed in it: a scroll container in a squeezed flex column has no floor of its own, and measured at 1280x460 with Settings open the body was 0px of visible height against 34px of content, with the page not overflowing either — so no scroll anywhere reached the list. It has 8rem now, and past that the page scrolls, which the pane row and the rail already document as the accepted degradation.

Whether a panel is open is decided in lib/expansion, the way the Data tab's width is, and for the same reason: an open panel has collapsed the only other thing in the workspace, so a panel whose content went away underneath it (drafts cleared, another profile inspected) would leave an empty box and no button to shut it. A panel the row cannot offer is not shown, and the row only offers what it has something to put in.

That rule was not enough alone. A panel every database can offer survives a change of database, so a search hit in another one landed on whatever was open — measured, the detail pane came back at 0px with an enum list on screen, in a database the operator had not been looking at. Naming a relation and changing database both shut it: the first is a request for the pane the panel collapsed, the second is a different workspace. Drafting a statement opens the drafts panel — emitting asks for the surface that holds what was emitted, the same way opening Data asks for the width.

The rail stows

From the header. The rail says nothing but which databases exist, and the selected one is named in the bar above the workspace, so between switches it is 13rem spent on a list nobody is reading. Manual only — what was asked for is a menu that stows, not a width that guesses; folding at a narrow window is a separate question and stays where it was.

The width goes to the map with no new arithmetic. Measured at 1280px: the map goes 529px → 751px, detail column unchanged. The e2e asserts those widths rather than the rail's absence, because "the rail is gone" would pass while the width went nowhere. The button stays in the header while stowed because a control that hides something cannot sit inside what it hides — the rail is not the only way to change database (search jumps across them, a card selects one), but it is the only place they are all listed.

Local: typecheck / lint / test:unit (341) / test:e2e (9) green after pnpm build.

Deferred, not fixed — including one falsehood

  • A8 — the commit message contains a false sentence. "the detail column is stated against the viewport, so it does not move" is false below roughly 645px, because --detail-w is a min(): measured, +6px at 620px and +20px at 560px. The README is not wrong, because it states the window width it measured at. Left in the message rather than amended; say the word and I will amend it.
  • A4 — the bottom row's buttons expose no state to assistive tech. They have stable noun names, so aria-expanded applies, and the rail-toggle in the same commit uses it correctly — so this is a self-inconsistency, and the cheapest of these to fix.
  • A5 — the new e2e passes an empty body. Deleting the EnumsPanel branch leaves it green.
  • A6 / A7 — the fixture has no functions, so the functions branch and "Show AI view" are unreached by any suite; closing the panel resets showAi.
  • A9 / A10 — as recorded in the review notes.

Design-challenge candidates raised by review and blocked (operator's call)

Reported rather than applied — all four reverse a settled choice:

  1. Open the drafts panel automatically on emit in more cases than the one implemented.
  2. Make bottomOpen per-profile.
  3. Size the expanded body to its content with a cap, instead of the switch-and-collapse.
  4. Persist railFolded.

Closes

Merging this completes decision_01KZ8JJTWW (layout overhaul). Card slimming was dropped separately under decision_01KZNH04MC.

The last two items of the layout work, and both are about width and height
the workspace was spending on things nobody had asked to see.

Enum types, Functions and Drafts each collapsed themselves, so all three
shut cost the workspace three rows below the pane row the rest of this
work spent its time giving a definite height to. Measured in the built app
at the default 1280x840 window, a shut panel is 34px of that. They now
share one row that names whichever of them this database has something for,
and the row is 23px whether it holds one name or two.

Opening one gives it the workspace and collapses the pane row - the same
switch the Data tab makes rather than a division of the row, and the
control that shuts it stays on screen below. The pane row goes out of the
flow entirely, floor and all: hidden while keeping its 460px the body comes
out at 7px of visible area, a scroll box with nothing in view, which the
workspace absorbs by squeezing rather than by spilling. That is the shape
of defect the rail's own floor comment was written about, and it is what
the height assertion in the e2e is for - `toBeVisible()` and a
page-overflow check both accept 7px.

Releasing that floor is also what left the open body with nothing under
it, which the review of this commit found and this commit now fixes: a
scroll container in a squeezed flex column has no floor of its own, and
measured at a 1280x460 window with Settings open the body was 0px of
visible height against 34px of content, with the page not overflowing
either - so no scroll anywhere reached the list. It has 8rem now, and past
that the page scrolls, which the pane row and the rail already document as
the accepted degradation.

Whether a panel is open is decided the way the Data tab's width is, in
`lib/expansion` and for the same reason: an open panel has collapsed the
only other thing in the workspace, so a panel whose content went away
underneath it - the drafts cleared, another profile inspected - would leave
an empty box and no button to shut it. A panel the row cannot offer is not
shown, and the row only offers what it has something to put in.

That rule was not enough on its own. A panel every database can offer
survives a change of database, so a search hit in another one landed on
whatever was open - measured, the detail pane came back at 0px with an enum
list on screen, in a database the operator had not been looking at. Naming
a relation and changing database now both shut it: the first is a request
for the pane the panel collapsed, and the second is a different workspace.

Drafting a statement opens the drafts panel. Emitting asks for the surface
that holds what was emitted, the same way opening Data asks for the width;
a statement generated into a row the operator has to think to click is one
they have no reason to believe exists.

The rail stows from the header. It says nothing but which databases exist,
and the selected one is named in the bar above the workspace, so between
switches it is 13rem spent on a list nobody is reading. Manual only - what
was asked for is a menu that stows, not a width that guesses; folding at a
narrow window is a separate question and stays where it was.

The width it gives up goes to the map, and that needed no new arithmetic:
the detail column is stated against the viewport, so it does not move, and
the map has the row's `1fr`. Measured at 1280px: the map goes from 529px to
751px and the detail column is unchanged. The e2e asserts those widths
rather than the rail's absence, because "the rail is gone" would pass while
the width went nowhere. The button stays in the header while stowed because
a control that hides something cannot sit inside what it hides - the rail
is not the only way to change database, the search jumps across them and a
card selects one, but it is the only place they are all listed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@takashi-matsuyama
takashi-matsuyama force-pushed the feat/workspace-bottom-row-and-rail-fold branch from 8b0ca67 to 541da51 Compare August 10, 2026 15:53
@takashi-matsuyama
takashi-matsuyama merged commit f5e4245 into main Aug 10, 2026
2 checks passed
takashi-matsuyama added a commit that referenced this pull request Aug 10, 2026
The bottom-panel height guard from #41 went red on main's `macos-e2e`, which is
the only job that runs it: the runner's screen is shorter than the 840px window
this app asks for, so the pane row was pinned to its 460px floor and the open
body came out at 309px against the 456 the guard demanded.

The product did what it is documented to do. The floor's own comment says the
row keeps 460px when the window cannot pay for it, the content then overflows
and the page scrolls, and that is the accepted degradation rather than a
failure; the body's floor comment says the body gets 8rem and scrolls past that,
for the same reason. The guard asserted `body >= paneHeight - 4` unconditionally,
so it went red in a state the design allows - which is the rule stated 100 lines
above it in this same file, about the map pane, and the new guard had broken it.

What the body actually gets is the pane row's height less the part of it the
window never had. Measured at seven window heights (812, 772, 740, 712, 672, 612
and 532px of viewport), `paneHeight - unpaid` is not an approximation of the body
but exactly it: 0px of slack at every one, while `paneHeight - 4` holds at 812
and nowhere below. `unpaid` is `.workspace`'s own overflow, `scrollHeight -
clientHeight`, read while the row is still shut - both because it is the shut
state's shortfall that the open body does not inherit, and because a break in
the open state then cannot inflate the allowance to let itself pass.

Driving this test at a 676px window reproduces the runner exactly, body and all:
309px. Broken four ways from there: the floor left in place at the default window
(469 wanted, 128 given, the body falling to its own 8rem), the floor left in
place at 676 (305 wanted, 128), the old form at 676 (456 wanted, 309 - the CI
failure, locally), and the fixed form at 676, which passes. So the guard still
fails for the defect it exists for, in both regimes, and no longer fails for the
window.

One measurement in the comment above it was also stale: `7px of 477` was taken
before the body had a floor of its own, and the same break lands on that floor
now. Both numbers are named.

Test-only. No product code changed.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@takashi-matsuyama
takashi-matsuyama deleted the feat/workspace-bottom-row-and-rail-fold branch August 11, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant