- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构) - ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本) - 投喂指南、分卷、逐节文件 - 调研记录、一致性基线、生成与质检脚本
16 KiB
16 KiB
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)。settings18 个字段:text/template/hour12/seconds/target/targetDate/countdownTitle/locationName/latitude/longitude/display/count/showPeriod/showProgress/direction/gap/interval/speed(:80-99)。appearance14 个字段(:61-76);advanced4 个字段(: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 口径更新(已回填)
- 字段名:
appearance.family: 'classisland' | 'winisland'(不是改style);style继续表示 winisland 下的 black/glass/tinted 色调。 - 默认值:新安装
classisland;老用户升级保持winisland(避免观感突变)→ 已写入 7.3.1 的迁移规则。 - fixed 重定义:
classisland下 fixed = ClassIsland 风格信息行(1 行 = 日期 + 课程表、行高 40、圆角 8、背景 0.5、底部 3px 进度条;消息在同一行内展开气泡,保留既有业务规则);"胶囊 + 详情卡"只在winisland下保留 → 已重写 7.1.2、7.3.2/7.3.3、验收 2/3。 - custom 仍用 schemes/rows/nodes 模型升级 → 7.2、7.4 覆盖。
- 气泡不增高行(第三条口径):
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。 - 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。 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 确认
appearance.theme(fluent/classic)与本文的衔接:第 11 部分已列该字段,第 6 部分负责 token;本文只在 7.3.1 第 6 条要求"行背景/描边/阴影/遮罩参数随 theme 切换"。需要 part 06 给出 Fluent/Classic 两套实际色值(ClassIsland 侧SolidBackgroundFillColorSecondaryBrush等仍未被取色)。scheme.rowHeight / componentGap / showProgress:第 13 部分(milestones)提到这三个 scheme 字段,第 5 部分负责 schema;本文已按"scheme 覆盖 > 外观族默认"写入 7.2.2,需与第 5 部分字段命名对齐。- fixed(classisland)的消息卡形态:本文规定"同一行内展开气泡 + 斜切遮罩 + 倒计时进度,保留 ClassHelper 暂存/紧急/叫人/已读/去重",但气泡内的列表/按钮排布归第 8 部分;需要第 8 部分确认是否复用现有
ClassicNotifications.vue(含 list-mode)还是新写ClassislandBubble.vue。本文建议复用并加data-family样式覆盖。 - fixed 模式的"1 行默认组件"存放位置:本文建议新建内置 fixed 方案(复用
scheme.rows结构),但islandLayout现有结构里 fixed 模式不读 schemes(LayoutIslandApp.vue:21只按 layout 分流)。需要第 5 部分决定:fixed 的默认行是"内置常量"还是"schemes 里的一条特殊方案"。 contentMaxHeight上报 IPC:本文建议新增island:report-layout-metrics,但第 4 部分(file-plan)负责 IPC 清单;需确认命名与白名单(preload/island.ts:14-62)。windowBox()的 custom 高度:现为min(640, h-marginY)(main/island.ts:1527)。本文改为"内容上限",但内容上限需要渲染层测量后才知道;首帧仍用 640 兜底。需确认是否接受首帧到测量完成之间的一次setBounds。- 触摸模式与固定包围盒的交互:触摸模式窗口贴合岛体(
windowBox分支),classisland fixed 现在高度恒 40(气泡不再增高行),因此该冲突已消除;仅剩"行宽变化时触摸窗口只增不减"需在真机确认。 WeatherBrief.vue未细读:只确认了文件存在与大小(2.9KB)。7.4.3 给出目标 DOM/尺寸,但现有字段与数据形状需实现时先读该文件(未决)。lesson-ending.css徽标 30×30 与 ClassIsland(课程名右侧蓝色圆形、剩余秒数-1)一致,但 ClassIsland 的徽标尺寸未见源码定义(其计数徽标在LessonControlExpanded.axaml内)。本文按 ClassHelper 现值保留,若第 8 部分要改成 ClassIsland 尺寸需同步。parts/04/parts/05的引用方式:本文用行号引用上一轮 part 的结论(如parts/04§2.2),最终汇总时需确认跨文件引用是否会被 Lead 改写为"直接证据路径"。style旧值迁移:现有ISLAND_STYLES = black|glass|tinted;本轮不删,继续作为 winisland 色调。旧配置升级时family缺省 → winisland,style原样保留,因此"毛玻璃用户"升级后外观不变(符合 Lead 口径)。- 编辑器选中框 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. 自检
- 只读:未构建、未运行、未启动 Electron、未截图、未冒烟、未安装依赖、未改
repos/。 - 必读清单 18 个文件全部读过(
WeatherBrief.vue仅列目录,已在未决 §4.8 标注)。 - 覆盖:窗口/几何(7.1)、行/背景/进度/遮罩/淡出/隐藏(7.2)、两套 family(7.3)、11 内置 + 3 消息入口 + 课件(7.4)、编辑器(7.5)、token(7.5.5)、验收(7.6)。
- 每处像素值给
packages/...:行号或repos/ClassIsland/...:行号;无法确认标【推断】(如气泡宽度上限 720、ClassIsland 徽标尺寸)。 - 已按 Lead 四条口径更新:
appearance.family字段名、fixed 的 classisland=信息行重定义、老用户保持 winisland、气泡不增高行(40px 内)、custom 不被课程提醒接管。 - 中文祈使句,无"建议考虑"式模糊表述("建议"仅出现在给 Lead 的未决项里)。
- CJK ≈ 8100 字(本轮无硬性字数要求,按上一轮 5000 标准超额满足)。