From 4bb725f7f3a5b25d6c65f6b3ecbee8a1aca8fb13 Mon Sep 17 00:00:00 2001 From: Bob Lee Date: Thu, 30 Jul 2026 01:33:51 -0700 Subject: [PATCH] fix(web-ui): restore padding inside flow chat cards --- .../modern/FlowChatCollapseAlignment.test.ts | 44 +++++++++++-------- .../components/modern/SubagentItems.scss | 6 +-- .../components/modern/VirtualMessageList.scss | 7 +-- .../subagent/SubagentProjectionView.scss | 2 +- .../flow_chat/tool-cards/BaseToolCard.scss | 6 +-- .../flow_chat/tool-cards/CompactToolCard.scss | 2 +- .../flow_chat/tool-cards/GitToolDisplay.scss | 4 +- .../tool-cards/MiniAppToolDisplay.scss | 2 +- .../flow_chat/tool-cards/TaskToolDisplay.scss | 13 +++--- .../tool-cards/TerminalToolCard.scss | 2 +- .../tool-cards/TodoWriteDisplay.scss | 6 +-- 11 files changed, 46 insertions(+), 48 deletions(-) diff --git a/src/web-ui/src/flow_chat/components/modern/FlowChatCollapseAlignment.test.ts b/src/web-ui/src/flow_chat/components/modern/FlowChatCollapseAlignment.test.ts index ebd816ba16..38cda7c617 100644 --- a/src/web-ui/src/flow_chat/components/modern/FlowChatCollapseAlignment.test.ts +++ b/src/web-ui/src/flow_chat/components/modern/FlowChatCollapseAlignment.test.ts @@ -17,8 +17,8 @@ function extractBlock(stylesheet: string, selector: string): string { return match?.groups?.body ?? ''; } -describe('FlowChat collapse leading-edge alignment', () => { - it('guards every shared collapse body against leading indentation', () => { +describe('FlowChat collapse spacing', () => { + it('keeps every shared collapse body on the same outer leading edge', () => { const stylesheet = readSource('./VirtualMessageList.scss'); const projectionRoots = [ '.explore-region__content', @@ -35,10 +35,10 @@ describe('FlowChat collapse leading-edge alignment', () => { expect(stylesheet).toContain(selector); } expect(stylesheet).toContain('margin-inline-start: 0;'); - expect(stylesheet).toContain('padding-inline-start: 0;'); + expect(stylesheet).not.toContain('padding-inline-start: 0;'); }); - it('keeps custom explore and thinking collapse bodies on their header edge', () => { + it('keeps unframed explore and thinking disclosures on their header edge', () => { const exploreStyles = readSource('./ExploreRegion.scss'); const thinkingStyles = readSource('../../tool-cards/ModelThinkingDisplay.scss'); const exploreContent = extractBlock(exploreStyles, '.explore-region__content'); @@ -50,22 +50,29 @@ describe('FlowChat collapse leading-edge alignment', () => { ); }); - it('keeps tool, image, and subagent detail roots free of leading offsets', () => { + it('keeps bordered tool and subagent bodies padded on every side', () => { const baseToolStyles = readSource('../../tool-cards/BaseToolCard.scss'); const compactToolStyles = readSource('../../tool-cards/CompactToolCard.scss'); const imageStyles = readSource('../../tool-cards/ViewImageToolCard.scss'); const subagentStyles = readSource('./SubagentItems.scss'); + const subagentProjectionStyles = readSource('../subagent/SubagentProjectionView.scss'); const taskStyles = readSource('../../tool-cards/TaskToolDisplay.scss'); expect(extractBlock(baseToolStyles, '.base-tool-card-expanded')).toMatch( - /padding:\s*var\(--flowchat-card-expanded-pad-y\)\s*var\(--tool-card-expanded-pad-x\)\s*var\(--flowchat-card-expanded-pad-y\)\s*0;/, + /padding:\s*var\(--flowchat-card-expanded-pad-y\)\s*var\(--tool-card-expanded-pad-x\)\s*var\(--flowchat-card-expanded-pad-y\)\s*var\(--tool-card-expanded-pad-x\);/, ); expect(extractBlock(baseToolStyles, '.base-tool-card-error')).toContain( 'margin-left: 0;', ); + expect(extractBlock(baseToolStyles, '.base-tool-card-error')).toMatch( + /padding:\s*var\(--flowchat-card-expanded-pad-y\)\s*var\(--flowchat-card-expanded-pad-x\)\s*var\(--flowchat-card-expanded-pad-y\)\s*var\(--flowchat-card-expanded-pad-x\);/, + ); expect(extractBlock(compactToolStyles, '.compact-tool-card-expanded')).toContain( 'margin-left: 0;', ); + expect(extractBlock(compactToolStyles, '.compact-tool-card-expanded')).toContain( + 'padding: 12px;', + ); expect(extractBlock(compactToolStyles, '.flow-tool-card-note')).toContain( 'margin-left: 0;', ); @@ -73,36 +80,37 @@ describe('FlowChat collapse leading-edge alignment', () => { 'margin: 8px 0 0;', ); expect(extractBlock(subagentStyles, '.subagent-items-container')).toContain( - 'padding: 10px 10px 10px 0;', + 'padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x);', + ); + expect( + extractBlock(subagentProjectionStyles, '.subagent-projection-container--expanded'), + ).toContain( + 'padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x);', ); expect( extractBlock(taskStyles, '.task-expanded-content .task-prompt-content'), - ).toContain('padding: 0 var(--flowchat-card-pad-x) 0 0;'); + ).toContain('padding: 0;'); expect(taskStyles).toContain( '.subagent-projection-container--expanded {\n' + - ' padding:\n' + - ' 8px\n' + - ' calc(var(--flowchat-card-expanded-pad-x) + var(--flowchat-card-pad-x))\n' + - ' 10px\n' + - ' 0;', + ' padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x);', ); }); - it('does not pull expanded footer or list surfaces past the leading edge', () => { + it('lets full-bleed footer and list surfaces consume the shared body inset', () => { const terminalStyles = readSource('../../tool-cards/TerminalToolCard.scss'); const gitStyles = readSource('../../tool-cards/GitToolDisplay.scss'); const miniAppStyles = readSource('../../tool-cards/MiniAppToolDisplay.scss'); const todoStyles = readSource('../../tool-cards/TodoWriteDisplay.scss'); expect(terminalStyles).toContain( - '.base-tool-card-wrapper.terminal-tool-card .terminal-result-footer {\n margin-left: 0;', + '.base-tool-card-wrapper.terminal-tool-card .terminal-result-footer {\n margin-left: calc(-1 * var(--flowchat-card-expanded-pad-x));', ); - expect(gitStyles).not.toMatch(/git-result-footer[\s\S]{0,120}margin-left:\s*-\d/); + expect(gitStyles).toMatch(/git-result-footer[\s\S]{0,120}margin-left:\s*-\d/); expect(miniAppStyles).toContain( - '.base-tool-card-wrapper.miniapp-tool-display .miniapp-result-footer {\n margin-left: 0;', + '.base-tool-card-wrapper.miniapp-tool-display .miniapp-result-footer {\n margin-left: calc(-1 * var(--flowchat-card-expanded-pad-x));', ); expect(extractBlock(todoStyles, '.todo-expanded-body')).toMatch( - /margin:\s*calc\(var\(--flowchat-card-expanded-pad-y\) \* -1\)\s*calc\(var\(--tool-card-expanded-pad-x\) \* -1\)\s*calc\(var\(--flowchat-card-expanded-pad-y\) \* -1\)\s*0;/, + /margin:\s*calc\(var\(--flowchat-card-expanded-pad-y\) \* -1\)\s*calc\(var\(--tool-card-expanded-pad-x\) \* -1\);/, ); }); }); diff --git a/src/web-ui/src/flow_chat/components/modern/SubagentItems.scss b/src/web-ui/src/flow_chat/components/modern/SubagentItems.scss index 533242e19a..137b8a0583 100644 --- a/src/web-ui/src/flow_chat/components/modern/SubagentItems.scss +++ b/src/web-ui/src/flow_chat/components/modern/SubagentItems.scss @@ -27,9 +27,9 @@ // Subagent container for items under the same parent task. .subagent-items-container { - // Do not offset projected content past the task icon rail: expansion and - // collapse must keep the same leading edge. - padding: 10px 10px 10px 0; + // Keep projected output clear of every card edge while the outer container + // stays aligned with the task header. + padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x); // Continue the task card border on left/right/bottom; top border is hidden. background: var(--color-bg-scene); diff --git a/src/web-ui/src/flow_chat/components/modern/VirtualMessageList.scss b/src/web-ui/src/flow_chat/components/modern/VirtualMessageList.scss index 08e0003b12..274093022a 100644 --- a/src/web-ui/src/flow_chat/components/modern/VirtualMessageList.scss +++ b/src/web-ui/src/flow_chat/components/modern/VirtualMessageList.scss @@ -14,10 +14,8 @@ /* * FlowChat collapse contract: revealing a body may change height, never its - * leading edge. Owner styles also keep their offsets at zero; this selector - * is the surface-level guard for FlowChat's collapsible projection roots. - * It stays explicit so ordinary card-internal padding (for example question - * options) remains untouched. + * outer leading edge. Internal card padding belongs to each projection + * owner, so text keeps breathing room without shifting the card itself. */ .explore-region__content, .thinking-content, @@ -28,7 +26,6 @@ .subagent-items-container, .subagent-projection-container--expanded { margin-inline-start: 0; - padding-inline-start: 0; } diff --git a/src/web-ui/src/flow_chat/components/subagent/SubagentProjectionView.scss b/src/web-ui/src/flow_chat/components/subagent/SubagentProjectionView.scss index 58b83b0f20..2844f6e615 100644 --- a/src/web-ui/src/flow_chat/components/subagent/SubagentProjectionView.scss +++ b/src/web-ui/src/flow_chat/components/subagent/SubagentProjectionView.scss @@ -13,7 +13,7 @@ .subagent-projection-container--expanded { max-height: min(48vh, 640px); - padding: 8px 0 10px; + padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x); } .subagent-projection-container--collapsed { diff --git a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss index 835f8d7a0f..f9c141f818 100644 --- a/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/BaseToolCard.scss @@ -218,12 +218,12 @@ /* ========== Expanded content area ========== */ .base-tool-card-expanded { - /* Full-bleed dividers in children use these (header pad-x is 0; do not conflate). */ + /* Full-bleed dividers in children use these shared body insets. */ padding: var(--flowchat-card-expanded-pad-y) var(--tool-card-expanded-pad-x) var(--flowchat-card-expanded-pad-y) - 0; + var(--tool-card-expanded-pad-x); background: transparent; position: relative; opacity: 1; @@ -238,7 +238,7 @@ var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x) var(--flowchat-card-expanded-pad-y) - 0; + var(--flowchat-card-expanded-pad-x); margin-left: 0; background: none !important; border: none !important; diff --git a/src/web-ui/src/flow_chat/tool-cards/CompactToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/CompactToolCard.scss index ed13a4fc36..905b26d00d 100644 --- a/src/web-ui/src/flow_chat/tool-cards/CompactToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/CompactToolCard.scss @@ -299,7 +299,7 @@ position: relative; margin-top: 8px; margin-left: 0; - padding: 12px 12px 12px 0; + padding: 12px; background: var(--color-bg-primary); border: 1px solid var(--border-base); border-radius: 6px; diff --git a/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss index 8849fa7324..b217956997 100644 --- a/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/GitToolDisplay.scss @@ -51,7 +51,7 @@ /* Footer bar: full width + background to bottom inner edge of expanded content (matches .compact-tool-card-expanded padding). */ .base-tool-card-wrapper.git-tool-display .git-result-footer, .compact-tool-card-wrapper.git-tool-display .git-result-footer { - margin-left: 0; + margin-left: -8px; margin-right: -8px; margin-bottom: -8px; padding: 0.375rem 0.5rem; @@ -65,7 +65,7 @@ /* Expanded + same shell as Terminal: match `terminal-result-footer` inset from `TerminalToolCard.scss`. */ .base-tool-card-wrapper.terminal-tool-card.git-tool-display .git-result-footer { - margin-left: 0; + margin-left: -12px; margin-right: -12px; margin-bottom: -12px; padding: 0.375rem var(--flowchat-card-pad-x); diff --git a/src/web-ui/src/flow_chat/tool-cards/MiniAppToolDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/MiniAppToolDisplay.scss index 697768f7e9..da78d04dee 100644 --- a/src/web-ui/src/flow_chat/tool-cards/MiniAppToolDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/MiniAppToolDisplay.scss @@ -13,7 +13,7 @@ } .base-tool-card-wrapper.miniapp-tool-display .miniapp-result-footer { - margin-left: 0; + margin-left: calc(-1 * var(--flowchat-card-expanded-pad-x)); margin-right: calc(-1 * var(--flowchat-card-expanded-pad-x)); margin-bottom: calc(-1 * var(--flowchat-card-expanded-pad-y)); padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x); diff --git a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss index 24b7fab344..6b56a8f7d7 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/TaskToolDisplay.scss @@ -340,7 +340,7 @@ The generic thinking content has vertical padding; with a one-line max-height that can leave only padding visible and push the prompt text out of view. */ .task-expanded-content .task-prompt-content { - padding: 0 var(--flowchat-card-pad-x) 0 0; + padding: 0; max-height: 3.2em; overflow-y: auto; } @@ -370,7 +370,7 @@ .task-interruption-divider { height: 1px; background: var(--border-base); - margin: -2px calc(-1 * var(--tool-card-expanded-pad-x)) 0 0; + margin: -2px calc(-1 * var(--tool-card-expanded-pad-x)) 0; } .task-expanded-content .task-prompt-markdown { @@ -610,13 +610,10 @@ border-top: 1px solid var(--border-base); } - // Keep projected subagent output on the task card's leading edge. + // Keep the subagent body aligned with the task card while preserving the + // same internal inset on every side. .subagent-projection-container--expanded { - padding: - 8px - calc(var(--flowchat-card-expanded-pad-x) + var(--flowchat-card-pad-x)) - 10px - 0; + padding: var(--flowchat-card-expanded-pad-y) var(--flowchat-card-expanded-pad-x); } // Hide the header top accent line — the wrapper border already frames diff --git a/src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.scss b/src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.scss index 8c6f803994..963c540e26 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.scss +++ b/src/web-ui/src/flow_chat/tool-cards/TerminalToolCard.scss @@ -69,7 +69,7 @@ /* Footer bar: full width + background to bottom inner edge of expanded content (matches .base-tool-card-expanded padding). */ .base-tool-card-wrapper.terminal-tool-card .terminal-result-footer { - margin-left: 0; + margin-left: calc(-1 * var(--flowchat-card-expanded-pad-x)); margin-right: calc(-1 * var(--flowchat-card-expanded-pad-x)); margin-bottom: calc(-1 * var(--flowchat-card-expanded-pad-y)); padding: var(--flowchat-inline-gap) var(--flowchat-card-expanded-pad-x); diff --git a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss index 32f733bf3c..b1386bd144 100644 --- a/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss +++ b/src/web-ui/src/flow_chat/tool-cards/TodoWriteDisplay.scss @@ -154,11 +154,7 @@ /* Expanded body — align list with card edges */ .todo-expanded-body { - margin: - calc(var(--flowchat-card-expanded-pad-y) * -1) - calc(var(--tool-card-expanded-pad-x) * -1) - calc(var(--flowchat-card-expanded-pad-y) * -1) - 0; + margin: calc(var(--flowchat-card-expanded-pad-y) * -1) calc(var(--tool-card-expanded-pad-x) * -1); } .todo-full-list { background: transparent;