fix(island,classisland,server,desktop,plugin): 灵动岛去掉整窗背景材质(修卡片外圈白底面板)+ 左右边距只在左/右停靠生效 + 镜像课表补课间

- 灵动岛:移除 win.setBackgroundMaterial() 与 applyBackgroundMaterial/getBackgroundMaterial。它把系统材质刷在整个窗口矩形上(岛是"固定大包围盒窗口",卡片外还有留白),且明暗跟随应用的浅色主题 → 卡片周围出现一圈浅色面板;更糟的是调用过一次(含 none)后窗口就回不到逐像素透明,从 glass 切到 black/tinted 会永久留一圈纯白。glass 因此改为纯 CSS 半透明深色卡(WinIsland 拿不到 host backdrop 时的降级色 rgba(32,32,36,.804))
- 回归用例:新增「个性设置:卡片外圈透出桌面(三种风格都没有白底面板)」——整屏截图取样,并在岛底下垫一块已知颜色底板,让"环 = 底板色"可被精确断言(webContents.capturePage() 拍不到窗口之后的材质,是当初漏掉这个 bug 的原因)
- 边距:左右边距只在"左/右停靠"时生效(默认顶部居中时水平锚点就是屏幕中线),设置页把该滑块置灰并说明,避免被当成"调了不生效"
- 课间:镜像回 ClassIsland 的课表改为每两节之间补一段课间、最后一节之后不补(放学);服务端 synthesizeTimeLayout 同口径,不再依赖导入的时间表里有没有课间点
- 文档:README / AGENTS.md / docs/winisland-design-tokens.md / 插件 README 同步

门禁:pnpm lint 0 error、pnpm typecheck 四包通过。未跑:verify:desktop(需先 build:desktop)、verify:e2e / verify:classisland(需后端启动)。
This commit is contained in:
LoveChengke committed 2026-09-27 18:08:51 +08:00
1 parent 7536abfc95
commit 5c27586af9
12 files changed
+678 -141

No files matched your search

+28 -22
View File
@@ -426,7 +426,7 @@ pnpm verify:packaged # 对**打包后/已安装**的客户端 EXE 跑同一
> 冒烟用 DOM 几何断言(`dx > 0 且 dy < 0`)守住。
> **视觉与排版参考 [WinIsland](https://github.com/WinIslandProject/WinIsland)(Rust/Direct2D 的 Windows 动态岛)重写**:
> 连续圆角(超椭圆 squircle)而不是 `border-radius`、纯黑/亚克力毛玻璃/主题色三种底、
> 连续圆角(超椭圆 squircle)而不是 `border-radius`、纯黑/半透明毛玻璃/主题色三种底、
> Apple 系统色强调色、白字 alpha 分级、**所有文本 = 基础字号 × 排版系数**、
> 胶囊 `h/2` 满圆角 + 展开卡 `min(48, w/2, h/2)`(WinIsland `expanded_island_radius`)、
> 顶/底 × 左/中/右 **6 个停靠位**、可选"空闲细缝"(WinIsland `hidden_width`)。
@@ -537,6 +537,9 @@ pnpm verify:packaged # 对**打包后/已安装**的客户端 EXE 跑同一
### 个性化设置与系统托盘
- **设置 → 灵动岛 · 个性化**新增:左右 / 上下**边距**(贴边距离,任务栏在侧面时调大)、
**跟随鼠标屏幕**(多显示器教室电脑:岛出现在鼠标所在那块屏)。
> 注意:**左右边距只在"左 / 右停靠"时生效**;默认的"居中停靠"下水平锚点就是屏幕中线,
> 设置页会把该滑块置灰并说明(否则会以为"调了没反应")。
- **设置 → ClassIsland 联动**:联动状态(设备名 / 最后上报)+ 通知模式(两者都弹 / 灵动岛 / ClassIsland)。
- **设置 → 作业录入**:作业快捷短语的增删与恢复默认。
@@ -544,20 +547,20 @@ pnpm verify:packaged # 对**打包后/已安装**的客户端 EXE 跑同一
**设置 → 灵动岛 · 个性化**(改动即实时生效,保存后写入本地配置,重启仍生效):
| 设置项 | 区间/取值 | 说明 |
| ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 灵动岛高度 | 36–72px | 胶囊高度;展开卡按同差值联动(`+186/+202/+218px`),内容用 flex 承载且不溢出 |
| 灵动岛宽度 | 220–420px | 同上,展开卡按差值联动(`+156/+172/+188px`) |
| 圆角 | 8–32px | 胶囊取 `min(圆角, h/2)`(WinIsland 胶囊是满圆角);展开卡取 `min(48×圆角/20, w/2, h/2)` |
| 不透明度 | 40%–100% | 窗口整体不透明度(所有显示路径都会应用,含"隐藏后再弹出胶囊") |
| **字号** | **11–20px** | **基础字号**:岛内所有文本 = 基础字号 × 排版系数(标题 1.08 / 正文 0.95 / 次要 0.78 / 徽标与按钮 0.76 / 胶囊标题 0.92 / 胶囊副题 0.74),改一处整体等比缩放 |
| 动画速度 | 0.5×–2× | 形变/淡入时长倍率 |
| 主题色 | 取色器(默认 Apple 系统蓝 `#0a84ff`) | 用于高亮、按钮、进度条、主题色风格(CSS 变量下发到灵动岛渲染进程) |
| **视觉风格** | **纯黑 / 毛玻璃(亚克力)/ 主题色渐变** | 纯黑 = WinIsland `default`;毛玻璃调用 `win.setBackgroundMaterial('acrylic')`(真·桌面模糊,等价 HostBackdropBrush) |
| **显示位置** | **顶部/底部 × 左/中/右(6 个锚点)** | 按 `workArea` 计算;顶/底决定不动的是上边还是下边,左/中/右决定水平锚点 |
| 动画开关 | 开/关 | 关闭后展开/收起瞬时生效(不再逐帧插值) |
| 始终置顶 | 开/关 | 对应 `setAlwaysOnTop` |
| **空闲细缝** | **开/关(默认关)** | 参考 WinIsland `hidden_width`:开启后没有消息时不再完全隐藏,而是留一条 6px 宽的竖条(窗口是固定包围盒,不受 Windows 最小窗口高度限制) |
| 设置项 | 区间/取值 | 说明 |
| ------------ | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 灵动岛高度 | 36–72px | 胶囊高度;展开卡按同差值联动(`+186/+202/+218px`),内容用 flex 承载且不溢出 |
| 灵动岛宽度 | 220–420px | 同上,展开卡按差值联动(`+156/+172/+188px`) |
| 圆角 | 8–32px | 胶囊取 `min(圆角, h/2)`(WinIsland 胶囊是满圆角);展开卡取 `min(48×圆角/20, w/2, h/2)` |
| 不透明度 | 40%–100% | 窗口整体不透明度(所有显示路径都会应用,含"隐藏后再弹出胶囊") |
| **字号** | **11–20px** | **基础字号**:岛内所有文本 = 基础字号 × 排版系数(标题 1.08 / 正文 0.95 / 次要 0.78 / 徽标与按钮 0.76 / 胶囊标题 0.92 / 胶囊副题 0.74),改一处整体等比缩放 |
| 动画速度 | 0.5×–2× | 形变/淡入时长倍率 |
| 主题色 | 取色器(默认 Apple 系统蓝 `#0a84ff`) | 用于高亮、按钮、进度条、主题色风格(CSS 变量下发到灵动岛渲染进程) |
| **视觉风格** | **纯黑 / 毛玻璃(半透明)/ 主题色渐变** | 纯黑 = WinIsland `default`;毛玻璃 = **CSS 半透明深色卡**(WinIsland 无 host backdrop 时的降级色 `rgba(32,32,36,.804)`)。**不用** `setBackgroundMaterial()`:它是整窗系统材质,会跟随应用主题把卡片外那一圈垫成白底(详见 AGENTS.md §5 第 21 条) |
| **显示位置** | **顶部/底部 × 左/中/右(6 个锚点)** | 按 `workArea` 计算;顶/底决定不动的是上边还是下边,左/中/右决定水平锚点 |
| 动画开关 | 开/关 | 关闭后展开/收起瞬时生效(不再逐帧插值) |
| 始终置顶 | 开/关 | 对应 `setAlwaysOnTop` |
| **空闲细缝** | **开/关(默认关)** | 参考 WinIsland `hidden_width`:开启后没有消息时不再完全隐藏,而是留一条 6px 宽的竖条(窗口是固定包围盒,不受 Windows 最小窗口高度限制) |
- 越界值在**主进程**统一夹紧(`normalizeIslandAppearance`),用户填坏配置也不会让布局错乱。
- 「预览效果」按钮会本地推一条通知,立刻看到当前尺寸/配色/动画。
@@ -670,7 +673,8 @@ pnpm dist:win # nsis 安装包 + portable 单文件(需联网下载 NSIS
| **紧急叫人(URGENT + 叫人)** | ✅ 上课中也立即展开:`mode=expanded kind=call reason=call 徽标=叫人 按钮=收到` |
| **普通叫人(HIGH + 叫人)** | ✅ 上课只进队列:`mode=hidden active≠smoke-call-normal queued=[…smoke-call-normal]`;下课后自动弹出 `active=smoke-call-normal kind=call` |
| **WinIsland 排版:字号即时生效** | ✅ 13px → 19px:胶囊标题 `11.96→17.48`、胶囊副题 `9.62→14.06`、标题 `14.04→20.52`、正文 `12.35→18.05`、按钮 `9.88→14.44`,**倍率全部 1.462 = 19/13** |
| **WinIsland 风格:三种底即时切换** | ✅ 纯黑 `fill=rgb(0,0,0)`/材质 `none`;毛玻璃 `fill=rgba(10,10,14,.59)`/材质 **`acrylic`**;主题色 `fill=rgb(11,11,15)` |
| **WinIsland 风格:三种底即时切换** | ✅ 纯黑 `fill=rgb(0,0,0)`;毛玻璃 `fill=rgba(32,32,36,.804)`;主题色 `fill=rgb(11,11,15)` |
| **卡片外圈不透底(无白底面板)** | ✅ 三种风格都**整屏截图**取证(岛下垫已知色底板):环亮度 = 底板亮度、差 0、近场白底像素 0;把 `setBackgroundMaterial()` 加回去立刻复现 环=255/148/255(差 231/124/252、白底像素 7000+) |
| **WinIsland 空闲细缝** | ✅ 空闲时岛收成 `6x22`(窗口固定,不再受 Windows 36px 最小窗口高度限制)→ 来消息自动回到 `268x44`;关闭细缝后空闲 `isVisible=false` |
| **个性化:透明度 / 主题色** | ✅ `setOpacity` 实际 **0.62**(设置 0.62);`--island-accent` = `#ff7043` |
| **个性化:停靠位置(6 个锚点)** | ✅ 左上 `8,8` / 右上 `1216,8` / 底部居中 `586,800` / 底部左 / 底部右 / 顶部居中 `586,8` |
@@ -704,6 +708,8 @@ pnpm dist:win # nsis 安装包 + portable 单文件(需联网下载 NSIS
教室机器上只做"看作业 + 录作业"(服务端的完成数据与统计接口保持不变,Web 端照旧可用)。
- 录入时可以点**快捷短语**(默认 `P` / `大本` / `小本` / `卷子` / `背诵` / `默写` / `听写` / `预习` / `订正` / `读书`),
点一下追加到标题或内容;短语在客户端「设置 → 作业录入」里增删,存在本机配置里。
- **课间**:镜像回 ClassIsland 的课表按「每两节之间一段课间、最后一节之后不补」生成作息;
服务端合成的节次时间表(没有导入时间表时的兜底)也是同一口径。
- 接口:`GET /homeworks?date=YYYY-MM-DD`(按天)、`GET /homeworks/days?classId=&from=&to=`(哪些天有作业)、
`POST /homeworks`(附 `assignDate`;**班级账号也能调用**,用于教室机器录入)。
@@ -1348,12 +1354,12 @@ pnpm db:migrate && pnpm db:seed
阶段 11(参考 WinIsland 重写灵动岛)新增文件:
| 路径 | 说明 |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `docs/winisland-design-tokens.md` | 从 WinIsland 源码逐条提取的设计 token(几何/配色/排版/层级/布局/图标 + 动效与设置模型) |
| `packages/desktop-client/src/island/squircle.ts` | 连续圆角(超椭圆角)路径生成,对齐 WinIsland `utils/shape.rs` 的 continuous rounded rect |
| `packages/desktop-client/src/island/IslandApp.vue` | 灵动岛 UI 全量重写:squircle + 三种底 + Apple 系统色 + 字号系数驱动的排版 + 无回弹过渡 |
| `packages/desktop-client/src/main/island.ts` | 固定包围盒窗口、6 锚点、空闲细缝、亚克力材质、鼠标命中开关;岛尺寸增量与渲染层共用同一常量表 |
| 路径 | 说明 |
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `docs/winisland-design-tokens.md` | 从 WinIsland 源码逐条提取的设计 token(几何/配色/排版/层级/布局/图标 + 动效与设置模型) |
| `packages/desktop-client/src/island/squircle.ts` | 连续圆角(超椭圆角)路径生成,对齐 WinIsland `utils/shape.rs` 的 continuous rounded rect |
| `packages/desktop-client/src/island/IslandApp.vue` | 灵动岛 UI 全量重写:squircle + 三种底 + Apple 系统色 + 字号系数驱动的排版 + 无回弹过渡 |
| `packages/desktop-client/src/main/island.ts` | 固定包围盒窗口、6 锚点、空闲细缝、鼠标命中开关;岛尺寸增量与渲染层共用同一常量表(**刻意不设窗口背景材质**,见 AGENTS.md §7) |
阶段 10(学生端班级账号)新增文件: