Repository navigation
fix(ui): give BrowserPanel a narrow bottom-sheet layout (#546) - #818
Merged
Merged
Conversation
This was referenced Jul 12, 2026
Astro-Han
force-pushed
the
fix/546-artifact-browser-closeout
branch
5 times, most recently
from
July 12, 2026 12:59
5aa9996 to
33be4c9
Compare
2 tasks
Astro-Han
force-pushed
the
fix/546-artifact-browser-closeout
branch
from
July 12, 2026 13:09
33be4c9 to
bc1e2a7
Compare
BrowserPanel had no @media(max-width:990px) rule. Its grid auto row sized to the panel's max-content (toolbar height); the strip's flex:1 1 auto contributes 0 height without a definite container height, so the rAF loop mirrored a ~zero-height rect to main and the native WebContentsView was sized to nothing — the embedded browser disappeared beside a ~470px empty gap. ArtifactPane already had an explicit narrow bottom-sheet; BrowserPanel did not. Add a <=990px bottom-sheet rule for .maka-browser-panel mirroring ArtifactPane (full width, min-height:220px, max-height:min(42dvh,360px), border-left:0, top border + lift shadow). min-height:220px is the load-bearing declaration: it forces the auto row (and thus the strip) to a usable non-zero size so the native view is visible. width:100% turns the 520px right rail into a bottom sheet. BrowserPanel is always the second grid child (chat / browser / artifact), so it already occupies the explicit auto row; no grid-row change is needed (ArtifactPane as the third child uses an implicit auto row, which defaults to auto). Locked by a narrow PostCSS-based CSS contract test (the repo's established contract-test parser) that locks ONLY the declaration preventing the disappearing-browser defect: exactly one min-height:220px on .maka-browser-panel in the 990px media block, with no !important. min-height is genuinely exclusive to the narrow rule (the base rule does not declare it), so a source contract locks its effective value within the block. The test does NOT simulate the CSS cascade and does NOT claim to lock width/border-left (also declared by the base rule, won only by source order — not verifiable by a text contract), max-height (a space cap), or border-top/box-shadow (visual) — those belong to visual smoke review. A synthetic test locks the helper's collection/guard logic (catches a second overriding rule, a duplicate property, !important, and removal); the integration test fails if min-height is removed or overridden (verified). The existing ArtifactPane narrow contract and the 2348-test main suite stay green; the renderer build is clean. The both-present + very-short-window case (chat can collapse to 0) is a product-policy question tracked in #824; the CSS comment records it honestly. Part of the #546 Artifact pane + browser panel closure audit.
Astro-Han
force-pushed
the
fix/546-artifact-browser-closeout
branch
from
July 12, 2026 13:23
bc1e2a7 to
e42f000
Compare
3 tasks done
Astro-Han
added a commit
that referenced
this pull request
Jul 12, 2026
…826) Follow-up to #818. The narrow-layout CSS comment said "the user recovers by collapsing ArtifactPane or closing the browser (tracked in the PR notes)", which overstates reachability at the shortest window heights (closing the browser alone usually recovers the chat column, but at extreme short heights the ArtifactPane collapse control may be clipped, so recovery may require both) and points at the ephemeral PR notes instead of the durable tracker. Replace with the wording from the #818 review consult: the chat row (not "column") can collapse from the two 220px minima, the shared-height policy is tracked in #824, and recovery may require closing the browser and/or collapsing ArtifactPane. Doc-only; the browser-panel-layout contract test strips comments and stays green (2/2). Refs #546.
3 tasks done
Astro-Han
added a commit
that referenced
this pull request
Jul 12, 2026
At <=990px both ArtifactPane and BrowserPanel become bottom sheets, each with a fixed min-height: 220px. 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 BrowserWindow sets no minHeight and the 320px restore minimum is restore-only (runtime drag can go shorter). 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 22dvh so the chat row keeps the remainder. At >=1000px tall 22dvh == 220px (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). Recovery (close browser / collapse artifact) stays reachable because each panel's toolbar sits at the top of a non-zero-height row. Extend browser-panel-layout.test.ts with a both-present shared-height contract locking the :has() rule's dvh min-height + both-panel coverage + collapsed-artifact guard. Update the #818 narrow-layout comment to point at the implemented rule instead of "tracked in #824". Closes #824. Refs #546.
Astro-Han
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…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
added a commit
that referenced
this pull request
Jul 12, 2026
…w widths (#830) 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.
3 tasks done
Astro-Han
added a commit
that referenced
this pull request
Jul 12, 2026
…act (#819) BrowserPanel renderer chrome had no deterministic coverage, so layout/ a11y regressions (e.g. the #818 narrow-layout defect) could only be caught by manual real-window smoke. Add two deterministic layers: - VisualSmokeState.liveBrowserSessionIds + applyVisualSmokeFixture wiring + a `browser-empty` scenario that seeds the active turn session as a live browser session so BrowserPanel mounts. With no native WebContentsView in visual-smoke mode, browser.getState resolves null → EMPTY_STATE → the empty-state chrome (toolbar all-nav-disabled + <Empty> strip), exactly the #818 defect surface. Reuses the always-seeded turn session; no browser-specific on-disk seed. - browser-panel-chrome source contract (symmetric to artifact-pane-layout.test.ts) locking the 5 declarative chrome invariants that don't need a screenshot: back/forward :disabled track canGoBack/canGoForward; reload/stop icon + aria-label + onClick swap with loading; address bar snaps to live URL on blur when not editing; empty state present when !hasPage. The wiring IS the rendered DOM for these declarative bindings, so a source regex is a reliable proxy without a render harness (the repo has no jsdom/testing-library; BrowserPanel is IPC-driven). Loaded/loading/nav chrome states are intentionally not screenshot- fixture'd: their layout is identical to empty (#818 is a layout defect, not a state defect), loading/nav are transient, and their state invariants are locked by the source contract. Seeding BrowserState for a loaded screenshot would need a production test- seam (main-side visual-smoke browser:state hook or BrowserPanel visual-smoke read) for no layout-regression value. 8 baseline PNGs (1280/990 × light/dark × motion/reduced) generated in apps/desktop/tests/screenshots/browser-empty/ (gitignored generated captures) as a stable-subset candidate, pending visual review + promotion to screenshots-baseline/ via a separate baseline commit (the established pattern — baselines are committed separately from fixture code).
Astro-Han
added a commit
that referenced
this pull request
Jul 12, 2026
…act (#819) (#838) BrowserPanel renderer chrome had no deterministic coverage, so layout/ a11y regressions (e.g. the #818 narrow-layout defect) could only be caught by manual real-window smoke. Add two deterministic layers: - VisualSmokeState.liveBrowserSessionIds + applyVisualSmokeFixture wiring + a `browser-empty` scenario that seeds the active turn session as a live browser session so BrowserPanel mounts. With no native WebContentsView in visual-smoke mode, browser.getState resolves null → EMPTY_STATE → the empty-state chrome (toolbar all-nav-disabled + <Empty> strip), exactly the #818 defect surface. Reuses the always-seeded turn session; no browser-specific on-disk seed. - browser-panel-chrome source contract (symmetric to artifact-pane-layout.test.ts) locking the 5 declarative chrome invariants that don't need a screenshot: back/forward :disabled track canGoBack/canGoForward; reload/stop icon + aria-label + onClick swap with loading; address bar snaps to live URL on blur when not editing; empty state present when !hasPage. The wiring IS the rendered DOM for these declarative bindings, so a source regex is a reliable proxy without a render harness (the repo has no jsdom/testing-library; BrowserPanel is IPC-driven). Loaded/loading/nav chrome states are intentionally not screenshot- fixture'd: their layout is identical to empty (#818 is a layout defect, not a state defect), loading/nav are transient, and their state invariants are locked by the source contract. Seeding BrowserState for a loaded screenshot would need a production test- seam (main-side visual-smoke browser:state hook or BrowserPanel visual-smoke read) for no layout-regression value. 8 baseline PNGs (1280/990 × light/dark × motion/reduced) generated in apps/desktop/tests/screenshots/browser-empty/ (gitignored generated captures) as a stable-subset candidate, pending visual review + promotion to screenshots-baseline/ via a separate baseline commit (the established pattern — baselines are committed separately from fixture code).
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
Gives
BrowserPanela<=990pxbottom-sheet layout, mirroringArtifactPane, so a live embedded browser stays usable on narrow windows instead of collapsing to an invisible 520px rail. Adds a narrow PostCSS-based CSS contract test that locks the one declaration preventing the disappearing-browser defect (min-height: 220px).Why
BrowserPanelhad no@media (max-width: 990px)rule. Its grid auto row sized to the panel's max-content (toolbar height); the strip'sflex: 1 1 autocontributes 0 height without a definite container height, so the rAF loop mirrored a ~zero-height rect to main and the nativeWebContentsViewwas sized to nothing — the embedded browser disappeared beside a ~470px empty gap.ArtifactPanealready had an explicit narrow bottom-sheet;BrowserPaneldid not.Part of the #546 Artifact pane + browser panel closure audit. Refs #546.
Scope
.maka-browser-panelgains a@media (max-width: 990px)bottom-sheet rule mirroringArtifactPane(full width,min-height: 220px,max-height: min(42dvh, 360px),border-left: 0, top border + lift shadow).min-height: 220pxis the load-bearing declaration: it forces the auto row (and thus the strip) to a usable non-zero size so the native view is visible;width: 100%turns the 520px right rail into a bottom sheet.BrowserPanelis always the second grid child (chat / browser / artifact), so it already occupies the explicitautorow;ArtifactPaneas the third child uses an implicitautorow (grid-auto-rows defaults toauto), so the existingminmax(0, 1fr) autoalready accommodates all three.browser-panel-layout.test.tsuses PostCSS (the repo's established contract-test parser) to lock ONLY the declaration that prevents the defect: exactly onemin-height: 220pxon.maka-browser-panelin the 990px media block, with no!important.min-heightis genuinely exclusive to the narrow rule (the base rule does not declare it), so a source contract locks its effective value within the block. The test does NOT simulate the cascade and does NOT claim to lockwidth/border-left(also declared by the base rule, won only by source order — not verifiable by a text contract),max-height(a space cap), orborder-top/box-shadow(visual); those belong to visual smoke review. A synthetic test locks the helper's collection/guard logic (a second overriding rule, a duplicate property,!important, and removal each surface so the integration guard fails).Non-goals: redesigning the browser chrome; adding a deterministic browser visual-smoke fixture (filed as #819); changing the rAF viewport-mirroring mechanism; a shared-height policy for the both-present narrow case (tracked as #824); locking the full computed layout (would need a real browser computed-style check, out of scope for a CSS fix of this size).
Verification
min-height: 220pxis removed or overridden (verified — removal -> 0 declarations -> RED "expected exactly one min-height"; a second rule / duplicate property -> 2 declarations -> RED;!important-> RED). A synthetic test locks the helper's collection so the guard logic is permanently covered (not just the real-CSS pass path).artifact-pane-layout.test.ts2/2 green; full main suitenpm run test:dist-> 2348/2348 pass incl. console/a11y/copy checks;npm run build:renderer(vite) builds cleanly.BrowserPanelhas no deterministic visual-smoke fixture (tracked in feat(ui): add deterministic visual-smoke fixture + DOM contract for BrowserPanel renderer chrome #819). A reviewer should confirm the narrow bottom sheet vianpm --workspace @maka/desktop run devwith a live browser session at ~900px, or the real-window smoke. Substitute evidence: the CSS contract test (locks the load-bearing min-height) + the unchanged rAF mirroring path (the strip'sgetBoundingClientRectalready drives the native view; making the strip bounded viamin-heightis what produces the correct native rect); the bottom-sheet identity (width/borders/bound) is left to that visual review by design.Impact
<=990px), a live embedded browser renders as a full-width bottom sheet (usable) instead of an invisible 520px sliver with an empty gap. At>=991pxbehavior is unchanged.Reviewer notes
#824): with bothArtifactPaneand a liveBrowserPanelopen at<=990pxand a window<=~440pxtall, the chat row can collapse to 0 (twomin-height: 220pxbottom sheets). The browser close button stays at the top of the second row and is reachable down to the ~320px restore minimum, so closing the browser always recovers the chat column; at the shortest heights the ArtifactPane collapse button may be clipped, so recovery may require closing the browser and/or collapsing ArtifactPane. This is an edge-of-edge case (already unusable at similar heights before this change); a shared-height policy is a product decision tracked in fix(ui): reserve chat/composer height when both ArtifactPane and BrowserPanel are open at narrow widths #824, not bundled here. The CSS comment records this honestly.min-height: 220px, genuinely exclusive to the narrow rule), after earlier drafts over-reached by hand-modeling the CSS cascade (a parallel incomplete reimplementation of the browser's cascade resolver, which left a false-pass hole each round) and by locking cascade-dependent / cosmetic declarations a text contract cannot verify.Ready for review
Verificationexplains why it is not applicable