feat: 自定义皮肤模板(导出/最小模板脚手架/通用调色板导入)
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 401
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
### 使用场景 / Use case
我希望能给 Cindy 做一套自定义的「皮肤模板」——基于品牌色或个人偏好,生成一套完整、可复用、可分享的主题,而不只是改一两个颜色。例如:调好一套本地主题后一键导出分享给同事;或只给一组主色就自动生成整套配色。
### 当前问题 / Current limitation
读了桌面端源码(`apps/desktop`),Cindy 其实已有较完整的主题体系,但「自定义皮肤模板」对用户仍不友好:
- 本地主题存于 `~/.cindy/themes`(`.json`:`id`/`name`/`type`/`colors`/`brand`),由 `local-themes/{loader,writer,register}.ts` 管理;
- 模板引擎已存在:`theme-import/palette.ts` 的 `buildThemeColorsFromPalette` + `TEMPLATE_TOKEN_IDS`,能把 **13 个色板角色**派生出 **108 个 token** 完整主题,并已支持从 VS Code(`vscode.ts`)、Obsidian(`obsidian.ts`)导入抽取;
- 外观页 `AppearanceSection.tsx` 已有 `Copy`/`Import`/`FolderOpen`/`RefreshCw` 按钮。
但缺口是:
1. **无「导出为模板文件」入口**:调好一套本地主题后无法一键导出可分享的 `.json`,只能去目录手动找文件。
2. **无「空白模板骨架」**:新手想从零做,没有「只填 13 个色板角色即生成完整主题」的引导,需理解 108 个 token。
3. **无通用模板分发形态**:现有导入仅限 VS Code/Obsidian 源,不支持「粘贴一组 hex 色板即生成主题」。
4. **模板与 brand 资源脱节**:`brand.icon`/`logo` 需手动配路径,未纳入「一套皮肤」的整体产物。
### 期望方案 / Proposed solution
1. **一键导出当前主题为模板文件**:扩展 `local-themes/writer.ts` 新增导出 IPC,在 `AppearanceSection.tsx` 加 `Export` 按钮(与 Copy/Import 并列),输出标准 `LocalThemeJson`。
2. **最小模板脚手架**:基于 `palette.ts` 的 `TEMPLATE_TOKEN_IDS` / `buildThemeColorsFromPalette`,提供「只填色板 → 生成完整主题」的引导 UI 或 CLI 骨架。
3. **通用调色板导入**:在 `theme-import/` 增加「raw palette」源(解析 hex 列表),复用 `stripProtectedTokens` 守住语义豁免边界。
4. **复用而非新建**:保持本地主题 `.json` 契约不变,产物落回 `~/.cindy/themes`。
约束:守住 `protected-tokens.ts` 语义豁免族(登录色、品牌红、destructive、focus-ring、diff 等不可被模板覆盖);色板不全时按默认补齐并提示,不报错阻断;不破坏现有内置主题与导入链路。
### 已考虑的替代方案 / Alternatives considered
- **直接手写 `~/.cindy/themes/*.json`**:可行但门槛高,用户需理解 108 个 token 与 protected 边界,无引导、无分享入口——本需求正是补足这层产物化。
- **仅扩展 VS Code/Obsidian 导入**:覆盖不了「粘贴自有调色板 / 分享模板」的场景,通用性不足。
- **在线模板市场/云端同步**:一期范围过大,且涉及账号与分发基础设施;建议先聚焦本地导出+导入,云端后续再做。
- **在线模板市场/云端同步之外的「改组件布局/形态」**:超出 token 主题范畴,不在本需求内。
## 关联
- 模板引擎:`apps/desktop/src/shared/theme-import/{palette,vscode,obsidian,protected-tokens}.ts`
- 本地主题:`apps/desktop/src/main/local-themes/{loader,writer,register}.ts`
- 外观 UI:`apps/desktop/src/renderer/components/settings/AppearanceSection.tsx`
- 主题注册:`apps/desktop/src/renderer/themes/{registry,local-themes}.ts`
## 验收 / Acceptance
- [ ] 外观页可一键导出当前主题为可分享 `.json` 模板。
- [ ] 提供最小模板脚手架:仅填 13 个色板角色即生成完整主题。
- [ ] 支持粘贴通用色板(hex)生成主题,不限于 VS Code/Obsidian 源。
- [ ] 导入/套用受 `protected-tokens` 边界保护。
- [ ] 导出的模板可被他人一键导入并正确呈现。
- [ ] 覆盖基础单测(参考 `theme-import`、`local-themes` 相关测试)。
Contributor guide
Research direction
Start by reading the existing theme flow in apps/desktop/src/shared/theme-import/{palette,vscode,obsidian,protected-tokens}.ts and apps/desktop/src/main/local-themes/{loader,writer,register}.ts. Then inspect AppearanceSection.tsx and the theme registry/local-theme files, along with related theme-import and local-themes tests. Done means export, minimal palette scaffolding, generic hex import, protected-token handling, round-trip import, and baseline tests are covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- desktop, frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100