Skip to content

Commit ff7ccec

Browse files
committed
feat(theme): 增加多主题支持与主题切换功能
- 添加多种预设主题(暗色、Monokai、Dracula、GitHub Light/Dark、GitLab Light/Dark) - 支持自定义主题颜色并保存至 settings.json,实现个性化调色 - 在 AppContext 中提供主题版本、当前预设和主题切换相关接口 - 实现主题预览、切换和回退功能,动态更新终端界面主题 - 修改应用入口 AppContainer,集成主题状态管理与持久化逻辑 - 在 PromptInput 添加主题切换相关回调和状态支持,集成主题选择组件 - 替换原有 Static 为支持主题的 ThemeableStatic,提升界面一致性 - 优化退出逻辑,新增结构化退出总结视图呈现 - 增加颜色令牌 textBright,丰富主题色彩层次 - 更新文档说明,详细介绍主题配置、预设主题及运行时主题切换操作 - 优化权限提示颜色映射,统一使用主题色配置 - DropdownMenu 支持禁用项及自定义标签颜色,增强菜单表达能力
1 parent 3358ca8 commit ff7ccec

25 files changed

Lines changed: 999 additions & 170 deletions

docs/configuration.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,85 @@ MCP(Model Context Protocol)服务器配置。值是键值对,键为服务
128128
详细 MCP 使用说明请参考 [mcp.md](mcp.md)
129129

130130

131+
#### `theme` — 主题配置
132+
133+
Deep Code 支持自定义主题颜色,让你的终端界面更符合个人喜好。
134+
135+
**使用预设主题**
136+
137+
```json
138+
{
139+
"theme": {
140+
"preset": "dark"
141+
}
142+
}
143+
```
144+
145+
可用的预设主题:
146+
147+
| 预设名称 | 说明 |
148+
| --------------- | ------------------------------ |
149+
| `light` | 浅色主题(默认,浅色背景优化) |
150+
| `dark` | 暗色主题(深色背景优化) |
151+
| `github-light` | GitHub Light 风格主题 |
152+
| `github-dark` | GitHub Dark 风格主题 |
153+
| `gitlab-light` | GitLab Light 风格主题 |
154+
| `gitlab-dark` | GitLab Dark 风格主题 |
155+
| `monokai` | Monokai 风格主题 |
156+
| `dracula` | Dracula 风格主题 |
157+
158+
**自定义主题颜色**
159+
160+
使用 `preset: "custom"` 并通过 `overrides` 覆盖部分颜色:
161+
162+
```json
163+
{
164+
"theme": {
165+
"preset": "custom",
166+
"overrides": {
167+
"primary": "#ff6600",
168+
"success": "greenBright"
169+
}
170+
}
171+
}
172+
```
173+
174+
**可用的颜色 Token**
175+
176+
| Token | 说明 | 默认值 |
177+
| ------------ | -------------------------------------------- | ---------- |
178+
| `primary` | 品牌色:Logo、用户消息、选中项、标题 | `#229ac3` |
179+
| `secondary` | 辅助品牌色:边框、渐变 | `#229ac3e6`|
180+
| `success` | 成功:工具执行成功、低风险操作 | `#1a7f37` |
181+
| `error` | 错误:工具执行失败、高风险操作 | `#d1242f` |
182+
| `warning` | 警告:进行中状态、中风险操作 | `#fa8c16` |
183+
| `info` | 信息:技能、图片附件 | `#0969da` |
184+
| `text` | 主文字颜色 | `#3D4149` |
185+
| `textDim` | 次要文字:暗化提示、引用块 | `#646A71` |
186+
| `textBright` | 亮色文字:强调提示 | `#1F2329` |
187+
| `code` | 代码块/内联代码 | `#787f8a` |
188+
| `border` | 边框 | `#999` |
189+
| `gradients` | Logo 渐变色数组 | `["#229ac3", "#8250df"]` |
190+
191+
颜色值支持以下格式:
192+
- Hex 格式:`"#ff6600"``"#ff6600cc"`(带透明度)
193+
- Chalk 命名颜色:`"greenBright"``"cyanBright"``"red"`
194+
195+
**运行时切换主题**
196+
197+
在 CLI 中使用 `/theme` 命令可以快速切换预设主题:
198+
199+
```
200+
/theme # 显示主题选择器
201+
/theme dark # 切换到暗色主题
202+
/theme light # 切换回浅色主题
203+
/theme github-dark # 切换到 GitHub Dark 主题
204+
/theme gitlab-light # 切换到 GitLab Light 主题
205+
/theme monokai # 切换到 Monokai 主题
206+
```
207+
208+
切换后会自动保存到 `settings.json`,下次启动时生效。
209+
131210
#### `debugLogEnabled` — 调试日志
132211

133212
设为 `true` 可让程序输出详细的调试日志(默认 `false`),用于排查 API 调用和工具执行的问题。

docs/configuration_en.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,85 @@ Configuration for MCP (Model Context Protocol) servers. The value is a key-value
127127
128128
For detailed MCP usage instructions, refer to [mcp.md](mcp.md).
129129

130+
#### `theme` — Theme Configuration
131+
132+
Deep Code supports customizing theme colors to make your terminal interface match your personal preferences.
133+
134+
**Using Preset Themes**
135+
136+
```json
137+
{
138+
"theme": {
139+
"preset": "dark"
140+
}
141+
}
142+
```
143+
144+
Available preset themes:
145+
146+
| Preset Name | Description |
147+
| --------------- | ---------------------------------------- |
148+
| `light` | Light theme (default, optimized for light backgrounds) |
149+
| `dark` | Dark theme (optimized for dark backgrounds) |
150+
| `github-light` | GitHub Light style theme |
151+
| `github-dark` | GitHub Dark style theme |
152+
| `gitlab-light` | GitLab Light style theme |
153+
| `gitlab-dark` | GitLab Dark style theme |
154+
| `monokai` | Monokai-style theme |
155+
| `dracula` | Dracula-style theme |
156+
157+
**Custom Theme Colors**
158+
159+
Use `preset: "custom"` with `overrides` to customize specific colors:
160+
161+
```json
162+
{
163+
"theme": {
164+
"preset": "custom",
165+
"overrides": {
166+
"primary": "#ff6600",
167+
"success": "greenBright"
168+
}
169+
}
170+
}
171+
```
172+
173+
**Available Color Tokens**
174+
175+
| Token | Description | Default Value |
176+
| ------------ | ------------------------------------------------ | ------------- |
177+
| `primary` | Brand color: logo, user messages, selected items, headings | `#229ac3` |
178+
| `secondary` | Auxiliary brand color: borders, gradients | `#229ac3e6` |
179+
| `success` | Success: tool execution success, low-risk ops | `#1a7f37` |
180+
| `error` | Error: tool execution failure, high-risk ops | `#d1242f` |
181+
| `warning` | Warning: in-progress state, mid-risk ops | `#fa8c16` |
182+
| `info` | Info: skills, image attachments | `#0969da` |
183+
| `text` | Main text color | `#3D4149` |
184+
| `textDim` | Secondary text: dimmed hints, quote blocks | `#646A71` |
185+
| `textBright` | Bright text: emphasized hints | `#1F2329` |
186+
| `code` | Code blocks / inline code | `#787f8a` |
187+
| `border` | Borders | `#999` |
188+
| `gradients` | Logo gradient color array | `["#229ac3", "#8250df"]` |
189+
190+
Color values support the following formats:
191+
- Hex format: `"#ff6600"`, `"#ff6600cc"` (with alpha)
192+
- Chalk named colors: `"greenBright"`, `"cyanBright"`, `"red"`, etc.
193+
194+
**Runtime Theme Switching**
195+
196+
Use the `/theme` command in the CLI to quickly switch preset themes:
197+
198+
```
199+
/theme # Show theme picker
200+
/theme dark # Switch to dark theme
201+
/theme light # Switch back to light theme
202+
/theme github-dark # Switch to GitHub Dark theme
203+
/theme gitlab-light # Switch to GitLab Light theme
204+
/theme monokai # Switch to Monokai theme
205+
```
206+
207+
The switch is automatically saved to `settings.json` and will take effect on the next launch.
208+
130209
#### `debugLogEnabled` — Debug Log
131210

132211
Set to `true` to enable detailed debug logging (default `false`), useful for troubleshooting API calls and tool execution.

src/common/update-check.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as path from "path";
66
import { render, type Instance } from "ink";
77
import chalk from "chalk";
88
import { UpdatePrompt, type UpdatePromptChoice } from "../ui";
9-
import { DEFAULT_THEME } from "../ui/theme/presets";
9+
import { LIGHT_THEME } from "../ui/theme/presets";
1010
import { killProcessTree } from "./process-tree";
1111

1212
export type PackageInfo = {
@@ -59,7 +59,7 @@ export async function promptForPendingUpdate(packageInfo: PackageInfo): Promise<
5959
if (ok) {
6060
writeUpdateState({ ...state, pending: null });
6161
process.stdout.write(
62-
`\n${chalk.hex(DEFAULT_THEME.error)("Deep Code has been updated. Please restart the CLI to use the new version.")}\n\n`
62+
`\n${chalk.hex(LIGHT_THEME.error)("Deep Code has been updated. Please restart the CLI to use the new version.")}\n\n`
6363
);
6464
}
6565
return { installed: ok };
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import { test } from "node:test";
22
import assert from "node:assert/strict";
33
import { getScopeRiskColor } from "../ui/views/PermissionPrompt";
4+
import { LIGHT_THEME } from "../ui/theme";
45

56
test("getScopeRiskColor maps permission scopes by risk", () => {
6-
assert.equal(getScopeRiskColor("read-in-cwd"), "#52c41a");
7-
assert.equal(getScopeRiskColor("query-git-log"), "#52c41a");
7+
assert.equal(getScopeRiskColor("read-in-cwd"), LIGHT_THEME.success);
8+
assert.equal(getScopeRiskColor("query-git-log"), LIGHT_THEME.success);
89

9-
assert.equal(getScopeRiskColor("read-out-cwd"), "#faad14");
10-
assert.equal(getScopeRiskColor("write-in-cwd"), "#faad14");
11-
assert.equal(getScopeRiskColor("network"), "#faad14");
12-
assert.equal(getScopeRiskColor("mcp"), "#faad14");
10+
assert.equal(getScopeRiskColor("read-out-cwd"), LIGHT_THEME.warning);
11+
assert.equal(getScopeRiskColor("write-in-cwd"), LIGHT_THEME.warning);
12+
assert.equal(getScopeRiskColor("network"), LIGHT_THEME.warning);
13+
assert.equal(getScopeRiskColor("mcp"), LIGHT_THEME.warning);
1314

14-
assert.equal(getScopeRiskColor("write-out-cwd"), "#ff4d4f");
15-
assert.equal(getScopeRiskColor("delete-in-cwd"), "#ff4d4f");
16-
assert.equal(getScopeRiskColor("delete-out-cwd"), "#ff4d4f");
17-
assert.equal(getScopeRiskColor("mutate-git-log"), "#ff4d4f");
18-
assert.equal(getScopeRiskColor("unknown"), "#ff4d4f");
15+
assert.equal(getScopeRiskColor("write-out-cwd"), LIGHT_THEME.error);
16+
assert.equal(getScopeRiskColor("delete-in-cwd"), LIGHT_THEME.error);
17+
assert.equal(getScopeRiskColor("delete-out-cwd"), LIGHT_THEME.error);
18+
assert.equal(getScopeRiskColor("mutate-git-log"), LIGHT_THEME.error);
19+
assert.equal(getScopeRiskColor("unknown"), LIGHT_THEME.error);
1920
});

src/tests/slash-commands.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ test("buildSlashCommands prefixes skills before built-ins", () => {
2222
assert.deepEqual(builtinNames, [
2323
"skills",
2424
"model",
25+
"theme",
2526
"new",
2627
"init",
2728
"resume",
@@ -105,6 +106,13 @@ test("findExactSlashCommand returns built-in /raw", () => {
105106
assert.equal(item?.kind, "raw");
106107
});
107108

109+
test("findExactSlashCommand returns built-in /theme", () => {
110+
const items = buildSlashCommands(skills);
111+
const item = findExactSlashCommand(items, "/theme");
112+
assert.ok(item);
113+
assert.equal(item?.kind, "theme");
114+
});
115+
108116
test("findExactSlashCommand returns the matching skill", () => {
109117
const items = buildSlashCommands(skills);
110118
const item = findExactSlashCommand(items, "/code-review");

0 commit comments

Comments
 (0)