// 宽屏侧栏图标轨(WideSidebar)判据 —— 一比一复刻 WebUI 的 `Sidebar`(60px 图标轨)。 // // WebUI 的 `Sidebar`(components/Sidebar.tsx)是 60px 宽的图标列: // 品牌标(顶) / 通信·日历·联系人(中) / 设置(底) // 选中态 = 图标+文字变色 + 品牌浅底,**不加背景块/指示条**。 // // 鸿蒙侧原来是**没有**宽屏布局的(只有底部导航条),WideSidebar 补的就是 // "宽屏模式"这半:≥768vp 时 MainPage 挂侧栏、藏底部条(见 MainPage.build 的 onAreaChange)。 // 这条判据钉的是 Sidebar 自己的形状:宽 60vp、三项导航 + 设置、选中态只换颜色。 import { code, prose, stripComments } from './lib/read.mjs'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; import { test } from 'node:test'; import assert from 'node:assert/strict'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..', '..'); const HARMONY_ETS = join(ROOT, 'client/harmony/entry/src/main/ets'); const read = p => prose(join(HARMONY_ETS, p)); /** 取某个成员/方法正文(按行切到下一个成员声明) */ function memberBody(src, signature) { const lines = src.split('\n'); const start = lines.findIndex(l => l.includes(signature)); assert.ok(start > 0, `要能找到 ${signature}`); let stop = lines.length; for (let i = start + 1; i < lines.length; i++) { if (/^ (@Builder|build\(|NavItemBuilder\()/.test(lines[i])) { stop = i; break; } } return lines.slice(start, stop).join('\n'); } test('① 宽度:SIDEBAR_WIDTH = 60vp(WebUI 的 `w-[60px]` 是同一数字)', () => { const sidebar = read('pages/WideSidebar.ets'); const code_ = stripComments(sidebar); assert.match(code_, /export const SIDEBAR_WIDTH: number = 60\s*;/, '要导出 60 这个常量'); const main = read('pages/MainPage.ets'); assert.match(main, /WideSidebar\(/, 'MainPage 要真正挂 WideSidebar'); }); test('② 四项导航(与底栏同源):不再有单列的"设置"入口', () => { /* * ★★ 2026-09-18 重写。原来这条判的是「三项导航 + 设置按钮」, * 依据是"设置单列在下面、遍历 NAV_ITEMS 会出现两个 person 图标"。 * 那个依据**两半都错**: * · `NAV_CONTENT_ITEMS = NAV_ITEMS.slice(0, NAV_CONTENT_COUNT)` 而 * `NAV_CONTENT_COUNT = 4` ⇒ **四项全在**(含「我的」),不存在"只有前三项"; * · 单列的"设置"走 `onSettings → pushUrl('pages/SettingsPage')`, * 而那正是用户 2026-09-17 报过的「我的页面完全没有遵守 nav 的导航规则」 * (底栏那一支改成了窗格,侧栏这一支漏了)。 * * WebUI `Sidebar.tsx` 的真实形状:`navItems` 三项 + **底部一簇** * (账号头像 / 主题切换 / 退出)。「我的」在 WebUI 是 `viewMode === 'account'`, * 由侧栏底部那个**头像按钮**进入 —— 也就是说它是**导航项**,不是"推出去的页"。 * 鸿蒙的对应物是第 4 项「我的」窗格(与底栏一致)。 */ const sidebar = read('pages/WideSidebar.ets'); const code_ = stripComments(sidebar); assert.match(code_, /ForEach\(NAV_CONTENT_ITEMS,/, '侧栏要遍历 NAV_CONTENT_ITEMS(与底栏同一个清单 —— 两处各留一份会漂移)'); // 品牌标:WebUI 是 `