Repository navigation
fix(ui): scale auxiliary panels to dvh when both open at narrow widths - #830
Merged
Merged
Conversation
Astro-Han
force-pushed
the
fix/824-both-present-shared-height
branch
7 times, most recently
from
July 12, 2026 15:31
1e29d1f to
0a3db05
Compare
…w widths At <=990px both ArtifactPane and BrowserPanel become bottom sheets, each with a fixed min-height: 220px (from #818). When both are open and the detail area is short (<=~440px), the two fixed minima squeeze the chat row `minmax(0, 1fr)` to 0 and the composer is clipped — a reachable state since the 320px restore minimum in window-state.ts was restore-only and BrowserWindow set no minHeight, so runtime drag could go shorter. Fix with two coordinated changes: 1. chat-detail.css: add a :has()-scoped rule inside the 990px block that, when BrowserPanel AND a non-collapsed ArtifactPane are both present, scales each panel's min-height to min(22dvh, 220px) so the chat row keeps the remainder. min(22dvh, 220px) shrinks below 220px at short heights and never grows above 220px at tall heights, so >=1000px tall (where 22dvh == 220px) is unchanged; below that the panels yield proportionally. Single-panel (or a collapsed ArtifactPane) keeps the fixed 220px / 34px floor, so the rule scopes to both-present via :has() (already used in 8 other places) and skips the collapsed artifact. Recovery (close browser / collapse artifact) stays reachable because each panel's toolbar sits at the top of a non-zero-height row. 2. main-window.ts + window-state.ts: extract SAFE_MIN_WIDTH / SAFE_MIN_HEIGHT from window-state.ts (consolidating the 480x320 literals already used by sanitizeBounds + visualSmokeWindowBounds) and set BrowserWindow `minHeight: SAFE_MIN_HEIGHT` so the runtime resize floor matches the sanitizeBounds restore floor. This makes the 320px floor the dvh fix relies on actually enforced at runtime, not just at restore. Tests: - browser-panel-layout.test.ts: both-present shared-height contract locking the :has() rule's exact `min(22dvh, 220px)` value, both-panel coverage, and per-selector that each selector carries the full both-present + non-collapsed condition (rejects an unconditional panel selector that would leak dvh into single-panel, a collapsed-condition leak, a wrong value, or a missing guard). - app-region-hygiene-contract.test.ts: BrowserWindow `minHeight: SAFE_MIN_HEIGHT` contract tying the runtime floor to the shared constant exported from window-state.ts. Closes #824. Refs #546.
Astro-Han
force-pushed
the
fix/824-both-present-shared-height
branch
from
July 12, 2026 15:36
0a3db05 to
49fe726
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
<=990px, when both BrowserPanel and a non-collapsed ArtifactPane are open, scale each auxiliary panel'smin-heighttomin(22dvh, 220px)(via a:has()-scoped rule) so the chat row keeps 56% of the content viewport instead of being squeezed to 0 by two fixed 220px minima.BrowserWindow minHeight: SAFE_MIN_HEIGHT, extractingSAFE_MIN_WIDTH/SAFE_MIN_HEIGHTfromwindow-state.tsso the resize floor and the sanitizeBounds restore floor share one source of truth.Why
Closes #824. At
<=990pxboth ArtifactPane and BrowserPanel become bottom sheets, each with a fixedmin-height: 220px(from #818). When both are open and the detail area is short (<=~440px), the two fixed minima squeeze the chat rowminmax(0, 1fr)to 0 and the composer is clipped. The 320px restore minimum inwindow-state.tswas restore-only andBrowserWindowset nominHeight, so runtime drag could go shorter. #818's own comment flagged this edge and tracked the shared-height policy in #824.Scope
<=990px; aligning the BrowserWindow runtime height floor with the sanitizeBounds restore floor.<=990pxbreakpoint; the bottom-sheet pattern;minWidthenforcement (width isn't the clip cause —minWidthcoherence with sanitizeBounds is a separate follow-up); auseContentSizemigration (the window-vs-content frame relationship is pre-existing, see Verification).Verification
browser-panel-layout.test.ts; 13/13 inapp-region-hygiene-contract.test.ts; 7/7 inwindow-state.test.ts.npm --workspace @maka/desktop run typecheck(main + renderer + storybook) — pass.npm --workspace @maka/desktop test(full main suite) — 2354/2354 pass.:has()rule fires only when both BrowserPanel and a non-collapsed ArtifactPane are present, and no existing fixture seeds a browser panel (the browser fixture is feat(ui): add deterministic visual-smoke fixture + DOM contract for BrowserPanel renderer chrome #819). So the rule never applies in any current fixture;artifact-pane/artifact-errors/artifact-preview-*narrow baselines are unchanged. The screenshots are 820px tall × 990/1280 wide, all above the 320pxminHeight, so the window floor doesn't affect them either.1 - 2×22dvh), so the composer (~164px + 8px margin) stays usable while the content viewport is>=~307px(172 / 0.56).min(22dvh, 220px)shrinks below 220px below 1000px tall and caps at 220px above (so>=1000pxtall both-present is unchanged); at the 320px window floor the panels are ~70px each (toolbar + thin strip), recovery buttons reachable.minHeight: SAFE_MIN_HEIGHT(320) enforces the 320px WINDOW floor. On macOS (hiddenInsettitlebar) the content viewport ≈ window, so the composer-usable floor is ~320px. On Windows (titleBarOverlay~30px) and Linux (default frame ~35px) the frame reduces the content viewport, so the effective composer-usable floor is a slightly larger window (~335px). This window-vs-content gap is the pre-existing relationship inherited fromsanitizeBounds(a 320px window was never a 320px content viewport on Windows/Linux); auseContentSizemigration that would let the floor be expressed in content terms is out of fix(ui): reserve chat/composer height when both ArtifactPane and BrowserPanel are open at narrow widths #824 scope. The fix is a net improvement on all platforms (from chat-row-0 at<~440pxto chat-row-56%-of-content, usable at content>=~301px).Impact
<=990px) with both auxiliary panels open, short windows no longer clip the composer; the panels shrink proportionally instead. Normal-height and tall windows are unchanged (min(22dvh, 220px)== 220px at>=1000pxtall). The window can no longer be dragged below 320px tall (aligned with the restore floor).sanitizeBoundsstill accepts 320px-tall windows at restore (unchanged);BrowserWindownow enforces 320px-tall at resize. Existing saved windows>=320pxtall are unaffected.Reviewer notes
:has()over unconditional dvh: unconditionalmin-height: min(22dvh, 220px)on both panels would change the single-panelartifact-panenarrow baselines (220px → 180px at the 820px screenshot height). The:has()-scoped rule changes only the both-present case (no existing fixture) and leaves single-panel untouched.minmax(composer-min, 1fr)chat-row floor would push overflow into the auxiliary rows, clipping the ArtifactPane collapse button (~220px down) and breaking the recovery path fix(ui): reserve chat/composer height when both ArtifactPane and BrowserPanel are open at narrow widths #824 noted. The dvh-budget makes the panels yield, keeping both panels + the composer visible and recovery reachable.min(22dvh, 220px)over bare22dvh: bare22dvhgrows above 220px at tall windows (264px at 1200px, 352px at 1600px) and would exceed themax-height: 360pxcap (min-height wins over max-height in conflict) — a tall-window regression.min(22dvh, 220px)caps at 220px so>=1000pxtall is unchanged.minHeight: SAFE_MIN_HEIGHT(320) and not a higher platform-aware value: 320 is the sanitizeBounds restore floor (the owner of the minimum-size contract); aligning the runtime floor to it is the non-duplicate owner-level fix. A higher platform-specific magic number would decouple from sanitizeBounds and change restore behavior. The residual Windows/Linux content gap at the 320px window floor is the pre-existing frame relationship, documented in the CSS comment, not a fix(ui): reserve chat/composer height when both ArtifactPane and BrowserPanel are open at narrow widths #824-introduced regression.:has()compound selector (≈0,5,0) outranks the base.maka-browser-panel/.maka-artifact-panerules (0,1,0), somin-height: min(22dvh, 220px)wins when both present; the existingmin-height: 220pxexact-selector contract still passes because the:has()selector is compound, not bare.:has(), collapsed-condition leak, mixed selector-list, reordering, wrong target), the exactmin(22dvh, 220px)value, exactly onemin-heightdeclaration (case-insensitive prop match — catchesMIN-HEIGHT), no CSS-escaped property name (catchesm\69n-height), and exactly one:has()-scoped panel-targeting min-height rule (catches a same-specificity reordered-:has()competitor). ThenarrowBrowserMinHeights(fix(ui): give BrowserPanel a narrow bottom-sheet layout (#546) #818) helper is also case-insensitive + escape-fail-closed. This text contract does NOT model the CSS cascade, so a higher-specificity override (e.g. an#idrule) or anall:initialreset could still win — verifying the cascade-effective computed value is the job of the feat(ui): add deterministic visual-smoke fixture + DOM contract for BrowserPanel renderer chrome #819 computed-style fixture (the reliable layer per the Codex review).Ready for review
Verificationexplains why it is not applicable