fix(web): preserve subagent catalog styling

This commit is contained in:
kingwl
2026-08-03 18:24:25 +08:00
parent 70ad82ef00
commit 6585847144
3 changed files with 28 additions and 121 deletions

View File

@@ -1,5 +0,0 @@
menu: 360px; padding 4px; gap 4px; radius 12px
row: 352×54px; padding 7px 8px 7px 4px; radius 8px
content: 340×40px; left inset 8px; right inset 12px
label: 14px/20px/400
summary: 12px/18px/400

View File

@@ -21,7 +21,6 @@ const BASE_FIXTURE = fileURLToPath(new URL('./snapshots/live-interactions/sessio
const AVAILABLE_CHILD_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/ui.expected.md', import.meta.url))
const TREE_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/tree.expected.md', import.meta.url))
const BRANCHLESS_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/branchless.expected.md', import.meta.url))
const BRANCHLESS_LAYOUT_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/branchless-layout.expected.md', import.meta.url))
const STALE_CATALOG_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/stale-catalog.expected.md', import.meta.url))
const SIDEBAR_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/sidebar.expected.md', import.meta.url))
const UNAVAILABLE_GRANDCHILD_EXPECTED = fileURLToPath(new URL('./snapshots/subagent-conversation/nested.expected.md', import.meta.url))
@@ -402,79 +401,16 @@ describe('web e2e: persisted subagent conversation and human continuation', () =
const nestedRow = tree.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) })
expect(await nestedRow.locator(':scope > *').count()).toBe(1)
const clickArea = nestedRow.locator(':scope > *')
const label = nestedRow.getByText(NESTED_LABEL, { exact: true })
const summary = nestedRow.getByText('continuable · not running', { exact: true })
const [treeBox, rowBox, clickAreaBox, treeStyle, rowStyle, labelStyle, summaryStyle] = await Promise.all([
const [treeBox, clickAreaBox] = await Promise.all([
tree.boundingBox(),
nestedRow.boundingBox(),
clickArea.boundingBox(),
tree.evaluate((element) => {
const style = getComputedStyle(element)
return { gap: style.gap, padding: style.padding, radius: style.borderRadius }
}),
nestedRow.evaluate((element) => {
const style = getComputedStyle(element)
return { padding: style.padding, radius: style.borderRadius }
}),
label.evaluate((element) => {
const style = getComputedStyle(element)
return { size: style.fontSize, lineHeight: style.lineHeight, weight: style.fontWeight }
}),
summary.evaluate((element) => {
const style = getComputedStyle(element)
return { size: style.fontSize, lineHeight: style.lineHeight, weight: style.fontWeight }
}),
])
expect(treeBox).not.toBeNull()
expect(rowBox).not.toBeNull()
expect(clickAreaBox).not.toBeNull()
const leftInset = Math.round(clickAreaBox!.x - treeBox!.x)
const rightInset = Math.round(
treeBox!.x + treeBox!.width - clickAreaBox!.x - clickAreaBox!.width,
)
const layout = {
menuWidth: Math.round(treeBox!.width),
menuPadding: treeStyle.padding,
menuGap: treeStyle.gap,
menuRadius: treeStyle.radius,
rowWidth: Math.round(rowBox!.width),
rowHeight: Math.round(rowBox!.height),
rowPadding: rowStyle.padding,
rowRadius: rowStyle.radius,
contentWidth: Math.round(clickAreaBox!.width),
contentHeight: Math.round(clickAreaBox!.height),
leftInset,
rightInset,
label: labelStyle,
summary: summaryStyle,
}
expect(layout).toEqual({
menuWidth: 360,
menuPadding: '4px',
menuGap: '4px',
menuRadius: '12px',
rowWidth: 352,
rowHeight: 54,
rowPadding: '7px 8px 7px 4px',
rowRadius: '8px',
contentWidth: 340,
contentHeight: 40,
leftInset: 8,
rightInset: 12,
label: { size: '14px', lineHeight: '20px', weight: '400' },
summary: { size: '12px', lineHeight: '18px', weight: '400' },
})
await compareOrRefreshGolden(
BRANCHLESS_LAYOUT_EXPECTED,
[
`menu: ${layout.menuWidth}px; padding ${layout.menuPadding}; gap ${layout.menuGap}; radius ${layout.menuRadius}`,
`row: ${layout.rowWidth}×${layout.rowHeight}px; padding ${layout.rowPadding}; radius ${layout.rowRadius}`,
`content: ${layout.contentWidth}×${layout.contentHeight}px; left inset ${layout.leftInset}px; right inset ${layout.rightInset}px`,
`label: ${layout.label.size}/${layout.label.lineHeight}/${layout.label.weight}`,
`summary: ${layout.summary.size}/${layout.summary.lineHeight}/${layout.summary.weight}`,
].join('\n'),
MODE,
)
expect([
Math.round(clickAreaBox!.x - treeBox!.x),
Math.round(treeBox!.x + treeBox!.width - clickAreaBox!.x - clickAreaBox!.width),
]).toEqual([5, 5])
await compareOrRefreshGolden(
BRANCHLESS_EXPECTED,
await captureStableAria(page, '[role="tree"][aria-label="Subagent sessions"]', scaffold.workspaceCwd),

View File

@@ -49,43 +49,42 @@
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 4px;
width: 360px;
width: 336px;
max-width: min(400px, calc(100vw - 32px));
max-height: calc(100vh - 140px);
max-height: min(560px, calc(100vh - 140px));
padding: 4px;
overflow: auto;
border: 0;
border: 1px solid var(--dsw-alias-border-l2);
border-radius: 12px;
background: var(--dsw-specific-menu);
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
box-shadow: inset 0 0 0 1px var(--dsw-alias-border-inverted), var(--dsw-shadow-lv3);
box-shadow: var(--dsw-shadow-lv3);
}
.node {
position: relative;
display: flex;
flex-direction: column;
gap: 4px;
min-width: 0;
}
.menu > .node {
margin-left: -3px;
}
.row {
position: relative;
display: flex;
align-items: flex-start;
gap: 4px;
gap: 8px;
box-sizing: border-box;
width: 100%;
min-height: 54px;
padding: 7px 8px 7px 4px;
min-height: 50px;
padding: 7px 8px 7px 11px;
border: 0;
border-radius: 8px;
background: transparent;
color: var(--dsw-alias-label-primary);
font-size: 14px;
line-height: 20px;
font-size: 13px;
line-height: 18px;
text-align: left;
cursor: pointer;
outline: none;
@@ -102,26 +101,16 @@
flex: 1;
align-self: stretch;
align-items: flex-start;
gap: 6px;
gap: 8px;
min-width: 0;
border-radius: 12px;
margin: -7px -8px -7px;
padding: 7px 8px;
border-radius: 8px;
}
.row > :global([data-state]),
.clickarea > :global([data-state]) {
margin: 5px 3px 0;
}
.row:has(> .disclosure) > .clickarea,
.row:has(> .disclosureSpace) > .clickarea {
padding-left: 18px;
}
.row:has(> .disclosureSpace):not(:has(> .clickarea)) {
padding-left: 22px;
}
.row > :global([data-state]) {
margin: 5px 3px 0;
margin-top: 4px;
}
.disabled {
@@ -139,16 +128,9 @@
.disclosure,
.disclosureSpace {
position: absolute;
top: 7px;
left: 4px;
flex: none;
width: 14px;
height: 20px;
}
.disclosureSpace {
display: none;
height: 18px;
}
.disclosure {
@@ -175,7 +157,6 @@
display: flex;
flex: 1;
flex-direction: column;
gap: 2px;
min-width: 0;
}
@@ -188,21 +169,19 @@
.label {
color: inherit;
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.summary,
.metrics {
color: var(--dsw-alias-label-tertiary);
font-size: 12px;
line-height: 18px;
font-size: 11px;
line-height: 16px;
}
.metrics {
display: grid;
grid-template-rows: 20px 18px;
grid-template-rows: 18px 16px;
flex: none;
font-variant-numeric: tabular-nums;
text-align: right;
@@ -211,7 +190,7 @@
.metricToken {
grid-row: 1;
line-height: 20px;
line-height: 18px;
}
.metricDuration {
@@ -220,9 +199,6 @@
.children {
position: relative;
display: flex;
flex-direction: column;
gap: 4px;
margin-left: 18px;
padding-left: 4px;
}