跨端: 导航项徽标两侧补齐(我上次"撤回"错了 —— WebUI 是有的)
上一笔我凭"两侧导航都没有徽标"把刚写好的徽标**撤回**了。那是错的:
`client/electron/src/components/Sidebar.tsx:88-95,111-125` 明确有——
```
const badge = isComm ? unread + pendingPerms
: modes.includes('contacts') ? contacts.length : 0;
const badgeTone = isComm && pendingPerms > 0 ? 'perm' : isComm ? 'unread' : 'plain';
```
并且是 `absolute top-0.5 right-1` 压在导航项右上角,`>99` 显示 `99+`。
我当时只看了底栏 `NavItem`(那里确实没有),就把结论推到了"两侧都没有"。
## 补的东西
- 新增**纯逻辑** `model/NavItems.ts` 的 `navBadgeCount` / `navBadgeTone` / `navBadgeText`,
逐条对齐 WebUI 的口径:
· **通信** = 未读 + 待决策(两类"要动手"合起来);
· **联系人** = 联系人数;日历/「我的」= 0(没有徽标);
· 色调:待决策**橙**(有人卡在那儿等)优先于未读**红**(只是还没看);
· 负数当 0(计数来自网络,不假设它干净);`>99` → `99+`。
- **两侧**(底栏 `MainPage.NavItem` + 宽屏 `WideSidebar.NavItemBuilder`)都接上,
且读**同一组** AppStorage 键 —— 两处各算一套,数字迟早对不上,而用户同时看得到它们。
- 计数发布走 `AppStorage`(单向:窗格写、导航栏读),与 `KEY_WINDOW_INSETS` 同一套机制。
不把这两个数提到 `MainPage`:那样"从没进过通信页"也会去发请求。
- 徽标位置对齐 WebUI 的 `absolute top-0.5 right-1`(压在项的右上角)。
★ 第一版我排在文字**下面**,截图一眼可见那颗 3 掉到了「联系人」标签底下、
还把 48vp 的项撑高了 —— 方阵节奏乱掉。
## 判据(harmony-widescreen 6 → 7)
第 ⑦ 条**直接执行**鸿蒙侧的纯函数,且期望值在测试里**独立算一遍**
(不复用被测函数,否则是"用实现验实现")。
★ 接线部分我写错过一次,变异测试当场拆穿:第一版只判
`assert.match(src, /navBadgeCount\(/)` —— 把**渲染处**的调用换成 `0`
(徽标永远不显示),文件里仍留着一处调用,判据照样全绿。
⇒ 改成判**把值交给 Text 的那一行**,并且认出两侧写法不同(底栏走 helper
`Text(this.navBadgeOf(key))`,侧栏就地内联 `Text(navBadgeText(navBadgeCount(...)))`)。
**4 个变异方向全咬**:通信漏算待决策 ⇒ 红;色调优先级写反 ⇒ 红;
侧栏渲染处换空 ⇒ 红;底栏渲染处换空 ⇒ 红。
设备实测:侧栏「联系人」显示红 **3**(3 个联系人),位置在图标右上角。
This commit is contained in:
@ -187,3 +187,59 @@ export function navKeyAt(index: number): string {
|
||||
export function navLabelAt(index: number): string {
|
||||
return NAV_CONTENT_ITEMS[normalizeNavIndex(index)].label;
|
||||
}
|
||||
|
||||
/* ─────────────────── 导航项徽标 ─────────────────── */
|
||||
|
||||
/**
|
||||
* 导航项徽标的**取值**(纯逻辑 —— 判据直接执行这一层,不需要设备)。
|
||||
*
|
||||
* ★ 逐条对齐 WebUI `Sidebar.tsx:88-95` 的 `badge`:
|
||||
* `isComm ? unread + pendingPerms : (contacts ? contacts.length : 0)`
|
||||
* 三条口径都要跟:
|
||||
* · **通信**把两类"要动手"合起来显示(未读 + 待决策)—— 用户同时看底栏/侧栏,
|
||||
* 两处各算一套,数字迟早对不上;
|
||||
* · **联系人**挂联系人数("有几个线索在手");
|
||||
* · **日历/我的**没有徽标(日历的"有事"是某天的点标记,不是导航栏该喊的东西)。
|
||||
*/
|
||||
export function navBadgeCount(key: string, unread: number, pending: number, contactCount: number): number {
|
||||
const k: string = key.trim();
|
||||
if (k === 'comm') {
|
||||
// 负数当 0:计数来自网络响应,不假设它一定干净
|
||||
const u: number = unread > 0 ? unread : 0;
|
||||
const p: number = pending > 0 ? pending : 0;
|
||||
return u + p;
|
||||
}
|
||||
if (k === 'contacts') {
|
||||
return contactCount > 0 ? contactCount : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导航项徽标的**色调**:`'perm'`(待决策,橙)/ `'unread'`(未读,红)/ `'plain'`(中性)。
|
||||
*
|
||||
* 对齐 WebUI `Sidebar.tsx:95` 的 `badgeTone`:
|
||||
* `isComm && pendingPerms > 0 ? 'perm' : isComm ? 'unread' : 'plain'`
|
||||
*
|
||||
* ★ 待决策用橙、未读用红**不是配色偏好**:未读是「有内容没看」,
|
||||
* 待决策是「有 Agent 卡在那儿等我」—— 后者更急。WebUI 的注释把这条写明了,
|
||||
* 两边用同一个优先级才不至于一个喊一个不喊。
|
||||
*/
|
||||
export function navBadgeTone(key: string, pending: number): string {
|
||||
const k: string = key.trim();
|
||||
if (k === 'comm') {
|
||||
return pending > 0 ? 'perm' : 'unread';
|
||||
}
|
||||
return 'plain';
|
||||
}
|
||||
|
||||
/** 徽标文字:0 → 空串(页面据此不渲染),>99 → '99+'(与 WebUI 同一写法) */
|
||||
export function navBadgeText(n: number): string {
|
||||
if (n <= 0) {
|
||||
return '';
|
||||
}
|
||||
if (n > 99) {
|
||||
return '99+';
|
||||
}
|
||||
return n + '';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user