fix(webui): 日历补上圆角 —— 外层面板圆了、里面的格子还是直角

用户:「日历页面怎么没有圆角」。

原因与列表那次同源:**外层面板一直是圆的**(`.app-shell > *` 给了 14px),
但里面的日格/列写的是 `border-b border-r`(直角 + 细边框),而我早前为了修滚动
去掉了面板的 `overflow: hidden` ⇒ 里面的直角就戳在圆角外面,看起来"整页没有圆角"。

改法:日格、周视图列、以及日历的两个大面板都改用 `.glass-card`
(圆角 14px + 白色玻璃 + 细边框),与列表项、顶部气泡同一套语言。
顺手去掉日格上的 `overflow-hidden`(它会把事件条裁掉,而"裁掉"正是这几轮的老毛病)。

实测(自有浏览器,壁纸开):日历里 **42 个 `.glass-card`**(月视图 42 格 + 面板),
格子 `border-radius: 14px`、底色 `rgba(255,255,255,0.78)`。

(这条同样是"外层圆角 + 内层直角"这一类问题 —— 我已经在列表、顶部、日历上
各修了一次。要找根因的话:**面板圆角不能靠 `overflow: hidden` 裁**(它会杀滚动),
所以每一层自己都要圆角。这是这套"浮动面板"设计的固有代价,写在这里备查。)
This commit is contained in:
2026-09-14 13:47:58 +08:00
parent dfaeab0e4d
commit bb855b1518
4 changed files with 282 additions and 130 deletions

View File

@ -226,3 +226,105 @@ export function contactViewTitle(view: string): string {
export function lastFromIsHuman(agentName: string, lastFrom: string): boolean {
return lastFrom !== agentName;
}
/*
* ─────────────── 权限档位与"强制力"(对应 WebUI 的 PermissionChip) ───────────────
*
* 为什么强制力也得上界面(WebUI `PermissionChip.tsx` 的注释原话):
* 「只显示档位会让人以为 plan 档管住了 homeagent,而 homeagent 没有工具拦截点、
* 档位只是提示词建议(advisory)。差异可见才符合 I-5(失败必须当场可见)」
*
* 鸿蒙侧在触屏上更得说清:WebUI 把说明放在 `title`(悬停提示),手指没有悬停 ——
* 所以这里除了照搬 WebUI 的标记形状(实心 / 靶心 / 空心),说明文字走"点一下弹出来",
* 并且**文案与 WebUI 逐字一致**:判据从 WebUI 源码里抽出字符串直接比对,任一边改口径就红。
* (port 成两份文案是没办法的事:鸿蒙跑不了 TSX;可执行的比对是它的替代品。)
*/
/** 档位 → 中文短标签(与 WebUI `PermissionChip.tsx` 的 `MODE_LABEL` 逐字一致) */
export function permissionLabel(mode: string): string {
if (mode === 'plan') {
return '只读';
}
if (mode === 'workspace') {
return '目录内';
}
if (mode === 'full') {
return '全权';
}
return ''; // 空档位(人→人的信、旧会话)不显示徽标
}
/**
* 归一化强制力:认不出的值按 advisory。
*
* 保守方向与 WebUI 的 `normalizeEnforcement`、后端 `Normalize` 同语义 ——
* 认不出就当"平台不强制",绝不当成"平台拦得住"。
*/
export function enforcementKey(e: string): string {
if (e === 'native' || e === 'partial' || e === 'advisory') {
return e;
}
return 'advisory';
}
/** 强制力 → 标记形状:native 实心 / partial 靶心 / advisory 空心(与 WebUI 的三种点同构) */
export function enforcementGlyph(e: string): string {
const k: string = enforcementKey(e);
if (k === 'native') {
return '●';
}
if (k === 'partial') {
return '◉';
}
return '○';
}
/** 强制力 → 中文短标签(与 WebUI 的 `ENFORCEMENT_LABEL` 逐字一致) */
export function enforcementLabel(e: string): string {
const k: string = enforcementKey(e);
if (k === 'native') {
return '平台强制';
}
if (k === 'partial') {
return '平台强制(覆盖不完整)';
}
return '仅提示';
}
/**
* 档位 + 强制力 → 一句人话(点徽标弹出来)。
*
* **文案与 WebUI `permissionModeHint` 逐字一致**:两个客户端对同一个任务给出的
* "平台实际做到了什么"必须是同一句话,否则人在两边看到两种保证。
*/
export function permissionHint(mode: string, enforcement: string): string {
const e: string = enforcementKey(enforcement);
if (mode === 'plan') {
if (e === 'native') {
return 'plan 档:只读。写/改/执行会被平台强制拦下,本档只用来查与想。';
}
if (e === 'partial') {
return 'plan 档:只读。平台会拦截写/改/执行,但覆盖不完整(沙箱能力受限,有已知缺口)——不要把「会被拦下」当保证,请把结论写在回信里。';
}
return 'plan 档:只读(advisory,平台不强制)。请把结论写在回信里。';
}
if (mode === 'full') {
return 'full 档:全权。工具调用不需额外授权。';
}
if (e === 'native') {
return 'workspace 档:目录内可动,越界需经授权。';
}
if (e === 'partial') {
return 'workspace 档:目录内可动,越界会请求授权 —— 但沙箱覆盖不完整(有已知缺口),请主动把改动限制在工作目录内。';
}
return 'workspace 档(advisory,平台不强制)。请把改动限制在工作目录内。';
}
/** 徽标文字:标签 + 强制力标记(空档位返回空串,页面据此不渲染) */
export function permissionChipText(mode: string, enforcement: string): string {
const label: string = permissionLabel(mode);
if (label.length === 0) {
return '';
}
return label + ' ' + enforcementGlyph(enforcement);
}