fix(client): give the sidebar Context panel the tab's main-row layout

The right Sidebar's Context panel split its three main cards into three
columns, so a pane too narrow for three folded into a ragged 2+1: a hole
under the composition card and the trend card alone on its own row. The
conversation tab read differently, from the same component.

Drop the per-host arrangement: both hosts now use one two-column row
(composition over trend in the left column, the browser beside it and
stretched to the pair's height). The panel's row simply folds to a single
column at the shared 360px floor instead of splitting across two rows.
The head row is untouched, so the panel still shows its two donut cards.
This commit is contained in:
Bowen Liang committed 2026-09-10 01:37:25 +08:00
1 parent 771bc02556
commit 6bdd6bdf59
3 files changed
+24 -40

No files matched your search

+11 -20
View File
@@ -363,7 +363,8 @@ export function makeContextView(
// urges the upgrade. Absent record = a supported harness, no gate.
const gate = unsupportedOf(data.unsupported)
// The three main-row cards, built once and arranged per host below.
// The three main-row cards, built once and laid out by the shared
// arrangement below (every host uses the same row).
const compositionCard = (
<CurrentComposition
head={head}
@@ -492,26 +493,16 @@ export function makeContextView(
{inSidebar ? null : <PluginInfo />}
</div>
{/* Arranged per host: the tab keeps the two-column split (composition
+ trend beside the browser); the sidebar panel is a narrow column,
so it stacks the three and puts the browser right after the
composition card, before the trend. */}
{/* One arrangement for every host: composition over trend in the left
column, the browser beside them and stretched to the pair's height.
The sidebar panel's column simply folds to one at the shared 360px
floor instead of splitting the three cards across two ragged rows. */}
<div className="lc-cols lc-cols-main">
{inSidebar ? (
<>
<div className="lc-col">{compositionCard}</div>
<div className="lc-col lc-col-browser">{browserCard}</div>
<div className="lc-col">{trendCard}</div>
</>
) : (
<>
<div className="lc-col">{compositionCard}{trendCard}</div>
{/* `lc-col-browser` stretches the browser card to the left column's height — Context tab only; the /context modal must stay
content-sized.
*/}
<div className="lc-col lc-col-browser">{browserCard}</div>
</>
)}
<div className="lc-col">{compositionCard}{trendCard}</div>
{/* `lc-col-browser` stretches the browser card to the left column's
height; the /context modal, which draws its own stack, must stay
content-sized. */}
<div className="lc-col lc-col-browser">{browserCard}</div>
</div>
<div className="lc-cols">
+3 -4
View File
@@ -72,10 +72,9 @@
.lc-cols { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
/* Columns fold at 360px: the cards that pair up — the main row's composition/trend
against the browser, and the events card against file activity — read cramped at a
quarter-share of a narrow pane. The tab's main row needs 2 x 360px + the 7px gap,
the sidebar panel's three stacked cards 3 x 360px + two gaps. min() caps the floor
at the row's own width: on a sub-360px pane the column narrows instead of
overflowing. */
quarter-share of a narrow pane, so the main row needs 2 x 360px + the 7px gap to stay
side by side. min() caps the floor at the row's own width: on a sub-360px pane the
column narrows instead of overflowing. */
.lc-col { flex: 1; min-width: min(360px, 100%); }
.lc-cols > .lc-card { margin-bottom: 0; }
.lc-col > .lc-card:last-child { margin-bottom: 0; }
+10 -16
View File
@@ -199,25 +199,19 @@ describe('ContextView — the sidebar host', () => {
await panel.unmount()
})
test('the panel orders the main row composition, browser, trend; the tab keeps composition+trend beside it', async () => {
test('both hosts arrange the main row as composition+trend beside the browser', async () => {
const View = makeView(new TestClientCtx())
const projections = projectionsFor(richTimeline())
const tab = await mount(h(View, { useProjection: projections }))
const tabCols = queryAll(tab.container, '.lc-cols-main > .lc-col')
assert.equal(tabCols.length, 2, 'the tab keeps the two-column split')
assert.ok(tabCols[0].querySelector('.lc-overview-num') !== null, 'composition leads the left column')
assert.ok(tabCols[0].querySelector('.lc-trend-ctl') !== null, 'the trend follows in the same column')
assert.ok(tabCols[1].querySelector('.lc-br-dna-ctl') !== null, 'the browser owns the right column')
await tab.unmount()
const panel = await mount(h(View, { host: 'sidebar', useProjection: projections }))
const panelCols = queryAll(panel.container, '.lc-cols-main > .lc-col')
assert.equal(panelCols.length, 3, 'the panel stacks the three main cards')
assert.ok(panelCols[0].querySelector('.lc-overview-num') !== null, 'composition first')
assert.ok(panelCols[1].querySelector('.lc-br-dna-ctl') !== null, 'the browser second')
assert.ok(panelCols[2].querySelector('.lc-trend-ctl') !== null, 'the trend last')
await panel.unmount()
for (const props of [{ useProjection: projections }, { host: 'sidebar' as const, useProjection: projections }]) {
const m = await mount(h(View, props))
const cols = queryAll(m.container, '.lc-cols-main > .lc-col')
assert.equal(cols.length, 2, 'one two-column split')
assert.ok(cols[0].querySelector('.lc-overview-num') !== null, 'composition leads the left column')
assert.ok(cols[0].querySelector('.lc-trend-ctl') !== null, 'the trend follows in the same column')
assert.ok(cols[1].querySelector('.lc-br-dna-ctl') !== null, 'the browser owns the right column')
await m.unmount()
}
})
})