From 751b970997fe340340ae9a2176db2c46da159cc2 Mon Sep 17 00:00:00 2001 From: kingwl Date: Thu, 30 Jul 2026 12:25:48 +0800 Subject: [PATCH] fix(web): align queue panel with responsive composer --- apps/web/tests/queue-actions.e2e.ts | 20 +++++++++++++++++++ .../src/client/queue/QueueDock.module.css | 17 +++++++++++++--- .../src/client/queue/QueueDock.tsx | 2 +- .../skeleton/ConversationRoot.module.css | 5 +++++ .../src/client/skeleton/HeroShell.module.css | 4 ++-- .../src/client/skeleton/InputBar.module.css | 9 +++++---- .../src/client/skeleton/TodoPanel.module.css | 18 +++++++++++++---- 7 files changed, 61 insertions(+), 14 deletions(-) diff --git a/apps/web/tests/queue-actions.e2e.ts b/apps/web/tests/queue-actions.e2e.ts index be5e73f9a6..19a5005e50 100644 --- a/apps/web/tests/queue-actions.e2e.ts +++ b/apps/web/tests/queue-actions.e2e.ts @@ -85,6 +85,26 @@ describe('web e2e: queue row actions', () => { { timeout: 10_000 }, ).toBe(2) + await page.setViewportSize({ width: 640, height: 1000 }) + const queueBox = await page.locator('[data-queue-dock]').boundingBox() + const composerBox = await page.locator('[data-composer-card]').boundingBox() + expect(queueBox).not.toBeNull() + expect(composerBox).not.toBeNull() + expect(queueBox!.x).toBeGreaterThanOrEqual(composerBox!.x) + expect(queueBox!.x + queueBox!.width) + .toBeLessThanOrEqual(composerBox!.x + composerBox!.width) + const queueLeftInset = queueBox!.x - composerBox!.x + const queueRightInset = composerBox!.x + composerBox!.width - queueBox!.x - queueBox!.width + const composerMetrics = await page.locator('[data-composer-card]').evaluate((element) => { + const style = getComputedStyle(element) + return { + dockInset: Number.parseFloat(style.getPropertyValue('--dsh-composer-dock-inset')), + } + }) + expect(queueLeftInset).toBeCloseTo(composerMetrics.dockInset, 1) + expect(queueRightInset).toBeCloseTo(composerMetrics.dockInset, 1) + await page.setViewportSize({ width: 1680, height: 1000 }) + const editRow = page.getByText(EDIT, { exact: true }).locator('..') await editRow.getByRole('button', { name: '编辑排队消息' }).click() const editor = page.getByRole('textbox', { name: '编辑排队消息' }) diff --git a/packages/client/ui-conversation/src/client/queue/QueueDock.module.css b/packages/client/ui-conversation/src/client/queue/QueueDock.module.css index 4c05c2cbca..5a918a3c6d 100644 --- a/packages/client/ui-conversation/src/client/queue/QueueDock.module.css +++ b/packages/client/ui-conversation/src/client/queue/QueueDock.module.css @@ -1,10 +1,21 @@ -/* Figma .FileContainerText 1:791: 776px wrapper around the inset 752px panel. */ +/* Figma .FileContainerText 1:791: the wrapper uses the shared dock inset + inside the composer card around the inset panel. */ .dock { box-sizing: border-box; flex: none; - width: 100%; - max-width: 776px; + width: calc( + 100% - + var(--dsh-composer-side-clearance) - + var(--dsh-composer-side-clearance) - + var(--dsh-composer-dock-inset) - + var(--dsh-composer-dock-inset) + ); + max-width: calc( + var(--dsh-composer-card-max-width) - + var(--dsh-composer-dock-inset) - + var(--dsh-composer-dock-inset) + ); /* Eat InputBar's 6px top padding and tuck the panel 2px under the card; the later composer sibling paints its surface and shadow over this edge. */ margin: 0 auto -10px; diff --git a/packages/client/ui-conversation/src/client/queue/QueueDock.tsx b/packages/client/ui-conversation/src/client/queue/QueueDock.tsx index 99b91f301d..b55ef8b007 100644 --- a/packages/client/ui-conversation/src/client/queue/QueueDock.tsx +++ b/packages/client/ui-conversation/src/client/queue/QueueDock.tsx @@ -61,7 +61,7 @@ export function QueueDock({ useSession, updateQueue, notify }: QueueDockProps) { } return ( -
+
    {queue.map(row => ( diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css index 272bbae873..a3ba4b15da 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css @@ -131,6 +131,11 @@ .composerStack { display: flex; flex-direction: column; + /* InputBar and dock registrants derive their horizontal geometry from the + same card width, outer clearance, and dock inset. */ + --dsh-composer-card-max-width: 800px; + --dsh-composer-side-clearance: 32px; + --dsh-composer-dock-inset: 12px; } /* Common seat for the composer chain (fallback + elected overlay siblings). */ diff --git a/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css b/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css index 71b90bfdfa..523f640c0b 100644 --- a/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/HeroShell.module.css @@ -11,7 +11,7 @@ padding: 0 24px; } -/* Cap matches InputBar card width (800). Glow may paint past the sides. */ +/* Cap matches the InputBar card. Glow may paint past the sides. */ .stack { display: flex; flex-direction: column; @@ -19,7 +19,7 @@ /* figma 75:8208: 12 between title block / workspace / card. */ gap: 12px; width: 100%; - max-width: 800px; + max-width: var(--dsh-composer-card-max-width); overflow: visible; } diff --git a/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css b/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css index 8837752830..401bbb73d8 100644 --- a/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/InputBar.module.css @@ -23,7 +23,7 @@ /* figma Input_Bottom: pad L32/R32/B12; the bottom gradient mask is owned by the chat scroller. Top 6 is the gap under the dock todo strip (12px todo margin + 6px here); error/status strips still carry their own margin. */ - padding: 6px 32px 12px; + padding: 6px var(--dsh-composer-side-clearance) 12px; } .hero { @@ -33,7 +33,7 @@ .error, .status { width: 100%; - max-width: 800px; + max-width: var(--dsh-composer-card-max-width); margin-bottom: 6px; padding: 4px 8px; border-radius: 8px; @@ -48,7 +48,7 @@ .notice { width: 100%; - max-width: 800px; + max-width: var(--dsh-composer-card-max-width); margin-bottom: 6px; padding: 4px 8px; border-radius: 8px; @@ -69,6 +69,7 @@ } .card { + box-sizing: border-box; position: relative; /* overlay anchor positioning context */ display: flex; flex-direction: column; @@ -76,7 +77,7 @@ top pad on the card before .InputText. */ gap: 12px; width: 100%; - max-width: 800px; + max-width: var(--dsh-composer-card-max-width); padding-top: 10px; /* Input stroke: black/0.10 light, white/0.06 dark (figma darkmode note says the input border is one notch weaker than buttons) — exactly the diff --git a/packages/client/ui-conversation/src/client/skeleton/TodoPanel.module.css b/packages/client/ui-conversation/src/client/skeleton/TodoPanel.module.css index 7b506b5553..94abf3871a 100644 --- a/packages/client/ui-conversation/src/client/skeleton/TodoPanel.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/TodoPanel.module.css @@ -1,13 +1,23 @@ /* Todo strip above the composer (figma 772:51905 / 772:52972 / 772:53419): - tip surface, 14px radius, status icons + secondary item labels. Column is - calc(100% - 88px) / max 776, centered; InputBar top pad supplies the gap. */ + tip surface, 14px radius, status icons + secondary item labels. It shares + the composer card geometry and adds the dock inset on both sides. */ .root { flex: none; overflow: hidden; margin: 0 auto; - width: calc(100% - 88px); - max-width: 776px; + width: calc( + 100% - + var(--dsh-composer-side-clearance) - + var(--dsh-composer-side-clearance) - + var(--dsh-composer-dock-inset) - + var(--dsh-composer-dock-inset) + ); + max-width: calc( + var(--dsh-composer-card-max-width) - + var(--dsh-composer-dock-inset) - + var(--dsh-composer-dock-inset) + ); border: 1px solid var(--dsw-alias-border-l1); border-radius: 14px; background: var(--dsw-specific-tip);