diff --git a/webviews/src/agent-session/acpmux/conversation/conversation.css b/webviews/src/agent-session/acpmux/conversation/conversation.css index ae011a29cd2d..e4ed9fbc4f62 100644 --- a/webviews/src/agent-session/acpmux/conversation/conversation.css +++ b/webviews/src/agent-session/acpmux/conversation/conversation.css @@ -494,7 +494,7 @@ pane's right edge, its own width (data-enter, ui/presence.ts). */ .acpmux-artifact { --ui-enter-distance: 100%; - flex: 0 0 clamp(320px, 46%, 760px); + flex: 0 0 var(--acpmux-artifact-width, clamp(320px, 46vw, 760px)); min-width: 0; display: flex; flex-direction: column; @@ -509,6 +509,11 @@ margin-top: var(--acpmux-tab-row-height); max-height: calc(100% - var(--acpmux-tab-row-height)); } +/* The header lives in the chat column while Preview is a shell sibling. Keep its tools at the + pane edge, across the Preview column, just as the inline Summary does. */ +.acpmux-shell[data-tab-row]:has(> .acpmux-artifact) .acpmux-header[data-tab-row] { + width: calc(100% + var(--acpmux-artifact-width, clamp(320px, 46vw, 760px))); +} @media (max-width: 720px) { .acpmux-artifact { position: absolute; @@ -516,6 +521,9 @@ z-index: var(--layer-overlay); box-shadow: none; } + .acpmux-shell[data-tab-row]:has(> .acpmux-artifact) .acpmux-header[data-tab-row] { + width: 100%; + } } .acpmux-artifact-bar { flex: 0 0 44px; diff --git a/webviews/test/summary-header-surface.test.ts b/webviews/test/summary-header-surface.test.ts index 82cec0c7bf34..f0340de878fb 100644 --- a/webviews/test/summary-header-surface.test.ts +++ b/webviews/test/summary-header-surface.test.ts @@ -19,7 +19,10 @@ await requireBrowserLane("summary-header-surface.test.ts", async () => { }); await server.listen(); browser = await chromium.launch({ headless: true }); - await warmGalleryFrame(server, "agent-pane.summary-card", { browser, params: { variant: "shared-tab-row" } }); + await warmGalleryFrame(server, "agent-pane.summary-card", { + browser, + params: { variant: "shared-tab-row" }, + }); }); afterAll(async () => { await browser?.close(); @@ -28,7 +31,9 @@ await requireBrowserLane("summary-header-surface.test.ts", async () => { for (const height of [28, 40]) { for (const theme of ["Apple System Colors", "Apple System Colors Light"]) { test(`inline Summary leaves the ${height}px native tools row clear (${theme})`, async () => { - const page = await browser.newPage({ viewport: { width: 720, height: 560 } }); + const page = await browser.newPage({ + viewport: { width: 720, height: 560 }, + }); try { const port = (server.httpServer!.address() as { port: number }).port; await page.goto( @@ -39,7 +44,9 @@ await requireBrowserLane("summary-header-surface.test.ts", async () => { (node as HTMLElement).style.setProperty("--acpmux-tab-row-height", `${pixels}px`); }, height); if (process.env.CMUX_SUMMARY_CAPTURE_DIR) { - await mkdir(process.env.CMUX_SUMMARY_CAPTURE_DIR, { recursive: true }); + await mkdir(process.env.CMUX_SUMMARY_CAPTURE_DIR, { + recursive: true, + }); await page.screenshot({ path: path.join( process.env.CMUX_SUMMARY_CAPTURE_DIR, @@ -100,29 +107,54 @@ await requireBrowserLane("summary-header-surface.test.ts", async () => { } for (const width of [640, 1000]) { for (const height of [28, 40]) { - test(`Preview leaves the ${height}px native row clear at ${width}px`, async () => { - const page = await browser.newPage({ viewport: { width, height: 560 }, reducedMotion: "reduce" }); - try { - const port = (server.httpServer!.address() as { port: number }).port; - await page.goto( - `http://127.0.0.1:${port}${galleryFrame("agent-pane.summary-card", { variant: "preview-tab-row" })}`, - ); - await page.waitForFunction(() => document.documentElement.dataset.galleryReady === "1"); - await page.locator(".acpmux-shell").evaluate((node, pixels) => { - (node as HTMLElement).style.setProperty("--acpmux-tab-row-height", `${pixels}px`); - }, height); - await page.locator(".acpmux-artifact").waitFor(); - const actual = await page.evaluate(() => { - const shell = document.querySelector(".acpmux-shell")!.getBoundingClientRect(); - const panel = document.querySelector(".acpmux-artifact")!.getBoundingClientRect(); - return { top: panel.top - shell.top, bottom: panel.bottom - shell.bottom }; + for (const theme of ["Apple System Colors", "Apple System Colors Light"]) { + test(`Preview leaves the ${height}px native row clear at ${width}px (${theme})`, async () => { + const page = await browser.newPage({ + viewport: { width, height: 560 }, + reducedMotion: "reduce", }); - expect(actual.top).toBe(height); - expect(actual.bottom).toBeLessThanOrEqual(0); - } finally { - await page.close(); - } - }); + try { + const port = (server.httpServer!.address() as { port: number }).port; + await page.goto( + `http://127.0.0.1:${port}${galleryFrame("agent-pane.summary-card", { variant: "preview-tab-row", theme })}`, + ); + await page.waitForFunction(() => document.documentElement.dataset.galleryReady === "1"); + await page.locator(".acpmux-shell").evaluate((node, pixels) => { + (node as HTMLElement).style.setProperty("--acpmux-tab-row-height", `${pixels}px`); + }, height); + await page.locator(".acpmux-artifact").waitFor(); + if (process.env.CMUX_SUMMARY_CAPTURE_DIR) { + await mkdir(process.env.CMUX_SUMMARY_CAPTURE_DIR, { + recursive: true, + }); + await page.screenshot({ + path: path.join( + process.env.CMUX_SUMMARY_CAPTURE_DIR, + `preview-${height}-${width}-${theme.endsWith("Light") ? "light" : "dark"}.png`, + ), + }); + } + const actual = await page.evaluate(() => { + const shell = document.querySelector(".acpmux-shell")!.getBoundingClientRect(); + const panel = document.querySelector(".acpmux-artifact")!.getBoundingClientRect(); + const tools = document.querySelector(".acpmux-header-tools")!.getBoundingClientRect(); + return { + top: panel.top - shell.top, + bottom: panel.bottom - shell.bottom, + toolsWidth: tools.width, + toolsRight: tools.right, + shellRight: shell.right, + }; + }); + expect(actual.top).toBe(height); + expect(actual.bottom).toBeLessThanOrEqual(0); + expect(actual.toolsWidth).toBeGreaterThan(0); + expect(actual.toolsRight).toBe(actual.shellRight); + } finally { + await page.close(); + } + }); + } } } });