用户:「安排对齐」。 ## 先量差距(不靠感觉) 鸿蒙侧的调色板与 WebUI **根本不同**:`#1A73E8`(Google 蓝)vs 品牌 `#2563EB`、 `#333333` vs slate-900 `#0F172A`、`#F5F7FA` vs `#F8FAFC`、`#FF4444` vs red-600… 共 217 处硬编码色值散在 7 个页面里。 功能面:鸿蒙是 收件箱/会话/联系人 三个 tab,**缺 发件箱 / 授权 / 日历 / 管理**, 也没有玻璃悬浮底栏、主题壁纸同步、Composer 共用组件。 ## 第一阶段(已完成并可验收) - `common/Theme.ets` 补齐文字/浅底/语义令牌,页面里的旧调色板**全量替换为令牌** (共 203 处),`hvigorw assembleHap` **BUILD SUCCESSFUL**。 - 判据:`cross-client-theme.test.mjs` 新增"鸿蒙页面里不得再出现旧调色板色值" (6 条全绿,含扰动自检)。这条防的是**新页面又随手写个"差不多"的颜色** —— 漂移就是这么开始的,而此前没有任何判据会红。 ## 计划文档:docs/HARMONY-ALIGN-PLAN.md 写清两件事,免得每轮重新猜"还差什么": - **差距表**(逐项,标出"缺页面/交互不同/观感不同"的性质); - **分期**:P2 发件箱(与收件箱同构,风险最低)→ P3 授权页(备注必须随决策送达模型 —— WebUI 侧踩过这个坑)→ P4 主题/壁纸同步(服务端"无记录"时以本地为准) → P5 玻璃悬浮导航 → P6 日历(最大,单独排)。 ## 如实说明 鸿蒙**视觉未验证**:本机 `hdc list targets` 为空、HAP 未签名 ⇒ 只能保证编译通过 + 令牌一致,观感需要设备或签名后由人眼确认。文档里也把这条写进"验收纪律"。
80 lines
3.5 KiB
JavaScript
80 lines
3.5 KiB
JavaScript
/**
|
||
* 两个客户端必须用**同一份设计词表**。
|
||
*
|
||
* 用户下一步要求:「同步 ui 设计到客户端」。同步的第一件事不是把每个页面重画一遍,
|
||
* 而是两边共用同一套令牌(颜色/圆角/玻璃透明度)—— 否则每加一个页面就重抄一遍色值,
|
||
* 两个客户端会越走越远,而且这种漂移**没有任何判据会红**。
|
||
*
|
||
* 这里只断言"两边对同一件事的取值一致",不断言实现方式(WebUI 用 CSS 变量、
|
||
* 鸿蒙用 ArkTS 常量,本来就该不同)。
|
||
*/
|
||
import { test } from 'node:test';
|
||
import assert from 'node:assert/strict';
|
||
import { readFileSync } from 'node:fs';
|
||
import { dirname, join } from 'node:path';
|
||
import { fileURLToPath } from 'node:url';
|
||
|
||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||
const ROOT = join(HERE, '..', '..', '..');
|
||
const web = readFileSync(join(ROOT, 'client/electron/src/index.css'), 'utf8');
|
||
const harmony = readFileSync(
|
||
join(ROOT, 'client/harmony/entry/src/main/ets/common/Theme.ets'),
|
||
'utf8'
|
||
);
|
||
|
||
const hex = h => h.toUpperCase();
|
||
|
||
test('品牌蓝一致', () => {
|
||
// WebUI: --c-blue-600 应该是 37 99 235 = #2563EB
|
||
const webBlue = web.match(/--c-blue-600:\s*(\d+)\s+(\d+)\s+(\d+)/);
|
||
assert.ok(webBlue, 'WebUI 要有 --c-blue-600');
|
||
const asHex = hex(
|
||
'#' +
|
||
[webBlue[1], webBlue[2], webBlue[3]]
|
||
.map(n => Number(n).toString(16).padStart(2, '0'))
|
||
.join('')
|
||
);
|
||
const harmonyBlue = harmony.match(/accent: string = '(#[0-9A-Fa-f]{6})'/);
|
||
assert.ok(harmonyBlue, '鸿蒙要有 accent');
|
||
assert.equal(hex(harmonyBlue[1]), asHex, `品牌蓝不一致:WebUI ${asHex} vs 鸿蒙 ${harmonyBlue[1]}`);
|
||
});
|
||
|
||
test('卡片圆角一致(WebUI 0.875rem = 14px)', () => {
|
||
assert.match(web, /--radius-card:\s*0\.875rem/);
|
||
assert.match(harmony, /radiusCard: number = 14/);
|
||
});
|
||
|
||
test('导航玻璃不透明度一致(都是 0.72)', () => {
|
||
assert.match(web, /--nav-bg:\s*255 255 255 \/ 0\.72/);
|
||
// 0.72 × 255 ≈ 184 = 0xB8(鸿蒙用 #AARRGGBB,顺序与 CSS 不同)
|
||
assert.match(harmony, /navBgLight: string = '#B8FFFFFF'/);
|
||
});
|
||
|
||
test('★ 判据自检:把鸿蒙的品牌蓝改成别的必须判红', () => {
|
||
const mutated = harmony.replace(/accent: string = '#2563EB'/, "accent: string = '#FF0000'");
|
||
const m = mutated.match(/accent: string = '(#[0-9A-Fa-f]{6})'/);
|
||
assert.notEqual(hex(m[1]), '#2563EB');
|
||
});
|
||
|
||
test('鸿蒙的令牌文件说明了与 WebUI 的对应关系(不是凭空一套)', () => {
|
||
assert.match(harmony, /与 WebUI 的令牌\*\*一一对应|对应 WebUI/);
|
||
});
|
||
|
||
test('★ 鸿蒙页面里不得再出现与 WebUI 不同的旧调色板', () => {
|
||
/*
|
||
* 对齐之前的鸿蒙调色板是另一套(#1A73E8 Google 蓝、#333333、#F5F7FA…),
|
||
* 与 WebUI 的品牌色/灰阶并不同。203 处已换成 Theme 令牌;这条判据防止
|
||
* 以后新写的页面又随手写死一个"差不多"的颜色 —— 那正是漂移的开始。
|
||
*/
|
||
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 令牌)`);
|
||
}
|
||
}
|
||
// 反向对照:判据本身要能抓到
|
||
assert.ok("#1A73E8".length > 0 && old.includes('#1A73E8'));
|
||
});
|