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)); /*