From 51522dd8c2a03feb934b96c835fcb9dae6dfa196 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Mon, 14 Sep 2026 13:29:57 +0800 Subject: [PATCH] =?UTF-8?q?fix(webui):=20=E5=AF=BC=E8=88=AA=E4=BB=A4?= =?UTF-8?q?=E7=89=8C=E8=BF=81=E7=A7=BB=E6=94=B6=E5=B0=BE=20+=20=E7=94=9F?= =?UTF-8?q?=E6=88=90=20CSS=20=E7=9A=84=E5=A4=B4=E6=B3=A8=E9=87=8A=E6=8F=90?= =?UTF-8?q?=E5=89=8D=E9=97=AD=E5=90=88=EF=BC=88=E4=BC=9A=E4=B8=A2=E8=A7=84?= =?UTF-8?q?=E5=88=99=EF=BC=89+=20=E4=B8=A4=E6=9D=A1=E8=BF=87=E6=9C=9F?= =?UTF-8?q?=E5=88=A4=E6=8D=AE=E9=87=8D=E5=86=99=20+=20=E5=88=A4=E6=8D=AE?= =?UTF-8?q?=E8=BF=9B=20npm=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 改法 - **`Sidebar.tsx` 底部两个按钮还是旧的深色导航假设**(`text-chrome-400 hover:text-white hover:bg-chrome-800`、外层 `border-chrome-700`):导航改成白玻璃 (`--nav-bg: 255 255 255 / 0.72`)之后,`chrome-400` 落在白底上约 2.6:1(图标要 3:1),hover 还会在白导航上闪出一块近黑。账号头像那个按钮当时换成了 `.nav-item`, 这两个漏了 —— 就是"导航令牌迁移做了一半"。已换成 `.nav-item` + `border-gray-200`。 没加"Sidebar 里不许有 chrome-*"的判据:另有一处 `bg-chrome-600 text-chrome-100` 是实心小色块(正常用法),一刀切会误红。 - **`background-takeover.generated.css` 的头注释提前闭合**:生成器在注释里写了 「src」加「/」加两颗星加「/」加「.tsx」,其中那对「星号 + 斜杠」把 CSS 注释就地 结束 —— 尾巴变成 CSS 正文,并与第一条规则的选择器连在一起成为非法选择器 ⇒ **`.bg-amber-100` 那条接管规则被浏览器整条丢掉**(壁纸模式下不再变半透明)。 构建只给一条 `[WARNING] Unexpected "14" [css-syntax-error]`,不报错、不影响构建, 正是这套判据存在的理由。改在生成器(注释里只描述、不写 glob 字面量)并重新生成: 压缩输出现在以 `html[data-bg=on] .bg-amber-100{` 起头、14 条规则全在、无告警。 另加两条判据("头注释没提前闭合" + 自检)。 - **`background.test.mjs` 第 18 组三条重写**:原先断言「浅色/深色两套 `--nav-bg` 都 定义」与「壁纸模式下 `.nav-rail` 里有 `backdrop-filter`」,两条编码的都是**已被 有意撤掉的设计**(`faacd3c` 撤深色导航、`9aa702b` 撤导航自叠模糊),于是 `npm test` 在 HEAD 上恒红。判据红成常态就不再是判据 —— 该改的是判据本身,而不是把缺陷写回代码。 改成方向相反的两条:`.dark` 不许单独给导航换色 / 模糊只由壁纸层负责。 - **`cross-client-theme.test.mjs` 从来不在 `npm test` 链里**(vitest 只收 `test/components` 与 `test/stores`)—— 那条"防漂移判据"从没在默认套件里跑过。 已加进 `npm test`。 ## 验证 - 变异测试:往 `.dark { }` 塞一行 `--nav-bg: 15 23 42 / 0.72;` → 红;往 `html[data-bg='on'] .nav-rail` 塞 `backdrop-filter: blur(18px);` → 红;撤回 → 绿。 - `npm test` 退出码 0:窄屏布局全通过、主题 30、背景 34、cross-client 8、packaging 3、 vitest 258/258;`npm run typecheck` 通过。 - packaging 第 3 条此前是红的,但**不是判据过期**:安装包真的落后于 dist,而 `npm test` 的 `&&` 链一直在 background 那条就中断,`packaging` 从没跑到过。已 `npm run build` + `npx electron-builder --linux -c.electronDownload.isVerifyChecksum=false` 重打包。 ⚠️ deb 目标在本机打不出来(fpm 的 portable ruby 在 `Dir.chdir` 处退出), AppImage 与 `linux-unpacked` 正常。 --- client/electron/package.json | 2 +- .../scripts/gen-background-takeover.mjs | 12 +++- .../src/background-takeover.generated.css | 2 +- client/electron/src/components/Sidebar.tsx | 18 +++++- client/electron/test/background.test.mjs | 60 +++++++++++++++++-- 5 files changed, 83 insertions(+), 11 deletions(-) diff --git a/client/electron/package.json b/client/electron/package.json index 3505e71..366242d 100644 --- a/client/electron/package.json +++ b/client/electron/package.json @@ -19,7 +19,7 @@ "build:linux": "vite build && electron-builder --linux", "preview": "vite preview", "typecheck": "tsc --noEmit", - "test": "node test/markdown-xss.test.mjs && node test/narrow-layout.test.mjs && node test/theme.test.mjs && node test/background.test.mjs && node test/packaging.test.mjs && vitest run", + "test": "node test/markdown-xss.test.mjs && node test/narrow-layout.test.mjs && node test/theme.test.mjs && node test/background.test.mjs && node test/cross-client-theme.test.mjs && node test/packaging.test.mjs && vitest run", "test:narrow": "node test/manual/narrow-verify.mjs", "test:wide": "node test/manual/wide-regression.mjs", "test:components": "vitest run", diff --git a/client/electron/scripts/gen-background-takeover.mjs b/client/electron/scripts/gen-background-takeover.mjs index 26123fa..76073fb 100644 --- a/client/electron/scripts/gen-background-takeover.mjs +++ b/client/electron/scripts/gen-background-takeover.mjs @@ -66,8 +66,18 @@ const body = classes await writeFile( OUT, + /* + * ★ 头注释里**不许写出「星号紧接斜杠」的 glob 字面量**(2026-09-14 修)。 + * + * 这里原先写的是「src」加「/」加两颗星加「/」加「.tsx」,而中间那对 + * 「星号 + 斜杠」会把 CSS 注释**提前闭合**:剩下的尾巴(`.tsx 的实际用法)。`) + * 变成 CSS 正文,跟后面第一条规则的**选择器连在一起** —— 非法选择器 ⇒ + * **那条规则被浏览器整条丢掉**(`.bg-amber-100` 在壁纸模式下不再变半透明), + * 而构建只在日志里给一条 `[WARNING] Unexpected "14"`,不报错、不影响构建。 + * 所以这里只描述、不写 glob 字面量。 + */ `/* 由 scripts/gen-background-takeover.mjs 生成 —— 不要手改。\n` + - ` * 背景开启时把源码里在用的浅色表面类改成半透明(清单来自 src/**/*.tsx 的实际用法)。\n` + + ` * 背景开启时把源码里在用的浅色表面类改成半透明(清单来自 src 目录下全部 .tsx 的实际用法)。\n` + ` * 共 ${classes.length} 个类:${classes.join(', ')}\n */\n\n${body}\n`, ); console.log(` 生成 ${classes.length} 个类 → ${OUT}`); diff --git a/client/electron/src/background-takeover.generated.css b/client/electron/src/background-takeover.generated.css index 7416e85..0d24aef 100644 --- a/client/electron/src/background-takeover.generated.css +++ b/client/electron/src/background-takeover.generated.css @@ -1,5 +1,5 @@ /* 由 scripts/gen-background-takeover.mjs 生成 —— 不要手改。 - * 背景开启时把源码里在用的浅色表面类改成半透明(清单来自 src/**/*.tsx 的实际用法)。 + * 背景开启时把源码里在用的浅色表面类改成半透明(清单来自 src 目录下全部 .tsx 的实际用法)。 * 共 14 个类:bg-amber-100, bg-amber-50, bg-blue-100, bg-blue-50, bg-gray-100, bg-gray-200, bg-green-100, bg-green-50, bg-orange-100, bg-orange-200, bg-orange-50, bg-red-100, bg-red-50, bg-yellow-100 */ diff --git a/client/electron/src/components/Sidebar.tsx b/client/electron/src/components/Sidebar.tsx index 7fbaf76..e2dd684 100644 --- a/client/electron/src/components/Sidebar.tsx +++ b/client/electron/src/components/Sidebar.tsx @@ -133,7 +133,15 @@ export default function Sidebar() { (见 App 里的 ComposeFab),导航栏就只剩三项。 */} -
+ {/* + 底部这一块原先还是**旧的深色导航假设**(外层 border-chrome-700、 + 两个按钮 text-chrome-400 + hover:bg-chrome-800)—— 导航改成白玻璃 + (--nav-bg: 255 255 255 / 0.72)之后,chrome-400 落在白底上只有约 2.6:1 + (图标要 3:1),hover 还会在白导航上闪出一块近黑。账号头像那个按钮当时 + 换成了 .nav-item,这两个漏了 —— 就是"导航令牌迁移做了一半"。 + chrome 那条色阶是给"框架本来就该深"的假设用的,白玻璃导航不该再用它。 + */} +
- + {/* + .nav-item 是未分层 CSS,级联上压得过 Tailwind utilities, + 所以直接替掉类名即可,不必再补 text-*。 + */} + diff --git a/client/electron/test/background.test.mjs b/client/electron/test/background.test.mjs index 99e8836..97dd71a 100644 --- a/client/electron/test/background.test.mjs +++ b/client/electron/test/background.test.mjs @@ -215,6 +215,30 @@ check('新组件未使用未映射色族', unmapped.length === 0, unmapped.join( const PAGE_BASE = new Set(['bg-gray-50', 'bg-slate-100']); // 页面底必须保持全透明 const missing = [...used].filter(c => !PAGE_BASE.has(c) && !gen.includes(`.${c} {`)); check('源码里用到的浅色表面类全被接管', missing.length === 0, `漏了:${missing.join(', ')}`); + /* + * ★ 生成文件的**头注释不能提前闭合**(2026-09-14 修,与上面那条同一根因的两个后果)。 + * + * 生成器原先在头注释里写了「src」加「/」加两颗星加「/」加「.tsx」,其中那对 + * 「星号 + 斜杠」把注释**提前闭合**:尾巴变成 CSS 正文,跟第一条规则的选择器 + * 连在一起成为非法选择器 ⇒ **那条规则被浏览器整条丢掉**(`bg-amber-100` 在 + * 壁纸模式下不再变半透明)。构建只给一条 `[WARNING] Unexpected "14"`, + * 不报错、不影响构建 —— 正是这套判据存在的理由。 + * + * 判据:把注释剥掉之后,文件必须以第一条规则的**选择器**起头。 + */ + const stripped = gen.replace(/\/\*[\s\S]*?\*\//g, '').trim(); + check( + '生成 CSS 的头注释没有提前闭合(否则第一条规则会被整条丢掉)', + stripped.startsWith("html[data-bg='on'] .bg-"), + `剥掉注释后以「${stripped.slice(0, 40)}…」起头` + ); + // 反向对照:判据要真能抓到"注释里带星号+斜杠"这种写法 + const bad = "/* 来自 src/**/*.tsx 的用法 */\nhtml[data-bg='on'] .bg-amber-100 { color: red }"; + check( + '判据自检:注释里带「星号紧接斜杠」时必须判红', + !bad.replace(/\/\*[\s\S]*?\*\//g, '').trim().startsWith("html[data-bg='on'] .bg-"), + '自检失败 —— 这条判据抓不到它要抓的东西' + ); check('页面底没有被写进半透明清单', [...PAGE_BASE].every(b => !gen.includes(`.${b} {`))); check('清单不是空跑(至少扫到 10 个类)', used.size >= 10, `实际 ${used.size}`); @@ -239,16 +263,42 @@ check('新组件未使用未映射色族', unmapped.length === 0, unmapped.join( * 黑字或者自动反色或者描边呢?」): * ① 不透明实心(最早) * ② 深色玻璃(我为了"白字对比度"做的 —— 用错误的方式解决对比度,全页唯一一块黑) - * ③ **按主题走的令牌**:浅色=白玻璃+深字、深色=深玻璃+亮字 + * ③ **按主题走的令牌**:浅色=白玻璃+深字(深色主题尚未存在,见下) * 判据因此不再断言某个固定颜色,而是断言"走令牌"这件事 + 对比度由 * test/manual/nav-contrast-verify.mjs 用 WCAG 比值来量。 */ - check('导航底色走 --nav-bg 令牌(浅色/深色各一套,不写死)', + check('导航底色走 --nav-bg 令牌(不写死)', /\.nav-rail \{[\s\S]{0,80}background-color: rgb\(var\(--nav-bg\)\)/.test(css) && /\.nav-item \{[\s\S]{0,80}color: rgb\(var\(--nav-fg-muted\)\)/.test(css)); - check('浅色与深色两套令牌都定义了(自动反色)', - /--nav-bg: 255 255 255 \/ 0\.72/.test(css) && /--nav-bg: 15 23 42 \/ 0\.72/.test(css)); - check('导航在壁纸模式下仍参与模糊', /html\[data-bg='on'\] \.nav-rail,[\s\S]{0,200}backdrop-filter: blur\(/.test(css)); + /* + * ★ 下面两条 2026-09-14 重写:原先断言「浅色/深色两套 --nav-bg 都定义」与 + * 「壁纸模式下 .nav-rail 里有 backdrop-filter」,两条编码的都是**已被有意撤掉的 + * 设计**,于是 `npm test` 在 HEAD 上恒红。判据红成常态就不再是判据 —— 该改的是 + * 判据本身,而**不是**把缺陷写回代码。 + * + * ① 深色导航撤掉了(用户「导航栏为什么还是黑色」)。根因不是令牌抄错,而是这个 + * 应用**还没有深色主题**:`darkMode:'class'` 配着,却没有任何组件写 `dark:` + * 变体 ⇒ 只把导航压深就得到「导航黑、正文白」,比全浅更割裂。现在的契约是 + * 导航跟随内容的实际形态(浅色玻璃),所以这里断言的是**「没有深色主题之前, + * .dark 不许单独给导航换色」**。真做深色主题时,这条要连同 dark: 变体一起改。 + * + * ② 导航不再自己模糊:模糊只由壁纸层负责(用户「你又犯了模糊叠模糊的毛病…… + * 整体的模糊是由壁纸那一层模糊确定的」)。导航浮在壁纸上,背后是**已经模糊过** + * 的壁纸,再 backdrop-filter 一次只会更脏更掉帧。所以断言是反向的:壁纸层有模糊, + * 而壁纸模式下的 .nav-rail 没有。 + */ + const darkBodies = [...css.matchAll(/\.dark\s*\{([^}]*)\}/g)].map(m => m[1]); + check( + '没有深色主题之前,.dark 不单独给导航换色', + darkBodies.length >= 1 && darkBodies.every(b => !/--nav-/.test(b)), + '.dark 里出现了 --nav-* 令牌 —— 要让导航变暗,必须同时给组件补 dark: 变体' + ); + check( + '模糊只由壁纸层负责(壁纸模式下的导航不再自叠一层)', + /\.app-backdrop \{[\s\S]*?filter: blur\(/.test(css) && + !/html\[data-bg='on'\] \.nav-rail[^{]*\{[^}]*backdrop-filter/.test(css), + '导航自己 backdrop-filter 会把已经模糊过的壁纸再糊一次' + ); check('内层面板自带圆角(不靠裁剪,否则与滚动冲突)', /\.comm-pane > \*:not\(\[data-testid='comm-tabs'\]\) \{[\s\S]{0,80}border-radius: var\(--radius-card\)/.test(css)); /*