diff --git a/dash/docs/theme-switching-plan.zh.md b/dash/docs/theme-switching-plan.zh.md new file mode 100644 index 0000000..e658d80 --- /dev/null +++ b/dash/docs/theme-switching-plan.zh.md @@ -0,0 +1,497 @@ +# Kindle Dashboard 多主题切换方案 + +## 1. 背景 + +当前仓库已经具备一条稳定的单主题链路: + +- `calendar/` 负责渲染仪表盘网页,并导出 `kindlebg.png` +- `dash/` 运行在 Kindle 上,按固定 URL 拉取背景图 +- Kindle 本机每分钟只重画时钟区域,不重新联网渲染整页 + +当前关键约束如下: + +- Kindle 端默认只认识一个背景地址:`BACKGROUND_URL` +- 背景图文件名固定为 `kindlebg.png` +- 本机时钟素材与时钟区域参数由 Kindle 本地管理 +- KUAL 菜单当前只有启动和调试入口,没有切换主题入口 + +这意味着“多主题”不能只靠改前端样式,还需要把主题标识、产物路径和 Kindle 侧的选择逻辑一起设计出来。 + +## 2. 目标 + +本方案要解决的问题是: + +1. 访问 `calendar` 网站时,可以通过菜单预览不同主题样式 +2. 现有日历背景生成流程保持兼容,不因预览主题而被破坏 +3. 后续如果需要,`calendar/` 仍能稳定产出多个主题的背景图 +4. Kindle 能在不改代码、不重新部署整套程序的前提下切换当前主题 +5. 主题切换后,下一次背景刷新即可生效 +SH: 主题切换后,即刻拉取一次 +6. 后续如果主题不仅改背景,还改表盘素材与时钟区域,也能平滑扩展 + +非目标: + +- 不在 Kindle 上重新渲染整张日历页 +- 不引入 Kindle 端复杂主题模板引擎 +- 不要求首次版本就支持任意数量主题的自动发现 + +## 3. 设计原则 + +### 3.1 渲染留在 `calendar/` + +推荐继续保持现有职责边界: + +- `calendar/` 负责主题样式、布局、导出 +- Kindle 只负责选择当前主题并拉取对应产物 + +原因: + +- Kindle 算力和调试体验都不适合承载整页主题渲染 +- 当前链路已经验证“远端产图 + 本机分钟级叠时钟”可行 +- 主题扩展主要发生在样式层,天然更适合留在前端工程里 + +### 3.2 Kindle 只保存“当前主题 ID” + +Kindle 端不保存复杂主题配置,只保存一个很小的状态: + +- 当前主题名,例如 `paper` + +围绕这个主题名决定: + +- 去哪个 URL 拉取背景图 +- 使用哪套本地表盘素材 +- 使用哪份时钟区域配置 + +### 3.3 先做“背景主题切换”,再做“完整主题切换” + +建议分两阶段: + +- 阶段 1:只切换背景主题,保持本地表盘素材不变 +- 阶段 2:背景、表盘素材、时钟区域一起切换 + +这样可以先验证交互链路和配置模型,再扩展到完整主题包。 + +### 3.4 预览与导出解耦 + +主题预览只是 `calendar` 网站访问时的交互能力,不应反向改变现有导出主流程。 + +建议明确两条链路: + +- 预览链路:用户访问网站,通过菜单切换 `theme` +- 导出链路:脚本继续按当前默认行为生成 `calendar/dist/kindlebg.png` + +只有在后续正式接入 Kindle 多主题切换时,再额外增加“按主题导出”的产物目录。 + +## 4. 方案总览 + +### 4.1 推荐架构 + +推荐采用“主题目录 + 当前主题状态文件”的方式。 + +远端发布结构: + +```text +https://shell.biboer.cn:20001/themes/paper/kindlebg.png +https://shell.biboer.cn:20001/themes/paper/dashboard-manifest.json +https://shell.biboer.cn:20001/themes/classic/kindlebg.png +https://shell.biboer.cn:20001/themes/classic/dashboard-manifest.json +``` + +Kindle 本地结构: + +```text +/mnt/us/dashboard/local/theme.env +/mnt/us/dashboard/local/themes/paper/ +/mnt/us/dashboard/local/themes/classic/ +``` + +其中: + +- `theme.env` 只记录当前主题 ID +- 每个主题目录可以逐步承载本地专属素材 + +### 4.2 当前主题状态 + +建议新增本地状态文件: + +```sh +export THEME_ID=${THEME_ID:-paper} +``` + +优先级建议如下: + +1. `/mnt/us/dashboard/local/theme.env` +2. `/mnt/us/dashboard/local/env.sh` 中的默认值 +3. 代码里的兜底默认值 + +这样做的好处是: + +- 切换主题不必改主配置文件 +- 主题状态和设备级参数可以分开管理 +- 后续可以由 KUAL 菜单脚本单独改写 `theme.env` + +## 5. `calendar/` 侧改造建议 + +### 5.1 新增 `theme` URL 参数 + +当前已有 `mode` 参数: + +- `/?mode=full` +- `/?mode=background` +- `/?mode=clock-face` + +建议扩展为: + +- `/?mode=full&theme=paper` +- `/?mode=background&theme=paper` +- `/?mode=background&theme=classic` + +约定: + +- `mode` 决定页面用途 +- `theme` 决定视觉主题 + +### 5.2 网站访问时提供主题预览菜单 + +主题预览菜单只服务于网站访问场景,不直接参与背景导出。 + +建议行为: + +1. 用户访问 `/?mode=full` 时,可以在页面菜单中切换主题 +2. 菜单切换只更新当前页面的 `theme` 参数 +3. 可以把当前主题同步到 URL,便于分享和复现 +4. 可以选择是否额外写入 `localStorage`,用于下次访问时记住上次预览主题 + +菜单本身建议只出现在预览页面,不出现在背景导出页面里。 + +也就是说: + +- `/?mode=full&theme=paper` 可以显示主题切换菜单 +- `/?mode=background&theme=paper` 只负责导出背景,不显示菜单 + +### 5.3 主题定义集中管理 + +建议在 `calendar/src/` 下引入统一主题描述,例如: + +```ts +type ThemeId = 'paper' | 'classic' | 'minimal'; + +type DashboardTheme = { + id: ThemeId; + label: string; + clockRegion: { + x: number; + y: number; + width: number; + height: number; + }; + managedOnKindle: boolean; +}; +``` + +主题配置至少要能描述: + +- 主题 ID +- 主题显示名 +- 时钟区域位置与尺寸 +- 是否依赖 Kindle 本地表盘素材 + +### 5.4 保持现有导出流程兼容 + +当前导出主流程建议保持不变: + +```text +calendar/dist/kindlebg.png +calendar/dist/dashboard-manifest.json +calendar/dist/clock-region.json +``` + +默认规则: + +- 如果导出脚本未显式传入 `theme`,就使用默认主题,例如 `paper` +- 继续保留现有 `kindlebg.png` 单产物出口 +- 现有部署和 Kindle 拉图流程无需立刻修改 + +这样可以保证: + +- 先落地网站主题预览能力 +- 不打断当前背景导出与发布链路 +- 后续再增量接入主题化产物 + +### 5.5 多主题导出作为附加能力 + +当需要支持 Kindle 端切换主题时,再额外增加按主题导出的能力,例如: + +```text +calendar/dist/themes/paper/kindlebg.png +calendar/dist/themes/paper/dashboard-manifest.json +calendar/dist/themes/paper/clock-region.json + +calendar/dist/themes/classic/kindlebg.png +calendar/dist/themes/classic/dashboard-manifest.json +calendar/dist/themes/classic/clock-region.json +``` + +这里的重点是“新增”,不是“替换”: + +- 原有 `calendar/dist/kindlebg.png` 继续保留 +- 主题目录产物只用于多主题发布和 Kindle 切换 +- 现有单主题导出脚本不需要被强制改成批量导出 + +建议后续新增独立命令,例如: + +- `export:background` 继续生成默认背景 +- `export:themes` 额外生成多个主题目录 + +### 5.6 `dashboard-manifest.json` 增加主题字段 + +建议每个主题目录下的 manifest 包含: + +```json +{ + "theme": { + "id": "paper", + "label": "Paper" + }, + "background": { + "path": "kindlebg.png", + "url": "https://shell.biboer.cn:20001/themes/paper/kindlebg.png", + "refreshIntervalMinutes": 120 + }, + "clockRegion": { + "x": 262, + "y": 55, + "width": 220, + "height": 220 + }, + "clockFace": { + "path": "assets/clock-face.png", + "managedOnKindle": true + } +} +``` + +核心变化只有两点: + +- 增加 `theme.id` +- 背景 URL 改为带主题目录 + +## 6. Kindle 侧改造建议 + +### 6.1 拉取路径由主题拼装 + +不建议继续把 `BACKGROUND_URL` 写死为单一地址。 + +建议改成两段式配置: + +```sh +export BACKGROUND_BASE_URL=${BACKGROUND_BASE_URL:-"https://shell.biboer.cn:20001/themes"} +export THEME_ID=${THEME_ID:-paper} +``` + +实际拉取地址在运行时拼成: + +```text +$BACKGROUND_BASE_URL/$THEME_ID/kindlebg.png +``` + +这样后续新增主题时,不需要再改 Kindle 端脚本逻辑。 + +### 6.2 增加切换脚本 + +建议新增脚本: + +```text +/mnt/us/dashboard/switch-theme.sh +``` + +行为建议: + +1. 校验主题 ID 是否在允许列表内 +2. 写入 `/mnt/us/dashboard/local/theme.env` +3. 删除或重置背景更新时间戳 +4. 可选:立即重启 `dash.sh`,或等待下一次刷新周期生效 + +其中第 3 步很重要,因为如果不清空背景更新时间,当前缓存可能会延迟两个小时才被新主题替换。 + +### 6.3 KUAL 菜单作为切换入口 + +推荐在 KUAL 菜单里增加主题项,例如: + +```text +Kindle Dashboard +Theme: Paper +Theme: Classic +Theme: Minimal +Dashboard Debug On +Dashboard Debug Off +``` + +这样用户在 Kindle 上就能直接切换当前主题,不依赖 SSH。 + +如果后续主题数量增加到 5 个以上,再考虑改成: + +- 一个“循环切换下一个主题”的脚本 +- 或由脚本生成菜单 JSON + +### 6.4 完整主题包的本地目录 + +当主题不只是改背景,而是还改表盘样式时,建议 Kindle 本地按主题存放资源: + +```text +/mnt/us/dashboard/local/themes/paper/clock-region.env +/mnt/us/dashboard/local/themes/paper/assets/clock-face.png +/mnt/us/dashboard/local/themes/paper/assets/hour-hand/000.png +/mnt/us/dashboard/local/themes/paper/assets/minute-hand/00.png + +/mnt/us/dashboard/local/themes/classic/clock-region.env +/mnt/us/dashboard/local/themes/classic/assets/clock-face.png +``` + +切换主题时同时切换: + +- 背景拉取路径 +- 本地时钟素材根目录 +- 时钟区域参数 + +## 7. 两种落地级别 + +### 7.1 级别 A:只切背景 + +适用场景: + +- 多个主题只改卡片风格、字体、配色、排版 +- 所有主题共用同一套 Kindle 本地表盘素材 + +优点: + +- 改动最小 +- 风险最低 +- 最快落地 + +限制: + +- 不支持不同主题使用不同表盘位置或不同指针样式 + +### 7.2 级别 B:完整主题切换 + +适用场景: + +- 不同主题拥有不同表盘造型 +- 时钟区域位置和尺寸可能变化 +- 指针、刻度、中心点等素材也需要按主题变化 + +优点: + +- 主题能力完整 +- 页面视觉更统一 + +成本: + +- Kindle 本地资源管理会更复杂 +- 切换时需要同步处理更多状态 + +## 8. 推荐实施顺序 + +建议分四步推进。 + +### 第一步:引入主题 ID,但只做单主题兼容 + +目标: + +- 网站访问时支持 `theme` +- 增加主题预览菜单 +- 默认主题仍然只有 `paper` + +结果: + +- 用户可以在网站上切换预览主题 +- 现有背景导出行为保持不变 + +### 第二步:产出双主题背景 + +目标: + +- 增加可选的按主题导出能力 +- `calendar/` 能同时生成两个主题目录 +- 发布层能稳定提供两组 URL + +结果: + +- 远端资源准备完成 +- 现有默认导出链路仍可继续使用 + +### 第三步:Kindle 支持背景主题切换 + +目标: + +- 增加 `theme.env` +- 增加 `switch-theme.sh` +- 增加 KUAL 菜单入口 + +结果: + +- 用户可以在 Kindle 上切换背景主题 + +### 第四步:扩展到完整主题包 + +目标: + +- 将时钟素材和时钟区域配置也按主题管理 + +结果: + +- 主题系统从“背景切换”升级为“完整主题切换” + +## 9. 风险与约束 + +### 9.1 主题切换后的缓存失效 + +如果只改了主题 ID,但没有重置背景更新时间戳,Kindle 可能继续显示旧主题缓存。 + +因此切换脚本必须显式清理以下状态之一: + +- `/mnt/us/dashboard/local/state/background-updated-at` +- 或缓存背景文件本身 + +### 9.2 主题数量增长后的菜单维护 + +若主题数较多,手写 KUAL 菜单会越来越笨重。 + +到那时建议: + +- 用一个脚本根据主题清单生成菜单 +- 或保留“下一个主题”这种单按钮切换方式 + +### 9.3 远端发布必须保持目录稳定 + +一旦 Kindle 端按 `/themes//kindlebg.png` 约定拉图,发布层就必须保持目录和文件名稳定,否则会出现主题切换后 404。 + +## 10. 推荐结论 + +推荐采用下面这条路线: + +1. 保持“`calendar/` 渲染,Kindle 只拉图和切换主题 ID”的职责边界 +2. 先实现网站访问时的主题预览菜单,并保持现有导出流程不变 +3. 再增量接入“背景主题切换” +4. 等确认交互和运维链路稳定后,再升级到“完整主题包” + +这个路线最符合当前仓库的实际状态: + +- 复用现有 `mode` 和导出链路 +- 不会打断当前 `kindlebg.png` 生成与发布流程 +- 对 Kindle 主循环改动小 +- 不会把主题复杂度压到 Kindle 设备上 +- 后续也能自然扩展到本地表盘素材切换 + +## 11. 待确认问题 + +进入实现前,建议先明确这几个评审点: + +1. 网站预览菜单放在哪个区域最合适,是否只在 `mode=full` 显示 +2. 第一阶段是否只做 2 个主题,例如 `paper` 和 `classic` +3. 第一阶段主题是否允许改变时钟区域位置 +4. KUAL 菜单是否接受“每个主题一个菜单项”的交互形式 +5. 远端发布目录是否可以稳定提供 `/themes//kindlebg.png` + +如果以上五点都确认,本方案可以直接拆成小步实现。