style(home): color the success-rate meter by rate

The home overview bar stayed brown down to 80%. Color it continuously from red through yellow to green so it follows the measured success rate.
This commit is contained in:
lzt404 committed 2026-10-06 13:41:35 +08:00
1 parent 317c6df98f
commit 5183cf2bfe
3 files changed
+40 -4

No files matched your search

+1 -1
View File
@@ -283,7 +283,7 @@
.home-stat-card h3 { margin: 0; color: var(--text-secondary); font-size: 12px; font-weight: 500; line-height: 1.5; }
.home-stat-value { display: block; color: var(--text-primary); font-family: var(--font-mono); font-size: 28px; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.15; letter-spacing: -.03em; }
.home-stat-track { height: 5px; margin: 2px 0; overflow: hidden; border-radius: 3px; background: color-mix(in srgb, var(--stat-color) 13%, transparent); }
.home-stat-track > span { display: block; height: 100%; border-radius: inherit; background: var(--stat-color); }
.home-stat-track > span { display: block; height: 100%; border-radius: inherit; background: var(--stat-color); transition: width .25s ease, background-color .25s ease; }
.home-stat-card p { margin: 0; color: var(--text-tertiary); font-size: 11px; line-height: 1.6; overflow-wrap: anywhere; }
/* Use the desktop workspace height; smaller windows retain natural scrolling. */
+5 -3
View File
@@ -1,6 +1,7 @@
import type { ReactNode } from 'react';
import type { CSSProperties, ReactNode } from 'react';
import { RefreshCw } from 'lucide-react';
import { useI18n } from '../i18n';
import { requestRateColor } from '../services/authFileRequests';
import type { HomeOverviewSnapshot } from '../services/homeOverview';
export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, actions }: {
@@ -20,10 +21,11 @@ export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, act
id: 'usage', label: t('home.overview.successRate'),
value: rate == null ? '—' : `${formatNumber(rate, { maximumFractionDigits: 1 })}%`,
description: usage ? t(usage.totalRequests ? 'home.overview.requests' : 'home.overview.noRequests', { count: formatNumber(usage.totalRequests) }) : unavailable(false),
tone: rate == null ? 'neutral' : rate >= 95 ? 'success' : rate >= 80 ? 'warning' : 'error',
tone: 'neutral',
error: snapshot?.errors.usage,
percent: rate ?? null,
meterLabel: t('home.overview.successRate'),
meterColor: rate == null ? undefined : requestRateColor(rate / 100),
},
{
id: 'credentials', label: t('home.overview.credentials'),
@@ -56,7 +58,7 @@ export function HomeOverviewCards({ snapshot, loading, coreReady, onRefresh, act
<div className="home-overview-actions">{actions}<button type="button" className="icon-button quiet" aria-label={t('home.overview.refresh')} title={t('home.overview.refresh')} disabled={loading} onClick={onRefresh}><RefreshCw size={14} className={loading ? 'spin' : undefined} /></button></div>
</div>
<div className="home-stat-grid">
{cards.map((card) => <article className={`home-stat-card ${card.tone}`} key={card.id} data-stat={card.id}>
{cards.map((card) => <article className={`home-stat-card ${card.tone}`} key={card.id} data-stat={card.id} style={'meterColor' in card && card.meterColor ? { '--stat-color': card.meterColor } as CSSProperties : undefined}>
<h3>{card.label}</h3>
<strong className="home-stat-value">{card.value}</strong>
{'percent' in card && <div
+34
View File
@@ -0,0 +1,34 @@
import { expect, it } from 'bun:test';
import { renderToStaticMarkup } from 'react-dom/server';
import { I18nProvider } from '../src/i18n';
import { HomeOverviewCards } from '../src/pages/HomeOverviewCards';
import { requestRateColor } from '../src/services/authFileRequests';
import type { HomeOverviewSnapshot } from '../src/services/homeOverview';
const snapshot = (rate: number | null): HomeOverviewSnapshot => ({
usage: {
totalRequests: rate == null ? 0 : 100,
successCount: rate ?? 0,
failureCount: rate == null ? 0 : 100 - rate,
canceledCount: 0,
successRate: rate,
},
credentials: null,
providerKeys: null,
models: null,
errors: {},
});
const render = (rate: number | null) => renderToStaticMarkup(
<I18nProvider>
<HomeOverviewCards snapshot={snapshot(rate)} loading={false} coreReady onRefresh={() => {}} />
</I18nProvider>,
);
it('colors the success meter continuously from red through yellow to green', () => {
expect(render(100)).toContain(`--stat-color:${requestRateColor(1)}`);
expect(render(50)).toContain(`--stat-color:${requestRateColor(0.5)}`);
expect(render(0)).toContain(`--stat-color:${requestRateColor(0)}`);
expect(render(95)).not.toContain('home-stat-card warning');
expect(render(null)).not.toContain('--stat-color');
});