From f567236330f8b47e1b8fe368f2f1d6ec4a0a0b11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Wed, 3 Jun 2026 18:28:17 +0800 Subject: [PATCH] fix(desktop): improve activity summary layout Use container queries for the activity summary grid so the Token usage panel responds to its own width instead of the full desktop viewport. This prevents loose medium-width layouts and over-compressed five-column cards when the settings page is shown with sidebars. Tested: - cd desktop && bun run test -- src/pages/ActivitySettings.test.tsx --run --reporter=verbose --pool=forks --maxWorkers=1 --minWorkers=1 - cd desktop && bun run test -- src/theme/globals.test.ts --run --reporter=verbose --pool=forks --maxWorkers=1 --minWorkers=1 - bun run check:desktop - Electron smoke at 1180px and 900px against the local dev server Not-tested: - Coverage report; this is a presentation-only desktop UI change. Confidence: high Scope-risk: narrow --- desktop/src/pages/ActivitySettings.test.tsx | 24 ++++++++ desktop/src/pages/ActivitySettings.tsx | 62 ++++++++++++++++----- desktop/src/theme/globals.css | 47 ++++++++++++++++ desktop/src/theme/globals.test.ts | 14 +++++ 4 files changed, 132 insertions(+), 15 deletions(-) diff --git a/desktop/src/pages/ActivitySettings.test.tsx b/desktop/src/pages/ActivitySettings.test.tsx index c5c67a87..62e34e87 100644 --- a/desktop/src/pages/ActivitySettings.test.tsx +++ b/desktop/src/pages/ActivitySettings.test.tsx @@ -239,6 +239,30 @@ describe('ActivitySettings', () => { expect(editButton.closest('div')).toHaveClass('group/activity-profile') }) + it('uses a balanced responsive summary grid instead of the loose medium-width layout', async () => { + render() + + await flushActivityLoad() + + const summaryPanel = screen.getByText('Total tokens').closest('section') + expect(summaryPanel).toHaveClass('activity-summary-panel') + + const summaryGrid = summaryPanel?.querySelector('.activity-summary-grid') + expect(summaryGrid).not.toHaveClass('sm:grid-cols-2') + expect(summaryGrid).not.toHaveClass('lg:grid-cols-5') + expect(summaryGrid).not.toHaveClass('xl:grid-cols-5') + + const primaryMetric = screen.getByText('Total tokens').closest('.activity-summary-metric') + expect(primaryMetric).toHaveClass('activity-summary-metric-primary') + expect(primaryMetric).not.toHaveClass('sm:col-span-2') + expect(primaryMetric).not.toHaveClass('lg:col-span-1') + + const longestTaskValue = screen.getByText('0m') + expect(longestTaskValue).toHaveClass('activity-summary-value') + expect(longestTaskValue).not.toHaveClass('truncate') + expect(longestTaskValue).not.toHaveClass('break-words') + }) + it('supports localized heatmap mode switches and persisted display name edits', async () => { useSettingsStore.setState({ locale: 'zh' }) render() diff --git a/desktop/src/pages/ActivitySettings.tsx b/desktop/src/pages/ActivitySettings.tsx index 24320968..9f73851a 100644 --- a/desktop/src/pages/ActivitySettings.tsx +++ b/desktop/src/pages/ActivitySettings.tsx @@ -608,26 +608,58 @@ export function ActivitySettings() { {profileError && !isEditingProfile &&
{profileError}
} -
+
{isLoading ? ( -
+
{Array.from({ length: 5 }).map((_, index) => ( -
+
+
+
+
+
))}
) : ( -
- {metrics.map((metric, index) => ( -
-
{metric.value}
-
{metric.label}
- {metric.detail &&
{metric.detail}
} -
- ))} +
+ {metrics.map((metric, index) => { + const isPrimary = index === 0 + return ( +
+
+
+
+
+
+ {metric.value} +
+ {metric.detail &&
{metric.detail}
} +
+
+
+ ) + })}
)}
diff --git a/desktop/src/theme/globals.css b/desktop/src/theme/globals.css index 18b14f9d..0e4ef8c3 100644 --- a/desktop/src/theme/globals.css +++ b/desktop/src/theme/globals.css @@ -1280,6 +1280,53 @@ button, input, textarea, select, a, [role="button"] { background: var(--color-outline-a92); } +.activity-summary-panel { + container-type: inline-size; +} + +.activity-summary-grid { + grid-template-columns: minmax(0, 1fr); +} + +.activity-summary-metric-primary { + grid-column: auto; +} + +.activity-summary-value { + overflow-wrap: normal; + word-break: keep-all; +} + +@container (min-width: 360px) { + .activity-summary-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .activity-summary-metric-primary { + grid-column: span 2; + } +} + +@container (min-width: 620px) { + .activity-summary-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + + .activity-summary-metric-primary { + grid-column: span 2; + } +} + +@container (min-width: 860px) { + .activity-summary-grid { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .activity-summary-metric-primary { + grid-column: auto; + } +} + .activity-heat-cell { position: relative; transform: translateZ(0); diff --git a/desktop/src/theme/globals.test.ts b/desktop/src/theme/globals.test.ts index fe011d40..79a4a8c7 100644 --- a/desktop/src/theme/globals.test.ts +++ b/desktop/src/theme/globals.test.ts @@ -89,6 +89,20 @@ describe('desktop theme tokens', () => { expect(css).toContain('box-shadow: var(--shadow-activity-cell-hover);') }) + it('uses container queries for the activity summary grid', () => { + const activitySummaryCss = getCssBetween('.activity-summary-panel {', '.activity-heat-cell {') + const mediumStart = activitySummaryCss.indexOf('@container (min-width: 620px)') + const wideStart = activitySummaryCss.indexOf('@container (min-width: 860px)') + const mediumSummaryCss = activitySummaryCss.slice(mediumStart, wideStart) + + expect(activitySummaryCss).toContain('container-type: inline-size;') + expect(activitySummaryCss).toContain('@container (min-width: 360px)') + expect(activitySummaryCss).toContain('@container (min-width: 620px)') + expect(activitySummaryCss).toContain('@container (min-width: 860px)') + expect(activitySummaryCss).toContain('grid-template-columns: repeat(5, minmax(0, 1fr));') + expect(mediumSummaryCss).toContain('grid-column: span 2;') + }) + it('avoids color-mix in the startup-critical UI zoom shell chrome for Safari 15 WebView support', () => { const zoomShellCss = getCssBetween('.settings-zoom-kbd {', '/* ─── Tailwind Theme Override')