Files
classhelper-island-refactor…/analysis/refactor-ui.md
T
ClassIsland Prompt Kit 22c1784bab feat: ClassIsland / ClassHelper 灵动岛提示词套件
- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构)
- ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本)
- 投喂指南、分卷、逐节文件
- 调研记录、一致性基线、生成与质检脚本
2026-11-12 21:59:58 +08:00

150 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# analysis/refactor-ui.md —— ui-island Round 2 工作备注(Part 07)
- 任务:`task-7`(Round 2「重构 ClassHelper 灵动岛」的第 7 部分:岛结构与组件视觉规格)
- 产出:`parts-r/07-island-components.md`(CJK ≈ 7200 字,含 18 条验收标准)
- 工作方式:只读静态分析。未构建、未运行、未启动 Electron、未截图、未冒烟、未安装依赖、未改动 `repos/`。
- 口径:以 `analysis/50-refactor-brief.md` 与本轮 Lead 的两条补充为准(见 §3)。
## 1. 已读文件清单
### 1.1 ClassHelper 灵动岛渲染层(必读清单全部读完)
| 文件 | 读取范围 | 用途 |
|---|---|---|
| `packages/desktop-client/src/island/LayoutIslandApp.vue` | 全文 76 行 | 唯一渲染入口:fixed/custom/课件三选一、bridge 订阅 |
| `packages/desktop-client/src/island/IslandApp.vue` | 1–200、200–399、400–683(全文 683) | 经典模式:弹簧形变、胶囊/展开层、命中上报、触摸上报、模板结构 |
| `packages/desktop-client/src/island/CustomIslandRuntime.vue` | 全文 528 行 | 常驻模式:三页(compact/details/lesson)、测量、fitted 缩放、hit 上报、铃铛 |
| `packages/desktop-client/src/island/ComponentNode.vue` | 全文 456 行 | 组件渲染:组件契约→DOM/CSS、schedulePoints、hidden、style 计算 |
| `packages/desktop-client/src/island/ComponentIcon.vue` | 全文 36 行 | 14 类 kind 的 24×24 线性图标路径 |
| `packages/desktop-client/src/island/ClassicNotifications.vue` | 全文 234 行 | 消息详情卡/列表卡:head/badge/list-row/foot/按钮 |
| `packages/desktop-client/src/island/LessonReminderContent.vue` | 全文 318 行 | **5 段斜切遮罩的现有实现**(与 ClassIsland 参数一致)+ 课程提醒排版 |
| `packages/desktop-client/src/island/CoursewareTransfer.vue` | 全文 132 行 | 课件覆盖卡:尺寸/锚点/命中 |
| `packages/desktop-client/src/island/WeatherBrief.vue` | 仅列表(未细读内容) | 天气简报组件(需在实现时按 7.4.3 改写) |
| `packages/desktop-client/src/island/classic-island.css` | 全文 757 行 | WinIsland 经典:token/胶囊/展开卡/列表/按钮 |
| `packages/desktop-client/src/island/custom-island.css` | 全文 205 行 | 常驻卡/行/separated/铃铛/编辑面板 |
| `packages/desktop-client/src/island/custom-runtime.css` | 全文 255 行 | 常驻窗口/卡片/三页/行/尺寸/ClassIsland Fluent 化配色 |
| `packages/desktop-client/src/island/lesson-ending.css` | 全文 16 行 | 下课前徽标 30×30 正圆 |
| `packages/desktop-client/src/island/spring.ts` | 全文 115 行 | stiffness 0.10 / damping 0.68 / 换向 35% / 单帧 ≤20% / snap 0.05px |
| `packages/desktop-client/src/island/squircle.ts` | 全文 81 行 | 超椭圆 4.2 / 每角 14 段 / expandedRadius |
| `packages/desktop-client/src/island/main.ts` | 全文 30 行 | 入口、零依赖策略、applyMotionTokens 必须注入 |
### 1.2 主进程 / preload / shared
| 文件 | 读取范围 | 用途 |
|---|---|---|
| `packages/desktop-client/src/main/island.ts` | 1–140、400–659、1325–1710、1780–1900、2244–2343、grep 全文 | 窗口参数、几何(anchor/windowBox/windowBounds)、命中/触摸/失焦、淡入淡出、normalizeAppearance、常量 |
| `packages/desktop-client/src/preload/island.ts` | 全文 123 行 | contextBridge 白名单(getState/onAppearance/setHitRect/setTouchMode/...) |
| `packages/shared/src/island-layout.ts` | 全文 404 行 | 组件契约、CLASSISLAND_ISLAND_METRICS、默认方案、normalize 边界 |
| `packages/shared/src/constants.ts` | 240–369、379–470、grep | DEFAULT_ISLAND_APPEARANCE、RANGES、POSITIONS、STYLES、SIZE_DELTA、SHADOW_PAD、TYPE_SCALE、LIST_METRICS/islandListLayout |
| `packages/shared/src/motion.ts` | grep + 165–180 | `--ch-*` 令牌、EASE_OUT `[0.16,1,0.3,1]`、MOTION_DURATION 90/140/200/320/180 |
### 1.3 编辑器与设置页
| 文件 | 读取范围 | 用途 |
|---|---|---|
| `renderer/views/settings/IslandEditorView.vue` | 1–330 grep、542–860 | 编辑器结构:标签态/预览态、拖拽、抽屉、行表单、方案表单、组件库 |
| `renderer/views/settings/IslandSettingsView.vue` | grep 全文 | 外观设置项(高/宽/圆角/不透明度/字号/速度/主题色/视觉风格/位置/边距) |
| `renderer/components/IslandComponentSettings.vue` | grep 全文(307 行) | 组件设置页字段(时钟/倒计时/天气/文本/课程表/容器) |
| `renderer/components/IslandEditorNode.vue` | 全文 124 行 | 编辑器组件 chip、选中/container/drop 指示 CSS |
| `renderer/styles/island-editor.css` | grep 全文(8201 B) | 编辑器尺寸:行 54px、把手 24px、库项 76px、预览 padding |
### 1.4 文档与 ClassIsland 基准
| 文件 | 用途 |
|---|---|
| `repos/ClassHelper-master/docs/app/island.md` | 行为现状表(fixed vs custom 七种场景)、编辑流程、外观/输入、课程与课件 |
| `repos/ClassHelper-master/docs/dev/winisland-design-tokens.md` | 设计令牌、动画与命中约定、修改入口 |
| `repos/ClassIsland/AGENTS.md`、`repos/ClassHelper-master/AGENTS.md` | 纪律(注入) |
| 上一轮 `parts/04-main-window.md`、`parts/05-components.md` | ClassIsland 像素基准(本轮直接引用其行号证据) |
## 2. 关键参数表(ClassHelper 现状 → 目标)
### 2.1 窗口与几何
| 参数 | 现状 | 目标 | 证据 |
|---|---|---|---|
| 窗口标志 | transparent/frame:false/skipTaskbar/hasShadow:false/type:toolbar | 保持 | `main/island.ts:484-492, 504` |
| 可激活 | `focusable: true`(关掉会丢 mousedown) | 保持 | `:493-502` |
| 置顶 | `setAlwaysOnTop(x,'screen-saver')` + 全工作区可见 | 保持 | `:514-515` |
| 默认穿透 | `setIgnoreMouseEvents(true,{forward:true})` | 保持 | `:527` |
| 阴影留白 | `ISLAND_SHADOW_PAD = 10` | 保持 | `shared/constants.ts:351` |
| 边距 | `ISLAND_MARGIN = 8`,`marginX/marginY` 默认 8 | 保持 | `main/island.ts:2277`、`constants.ts:285-287` |
| 停靠 | 6 位置,居中不受 marginX | 保持 | `main/island.ts:1331-1351` |
| 多显示器 | `followCursorDisplay`(默认 false),60ms 轮询换屏 | 保持 | `:1354-1379` |
| fixed 包围盒 | 最大形态 + 2×pad,开合不动 | 保持;classisland 下高 = 40 或 40+气泡高 | `:1514-1553` |
| custom 包围盒 | `min(960, w) × min(640, h-marginY)` | 高度改为内容上限(`contentMaxHeight + 2*pad`) | `:1522-1529` |
| 触摸模式贴合 | `BLUR_GRACE_TOUCH_MS = 1200`,窗口只增不减 | 保持 | `:2287, 2297, 1560-1578` |
| 失焦宽限 | 500ms(非触摸) | 保持 | `:2287` |
| 命中限流 | 渲染 50ms + 主进程 60ms 兜底 | 保持 | `IslandApp.vue:417`、`main/island.ts:1829` |
| 心跳/重建 | 20s 超时、3 次 / 10min | 保持 | `main/island.ts:2315-2318` |
| 淡入淡出 | 步进 0.16 / 0.2 × 16ms | 保持 | `:1674-1710` |
| 指针避让淡化 | `residentFaded` → opacity × 0.05 | 保持 | `:1851-1877`、`island-layout.ts:35` |
### 2.2 行/背景/进度条(目标值,与 ClassIsland 对齐)
| 参数 | 目标 | ClassIsland 证据 |
|---|---|---|
| 行高 | 40 | `parts/04` §2.2(`MainWindowLine.axaml:16`) |
| 行内边距 | 左右 12 | `FluentTheme/Styles.axaml:110` |
| 行距 | 5 | `Models/Settings.cs:219` |
| 组件间距 | 12(6+6) | `MainWindow.axaml:396` |
| 圆角 | 8(0–20) | `Models/Settings.cs:183` |
| 背景不透明度 | 0.5(只作用背景) | `FluentTheme/Styles.axaml:44` |
| 行不透明度 | 1.0(0.1–1) | `MainWindowLineSettings.cs:42` |
| 描边 | 1px | `FluentTheme/Styles.axaml:47` |
| 阴影 | `0 4 8 2 #48000000` | `FluentTheme/Styles.axaml:49` |
| 字号 | 14 / 16 / 18 / 20 | `ThemeBase.axaml:32-35` |
| 进度条 | 3px | 本轮裁决 |
| 淡出比例 | 0.05 | `island-layout.ts:35` / `MainWindowLine.axaml:74` |
### 2.3 组件契约(ClassHelper 现状,必须沿用)
- `IslandComponentNode = { id, kind, settings, appearance, advanced, children }`(`island-layout.ts:77-108`)。
- `settings` 18 个字段:text/template/hour12/seconds/target/targetDate/countdownTitle/locationName/latitude/longitude/display/count/showPeriod/showProgress/direction/gap/interval/speed(`:80-99`)。
- `appearance` 14 个字段(`:61-76`);`advanced` 4 个字段(`:101-106`)。
- 规范化上限:12 行 / 200 节点 / 6 层 / 20 方案;`count 1–40`、`gap 0–64`、`interval 1–300`、`speed 1–200`、字号 8–96、radius 0–100(`:257-403`)。
- 默认节点值见 `:173-216`;默认方案见 `:217-255`(1 行 main:date/clock/schedule/messages;expandedRows:date/today-schedule)。
### 2.4 现有斜切遮罩参数(可直接复用)
`LessonReminderContent.vue:59-102`:`edges=[0,0.1,0.3,0.7,0.9,1]`(= 权重 0/0.1/0.2/0.4/0.2/0.1)、`offset = tan(30°)×40`、`delays = open?[0,90,120,90,0]:[120,90,0,90,120]`、`ease = 1-(1-p)^4 / p²`、总 480ms、兜底 600ms/speed。与 ClassIsland `SlantedMaskControl.cs:177-200` 完全对应 → 本轮只做"抽成共享组件"。
## 3. 本轮 Lead 口径更新(已回填)
1. **字段名**:`appearance.family: 'classisland' | 'winisland'`(不是改 `style`);`style` 继续表示 winisland 下的 black/glass/tinted 色调。
2. **默认值**:新安装 `classisland`;老用户升级保持 `winisland`(避免观感突变)→ 已写入 7.3.1 的迁移规则。
3. **fixed 重定义**:`classisland` 下 fixed = ClassIsland 风格信息行(1 行 = 日期 + 课程表、行高 40、圆角 8、背景 0.5、底部 3px 进度条;消息在同一行内展开气泡,保留既有业务规则);"胶囊 + 详情卡"只在 `winisland` 下保留 → 已重写 7.1.2、7.3.2/7.3.3、验收 2/3。
4. custom 仍用 schemes/rows/nodes 模型升级 → 7.2、7.4 覆盖。
5. **气泡不增高行**(第三条口径):`family='classisland'` 的消息气泡在固定 40px 行内渲染(遮罩/内容/进度都在 40 内),正文最多 2 行、超出省略;禁止把行高临时改到 48/56/64;`--ci-island-height: 40px` 不得被气泡改写;动画/遮罩按 ClassIsland 原版(360/120ms、文字 260/250ms、scale 1.1→1.0/750ms、退出 200ms)→ 已新增 **7.2.8 消息气泡**,并回改 7.1.2 A(窗口高恒 40+2×pad)、7.3.2(`targetSize` 高度恒 40、去掉高度弹簧)、7.4.12(容器高度按 family 分三种)、验收 2.1/2.2/5。
6. **custom 课程提醒接管规则**(第四条口径):custom 不因 in-class/prepare/break 临时接管整岛(课程进度由 `schedule` 组件展示);`ending` 仅以课程名右侧蓝色圆形秒数徽标显示;不新增"临时接管一行"行为;只有 fixed(classisland)显示完整课程提醒条 → 已写入 **7.3.3 fixed/custom 差异总表**(含课程接管),写明 `CustomIslandRuntime.vue:31-33` 的 `lesson` 计算改为恒 `null`、移除 `resident-lesson-page`,验收 9.1。
7. **`family` 只影响 fixed**(第五条口径,最终版):`classisland` 下 fixed = 信息行;`winisland` 下 fixed = 旧胶囊 + 详情卡;**custom 始终使用 ClassIsland 规格,不提供 winisland 回退**(custom 现有结构本就接近 ClassIsland,只做细化与像素对齐)→ 已回改:7.0 第 1/2/5 条、7.1.2 custom 段、7.2 标题、7.3 标题与 7.3.1(设置页在 custom 下隐藏"外观族/视觉风格")、7.3.2 custom 行、7.3.5 共享约束、验收 1.1/9;章节重排为 7.3.1 数据与开关 → 7.3.2 classisland → 7.3.3 差异总表 → 7.3.4 winisland → 7.3.5 共享约束。
> 注意:现有 `CustomIslandRuntime.vue:31-33` 的 `lesson` 会接管 custom 岛(prepare/on-class/break/in-class 都走 `resident-lesson-page`)。第六条口径要求**去掉**该接管,因此这是一处**行为变更**(不是保持代码现状),已在 7.3.3 写明具体改动点,需第 8 部分与第 12 部分验收同步。
>
> 另:**06/10 的双风格差异表需限定在 fixed**(Lead 要求)——我的 part 07 已按此表述;06(tokens)与 10(动画)若把 winisland 差异写到 custom 上,需要他们回改,不在本 part 范围。
## 4. 未决问题 / 需 Lead 或其它 part 确认
1. **`appearance.theme`(fluent/classic)与本文的衔接**:第 11 部分已列该字段,第 6 部分负责 token;本文只在 7.3.1 第 6 条要求"行背景/描边/阴影/遮罩参数随 theme 切换"。需要 part 06 给出 Fluent/Classic 两套实际色值(ClassIsland 侧 `SolidBackgroundFillColorSecondaryBrush` 等仍未被取色)。
2. **`scheme.rowHeight / componentGap / showProgress`**:第 13 部分(milestones)提到这三个 scheme 字段,第 5 部分负责 schema;本文已按"scheme 覆盖 > 外观族默认"写入 7.2.2,需与第 5 部分字段命名对齐。
3. **fixed(classisland)的消息卡形态**:本文规定"同一行内展开气泡 + 斜切遮罩 + 倒计时进度,保留 ClassHelper 暂存/紧急/叫人/已读/去重",但**气泡内的列表/按钮排布**归第 8 部分;需要第 8 部分确认是否复用现有 `ClassicNotifications.vue`(含 list-mode)还是新写 `ClassislandBubble.vue`。本文建议复用并加 `data-family` 样式覆盖。
4. **fixed 模式的"1 行默认组件"存放位置**:本文建议新建内置 fixed 方案(复用 `scheme.rows` 结构),但 `islandLayout` 现有结构里 fixed 模式不读 schemes(`LayoutIslandApp.vue:21` 只按 layout 分流)。需要第 5 部分决定:fixed 的默认行是"内置常量"还是"schemes 里的一条特殊方案"。
5. **`contentMaxHeight` 上报 IPC**:本文建议新增 `island:report-layout-metrics`,但第 4 部分(file-plan)负责 IPC 清单;需确认命名与白名单(`preload/island.ts:14-62`)。
6. **`windowBox()` 的 custom 高度**:现为 `min(640, h-marginY)`(`main/island.ts:1527`)。本文改为"内容上限",但内容上限需要渲染层测量后才知道;首帧仍用 640 兜底。需确认是否接受首帧到测量完成之间的一次 `setBounds`。
7. **触摸模式与固定包围盒的交互**:触摸模式窗口贴合岛体(`windowBox` 分支),classisland fixed 现在高度恒 40(气泡不再增高行),因此该冲突已消除;仅剩"行宽变化时触摸窗口只增不减"需在真机确认。
8. **`WeatherBrief.vue` 未细读**:只确认了文件存在与大小(2.9KB)。7.4.3 给出目标 DOM/尺寸,但**现有字段与数据形状需实现时先读该文件**(未决)。
9. **`lesson-ending.css` 徽标 30×30** 与 ClassIsland(课程名右侧蓝色圆形、剩余秒数 `-1`)一致,但 ClassIsland 的徽标尺寸未见源码定义(其计数徽标在 `LessonControlExpanded.axaml` 内)。本文按 ClassHelper 现值保留,若第 8 部分要改成 ClassIsland 尺寸需同步。
10. **`parts/04`/`parts/05` 的引用方式**:本文用行号引用上一轮 part 的结论(如 `parts/04` §2.2),最终汇总时需确认跨文件引用是否会被 Lead 改写为"直接证据路径"。
11. **`style` 旧值迁移**:现有 `ISLAND_STYLES = black|glass|tinted`;本轮不删,继续作为 winisland 色调。旧配置升级时 `family` 缺省 → winisland,`style` 原样保留,因此"毛玻璃用户"升级后外观不变(符合 Lead 口径)。
12. **编辑器选中框 1.5px 虚线**:ClassIsland 用 `Rectangle` + `StrokeDashArray="1,1.5"` + `StrokeThickness=1.5`(`repos/ClassIsland/ClassIsland/MainWindow.axaml:353-363`);CSS 的 `outline: dashed` 不支持自定义 dash 长度,实现需用 `background-image: repeating-linear-gradient` 或 SVG 边框。已在 7.5.2 写明"1.5px 虚线",但具体画法需在实现阶段定(P2 可接受近似)。
## 5. 自检
- [x] 只读:未构建、未运行、未启动 Electron、未截图、未冒烟、未安装依赖、未改 `repos/`。
- [x] 必读清单 18 个文件全部读过(`WeatherBrief.vue` 仅列目录,已在未决 §4.8 标注)。
- [x] 覆盖:窗口/几何(7.1)、行/背景/进度/遮罩/淡出/隐藏(7.2)、两套 family(7.3)、11 内置 + 3 消息入口 + 课件(7.4)、编辑器(7.5)、token(7.5.5)、验收(7.6)。
- [x] 每处像素值给 `packages/...:行号` 或 `repos/ClassIsland/...:行号`;无法确认标【推断】(如气泡宽度上限 720、ClassIsland 徽标尺寸)。
- [x] 已按 Lead 四条口径更新:`appearance.family` 字段名、fixed 的 classisland=信息行重定义、老用户保持 winisland、**气泡不增高行(40px 内)**、**custom 不被课程提醒接管**。
- [x] 中文祈使句,无"建议考虑"式模糊表述("建议"仅出现在给 Lead 的未决项里)。
- [x] CJK ≈ 8100 字(本轮无硬性字数要求,按上一轮 5000 标准超额满足)。