From ff206cecc460da975c24ffec1fab329a4e391565 Mon Sep 17 00:00:00 2001 From: ekko <152005280+EKKOLearnAI@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:23:27 +0800 Subject: [PATCH] unify frontend visual styles (#2014) --- packages/client/src/styles/global.scss | 13 ++++++++- packages/client/src/styles/variables.scss | 14 +++++----- .../client/src/views/hermes/DevicesView.vue | 17 ------------ .../client/src/views/hermes/JourneyView.vue | 17 ------------ .../client/src/views/hermes/KanbanView.vue | 9 ------- .../src/views/hermes/McpManagerView.vue | 21 ++------------- .../src/views/hermes/PerformanceView.vue | 17 ------------ .../client/src/views/hermes/PluginsView.vue | 8 +++--- .../src/views/hermes/SkillsUsageView.vue | 14 ++-------- .../client/src/views/hermes/UsageView.vue | 17 ------------ tests/client/style-system.test.ts | 27 +++++++++++++++++++ 11 files changed, 54 insertions(+), 120 deletions(-) create mode 100644 tests/client/style-system.test.ts diff --git a/packages/client/src/styles/global.scss b/packages/client/src/styles/global.scss index 17d83c96..5025e023 100644 --- a/packages/client/src/styles/global.scss +++ b/packages/client/src/styles/global.scss @@ -219,17 +219,28 @@ a { display: flex; align-items: center; justify-content: space-between; - padding: 21px 20px; + gap: 12px; + min-height: 64px; + padding: 14px 20px; border-bottom: 1px solid $border-color; flex-shrink: 0; } .header-title { + margin: 0; font-size: 16px; font-weight: 600; + line-height: 1.4; color: $text-primary; } +.page-header > .header-actions { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 8px; +} + // Responsive utility classes for inline width replacement .input-sm { width: 90px; } .input-md { width: 200px; } diff --git a/packages/client/src/styles/variables.scss b/packages/client/src/styles/variables.scss index b38d08ee..0dd7cb84 100644 --- a/packages/client/src/styles/variables.scss +++ b/packages/client/src/styles/variables.scss @@ -61,7 +61,7 @@ --bg-primary: #1a1a1a; --bg-secondary: #252525; --bg-sidebar: #202020; - --bg-card: #333333; + --bg-card: #2a2a2a; --bg-card-hover: #333333; --bg-input: #2a2a2a; @@ -75,8 +75,8 @@ --accent-muted: #888888; // Text - --text-primary: #f0f0f0; - --text-secondary: #c0c0c0; + --text-primary: #e0e0e0; + --text-secondary: #a0a0a0; --text-muted: #888888; // Status @@ -98,9 +98,9 @@ --accent-info: #6ba3d6; // RGB components - --accent-primary-rgb: 240, 240, 240; + --accent-primary-rgb: 224, 224, 224; --accent-hover-rgb: 245, 245, 245; - --text-primary-rgb: 240, 240, 240; + --text-primary-rgb: 224, 224, 224; --text-muted-rgb: 136, 136, 136; --success-rgb: 102, 187, 106; --error-rgb: 239, 83, 80; @@ -179,8 +179,8 @@ $breakpoint-mobile: 768px; // Radius $radius-sm: 6px; -$radius-md: 10px; -$radius-lg: 14px; +$radius-md: 8px; +$radius-lg: 8px; // Transition $transition-fast: 0.15s ease; diff --git a/packages/client/src/views/hermes/DevicesView.vue b/packages/client/src/views/hermes/DevicesView.vue index 353a9390..1a51d564 100644 --- a/packages/client/src/views/hermes/DevicesView.vue +++ b/packages/client/src/views/hermes/DevicesView.vue @@ -472,16 +472,6 @@ onMounted(() => { flex-direction: column; } -.page-header { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - .header-actions { display: flex; align-items: center; @@ -495,13 +485,6 @@ onMounted(() => { max-width: min(280px, 100%); } -.header-title { - margin: 0; - color: $text-primary; - font-size: 16px; - font-weight: 600; -} - .header-meta { display: flex; flex-wrap: wrap; diff --git a/packages/client/src/views/hermes/JourneyView.vue b/packages/client/src/views/hermes/JourneyView.vue index fa32bee0..d0c22294 100644 --- a/packages/client/src/views/hermes/JourneyView.vue +++ b/packages/client/src/views/hermes/JourneyView.vue @@ -760,23 +760,6 @@ watch(sceneNodes, () => { flex-direction: column; } -.page-header { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - -.header-title { - margin: 0; - color: $text-primary; - font-size: 16px; - font-weight: 600; -} - .header-actions { display: flex; align-items: center; diff --git a/packages/client/src/views/hermes/KanbanView.vue b/packages/client/src/views/hermes/KanbanView.vue index 8867e44f..7fddda72 100644 --- a/packages/client/src/views/hermes/KanbanView.vue +++ b/packages/client/src/views/hermes/KanbanView.vue @@ -379,15 +379,6 @@ async function handleDispatch() { flex-direction: column; } -.page-header { - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - -.header-title { - font-size: 16px; -} - .header-actions { display: flex; align-items: center; diff --git a/packages/client/src/views/hermes/McpManagerView.vue b/packages/client/src/views/hermes/McpManagerView.vue index 330562f9..cdd51a4b 100644 --- a/packages/client/src/views/hermes/McpManagerView.vue +++ b/packages/client/src/views/hermes/McpManagerView.vue @@ -675,23 +675,6 @@ async function saveToolsVisibility() { place-items: center; } -.page-header { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - -.header-title { - margin: 0; - color: $text-primary; - font-size: 16px; - font-weight: 600; -} - .header-actions { display: flex; align-items: center; @@ -714,8 +697,8 @@ async function saveToolsVisibility() { .summary-card { padding: 14px; border: 1px solid $border-color; - border-radius: 12px; - background: $bg-secondary; + border-radius: $radius-md; + background: $bg-card; display: flex; flex-direction: column; gap: 6px; diff --git a/packages/client/src/views/hermes/PerformanceView.vue b/packages/client/src/views/hermes/PerformanceView.vue index 7a9b538f..035fda92 100644 --- a/packages/client/src/views/hermes/PerformanceView.vue +++ b/packages/client/src/views/hermes/PerformanceView.vue @@ -215,23 +215,6 @@ onBeforeUnmount(() => { flex-direction: column; } -.page-header { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - -.header-title { - margin: 0; - color: $text-primary; - font-size: 16px; - font-weight: 600; -} - .header-actions { display: flex; align-items: center; diff --git a/packages/client/src/views/hermes/PluginsView.vue b/packages/client/src/views/hermes/PluginsView.vue index 0434d50b..ac909599 100644 --- a/packages/client/src/views/hermes/PluginsView.vue +++ b/packages/client/src/views/hermes/PluginsView.vue @@ -296,8 +296,8 @@ watch(() => profilesStore.activeProfileName || 'default', () => { .summary-card { padding: 14px; border: 1px solid $border-color; - border-radius: 12px; - background: $bg-secondary; + border-radius: $radius-md; + background: $bg-card; display: flex; flex-direction: column; gap: 6px; @@ -330,8 +330,8 @@ watch(() => profilesStore.activeProfileName || 'default', () => { .plugins-table-wrap { overflow-x: auto; border: 1px solid $border-color; - border-radius: 12px; - background: $bg-secondary; + border-radius: $radius-md; + background: $bg-card; } .plugins-table { diff --git a/packages/client/src/views/hermes/SkillsUsageView.vue b/packages/client/src/views/hermes/SkillsUsageView.vue index 59c909e3..6fd817da 100644 --- a/packages/client/src/views/hermes/SkillsUsageView.vue +++ b/packages/client/src/views/hermes/SkillsUsageView.vue @@ -313,16 +313,6 @@ onMounted(() => { flex-direction: column; } -.page-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; - flex-shrink: 0; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - .header-text { display: flex; align-items: baseline; @@ -379,9 +369,9 @@ onMounted(() => { .summary-card, .usage-panel { - background: $bg-secondary; + background: $bg-card; border: 1px solid $border-color; - border-radius: 12px; + border-radius: $radius-md; } .summary-card { diff --git a/packages/client/src/views/hermes/UsageView.vue b/packages/client/src/views/hermes/UsageView.vue index 4128e8d8..a6d9dea6 100644 --- a/packages/client/src/views/hermes/UsageView.vue +++ b/packages/client/src/views/hermes/UsageView.vue @@ -91,23 +91,6 @@ onMounted(() => { flex-direction: column; } -.page-header { - display: flex; - flex-shrink: 0; - align-items: center; - justify-content: space-between; - gap: 12px; - padding: 21px 20px; - border-bottom: 1px solid $border-color; -} - -.header-title { - margin: 0; - color: $text-primary; - font-size: 16px; - font-weight: 600; -} - .usage-toolbar, .period-selector { display: flex; diff --git a/tests/client/style-system.test.ts b/tests/client/style-system.test.ts new file mode 100644 index 00000000..aac6e259 --- /dev/null +++ b/tests/client/style-system.test.ts @@ -0,0 +1,27 @@ +import { readFileSync } from 'fs' +import { describe, expect, it } from 'vitest' + +const readClientFile = (path: string) => readFileSync(`packages/client/src/${path}`, 'utf8') + +describe('client style system', () => { + it('keeps shared page headers on one layout baseline', () => { + const globalStyles = readClientFile('styles/global.scss') + + expect(globalStyles).toContain('min-height: 64px;') + expect(globalStyles).toContain('padding: 14px 20px;') + expect(globalStyles).toContain('.page-header > .header-actions') + }) + + it('aligns SCSS surfaces and radii with the Naive UI theme', () => { + const variables = readClientFile('styles/variables.scss') + const theme = readClientFile('styles/theme.ts') + + expect(variables).toContain('--bg-card: #2a2a2a;') + expect(theme).toContain("cardColor: '#2a2a2a'") + expect(variables).toContain('$radius-sm: 6px;') + expect(variables).toContain('$radius-md: 8px;') + expect(variables).toContain('$radius-lg: 8px;') + expect(theme).toContain("borderRadius: '8px'") + expect(theme).toContain("borderRadiusSmall: '6px'") + }) +})