From 4e6eb32929f1aa822a6db85b5cb1b3935b0c901c Mon Sep 17 00:00:00 2001 From: jkooe <62494645+jkooe@users.noreply.github.com> Date: Sun, 11 Oct 2026 14:29:50 +0800 Subject: [PATCH] =?UTF-8?q?style(console):=20=E9=85=8D=E8=89=B2=E6=94=B6?= =?UTF-8?q?=E6=95=9B=E4=B8=BA=E3=80=8C=E7=AE=80=E7=BA=A6=E7=99=BD=20/=20?= =?UTF-8?q?=E9=AB=98=E7=BA=A7=E7=81=B0=E3=80=8D=E4=B8=A4=E5=A5=97=E4=B8=AD?= =?UTF-8?q?=E6=80=A7=E7=81=B0=E9=98=B6=E4=B8=BB=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原配色是深色 + 品牌青绿(#63e2b7)+ naive-ui 默认绿主色 —— 颜色种类多。 改为两套**只用中性灰阶**的主题,侧栏底部一行切换,选择存 localStorage: 简约白 页底 #f4f4f5 / 侧栏 #fafafa / 卡片 #ffffff 高级灰 页底 #1d1f22 / 侧栏 #181a1d / 卡片 #24262a 几处刻意的选择: 1. 白主题页底**不是纯白**。卡片本身是白的,两者同色就只能靠 1px 分线撑层次, 整页发「糊」;压一档浅灰后层次为「页底 < 侧栏 < 卡片」,且仍是白为主。 2. 主色位(naive-ui 的 primary)改**中性灰** —— 主按钮、开关激活态、进度条、 勾选框全吃这一个值。原来它们是绿色/青绿,正是「配色不简单」的主因。 3. 语义色(成功/警告/错误/信息)**降饱和而非去掉**。这是运维工具, 「运行中 / 出错」必须一眼可辨,全部灰化会导致误读。故它们只出现在徽章与 告警这类**小面积**上,底色观感仍是「白 + 灰」。 4. **色值只定义一份**:src/theme/index.ts 的 Palette 既生成 naive-ui 的 themeOverrides,又由 App.vue 运行期注入成 --na-* CSS 变量。 若「TS 调色板」与「CSS 写死色值」各存一份,换主题时会**一半新一半旧、 不报错、类型也抓不到** —— 正是本轮要消灭的失效模式。 为此清掉散在 8 个文件里的 17 处写死色值(日志三流着色、代码块底色、 节点选中边框、历史悬停…),复扫后自定义样式里硬编码色为 0。 5. 主题**只存 localStorage**,不落 Rust 侧 settings:那套 Settings 是给 「仅服务模式」(无窗口、常驻托盘)也生效的偏好用的;主题是纯图形偏好, 没有窗口时毫无意义 —— 为一件纯前端的事去动 Rust 命令面与契约守卫不划算。 6. index.html 内联一小段脚本做**首帧防闪**(否则深色用户每次启动闪一帧白)。 此处**刻意重复 2 个底色值**,已在 index.html 与 theme/index.ts 两处注明 「改底色时同步」—— 因为在它执行之前没有任何模块可依赖; 除此之外全应用再无第二份色值。 验证:vue-tsc 0 错 | 契约守卫 6/6 | 单测 280/280 | .app 重打通过(92.22 MiB)| 两套主题均以真实采集数据回填渲染核对 —— 截图脚本顺带读回 --na-bg 与 body 背景, 确认主题真的切过去了,而不是「看起来像」。 --- CHANGELOG.md | 25 + apps/console/index.html | 15 + apps/console/src/App.vue | 41 +- apps/console/src/components/AppShell.vue | 58 ++- apps/console/src/stores/theme.ts | 53 +++ apps/console/src/theme/index.ts | 478 ++++++++++++++++++++ apps/console/src/views/FilesView.vue | 2 +- apps/console/src/views/LocalServiceView.vue | 4 +- apps/console/src/views/LogsView.vue | 6 +- apps/console/src/views/NodesView.vue | 6 +- apps/console/src/views/OverviewView.vue | 6 +- apps/console/src/views/SoftwareView.vue | 2 +- apps/console/src/views/TerminalView.vue | 2 +- docs/console-plan.md | 50 ++ 14 files changed, 719 insertions(+), 29 deletions(-) create mode 100644 apps/console/src/stores/theme.ts create mode 100644 apps/console/src/theme/index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 336df0a..565dd40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ > 主题:**控制台「去命令行化」** —— 双击应用即用,启停/重启/更新/日志/托盘常驻/开机自启全部在界面里完成。 > 目标原文:「不再打开命令行窗口,运行应用之后,有启动、停止、重启、检查更新等功能, > 有日志功能,可以后台运行和开机自启等等功能」。 +> +> 末段另含两轮纯界面调整:**一律不使用图标**(emoji 在部分渲染器里退化成豆腐块)、 +> **配色收敛为「简约白 / 高级灰」两套中性灰阶主题**。 ### 新增 —— 本机被控端托管(`apps/console/src-tauri/src/agent.rs`,约 560 行) @@ -109,6 +112,28 @@ > 它们是**程序输出内容**,会原样出现在「服务日志」页里,但不是界面元素; > ③ 控件的结构性部件(下拉箭头、折叠箭头、输入框清除钮、表格排序箭头)。 +### 变更 —— 配色收敛为两套中性灰阶主题 + +- **两套可切换主题:`简约白`(浅)与 `高级灰`(深)**,侧栏底部一行切换,选择存 `localStorage`。 + 两套都**只用中性灰阶**:去掉原先的青色品牌字(`#63e2b7`)与 naive-ui 默认的绿色主色, + 主按钮 / 开关激活态 / 进度条 / 勾选框统一改吃「主色位 = 中性灰」这一个值。 + - 白主题的**页底刻意不是 `#ffffff`**(`#f4f4f5`):卡片本身是白的,两者同色就只能靠 1px 分线撑层次, + 整页发「糊」;压一档浅灰后层次为「页底 < 侧栏 < 卡片」,且仍是白为主。 +- **语义色不是去掉,而是降饱和**(灰绿 / 灰琥珀 / 灰红 / 灰蓝)。 + 这是运维工具,`运行中 / 出错` 必须一眼可辨,全部灰化会导致误读;故它们只出现在徽章与告警这类小面积上, + 底色观感仍是「白 + 灰」。严重程度在关闭图标后本就更依赖 `type` 的底色/边框。 +- **色值只有一份定义**(`src/theme/index.ts` 的 `Palette`):既生成 naive-ui 的 `themeOverrides`, + 又由 `App.vue` 在运行期注入成 `--na-*` CSS 变量供自定义样式使用。 + 原因是若「TS 调色板」与「CSS 写死的色值」各存一份,换主题时会**一半新一半旧且不报错、类型也抓不到** + —— 这正是本轮要消灭的失效模式。 +- **清掉 17 处写死的色值**(散在 8 个文件:日志三流着色、代码块/预览底色、节点选中边框、历史悬停等), + 全部改为 `var(--na-*)`。复扫后自定义样式里的硬编码色为 **0**。 +- **主题偏好只存 `localStorage`,不落 Rust 侧 settings**:那是给「仅服务模式」(无窗口、常驻托盘) + 也要生效的偏好用的,而主题是纯图形偏好 —— 没有窗口时毫无意义。为一件纯前端的事去动 Rust 命令面与契约守卫不划算。 +- **首帧防闪**:`index.html` 内联一段极小脚本,在 Vue 接管前先把上次主题的底色刷上, + 否则「高级灰」用户每次启动都会看到一帧刺眼的白。此处**刻意重复了 2 个底色值**(真值在 `theme/index.ts`), + 因为在此之前没有任何模块可依赖;已在两处都注明「改底色时同步」。 + ### 说明 —— 本轮**刻意不升版本号** 本轮新增的全部是**控制台**功能,**被控端能力集合未变**(未增删任何 `system.*` / `fs.*` / `app.*` 能力)。 diff --git a/apps/console/index.html b/apps/console/index.html index 1571290..74e813b 100644 --- a/apps/console/index.html +++ b/apps/console/index.html @@ -4,6 +4,21 @@ nodeagent 控制台 + diff --git a/apps/console/src/App.vue b/apps/console/src/App.vue index b358847..061bce6 100644 --- a/apps/console/src/App.vue +++ b/apps/console/src/App.vue @@ -1,17 +1,40 @@ diff --git a/apps/console/src/views/LogsView.vue b/apps/console/src/views/LogsView.vue index 687f86c..70706d9 100644 --- a/apps/console/src/views/LogsView.vue +++ b/apps/console/src/views/LogsView.vue @@ -137,7 +137,7 @@ function streamType(s: string) { height: calc(100vh - 300px); min-height: 320px; overflow: auto; - background: rgba(0, 0, 0, 0.18); + background: var(--na-sunken); border-radius: 6px; padding: 10px 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; @@ -160,10 +160,10 @@ function streamType(s: string) { margin-top: 1px; } .txt.stderr { - color: #e88080; + color: var(--na-err); } .txt.system { - color: #63e2b7; + color: var(--na-info); } .empty { opacity: 0.5; diff --git a/apps/console/src/views/NodesView.vue b/apps/console/src/views/NodesView.vue index 0809569..b75375c 100644 --- a/apps/console/src/views/NodesView.vue +++ b/apps/console/src/views/NodesView.vue @@ -195,11 +195,11 @@ const capGroups = computed(() => { align-items: center; justify-content: space-between; padding: 8px 12px; - border: 1px solid rgba(255, 255, 255, 0.09); + border: 1px solid var(--na-border); border-radius: 8px; } .node.active { - border-color: #63e2b7; + border-color: var(--na-accent); } .node-name { font-size: 14px; @@ -219,7 +219,7 @@ const capGroups = computed(() => { font-size: 12px; padding: 2px 8px; border-radius: 4px; - background: rgba(255, 255, 255, 0.06); + background: var(--na-sunken); } .logs { font-family: ui-monospace, Menlo, monospace; diff --git a/apps/console/src/views/OverviewView.vue b/apps/console/src/views/OverviewView.vue index b55068b..f0fc0a9 100644 --- a/apps/console/src/views/OverviewView.vue +++ b/apps/console/src/views/OverviewView.vue @@ -102,7 +102,7 @@ onUnmounted(stop); type="line" :percentage="Math.round(status?.cpu_pct ?? 0)" :height="10" - :color="(status?.cpu_pct ?? 0) > 80 ? '#e88080' : '#63e2b7'" + :color="(status?.cpu_pct ?? 0) > 80 ? 'var(--na-err)' : 'var(--na-ok)'" />
@@ -113,7 +113,7 @@ onUnmounted(stop); type="line" :percentage="Math.round(status?.memory_pct ?? 0)" :height="10" - :color="(status?.memory_pct ?? 0) > 85 ? '#e88080' : '#63e2b7'" + :color="(status?.memory_pct ?? 0) > 85 ? 'var(--na-err)' : 'var(--na-ok)'" />
diff --git a/apps/console/src/views/SoftwareView.vue b/apps/console/src/views/SoftwareView.vue index 95277da..998c8e0 100644 --- a/apps/console/src/views/SoftwareView.vue +++ b/apps/console/src/views/SoftwareView.vue @@ -175,7 +175,7 @@ onMounted(() => { margin: 12px 0 0; padding: 10px; border-radius: 8px; - background: rgba(255, 255, 255, 0.05); + background: var(--na-sunken); font-size: 12px; max-height: 200px; overflow: auto; diff --git a/apps/console/src/views/TerminalView.vue b/apps/console/src/views/TerminalView.vue index 823bffc..38ee6e6 100644 --- a/apps/console/src/views/TerminalView.vue +++ b/apps/console/src/views/TerminalView.vue @@ -161,6 +161,6 @@ function reuse(c: string) { opacity: 0.85; } .hist:hover code { - color: #63e2b7; + color: var(--na-accent); } diff --git a/docs/console-plan.md b/docs/console-plan.md index c08ca56..fd15fd7 100644 --- a/docs/console-plan.md +++ b/docs/console-plan.md @@ -572,6 +572,56 @@ node 去跑打包内的 sidecar,并走一次真实 JSON-RPC 握手 —— 源 > 该测试**已注入故障实测会红**(改 `agent_start` → `agent_startX`、`na-agent-state` → `na-agent-statee` > 当场 2 条失败),非空转守卫。 +## 界面观感约定(2026-10-11) + +两轮纯界面调整,方向都是「少即是多」。理由记下来,免得日后被当成"没做完"再补回去。 + +### 一、一律不使用图标 + +触发原因是一次真实的渲染事故:侧栏的 emoji 图标在非系统字体栈的渲染器里退化成**豆腐块**。 +试过三法,分别无效或更糟 —— 给图标指定 `Apple Color Emoji`、全局字体栈加 `!important`、 +乃至 `font-variant-emoji: emoji`(最后一招把 ASCII 数字也拆成了 emoji 呈现)。 +「哪套字体栈一定带 emoji」跨平台并不成立 —— **与其赌字形,不如不用**。 + +去掉的范围比"看得见的图标"宽得多(下面这三类都算): + +| 类别 | 处数 | 关法 | +|---|---|---| +| 侧栏 emoji | 9 | 路由表 `meta.icon` 字段**整体删除**,`NavMeta` 接口同步收窄 | +| `n-empty` 空态**插画** | **16** | `:show-icon="false"` —— 插画比图标更「图形」,散在 9 个页面,**最易漏** | +| `n-alert` 类型图标 | 7 | naive-ui 的 `showIcon` **默认就是 `true`**,不显式关它就一直都在 | +| `n-popconfirm` 询问图标 | 3 | 同上 | +| 文案里的符号 | 1 | 终端页「⚠ 高权限操作,请谨慎」保留纯文字 | + +顺带清掉 `public/{vite,tauri}.svg` 与 `src/assets/vue.svg`:`public/` 下的文件会被**整体复制进产物**, +此前等于把 Vite / Tauri 的 logo 一并发了出去(且 `index.html` 的 favicon 正指向它)。 +`index.html` 的 `` 还是模板默认的「Tauri + Vue + Typescript App」,也一并改齐 +(原生窗口标题取自 `tauri.conf.json`,故此前只是 dev 态标签页不一致)。 + +**刻意未动**:① 托盘图标 —— 菜单栏没图标就点不到,关窗后应用无法寻回,属**功能必需**; +② 被控端 CLI 自己打印的文本标记(`⚠️`/`ℹ️`/`✅`)—— 是**程序输出内容**,会原样出现在「服务日志」页里, +但不是界面元素;③ 控件的结构性部件(下拉/折叠箭头、输入框清除钮、表格排序箭头)。 + +### 二、配色收敛为两套中性灰阶主题 + +`简约白`(浅)/`高级灰`(深),侧栏底部一行切换,选择存 `localStorage`。 + +| 决定 | 理由 | +|---|---| +| **主色位改中性灰** | naive-ui 默认主色是**绿色**、原设计的品牌字是**青绿 `#63e2b7`** —— 都是"颜色",与「简单些」相悖。主按钮/开关激活/进度条/勾选框统一吃这一个值 | +| 白主题**页底不是纯白**(`#f4f4f5`) | 卡片本身是白的,两者同色就只能靠 1px 分线撑层次,整页发「糊」。压一档浅灰后层次为「页底 < 侧栏 < 卡片」,且仍是白为主 | +| 语义色**降饱和**而非去掉 | 这是运维工具,「运行中 / 出错」必须一眼可辨,全部灰化会导致误读。故它们只出现在徽章与告警这类**小面积**上,底色观感仍是「白 + 灰」 | +| **色值只定义一份** | `src/theme/index.ts` 的 `Palette` 同时喂 naive-ui 的 `themeOverrides` 与 `--na-*` CSS 变量(`App.vue` 运行期注入)。两处各写一份,换主题时会**一半新一半旧且不报错、类型也抓不到** | +| 主题**只存 `localStorage`**,不落 Rust settings | Rust 那套 `Settings` 是给「仅服务模式」(无窗口、常驻托盘)也要生效的偏好用的;主题是纯图形偏好,**没有窗口时毫无意义**。为一件纯前端的事去动 Rust 命令面与契约守卫不划算 | + +清掉散在 **8 个文件**里的 **17 处写死色值**(日志三流着色、代码块/预览底色、节点选中边框、历史悬停…), +全部改为 `var(--na-*)`。复扫后自定义样式里的硬编码色为 **0**。 + +**首帧防闪**:`index.html` 内联一小段脚本,在 Vue 接管前先把上次主题的底色刷上 +(否则「高级灰」用户每次启动都会看到一帧刺眼的白)。 +此处**刻意重复了 2 个底色值**,已在 `index.html` 与 `theme/index.ts` 两处注明「改底色时同步」—— +因为在它执行之前没有任何模块可依赖。除此之外全应用再无第二份色值。 + ### 本轮验证记录 | 条目 | 结果 |