style(usage): keep statistic card metadata on one line

This commit is contained in:
lzt404 committed 2026-08-02 14:33:41 +08:00
1 parent 5924faaac3
commit d59cee19fa
4 files changed
+21 -20

No files matched your search

+5 -5
View File
@@ -128,16 +128,16 @@ export const jaOverrides = {
'usage.stat.requests': '総リクエスト数',
'usage.stat.requestMeta': '成功 {success} · 失敗 {failed}',
'usage.stat.tokens': '合計 Token',
'usage.stat.tokenMeta': '入力 {input} · 出力 {output}',
'usage.stat.tokenMeta': '入 {input} · 出 {output}',
'usage.stat.successRate': '成功率',
'usage.stat.reasoningMeta': '推論 {tokens} Token',
'usage.stat.reasoningMeta': '推論 {tokens}',
'usage.stat.averageLatency': '平均レイテンシ',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': '{rpm} RPM · 平均レイテンシ {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.cacheHitRate': 'キャッシュヒット率',
'usage.stat.cacheHitMeta': 'ヒット {hit} / 入力 {input} Token',
'usage.stat.cacheHitMeta': 'キャッシュ {hit}/{input}',
'usage.stat.estimatedCost': '推定コスト',
'usage.stat.costMeta': '{priced} / {total} 件を計算済み · 参考値',
'usage.stat.costMeta': '計算 {priced}/{total} · 推定',
'usage.pricing.coverage': '{priced} / {total} 件を計算済み · 利用可能なモデル料金 {saved} 件',
'usage.pricing.search': 'モデルを検索',
'usage.pricing.add': '手動で追加',
+12 -12
View File
@@ -129,18 +129,18 @@ export const zhCN = {
'usage.filter.to': '至',
'usage.loading': '正在读取本地 SQLite 使用记录',
'usage.stat.requests': '请求总数',
'usage.stat.requestMeta': '{success} 成功 · {failed} 失败',
'usage.stat.requestMeta': '成功 {success} · 失败 {failed}',
'usage.stat.tokens': 'Token 总量',
'usage.stat.tokenMeta': '输入 {input} · 输出 {output}',
'usage.stat.tokenMeta': '入 {input} · 出 {output}',
'usage.stat.successRate': '成功率',
'usage.stat.reasoningMeta': '思考 {tokens} Token',
'usage.stat.reasoningMeta': '思考 {tokens}',
'usage.stat.averageLatency': '平均延迟',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': '{rpm} RPM · 平均延迟 {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.cacheHitRate': '缓存命中率',
'usage.stat.cacheHitMeta': '命中 {hit} / 输入 {input} Token',
'usage.stat.cacheHitMeta': '缓存 {hit}/{input}',
'usage.stat.estimatedCost': '预估成本',
'usage.stat.costMeta': '已计价 {priced} / {total} 次请求 · 仅供参考',
'usage.stat.costMeta': '计价 {priced}/{total} · 估算',
'usage.pricing.coverage': '已计价 {priced} / {total} 次请求 · 可用 {saved} 个模型价格',
'usage.pricing.search': '搜索模型',
'usage.pricing.add': '手动添加',
@@ -1018,18 +1018,18 @@ export const en: Record<MessageKey, string> = {
'usage.filter.to': 'to',
'usage.loading': 'Loading local SQLite usage history',
'usage.stat.requests': 'Total Requests',
'usage.stat.requestMeta': '{success} succeeded · {failed} failed',
'usage.stat.requestMeta': 'OK {success} · Fail {failed}',
'usage.stat.tokens': 'Total Tokens',
'usage.stat.tokenMeta': 'Input {input} · Output {output}',
'usage.stat.tokenMeta': 'In {input} · Out {output}',
'usage.stat.successRate': 'Success Rate',
'usage.stat.reasoningMeta': 'Reasoning {tokens} tokens',
'usage.stat.reasoningMeta': 'Reasoning {tokens}',
'usage.stat.averageLatency': 'Average Latency',
'usage.stat.tps': 'TPS',
'usage.stat.performanceMeta': '{rpm} RPM · Avg latency {latency} ms',
'usage.stat.performanceMeta': 'RPM {rpm} · {latency} ms',
'usage.stat.cacheHitRate': 'Cache Hit Rate',
'usage.stat.cacheHitMeta': '{hit} hit / {input} input tokens',
'usage.stat.cacheHitMeta': 'Cache {hit}/{input}',
'usage.stat.estimatedCost': 'Estimated Cost',
'usage.stat.costMeta': '{priced} / {total} requests priced · Estimate only',
'usage.stat.costMeta': 'Priced {priced}/{total} · Est.',
'usage.pricing.coverage': '{priced} / {total} requests priced · {saved} model prices available',
'usage.pricing.search': 'Search model',
'usage.pricing.add': 'Add Manually',
+2 -2
View File
@@ -414,7 +414,7 @@ export function UsageRecordsPage() {
function OverviewView({ overview }: { overview: UsageOverview }) {
const { t } = useI18n();
const cards = [
{ icon: Activity, label: t('usage.stat.requests'), value: compactNumber(overview.totalRequests), meta: t('usage.stat.requestMeta', { success: overview.successCount, failed: overview.failureCount }) },
{ icon: Activity, label: t('usage.stat.requests'), value: compactNumber(overview.totalRequests), meta: t('usage.stat.requestMeta', { success: compactNumber(overview.successCount), failed: compactNumber(overview.failureCount) }) },
{ icon: Sparkles, label: t('usage.stat.tokens'), value: compactNumber(overview.totalTokens), meta: t('usage.stat.tokenMeta', { input: compactNumber(overview.inputTokens), output: compactNumber(overview.outputTokens) }) },
{ icon: ShieldCheck, label: t('usage.stat.successRate'), value: `${overview.successRate.toFixed(1)}%`, meta: t('usage.stat.reasoningMeta', { tokens: compactNumber(overview.reasoningTokens) }) },
{ icon: Clock3, label: t('usage.stat.tps'), value: `${overview.tps.toFixed(1)} TPS`, meta: t('usage.stat.performanceMeta', { rpm: overview.rpm.toFixed(2), latency: Math.round(overview.averageLatencyMs) }) },
@@ -422,7 +422,7 @@ function OverviewView({ overview }: { overview: UsageOverview }) {
{ icon: CircleDollarSign, label: t('usage.stat.estimatedCost'), value: formatUsd(overview.estimatedCost), meta: t('usage.stat.costMeta', { priced: compactNumber(overview.pricedRequests), total: compactNumber(overview.totalRequests) }) },
];
return <div className="usage-overview-layout">
<div className="usage-stat-grid">{cards.map(({ icon: Icon, label, value, meta }) => <article className="panel usage-stat-card" key={label}><span><Icon size={16} />{label}</span><strong>{value}</strong><small>{meta}</small></article>)}</div>
<div className="usage-stat-grid">{cards.map(({ icon: Icon, label, value, meta }) => <article className="panel usage-stat-card" key={label}><span><Icon size={16} />{label}</span><strong>{value}</strong><small title={meta}>{meta}</small></article>)}</div>
<section className="panel usage-trend-panel"><div className="usage-section-heading"><div><strong>{t('usage.trend.title')}</strong><span>{t('usage.trend.description')}</span></div></div>{overview.timeline.length ? <UsageTrend points={overview.timeline} /> : <UsageEmpty />}</section>
<section className="panel usage-health-panel"><div className="usage-section-heading"><div><strong>{t('usage.token.title')}</strong><span>{t('usage.token.description')}</span></div></div><div className="usage-token-breakdown"><TokenMetric label={t('usage.token.input')} value={overview.inputTokens} total={overview.totalTokens} /><TokenMetric label={t('usage.token.output')} value={overview.outputTokens} total={overview.totalTokens} /><TokenMetric label={t('usage.token.reasoning')} value={overview.reasoningTokens} total={overview.totalTokens} /><TokenMetric label={t('usage.token.cacheRead')} value={overview.cacheReadTokens} total={overview.totalTokens} /><TokenMetric label={t('usage.token.cacheCreation')} value={overview.cacheCreationTokens} total={overview.totalTokens} /></div></section>
</div>;
+2 -1
View File
@@ -5749,11 +5749,12 @@ textarea:focus-visible {
.usage-stat-card > small {
overflow: hidden;
min-width: 0;
color: var(--theme-8a847c);
font-size: var(--font-size-caption);
line-height: var(--line-height-body);
text-overflow: ellipsis;
white-space: normal;
white-space: nowrap;
}
.usage-trend-panel,