diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts index f82a337..6ad7155 100644 --- a/src/i18n/locales/en.ts +++ b/src/i18n/locales/en.ts @@ -494,7 +494,7 @@ export const en: Record = { 'usage.stat.successMetaTitle': '{success} succeeded, {failed} failed, {canceled} canceled', 'usage.stat.averageLatency': 'Average Latency', 'usage.stat.tps': 'TPS', - 'usage.stat.performanceMeta': '{samples} samples · RPM {rpm} · {latency} ms', + 'usage.stat.performanceMeta': '{samples} samples · RPM {rpm}', 'usage.stat.performanceMetaTitle': 'TPS {tps} (weighted by total latency), {samples} valid samples, RPM {rpm}, average latency {latency} ms', 'usage.stat.cacheHitRate': 'Cache Hit Rate', 'usage.stat.cacheHitMeta': 'Read {hit} · Input {input}', @@ -1456,8 +1456,8 @@ export const en: Record = { 'kernel.install.completed': '{version} installed', 'kernel.error.progressListener': 'Failed to listen for download progress: {error}', 'kernel.action.start': 'start', - 'kernel.action.stop': 'stop', - 'kernel.action.restart': 'restart', + 'kernel.action.stop': 'Stop', + 'kernel.action.restart': 'Restart', 'kernel.notice.actionSuccess': 'Core {action} succeeded', 'kernel.notice.actionFailed': 'Core {action} failed: {error}', 'kernel.notice.networkRestarted': 'Network settings saved and the core restarted', diff --git a/src/pages/ConfigPanel.tsx b/src/pages/ConfigPanel.tsx index 9f9b433..69997ce 100644 --- a/src/pages/ConfigPanel.tsx +++ b/src/pages/ConfigPanel.tsx @@ -984,6 +984,7 @@ export function ConfigPanelPage() { return (
+

{t('app.nav.config')}

- + {loading ? t('common.loading') : settings === null diff --git a/src/pages/Kernel.tsx b/src/pages/Kernel.tsx index 4ca4ff2..5000edb 100644 --- a/src/pages/Kernel.tsx +++ b/src/pages/Kernel.tsx @@ -219,6 +219,7 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) { return (
+

{t('app.nav.home')}

@@ -426,7 +427,6 @@ export function KernelPage({ view = 'home' }: { view?: KernelView }) {

{t('kernel.versions.customMirrorDialogDescription')} @@ -758,11 +771,7 @@ export function VersionManagementPage() { type="button" className="secondary-button" disabled={versionSourceSaving} - onClick={() => { - setCustomMirrorDialogOpen(false); - setCustomMirrorDraft(''); - setVersionSourceError(''); - }} + onClick={closeCustomMirrorDialog} > {t('common.cancel')} diff --git a/src/styles.css b/src/styles.css index 964fdf6..77dbe72 100644 --- a/src/styles.css +++ b/src/styles.css @@ -106,7 +106,7 @@ --theme-f8f6f1: #f8f6f1; --theme-faf8f2: #faf8f2; --theme-faf8f4: #faf8f4; - --theme-faf9f5: #ffffff; + --theme-faf9f5: #f6f7f5; --theme-fdf1ee: #fdf1ee; --theme-fff: #fff; --theme-fff1ee: #fff1ee; @@ -115,7 +115,7 @@ --theme-fffdf8: #fffdf8; --theme-ffffff: #ffffff; - --bg-secondary: #ffffff; + --bg-secondary: #f6f7f5; --bg-primary: #ffffff; --bg-tertiary: #f8fafc; --bg-hover: #f1f5f9; @@ -8568,7 +8568,7 @@ textarea:focus-visible { .usage-overview-layout { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(260px, 0.65fr); - grid-template-rows: auto minmax(280px, 1fr); + grid-template-rows: max-content minmax(280px, 1fr); gap: 14px; align-items: stretch; overflow-x: hidden; diff --git a/src/styles/ui-refinements.css b/src/styles/ui-refinements.css index 76b2d44..0a9e6ad 100644 --- a/src/styles/ui-refinements.css +++ b/src/styles/ui-refinements.css @@ -4,12 +4,12 @@ /* 1. Global Light Theme Surface & Contrast Variables */ :root { - --bg-secondary: #ffffff; + --bg-secondary: #f6f7f5; --bg-primary: #ffffff; --bg-card: #ffffff; - --bg-tertiary: #f8fafc; - --bg-hover: #f1f5f9; - --bg-quinary: #f8fafc; + --bg-tertiary: #eff3f0; + --bg-hover: #f6f8f6; + --bg-quinary: #f9faf9; --border-color: #e2e8f0; --border-secondary: #f1f5f9; --border-primary: #cbd5e1; @@ -18,7 +18,7 @@ --text-secondary: #1e293b; --text-tertiary: #334155; --text-quaternary: #475569; - --theme-faf9f5: #ffffff; + --theme-faf9f5: #f6f7f5; --theme-faf8f4: #ffffff; --theme-faf8f2: #ffffff; --theme-fffdf8: #ffffff; @@ -216,6 +216,13 @@ body, html, #root { border: 1px solid var(--border-color); border-radius: 8px; padding: 6px 12px; + flex-shrink: 0; + white-space: nowrap; +} + +.client-api-panel .client-api-meta { + white-space: nowrap; + flex-shrink: 0; } .client-api-card { @@ -233,8 +240,16 @@ body, html, #root { } .client-api-card-heading { - width: 144px; - flex-basis: 144px; + min-width: 144px; + width: auto; + flex: 0 1 auto; +} + +.client-api-card-heading .client-api-format-tag, +.client-api-card-heading span { + font-size: var(--font-size-caption); + white-space: nowrap; + overflow: visible; } .client-api-card-heading .client-api-format-tag, @@ -450,6 +465,8 @@ body, html, #root { } .oauth-card { + display: flex; + flex-direction: column; padding: 22px; border: 1px solid var(--border-color); border-radius: 12px; @@ -458,6 +475,16 @@ body, html, #root { transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease; } +.oauth-card .oauth-card-body, +.oauth-card .oauth-hint { + flex: 1; +} + +.oauth-card .oauth-card-actions, +.oauth-card > button.primary-button { + margin-top: auto; +} + .oauth-card:hover { border-color: var(--border-primary); box-shadow: var(--ui-card-hover-shadow); @@ -786,7 +813,7 @@ body, html, #root { } .secondary-button { - background: #ffffff; + background: var(--bg-primary); border: 1px solid var(--border-color); color: var(--text-secondary); border-radius: 8px; @@ -800,6 +827,18 @@ body, html, #root { color: var(--text-primary); } +:root[data-theme='dark'] .secondary-button { + background: var(--bg-card); + border-color: var(--border-color); + color: var(--text-primary); +} + +:root[data-theme='dark'] .secondary-button:hover:not(:disabled) { + background: var(--bg-tertiary); + border-color: var(--border-primary); + color: var(--text-primary); +} + .danger-button { background: #fff1f2; border: 1px solid #fecdd3; @@ -815,6 +854,50 @@ body, html, #root { color: #ffffff; } +:root[data-theme='dark'] .danger-button { + background: rgba(225, 29, 72, 0.14); + border-color: rgba(225, 29, 72, 0.35); + color: #fb7185; +} + +:root[data-theme='dark'] .danger-button:hover:not(:disabled) { + background: #e11d48; + border-color: #e11d48; + color: #ffffff; +} + +/* Quota Progress Bar Polish */ +.real-quota-track { + height: 8px; + overflow: hidden; + border-radius: 999px; + background: var(--bg-hover); +} + +.real-quota-track span { + display: block; + height: 100%; + border-radius: inherit; + background: var(--ui-accent); +} + +/* Agent List & Config Scrollbar Polish */ +.agent-list-items::-webkit-scrollbar, +.agent-config-scroll-region::-webkit-scrollbar { + width: 6px; +} + +.agent-list-items::-webkit-scrollbar-thumb, +.agent-config-scroll-region::-webkit-scrollbar-thumb { + background: var(--border-primary); + border-radius: 4px; +} + +.agent-list-items::-webkit-scrollbar-track, +.agent-config-scroll-region::-webkit-scrollbar-track { + background: transparent; +} + /* Responsive Shell (Preserved from existing accessibility rules) */ @media (max-width: 900px) { .app-shell:not(.app-shell-easy-mode) { diff --git a/tests/app-shell-accessibility-ui.cjs b/tests/app-shell-accessibility-ui.cjs index bf804e0..0dda666 100644 --- a/tests/app-shell-accessibility-ui.cjs +++ b/tests/app-shell-accessibility-ui.cjs @@ -27,7 +27,7 @@ const path = require('node:path'); assert.equal(await page.getByRole('heading', { level: 1, name: '首页' }).count(), 1); - await page.getByRole('button', { name: '使用记录' }).click(); + await page.locator('.nav-section').getByRole('button', { name: '使用记录' }).click(); const tabs = page.getByRole('tab'); assert.equal(await tabs.count(), 5); assert.deepEqual(await tabs.evaluateAll((elements) => elements @@ -39,7 +39,7 @@ const path = require('node:path'); await page.getByRole('tab', { name: /数据管理/ }).click(); assert.equal(await page.locator('.usage-filter-panel').count(), 0); - await page.getByRole('button', { name: '高级功能' }).click(); + await page.locator('.nav-section').getByRole('button', { name: '高级功能' }).click(); assert.equal(await page.locator('h1').count(), 1); const configTabs = page.locator('.config-subpage-tabs').getByRole('tab'); assert.deepEqual(await configTabs.evaluateAll((elements) => elements @@ -60,7 +60,7 @@ const path = require('node:path'); assert.equal(await addKey.evaluate((element) => document.activeElement === element), true); await page.setViewportSize({ width: 640, height: 600 }); - await page.getByRole('button', { name: '首页' }).click(); + await page.locator('.nav-section').getByRole('button', { name: '首页' }).click(); const sidebarHeight = await page.locator('.sidebar').evaluate((element) => element.getBoundingClientRect().height); assert.ok(sidebarHeight < 150, `compact sidebar is too tall: ${sidebarHeight}px`);