Align page surfaces and simplify the top-level chrome

Use the home page background across pages, remove redundant titles, and match the usage records tabs and filters to the shared controls. Move the API refresh and add actions beside search, and drop the standalone provider total.
This commit is contained in:
lzt404 committed 2026-10-04 17:31:52 +08:00
1 parent d6bb29f79f
commit cadfe4f5f5
12 files changed
+237 -172

No files matched your search

+1 -5
View File
@@ -2026,11 +2026,7 @@ export function AgentsPage({ embedded = false, onConfigurationApplied }: AgentsP
<h1>{t('agents.embedded.title')}</h1>
<p>{t('agents.embedded.subtitle')}</p>
</>
) : (
<>
<h1>{t('agents.title')}</h1>
</>
)}
) : null}
</div>
<div className="agent-header-actions">
{detectionError ? (
+13 -22
View File
@@ -1402,8 +1402,6 @@ export function ApiAccessPage() {
void reorderProviders(source, target);
};
const totalCount = Object.values(records).reduce((sum, items) => sum + items.length, 0);
const countForDefinition = (definition: ProviderDefinition) =>
records[definition.section].filter((record) =>
providerCategoryMatchesRecord(definition.id, record, definition.section)
@@ -1412,23 +1410,6 @@ export function ApiAccessPage() {
return (
<section className="page management-page api-access-page">
{confirmationDialog}
<header className="management-header">
<div>
<h1>{t('apiAccess.title')}</h1>
</div>
<div className="management-heading-actions">
<span className="muted-summary">{t('apiAccess.count', { count: totalCount })}</span>
<button type="button" className="secondary-button compact-button" onClick={() => void loadProviders()} disabled={loading || busy}>
<RefreshCw size={16} aria-hidden="true" />
{t('common.refresh')}
</button>
<button type="button" className="primary-button compact-button" onClick={openCreate} disabled={loading || busy}>
<Plus size={16} aria-hidden="true" />
{t('apiAccess.add')}
</button>
</div>
</header>
{error ? <MessageNotice message={error} onDismiss={() => setError('')} /> : null}
<div className="provider-workbench real-provider-workbench">
<aside className="panel provider-category-panel">
@@ -1456,9 +1437,19 @@ export function ApiAccessPage() {
<h2 title={t(activeDefinition.labelKey)}>{t(activeDefinition.labelKey)}</h2>
<span>{t('apiAccess.matches', { count: rows.length })}</span>
</div>
<div className="management-toolbar compact-toolbar">
<Search size={16} aria-hidden="true" />
<input value={filter} onChange={(event) => setFilter(event.currentTarget.value)} placeholder={t('apiAccess.search')} />
<div className="api-access-heading-tools">
<button type="button" className="secondary-button compact-button" onClick={() => void loadProviders()} disabled={loading || busy}>
<RefreshCw size={16} aria-hidden="true" />
{t('common.refresh')}
</button>
<button type="button" className="primary-button compact-button" onClick={openCreate} disabled={loading || busy}>
<Plus size={16} aria-hidden="true" />
{t('apiAccess.add')}
</button>
<div className="management-toolbar compact-toolbar">
<Search size={16} aria-hidden="true" />
<input value={filter} onChange={(event) => setFilter(event.currentTarget.value)} placeholder={t('apiAccess.search')} />
</div>
</div>
</div>
-3
View File
@@ -374,9 +374,6 @@ export function AuthFileManagementPage() {
<section className="page management-page auth-files-page">
{confirmationDialog}
<header className="management-header">
<div>
<h1>{t('authFiles.title')}</h1>
</div>
<div className="management-heading-actions">
<span className="muted-summary">{t('authFiles.summary', { files: files.length, disabled: disabledCount })}</span>
<button type="button" className="secondary-button compact-button" onClick={() => {
-3
View File
@@ -984,9 +984,6 @@ export function ConfigPanelPage() {
return (
<section className="page config-page">
<header className="management-header config-page-header">
<div><h1>{t('app.nav.config')}</h1></div>
</header>
<div className="agent-subpage-tabs config-subpage-tabs" role="tablist" aria-label={t('config.tabs.label')}>
<button
type="button"
-3
View File
@@ -219,9 +219,6 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) {
return (
<section className="page kernel-page home-page">
<header className="management-header home-page-header">
<div><h1>{t('app.nav.home')}</h1></div>
</header>
<div className="kernel-layout home-layout">
<div className="panel control-panel">
<div className="panel-heading">
-1
View File
@@ -501,7 +501,6 @@ export function OAuthLoginPage() {
return (
<section className="page management-page">
<header className="management-header">
<div><h1>{t('oauth.title')}</h1></div>
<label className="oauth-browser-picker">
<span>{t('oauth.browser.label')}</span>
<select
-1
View File
@@ -144,7 +144,6 @@ export function QuotaPage() {
<section className="page management-page quota-page">
{confirmationDialog}
<header className="management-header">
<div><h1>{t('quota.title')}</h1></div>
<div className="management-heading-actions">
<span className="muted-summary">{t(files.length === 1 ? 'quota.queryableCredentials.one' : 'quota.queryableCredentials.other', { count: files.length })}</span>
<button type="button" className="secondary-button compact-button" onClick={() => void loadFiles()} disabled={loading || refreshing || querying}>
-5
View File
@@ -558,11 +558,6 @@ export function ThinkingAliasesPage({ embedded = false }: { embedded?: boolean }
<MessageNotice tone="success" message={!error ? notice : null} onDismiss={() => setNotice('')} />
<header className="management-header">
<div>
{embedded
? <h2>{t('app.nav.thinkingAliases')}</h2>
: <h1>{t('app.nav.thinkingAliases')}</h1>}
</div>
<div className="management-heading-actions">
<span className="muted-summary">{entries.length}</span>
<button
+1 -10
View File
@@ -3,15 +3,11 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, typ
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import {
Activity,
BarChart3,
ChevronLeft,
ChevronRight,
CircleDollarSign,
Columns3Cog,
Database,
FilterX,
List,
Pencil,
RefreshCw,
RotateCcw,
@@ -560,7 +556,7 @@ export function UsageRecordsPage() {
<div className="usage-topbar">
<div className="usage-page-navigation">
<h1>{t('usage.title')}</h1>
<h1 className="sr-only">{t('usage.title')}</h1>
<div className="usage-tabs" role="tablist" aria-label={t('usage.pageLabel')}>
<button
type="button"
@@ -573,7 +569,6 @@ export function UsageRecordsPage() {
onClick={() => setActiveTab('overview')}
onKeyDown={(event) => handleTabKeyDown(event, 'overview')}
>
<BarChart3 size={15} />
<span>{t('usage.tab.overview')}</span>
</button>
<button
@@ -587,7 +582,6 @@ export function UsageRecordsPage() {
onClick={() => setActiveTab('analysis')}
onKeyDown={(event) => handleTabKeyDown(event, 'analysis')}
>
<Activity size={15} />
<span>{t('usage.tab.analysis')}</span>
</button>
<button
@@ -601,7 +595,6 @@ export function UsageRecordsPage() {
onClick={() => setActiveTab('events')}
onKeyDown={(event) => handleTabKeyDown(event, 'events')}
>
<List size={15} />
<span>{t('usage.tab.events')}</span>
</button>
<button
@@ -615,7 +608,6 @@ export function UsageRecordsPage() {
onClick={() => setActiveTab('pricing')}
onKeyDown={(event) => handleTabKeyDown(event, 'pricing')}
>
<CircleDollarSign size={15} />
<span>{t('usage.tab.pricing')}</span>
</button>
<button
@@ -629,7 +621,6 @@ export function UsageRecordsPage() {
onClick={() => setActiveTab('data-management')}
onKeyDown={(event) => handleTabKeyDown(event, 'data-management')}
>
<Wrench size={15} />
<span>{t('usage.tab.dataManagement')}</span>
</button>
</div>
-3
View File
@@ -509,9 +509,6 @@ export function VersionManagementPage() {
return (
<section className="page management-page version-management-page">
<header className="management-header version-page-header">
<div><h1>{t('app.nav.versions')}</h1></div>
</header>
<MessageNotice message={versionSourceError} onDismiss={() => setVersionSourceError('')} />
<section className="panel version-list">
<div className="version-source-row" aria-label={t('kernel.versions.downloadSource')}>
+2 -1
View File
@@ -1940,7 +1940,8 @@ textarea:focus-visible {
@container workspace (min-width: 840px) {
.home-page {
grid-template-columns: minmax(320px, 1fr) minmax(360px, 1.15fr);
grid-auto-rows: 1fr;
grid-template-rows: auto auto;
grid-auto-rows: unset;
align-items: stretch;
}
+220 -115
View File
@@ -149,18 +149,13 @@ body, html, #root {
}
@container workspace (min-width: 840px) {
.home-page {
grid-template-rows: auto auto auto;
grid-auto-rows: unset;
}
.home-page > .home-layout,
.home-page > .client-api-panel {
grid-row: 2;
grid-row: 1;
}
.home-page > .home-quick-actions {
grid-row: 3;
grid-row: 2;
grid-column: 1 / -1;
}
}
@@ -358,6 +353,40 @@ body, html, #root {
font-weight: 600;
}
/* API access toolbar */
.api-access-page .management-panel-heading {
align-items: center;
flex-wrap: wrap;
}
.api-access-heading-tools {
display: flex;
min-width: 0;
flex: 1 1 420px;
align-items: center;
justify-content: flex-end;
gap: 8px;
}
.api-access-heading-tools .compact-toolbar {
width: min(280px, 100%);
flex: 1 1 180px;
}
@container workspace (max-width: 760px) {
.api-access-heading-tools {
width: 100%;
flex-basis: 100%;
flex-wrap: wrap;
justify-content: flex-start;
}
.api-access-heading-tools .compact-toolbar {
flex-basis: 100%;
}
}
/* 7. OAuth Management Page Polish */
.oauth-management-page .management-header h1 {
display: none;
@@ -444,62 +473,150 @@ body, html, #root {
outline-offset: -2px;
}
.usage-stat-card {
--usage-tone: var(--ui-accent);
position: relative;
gap: 7px;
/* Usage records follow the same shell surface as the home page. */
.usage-records-page {
gap: 16px;
color: #1d1d1f;
}
.usage-records-page .usage-topbar {
align-items: center;
}
.usage-records-page .usage-collector-state,
.usage-records-page .usage-refresh-btn {
height: 34px;
border: 0;
border-radius: 999px;
background: rgba(118, 118, 128, 0.12);
box-shadow: none;
color: #1d1d1f;
}
.usage-records-page .usage-collector-state strong {
color: #1d1d1f;
font-weight: 600;
}
.usage-records-page .usage-collector-state span,
.usage-records-page .usage-filter-label,
.usage-records-page .usage-section-heading span {
color: #6e6e73;
}
.usage-records-page .usage-trend-panel,
.usage-records-page .usage-health-panel,
.usage-records-page .usage-category-panel,
.usage-records-page .usage-events-panel {
border: 0;
border-radius: 18px;
background: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 10px 28px rgba(0, 0, 0, 0.045);
}
.usage-records-page .panel.usage-filter-panel {
display: grid;
gap: 8px;
padding: 0;
border: 0;
border-radius: 0;
background: transparent;
box-shadow: none;
}
.usage-records-page .usage-filter-item {
min-width: 0;
}
.usage-records-page .usage-filter-label {
padding-left: 12px;
}
.usage-records-page .usage-filter-item select,
.usage-records-page .usage-filter-item input {
height: 34px;
border: 1px solid var(--border-color);
border-radius: 8px;
background: var(--bg-primary);
color: var(--text-primary);
}
.usage-records-page .usage-filter-item select:hover,
.usage-records-page .usage-filter-item input:hover {
border-color: var(--border-hover);
}
.usage-records-page .usage-filter-item select:focus,
.usage-records-page .usage-filter-item input:focus {
border-color: var(--ui-accent);
box-shadow: 0 0 0 3px var(--ui-focus-ring);
}
.usage-records-page .usage-section-heading strong {
color: #1d1d1f;
font-weight: 650;
letter-spacing: -0.02em;
}
.usage-records-page .usage-stat-grid {
gap: 1px;
overflow: hidden;
padding: 13px 14px 12px 16px;
border-color: color-mix(in srgb, var(--usage-tone) 24%, var(--border-color));
border-radius: 12px;
background:
linear-gradient(180deg, color-mix(in srgb, var(--usage-tone) 13%, #fff) 0%, #fff 68%);
box-shadow: var(--ui-panel-shadow);
padding: 0;
border-radius: 18px;
background: #d8d8de;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 10px 28px rgba(0, 0, 0, 0.045);
}
.usage-stat-card {
--usage-tone: #1d1d1f;
position: relative;
gap: 8px;
overflow: hidden;
padding: 16px 16px 14px;
border: 0;
border-radius: 0;
background: #fff;
box-shadow: none;
}
.usage-stat-card::before {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 4px;
background: var(--usage-tone);
content: "";
content: none;
}
.usage-stat-card.tone-requests { --usage-tone: #0f766e; }
.usage-stat-card.tone-speed { --usage-tone: #2563eb; }
.usage-stat-card.tone-tokens { --usage-tone: #7c3aed; }
.usage-stat-card.tone-success { --usage-tone: #059669; }
.usage-stat-card.tone-cache { --usage-tone: #d97706; }
.usage-stat-card.tone-cost { --usage-tone: #0f766e; }
.usage-stat-card.tone-requests { --usage-tone: #1d1d1f; }
.usage-stat-card.tone-speed { --usage-tone: #007aff; }
.usage-stat-card.tone-tokens { --usage-tone: #5856d6; }
.usage-stat-card.tone-success { --usage-tone: #34c759; }
.usage-stat-card.tone-cache { --usage-tone: #ff9500; }
.usage-stat-card.tone-cost { --usage-tone: #007aff; }
.usage-stat-card:hover {
border-color: color-mix(in srgb, var(--usage-tone) 48%, var(--border-color));
box-shadow: var(--ui-card-hover-shadow);
border-color: transparent;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05), 0 14px 32px rgba(0, 0, 0, 0.06);
transform: none;
}
.usage-stat-card-label {
color: var(--usage-tone);
color: #6e6e73;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.01em;
font-weight: 590;
letter-spacing: -0.01em;
}
.usage-stat-card-value {
color: var(--text-primary);
font-size: 28px;
font-weight: 750;
letter-spacing: -0.035em;
line-height: 1.05;
color: var(--usage-tone);
font-size: 30px;
font-weight: 650;
letter-spacing: -0.045em;
line-height: 1.02;
}
.usage-stat-meter {
display: block;
height: 6px;
height: 5px;
overflow: hidden;
border-radius: 999px;
background: color-mix(in srgb, var(--usage-tone) 16%, #e2e8f0);
background: #e5e5ea;
}
.usage-stat-meter > span {
@@ -513,9 +630,9 @@ body, html, #root {
display: flex;
min-height: 0;
flex-wrap: wrap;
gap: 4px;
gap: 5px;
overflow: visible;
color: var(--text-secondary);
color: #6e6e73;
white-space: normal;
-webkit-line-clamp: unset;
-webkit-box-orient: unset;
@@ -525,28 +642,28 @@ body, html, #root {
display: inline-flex;
max-width: 100%;
align-items: center;
padding: 2px 7px;
padding: 2px 8px;
border-radius: 999px;
background: #f1f5f9;
color: var(--text-secondary);
background: #f2f2f7;
color: #3a3a3c;
font-size: 11px;
font-weight: 700;
line-height: 1.4;
font-weight: 590;
line-height: 1.45;
}
.usage-stat-chip.tone-ok {
background: #ecfdf5;
color: #047857;
background: rgba(52, 199, 89, 0.14);
color: #248a3d;
}
.usage-stat-chip.tone-bad {
background: #fef2f2;
color: #b91c1c;
background: rgba(255, 59, 48, 0.12);
color: #d70015;
}
.usage-stat-chip.tone-warn {
background: #fffbeb;
color: #b45309;
background: rgba(255, 149, 0, 0.16);
color: #c93400;
}
.usage-stat-chip.tone-note {
@@ -554,63 +671,8 @@ body, html, #root {
padding: 0;
border-radius: 0;
background: transparent;
color: var(--text-tertiary);
font-weight: 600;
}
.usage-filter-panel,
.usage-trend-panel,
.usage-health-panel,
.usage-category-panel,
.usage-events-panel,
.usage-collector-state,
.usage-refresh-btn {
border-color: var(--border-color);
background: var(--bg-card);
box-shadow: var(--ui-panel-shadow);
}
.usage-filter-panel {
padding: 12px 14px;
}
.usage-filter-label {
color: var(--text-tertiary);
}
.usage-filter-item select,
.usage-filter-item input {
border-color: var(--border-primary);
border-radius: 8px;
background: var(--bg-card);
color: var(--text-primary);
}
.usage-filter-item select:focus,
.usage-filter-item input:focus {
border-color: var(--ui-accent);
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
}
.usage-section-heading strong {
color: var(--text-primary);
}
.usage-section-heading span,
.usage-token-count,
.usage-token-pct,
.usage-trend-legend-item {
color: var(--text-tertiary);
}
.usage-token-name,
.usage-collector-state strong {
color: var(--text-primary);
}
.usage-token-bar-track {
height: 7px;
background: var(--bg-hover);
color: #6e6e73;
font-weight: 500;
}
.usage-metrics-grid .metric-card {
@@ -852,10 +914,53 @@ body, html, #root {
}
/* Dark Theme Adjustments for Refined Components */
:root[data-theme='dark'] .usage-records-page,
:root[data-theme='dark'] .usage-records-page .usage-section-heading strong,
:root[data-theme='dark'] .usage-records-page .usage-collector-state,
:root[data-theme='dark'] .usage-records-page .usage-collector-state strong {
color: #f5f5f7;
}
:root[data-theme='dark'] .usage-records-page .panel.usage-filter-panel {
background: transparent;
box-shadow: none;
}
:root[data-theme='dark'] .usage-records-page .usage-collector-state,
:root[data-theme='dark'] .usage-records-page .usage-refresh-btn {
background: #2c2c2e;
color: #f5f5f7;
}
:root[data-theme='dark'] .usage-records-page .usage-filter-item select,
:root[data-theme='dark'] .usage-records-page .usage-filter-item input {
background: var(--bg-primary);
border-color: var(--border-color);
color: var(--text-primary);
}
:root[data-theme='dark'] .usage-records-page .usage-trend-panel,
:root[data-theme='dark'] .usage-records-page .usage-health-panel,
:root[data-theme='dark'] .usage-records-page .usage-category-panel,
:root[data-theme='dark'] .usage-records-page .usage-events-panel,
:root[data-theme='dark'] .usage-stat-card {
background:
linear-gradient(180deg, color-mix(in srgb, var(--usage-tone) 24%, var(--bg-card)) 0%, var(--bg-card) 72%);
border-color: color-mix(in srgb, var(--usage-tone) 42%, var(--border-color));
background: #1c1c1e;
border-color: transparent;
box-shadow: none;
}
:root[data-theme='dark'] .usage-records-page .usage-stat-grid {
background: #3a3a3c;
box-shadow: none;
}
:root[data-theme='dark'] .usage-stat-card.tone-requests {
--usage-tone: #f5f5f7;
}
:root[data-theme='dark'] .usage-stat-card-label,
:root[data-theme='dark'] .usage-stat-chip.tone-note {
color: #98989d;
}
:root[data-theme='dark'] .usage-stat-chip {