fix(harmony): 令牌收尾 —— 裸色值清零、遮罩拆两段式、权限档位配色对齐 WebUI
接手核对时发现:「不许写死颜色」那条判据**只挡得住枚举的 8 个旧值** —— 判据全绿的 同期,pages/ 里还留着 14 处另一套写死的色(Google/Material:#E8F0FE、#E8F5E9、 #FFF3E0、#D93025、#777777×2、#555555、#444444、#cccccc、#aaaaaa、 遮罩 #80000000×2、透明 #00000000×2)。枚举挡不住漂移,只有"类"能挡。 ## 改法 - 14 处全部换成令牌。新增 accentStrong / warnBg / warnFg(取值对齐 WebUI `:root` 的 blue-700 / amber-50 / amber-700)与 `Theme.permBg/permFg` —— 权限档位徽标与 WebUI 的 `PermissionChip.tsx` **同一映射**(plan=蓝 / workspace=绿 / full=琥珀); 原先写成 `full ? 绿 : 橙`(Material 色),与 WebUI **反着来**。 - 遮罩拆成 `overlayColor` + `overlayAlpha`(照 WebUI 的 `--bg-scrim` + `--bg-dim` 两段式):遮罩色要能随主题换向,色与透明度焊死成一个 `#AARRGGBB` 等于把枚举写回 代码。ArkUI 只认单值,故由 `Theme.overlay()` 组装。 - 判据从"枚举旧值"改成"按类挡":pages/ 下**一个裸色值都不许有**(含 8 位 `#AARRGGBB`),页面清单从硬编码 7 个文件名改成**扫目录** —— 旧写法下, 接下来要加的发件箱/授权/日历会自动逃出判据。另加一条判据:权限档位配色与 WebUI `:root` 变量逐一比对,防"看起来差不多"。 ## 验证 - 变异测试:往 `InboxPage.ets` 塞一个 `#E8F0FE` → 判据红;撤回 → 绿。 - cross-client 判据 6 → 8 条全绿;`hvigorw assembleHap` BUILD SUCCESSFUL。 - **视觉未验**(模拟器在本机文件沙箱下起不来,见 `docs/HARMONY-ALIGN-PLAN.md` 5.4), 未写成"已完成"。
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
*/
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
@ -60,20 +60,79 @@ test('鸿蒙的令牌文件说明了与 WebUI 的对应关系(不是凭空一
|
||||
assert.match(harmony, /与 WebUI 的令牌\*\*一一对应|对应 WebUI/);
|
||||
});
|
||||
|
||||
test('★ 鸿蒙页面里不得再出现与 WebUI 不同的旧调色板', () => {
|
||||
test('★ 鸿蒙页面里不得出现任何裸色值(枚举挡不住漂移,"类"才能挡)', () => {
|
||||
/*
|
||||
* 对齐之前的鸿蒙调色板是另一套(#1A73E8 Google 蓝、#333333、#F5F7FA…),
|
||||
* 与 WebUI 的品牌色/灰阶并不同。203 处已换成 Theme 令牌;这条判据防止
|
||||
* 以后新写的页面又随手写死一个"差不多"的颜色 —— 那正是漂移的开始。
|
||||
* 上一版这条判据只列了 8 个旧色值(#1A73E8 / #333333…),于是判据全绿的
|
||||
* 同时,pages/ 里还留着 14 处**另一套**写死的色:Google/Material 的
|
||||
* #E8F0FE、#E8F5E9、#FFF3E0、#D93025 与 #777777/#555555/#444444/
|
||||
* #cccccc/#aaaaaa、遮罩 #80000000、透明 #00000000。
|
||||
* 枚举只能挡住"列出来的实例",挡不住漂移本身 —— 改成按类挡:
|
||||
* pages/ 下一个裸色值都不许有(含 8 位 #AARRGGBB),颜色只能来自 Theme.ets。
|
||||
*
|
||||
* 页面清单也一并改成扫目录:旧版硬编码 7 个文件名,**新加的页面会自动
|
||||
* 逃出判据** —— 而发件箱/授权/日历正是接下来要加的页面。
|
||||
*/
|
||||
const pages = ['MainPage', 'InboxPage', 'SessionsPage', 'MailDetailPage', 'ComposePage', 'SettingsPage', 'LoginPage'];
|
||||
const old = ['#1A73E8', '#333333', '#666666', '#999999', '#F5F7FA', '#F5F5F5', '#FF4444', '#F0F7FF'];
|
||||
for (const name of pages) {
|
||||
const src = readFileSync(join(ROOT, `client/harmony/entry/src/main/ets/pages/${name}.ets`), 'utf8');
|
||||
for (const c of old) {
|
||||
assert.ok(!src.includes(`'${c}'`), `${name}.ets 里还有旧调色板色值 ${c}(应改用 Theme 令牌)`);
|
||||
}
|
||||
const dir = join(ROOT, 'client/harmony/entry/src/main/ets/pages');
|
||||
const files = readdirSync(dir).filter(f => f.endsWith('.ets')).sort();
|
||||
assert.ok(files.length >= 8, `pages/ 下只扫到 ${files.length} 个 .ets,判据大概扫错了目录`);
|
||||
const literal = /#[0-9A-Fa-f]{6,8}\b/g;
|
||||
for (const f of files) {
|
||||
const hits = readFileSync(join(dir, f), 'utf8').match(literal);
|
||||
assert.equal(hits, null, `${f} 里有裸色值 ${hits ? hits.join('、') : ''}(应改用 Theme 令牌)`);
|
||||
}
|
||||
// 反向对照:判据本身要能抓到
|
||||
assert.ok("#1A73E8".length > 0 && old.includes('#1A73E8'));
|
||||
// 反向对照:判据要真能抓到裸色值(否则写错了正则也是一片绿)
|
||||
assert.deepEqual("fontColor('#E8F0FE')".match(literal), ['#E8F0FE']);
|
||||
assert.deepEqual("color('#80000000')".match(literal), ['#80000000']);
|
||||
// 令牌文件本身必须是**唯一**的颜色来源,否则上面那条会因为"哪儿都没有色值"而空转
|
||||
assert.ok(/#[0-9A-Fa-f]{6,8}/.test(harmony), 'Theme.ets 里应该有真正的色值');
|
||||
});
|
||||
|
||||
test('权限档位徽标两边同一套色(plan=蓝 / workspace=绿 / full=琥珀)', () => {
|
||||
// WebUI 的映射写在 PermissionChip.tsx 的类名里;鸿蒙的映射是 Theme.permBg/permFg。
|
||||
const chip = readFileSync(
|
||||
join(ROOT, 'client/electron/src/components/PermissionChip.tsx'),
|
||||
'utf8'
|
||||
);
|
||||
assert.match(chip, /plan'[\s\S]{0,80}bg-blue-50 text-blue-700/, 'WebUI plan 档应是蓝');
|
||||
assert.match(chip, /full'[\s\S]{0,80}bg-amber-50 text-amber-700/, 'WebUI full 档应是琥珀');
|
||||
assert.match(chip, /bg-green-50 text-green-700/, 'WebUI workspace 档应是绿');
|
||||
|
||||
// 鸿蒙侧取的是同一批值 —— 直接和 WebUI 的 :root 变量比,防的是"看起来差不多"
|
||||
const cssVar = (name, src) => {
|
||||
const m = src.match(new RegExp(`--${name}:\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)`));
|
||||
assert.ok(m, `WebUI 要有 --${name}`);
|
||||
return hex('#' + [m[1], m[2], m[3]].map(n => Number(n).toString(16).padStart(2, '0')).join(''));
|
||||
};
|
||||
const token = name => {
|
||||
const m = harmony.match(new RegExp(`${name}: string = '(#[0-9A-Fa-f]{6})'`));
|
||||
assert.ok(m, `鸿蒙要有令牌 ${name}`);
|
||||
return hex(m[1]);
|
||||
};
|
||||
assert.equal(token('accentSoft'), cssVar('c-blue-50', web), 'plan 底色应与 blue-50 一致');
|
||||
assert.equal(token('accentStrong'), cssVar('c-blue-700', web), 'plan 字色应与 blue-700 一致');
|
||||
assert.equal(token('approveBg'), cssVar('c-green-50', web), 'workspace 底色应与 green-50 一致');
|
||||
assert.equal(token('approveFg'), cssVar('c-green-700', web), 'workspace 字色应与 green-700 一致');
|
||||
assert.equal(token('warnBg'), cssVar('c-amber-50', web), 'full 底色应与 amber-50 一致');
|
||||
assert.equal(token('warnFg'), cssVar('c-amber-700', web), 'full 字色应与 amber-700 一致');
|
||||
});
|
||||
|
||||
test('鸿蒙的遮罩是「色 + 透明度」两段式(照 WebUI 的 --bg-scrim + --bg-dim)', () => {
|
||||
/*
|
||||
* WebUI 的遮罩是**两段**:`--bg-scrim`(颜色:浅色=白、深色=黑)+
|
||||
* `--bg-dim`(透明度),见 `index.css` 的 `.app-backdrop::after`。
|
||||
* 理由:遮罩色要能**随主题换向** —— 浅色主题用白把图案洗淡,深色主题必须换黑,
|
||||
* 否则浅色照片在深色界面里糊成一块亮斑、正文读不动(WebUI 侧实测踩过)。
|
||||
* 鸿蒙侧原先写成一个焊死的 `#80000000`,换向时只能再写一个常量 —— 又变成枚举。
|
||||
*/
|
||||
assert.match(harmony, /overlayColor: string = '#000000'/, '鸿蒙的遮罩**色**要单独成令牌');
|
||||
assert.match(harmony, /overlayAlpha: number = 0\.5/, '鸿蒙的遮罩**透明度**要单独成令牌');
|
||||
// 只查**代码**,不查注释:Theme.ets 的注释里正当地引用了旧值来解释为什么拆开
|
||||
const harmonyCode = harmony.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||
assert.ok(!/#80000000/.test(harmonyCode), '遮罩不该再写成色与透明度焊死的 #AARRGGBB 单值');
|
||||
// WebUI 侧同构:颜色两套(浅/深,同一个变量名换向)+ 透明度独立
|
||||
assert.match(web, /--bg-scrim: 255 255 255/, 'WebUI 浅色遮罩色');
|
||||
assert.match(web, /--bg-scrim: 0 0 0/, 'WebUI 深色遮罩色');
|
||||
assert.match(web, /--bg-dim:/, 'WebUI 的透明度是独立变量');
|
||||
// 反向对照:判据要真能抓到"焊死单值"
|
||||
assert.ok(/#80000000/.test("backgroundColor('#80000000')"), '自检:正则抓不到焊死的单值');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user