fix(webui): 导航令牌迁移收尾 + 生成 CSS 的头注释提前闭合(会丢规则)+ 两条过期判据重写 + 判据进 npm test
## 改法
- **`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` 正常。
This commit is contained in:
@ -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",
|
||||
|
||||
@ -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}`);
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
|
||||
@ -133,7 +133,15 @@ export default function Sidebar() {
|
||||
(见 App 里的 ComposeFab),导航栏就只剩三项。
|
||||
*/}
|
||||
|
||||
<div className="mt-2 pt-2 w-full flex flex-col items-center gap-1 border-t border-chrome-700">
|
||||
{/*
|
||||
底部这一块原先还是**旧的深色导航假设**(外层 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 那条色阶是给"框架本来就该深"的假设用的,白玻璃导航不该再用它。
|
||||
*/}
|
||||
<div className="mt-2 pt-2 w-full flex flex-col items-center gap-1 border-t border-gray-200">
|
||||
<button
|
||||
onClick={() => setViewMode('account')}
|
||||
title={`${user?.display_name || user?.username}(点击管理账号)`}
|
||||
@ -146,11 +154,15 @@ export default function Sidebar() {
|
||||
<ConnectionIndicator />
|
||||
</span>
|
||||
</button>
|
||||
<ThemeToggleButton className="w-9 h-7 rounded flex items-center justify-center text-chrome-400 hover:text-white hover:bg-chrome-800" />
|
||||
{/*
|
||||
.nav-item 是未分层 CSS,级联上压得过 Tailwind utilities,
|
||||
所以直接替掉类名即可,不必再补 text-*。
|
||||
*/}
|
||||
<ThemeToggleButton className="nav-item w-9 h-7 rounded flex items-center justify-center" />
|
||||
<button
|
||||
onClick={logout}
|
||||
title="退出登录"
|
||||
className="w-9 h-7 rounded flex items-center justify-center text-chrome-400 hover:text-white hover:bg-chrome-800"
|
||||
className="nav-item w-9 h-7 rounded flex items-center justify-center"
|
||||
>
|
||||
<LogoutIcon className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
|
||||
@ -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));
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user