From 07c6d79b8153699af4aff71ef00008c9cb9a1b51 Mon Sep 17 00:00:00 2001 From: lzt404 <2596933790@qq.com> Date: Mon, 21 Sep 2026 21:05:05 +0800 Subject: [PATCH] style(usage): compact overview stat cards and fit 6 cards in a single row --- src/pages/UsageRecordsPage.tsx | 7 ++-- src/styles.css | 58 +++++++++++++++++++--------------- tests/usage-layout-ui.cjs | 27 ++++++++++++++-- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/pages/UsageRecordsPage.tsx b/src/pages/UsageRecordsPage.tsx index 3a58062..6a70739 100644 --- a/src/pages/UsageRecordsPage.tsx +++ b/src/pages/UsageRecordsPage.tsx @@ -1028,7 +1028,7 @@ function OverviewView({ overview, range }: { overview: UsageOverview; range?: Pi }, { label: t('usage.stat.tps'), - value: overview.tpsSampleCount > 0 ? `${overview.tps.toFixed(1)} TPS` : '—', + value: overview.tpsSampleCount > 0 ? overview.tps.toFixed(1) : '—', meta: t('usage.stat.performanceMeta', { samples: compactNumber(overview.tpsSampleCount), rpm: overview.rpm.toFixed(2), @@ -1073,12 +1073,9 @@ function OverviewView({ overview, range }: { overview: UsageOverview; range?: Pi
{cards.map(({ label, value, meta, metaTitle }) => ( -
+
{label} {value} - - {meta} -
))}
diff --git a/src/styles.css b/src/styles.css index db8241c..a70999b 100644 --- a/src/styles.css +++ b/src/styles.css @@ -8439,47 +8439,53 @@ textarea:focus-visible { .usage-stat-grid { grid-column: 1 / -1; display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: 12px; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: 10px; } .usage-stat-card { - display: grid; - gap: 8px; - padding: 14px 16px; + display: flex; + flex-direction: column; + justify-content: center; + gap: 5px; + padding: 10px 12px; border: 1px solid var(--theme-e3e1db); - border-radius: 9px; + border-radius: 8px; background: var(--theme-fffdf8); + min-width: 0; transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease; } .usage-stat-card:hover { border-color: var(--theme-d5d2cb); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); + transform: translateY(-1px); } .usage-stat-card-label { color: var(--theme-7a746c); - font-size: var(--font-size-meta); - font-weight: var(--font-weight-semibold); + font-size: var(--font-size-caption); + font-weight: var(--font-weight-medium); + line-height: 1.25; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .usage-stat-card-value { color: var(--theme-2d2a26); - font-size: var(--font-size-metric-compact); + font-size: 20px; font-weight: var(--font-weight-semibold); font-variant-numeric: tabular-nums; - line-height: 1.15; + line-height: 1.2; letter-spacing: -0.01em; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .usage-stat-card-meta { - color: var(--theme-8a847c); - font-size: var(--font-size-caption); - line-height: 1.3; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + display: none; } /* Trend Panel */ @@ -10851,10 +10857,6 @@ body.table-col-resizing * { grid-template-columns: 200px minmax(0, 1fr); } - .usage-stat-grid { - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - } - .control-panel, .version-panel { grid-column: auto; @@ -11321,7 +11323,7 @@ body.table-col-resizing * { } .usage-stat-grid { - grid-template-columns: 1fr; + grid-template-columns: repeat(3, minmax(0, 1fr)); } .usage-custom-range { @@ -14554,13 +14556,13 @@ body.table-col-resizing * { .agent-workbench { grid-template-columns: 200px minmax(0, 1fr); } - - .usage-stat-grid { - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - } } @container workspace (max-width: 760px) { + .usage-stat-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } + .config-network-grid, .config-tls-fields, .config-management-form, @@ -14725,6 +14727,12 @@ body.table-col-resizing * { } } +@container workspace (max-width: 480px) { + .usage-stat-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + @container workspace (max-width: 540px) { .usage-data-management-heading, .usage-data-management-action, diff --git a/tests/usage-layout-ui.cjs b/tests/usage-layout-ui.cjs index 880504c..b507077 100644 --- a/tests/usage-layout-ui.cjs +++ b/tests/usage-layout-ui.cjs @@ -6,11 +6,34 @@ const base = 'http://127.0.0.1:1421'; (async () => { const browser = await chromium.launch({ channel: 'msedge', headless: true, args: ['--no-proxy-server'] }); try { - const page = await browser.newPage({ viewport: { width: 1100, height: 600 } }); + const page = await browser.newPage({ viewport: { width: 1213, height: 600 } }); await page.route('**/*', (route) => route.request().url().startsWith(`${base}/`) ? route.continue() : route.abort()); await page.goto(`${base}/tests/fixtures/usage-layout.html`, { waitUntil: 'domcontentloaded' }); await page.locator('.usage-trend-x-axis').waitFor(); + const statInfo1213 = await page.evaluate(() => { + const cards = Array.from(document.querySelectorAll('.usage-stat-card')); + const metas = Array.from(document.querySelectorAll('.usage-stat-card-meta')); + const tpsCard = cards.find((card) => card.querySelector('.usage-stat-card-label')?.textContent?.trim() === 'TPS'); + const tpsValue = tpsCard?.querySelector('.usage-stat-card-value')?.textContent?.trim() ?? ''; + return { + cardCount: cards.length, + metaCount: metas.length, + cardRows: new Set(cards.map((card) => Math.round(card.getBoundingClientRect().top))).size, + tpsValue, + }; + }); + + assert.equal(statInfo1213.cardCount, 6, 'There are 6 stat cards'); + assert.equal(statInfo1213.cardRows, 1, 'At 1213px width, all 6 cards fit into a single row'); + assert.equal(statInfo1213.metaCount, 0, 'Stat cards have no meta subtext displayed'); + assert.ok(!statInfo1213.tpsValue.includes('TPS'), `TPS value should not contain TPS unit: ${statInfo1213.tpsValue}`); + assert.ok(/^\d+(\.\d+)?$/.test(statInfo1213.tpsValue), `TPS value should be numeric: ${statInfo1213.tpsValue}`); + + // Now test constrained width where cards wrap and ensure vertical scrolling is preserved + await page.setViewportSize({ width: 750, height: 600 }); + await page.waitForTimeout(100); + const geometry = await page.evaluate(() => { const layout = document.querySelector('.usage-overview-layout'); const panel = document.querySelector('.usage-trend-panel'); @@ -45,7 +68,7 @@ const base = 'http://127.0.0.1:1421'; return axis.getBoundingClientRect().bottom <= layout.getBoundingClientRect().bottom + 1; }), 'The complete X axis is reachable by scrolling the overview'); - console.log('PASS: wrapped usage cards preserve the full trend chart and use vertical overview scrolling.'); + console.log('PASS: 1213px single row stat cards and constrained wrapped overview scrolling passed.'); } finally { await browser.close(); }