pi-web-ui 0.91.0 → 0.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/bin/pi-web-ui.mjs +21 -2
  3. package/dist/server/agent-service.js +443 -45
  4. package/dist/server/claim-files-tool.js +116 -0
  5. package/dist/server/claim-store.js +301 -0
  6. package/dist/server/client-state.js +49 -0
  7. package/dist/server/conversation-read-tool.js +369 -27
  8. package/dist/server/conversation-touches.js +357 -0
  9. package/dist/server/dsh/dsh-agent-service.js +7 -0
  10. package/dist/server/index.js +32 -4
  11. package/dist/server/model-admin.js +124 -2
  12. package/dist/server/model-enrich.js +478 -0
  13. package/dist/server/plugin-schedule.js +27 -2
  14. package/dist/server/plugins.js +65 -10
  15. package/dist/server/present-files-tool.js +303 -0
  16. package/dist/server/read-tool.js +91 -0
  17. package/dist/server/serialize.js +21 -1
  18. package/dist/server/settings-service.js +7 -0
  19. package/dist/server/text-sniff.js +15 -0
  20. package/dist/server/themes.js +17 -2
  21. package/dist/server/tool-manager.js +7 -1
  22. package/package.json +1 -1
  23. package/plugin-sdk/README.md +1 -0
  24. package/plugins/catalog.json +10 -0
  25. package/themes/catppuccin-latte.css +136 -0
  26. package/themes/catppuccin.css +140 -0
  27. package/themes/nord.css +130 -0
  28. package/themes/one-dark.css +131 -0
  29. package/themes/paper.css +12 -12
  30. package/themes/solarized-light.css +131 -0
  31. package/themes/tokyo-night.css +140 -0
  32. package/web/dist/assets/{TerminalPanel-GtDQ1h85.js → TerminalPanel-RACpk6AX.js} +1 -1
  33. package/web/dist/assets/index-BgrnP9Jz.js +364 -0
  34. package/web/dist/assets/index-Cy8dSTZt.css +1 -0
  35. package/web/dist/index.html +2 -2
  36. package/web/dist/assets/index-CdsKltOS.css +0 -1
  37. package/web/dist/assets/index-OoULNF70.js +0 -363
@@ -20,6 +20,10 @@ const PREVIEW_IMAGE_EXTS = new Set([
20
20
  "tiff",
21
21
  ]);
22
22
  const PREVIEW_VIDEO_EXTS = new Set(["mp4", "webm", "mov", "mkv", "avi", "m4v", "ogv", "mpg", "mpeg", "wmv", "flv"]);
23
+ /** 浏览器 <audio> 能直接播放的音频容器(present_files 的卡片与 /api/file 白名单
24
+ * 共用这一份):不在表里的(wma/aiff/midi/…)一律按二进制处理,让用户下载或
25
+ * 本地打开,而不是给一个永远播不出来的播放器。 */
26
+ const PREVIEW_AUDIO_EXTS = new Set(["mp3", "wav", "wave", "ogg", "oga", "opus", "m4a", "aac", "flac", "weba"]);
23
27
  const PREVIEW_TEXT_EXTS = new Set([
24
28
  // code
25
29
  "ts",
@@ -151,6 +155,17 @@ export function previewKind(name) {
151
155
  return "text";
152
156
  return "none";
153
157
  }
158
+ /**
159
+ * 扩展名是否为浏览器可直接播放的音频。与 previewKind 分开:PreviewKind 只有
160
+ * image/video/text/none 四档(右栏图标、附件、预览弹窗都按它分支),把音频塞进去
161
+ * 要动整条链路;而 /api/file 的媒体白名单与 present_files 的卡片只需要一个
162
+ * 「能不能 inline 播」的布尔判断。
163
+ */
164
+ export function isAudioFile(name) {
165
+ const dot = name.lastIndexOf(".");
166
+ const ext = dot > 0 ? name.slice(dot + 1).toLowerCase() : "";
167
+ return PREVIEW_AUDIO_EXTS.has(ext);
168
+ }
154
169
  /**
155
170
  * Content sniff for the preview: any data that has no NUL bytes and no
156
171
  * meaningful control-char ratio is treated as text — so files with unknown
@@ -22,9 +22,10 @@ const ID_RE = /^[A-Za-z0-9_-]+$/;
22
22
  * filename stays ASCII (id must match ID_RE). */
23
23
  const THEME_NAME_RE = /\/\*\s*theme-name:\s*(.+?)\s*\*\//;
24
24
  const THEME_NAME_EN_RE = /\/\*\s*theme-name-en:\s*(.+?)\s*\*\//;
25
+ const THEME_GROUP_RE = /\/\*\s*theme-group:\s*(.+?)\s*\*\//;
25
26
  function readDisplayName(path, fallback) {
26
27
  try {
27
- const head = readFileSync(path, "utf8").slice(0, 300);
28
+ const head = readFileSync(path, "utf8").slice(0, 400);
28
29
  return head.match(THEME_NAME_RE)?.[1]?.trim() || fallback;
29
30
  }
30
31
  catch {
@@ -33,13 +34,25 @@ function readDisplayName(path, fallback) {
33
34
  }
34
35
  function readDisplayNameEn(path) {
35
36
  try {
36
- const head = readFileSync(path, "utf8").slice(0, 300);
37
+ const head = readFileSync(path, "utf8").slice(0, 400);
37
38
  return head.match(THEME_NAME_EN_RE)?.[1]?.trim() || undefined;
38
39
  }
39
40
  catch {
40
41
  return undefined;
41
42
  }
42
43
  }
44
+ function readGroup(path) {
45
+ try {
46
+ const head = readFileSync(path, "utf8").slice(0, 400);
47
+ const g = head.match(THEME_GROUP_RE)?.[1]?.trim();
48
+ if (g === "classic")
49
+ return "classic";
50
+ }
51
+ catch {
52
+ // ignore
53
+ }
54
+ return "builtin";
55
+ }
43
56
  export function listThemes(builtinDir, userDir) {
44
57
  const scan = (dir, builtin) => {
45
58
  if (!existsSync(dir))
@@ -53,10 +66,12 @@ export function listThemes(builtinDir, userDir) {
53
66
  const id = f.slice(0, -4);
54
67
  const name = readDisplayName(path, id);
55
68
  const nameEn = readDisplayNameEn(path);
69
+ const group = readGroup(path);
56
70
  return {
57
71
  id,
58
72
  name,
59
73
  builtin,
74
+ group,
60
75
  ...(nameEn ? { nameEn } : {}),
61
76
  };
62
77
  });
@@ -58,9 +58,12 @@ export const SKILL_TOOL_NAME = "skill";
58
58
  export const SCHEDULE_TASK_TOOL_NAME = "schedule_task";
59
59
  export const SCHEDULE_LIST_TOOL_NAME = "schedule_list";
60
60
  export const SCHEDULE_CANCEL_TOOL_NAME = "schedule_cancel";
61
+ /** 展示文件工具(定义见 present-files-tool.ts):把图片/视频/文本作为预览卡片
62
+ * 推到对话里,卡片带预览/本地打开/在文件夹中显示/下载/复制路径。 */
63
+ export const PRESENT_FILES_TOOL_NAME = "present_files";
61
64
  /** 旧工具名(持久化迁移用;新代码一律用 MARKERS_LIST_TOOL_NAME)。 */
62
65
  export const LEGACY_MARKERS_LIST_TOOL_NAME = "markers_list";
63
- /** 可开关的 Agent 工具总目录(共 24 个;bash 本体与 SDK 内置 edit/read
66
+ /** 可开关的 Agent 工具总目录(共 25 个;bash 本体与 SDK 内置 edit/read
64
67
  * 不进目录——关了 agent 就残了,不给关)。 */
65
68
  export const AGENT_TOOL_CATALOG = [
66
69
  ...TERMINAL_TOOL_NAMES.map((name) => ({
@@ -92,6 +95,9 @@ export const AGENT_TOOL_CATALOG = [
92
95
  { name: SCHEDULE_TASK_TOOL_NAME, group: "other", defaultOn: true, dshVisible: false },
93
96
  { name: SCHEDULE_LIST_TOOL_NAME, group: "other", defaultOn: true, dshVisible: false },
94
97
  { name: SCHEDULE_CANCEL_TOOL_NAME, group: "other", defaultOn: true, dshVisible: false },
98
+ // 展示文件给用户(图片/视频内联、文本开预览弹窗、本地打开按钮):默认开,
99
+ // 不打开模型根本不知道能“给用户看”;DSH 引擎没有该 customTool(走 shipped preset)。
100
+ { name: PRESENT_FILES_TOOL_NAME, group: "other", defaultOn: true, dshVisible: false },
95
101
  ];
96
102
  const KNOWN_NAMES = new Set(AGENT_TOOL_CATALOG.map((t) => t.name));
97
103
  /** 是否为本表登记的可开关工具(未知名一律 false,不抛错)。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-web-ui",
3
- "version": "0.91.0",
3
+ "version": "0.92.0",
4
4
  "description": "Just open your browser to get all your work done — browser cockpit for AI coding agents (chat, code, files, terminal, Git in one tab)",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -120,6 +120,7 @@ describe("my-plugin", () => {
120
120
  | `kind: "select"` + `options` + `value`,`host.ui.update(id, { value })` 刷新 | ✅ | 顶栏/输入框/消息工具条已渲染 |
121
121
  | `when` 肯定形条件(`file.isDir` / `file.isFile` / `session.isRunning` / `message.hasSelection`) | — | 右键菜单现场求值,置灰 |
122
122
  | `settings` 新增 `secret` 类型(加密存,浏览器只见有无) | ✅ | 设置表单掩码 + 留空不改 |
123
+ | `settings` 的 `select` 支持 `optionsFrom`(宿主现算候选值:`models` / `thinkingLevels`) | ✅ | 下拉自动带「跟随全局默认」 |
123
124
  | `host.llm.complete`(孤立无工具补全,不建对话) | ✅(要 `llm` 能力族) | — |
124
125
  | `schedule` 持久版(`{id, persistent, catchUp, label}`,落盘+补跑+进后台面板) | ✅ | — |
125
126
  | `host.requestPermission`(动态授权:net 补主机 / llm 限模型,用户逐条确认可记住) | ✅(基础族须已声明) | 确认框 + 设置面板「已授权能力」 |
@@ -98,5 +98,15 @@
98
98
  "descriptionEn": "Image workbench: compress (with target-size binary search), crop, resize, rotate/flip, format conversion (PNG/JPEG/WebP/AVIF), batch ZIP export, watermark, filters, image info + EXIF, and direct workspace read/write. Ships 4 AI tools so the agent can compress/crop/resize/watermark workspace images itself.",
99
99
  "source": "xing-shuyin/pi-web-ui/plugins/image-toolkit",
100
100
  "homepage": "https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/image-toolkit"
101
+ },
102
+ {
103
+ "id": "notes",
104
+ "name": "笔记",
105
+ "icon": "📓",
106
+ "iconSvg": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 1024 1024\"><path d=\"M746.666667 64a170.666667 170.666667 0 0 1 170.666666 170.666667v554.666666a170.666667 170.666667 0 0 1-170.666666 170.666667H298.666667a170.666667 170.666667 0 0 1-170.666667-170.666667V234.666667a170.666667 170.666667 0 0 1 170.666667-170.666667h448z m0 74.666667H298.666667a96 96 0 0 0-95.893334 91.477333L202.666667 234.666667v554.666666a96 96 0 0 0 91.477333 95.893334L298.666667 885.333333h448a96 96 0 0 0 95.893333-91.477333L842.666667 789.333333V234.666667a96 96 0 0 0-91.477334-95.893334L746.666667 138.666667z\" fill=\"currentColor\"/><path d=\"M224 325.333333a37.333333 37.333333 0 0 1 3.072 74.538667l-3.072 0.128H106.666667a37.333333 37.333333 0 0 1-3.072-74.538667L106.666667 325.333333h117.333333zM224 624a37.333333 37.333333 0 0 1 3.072 74.538667l-3.072 0.128H106.666667a37.333333 37.333333 0 0 1-3.072-74.538667L106.666667 624h117.333333zM693.333333 346.666667a37.333333 37.333333 0 0 1 37.205334 34.261333l0.128 3.072v256a37.333333 37.333333 0 0 1-74.538667 3.072L656 640V384c0-20.608 16.725333-37.333333 37.333333-37.333333z\" fill=\"currentColor\"/></svg>",
107
+ "description": "随手记:笔记 + 待办 + 日程提醒三合一。顶栏按钮打开可自由拖拽的全局浮窗(位置/尺寸记忆,设置也在浮窗里,无独立视图页);提醒走服务端定时(重启不丢、错过补送),另有 5 个 AI 工具与 /note /todo /remind 快速捕获。",
108
+ "descriptionEn": "Notes, todos and scheduled reminders in one place: a freely draggable always-on-top panel (position, size and settings all live in it, no separate view tab); reminders fire server-side (survive restarts, delivered on next open), with 5 AI tools and /note /todo /remind quick capture.",
109
+ "source": "xing-shuyin/pi-web-ui/plugins/notes",
110
+ "homepage": "https://github.com/xing-shuyin/pi-web-ui/tree/main/plugins/notes"
101
111
  }
102
112
  ]
@@ -0,0 +1,136 @@
1
+ /* theme-name: Catppuccin 浅色 */
2
+ /* theme-name-en: Catppuccin Latte */
3
+ /* theme-group: classic */
4
+ :root {
5
+ color-scheme: light;
6
+ --bg: #eff1f5;
7
+ --bg-elev: #e6e9ef;
8
+ --bg-elev2: #dce0e8;
9
+ --border: #ccd0da;
10
+ --border-soft: #bcc0cc;
11
+ --text: #4c4f69;
12
+ --text-dim: #6c6f85;
13
+ --text-faint: #8c8fa1;
14
+ --accent: #1e66f5;
15
+ --accent-soft: rgba(30, 102, 245, 0.12);
16
+ --green: #40a02b;
17
+ --green-soft: rgba(64, 160, 43, 0.12);
18
+ --red: #d20f39;
19
+ --red-soft: rgba(210, 15, 57, 0.1);
20
+ --amber: #df8e1d;
21
+ --term-bg: #eff1f5;
22
+ --term-fg: #4c4f69;
23
+ --term-cursor: #dc8a78;
24
+ --term-cursor-accent: #eff1f5;
25
+ --term-selection: rgba(172, 176, 190, 0.35);
26
+ --term-black: #5c5f77;
27
+ --term-red: #d20f39;
28
+ --term-green: #40a02b;
29
+ --term-yellow: #df8e1d;
30
+ --term-blue: #1e66f5;
31
+ --term-magenta: #8839ef;
32
+ --term-cyan: #179299;
33
+ --term-white: #4c4f69;
34
+ --term-bright-black: #8c8fa1;
35
+ --term-bright-red: #d20f39;
36
+ --term-bright-green: #40a02b;
37
+ --term-bright-yellow: #df8e1d;
38
+ --term-bright-blue: #1e66f5;
39
+ --term-bright-magenta: #8839ef;
40
+ --term-bright-cyan: #179299;
41
+ --term-bright-white: #3c3e53;
42
+ --mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
43
+ --mermaid-font-size: 12px;
44
+ --tooltip-bg: #ffffff;
45
+ --code-bg: #e6e9ef;
46
+ --code-text: #4c4f69;
47
+ --code-border: var(--border-soft);
48
+ --code-pad: 8px 10px;
49
+ --card-body-pad: 4px 14px 12px;
50
+ --err-text: #d20f39;
51
+ --red-text: #d20f39;
52
+ --amber-text: #df8e1d;
53
+ --info-blue: #179299;
54
+ --link: #1e66f5;
55
+ --link-hover: #7287fd;
56
+ --link-soft: #1e66f5;
57
+ --md-strong: #3c3e53;
58
+ --skill-blue: #1e66f5;
59
+ --plugin-purple: #b58cff;
60
+ --auth-green: #40a02b;
61
+ --scroll-thumb: #ccd0da;
62
+ --scroll-thumb-hover: #bcc0cc;
63
+ --notice-err-bg: #401d23;
64
+ --notice-warn-bg: #38251f;
65
+ --notice-info-bg: #1b2544;
66
+ --notice-err-border: #ef4444;
67
+ --notice-warn-border: #f59e0b;
68
+ --notice-info-border: #3b82f6;
69
+ --send-blue: #1e66f5;
70
+ --send-blue-hover: #7287fd;
71
+ --brand-grad-a: #1e66f5;
72
+ --brand-grad-b: #8839ef;
73
+ --on-amber: #1a1a1a;
74
+ --search-active-fg: #1a1d26;
75
+ --switch-knob: #ffffff;
76
+ --bg-elev3: rgba(255, 255, 255, 0.06);
77
+ --sunken-bg: rgba(0, 0, 0, 0.15);
78
+ --glow-015: rgba(255, 255, 255, 0.015);
79
+ --glow-025: rgba(255, 255, 255, 0.025);
80
+ --glow-03: rgba(255, 255, 255, 0.03);
81
+ --glow-04: rgba(255, 255, 255, 0.04);
82
+ --glow-05: rgba(255, 255, 255, 0.05);
83
+ --glow-12: rgba(255, 255, 255, 0.12);
84
+ --glow-18: rgba(255, 255, 255, 0.18);
85
+ --glow-22: rgba(255, 255, 255, 0.22);
86
+ --glow-38: rgba(255, 255, 255, 0.38);
87
+ --control-fg: #6c6f85;
88
+ --control-bg: #dce0e8;
89
+ --control-border: #ccd0da;
90
+ --bg-image: none;
91
+ --bg-image-dim: 0.78;
92
+ --bg-image-blur: 0px;
93
+ --wallpaper-panel-alpha: 100%;
94
+ --topbar-bg: #e6e9ef;
95
+ --statusbar-bg: #e6e9ef;
96
+ --panel-bg: #e6e9ef;
97
+ --card-bg: #e6e9ef;
98
+ --chip-bg: #dce0e8;
99
+ --msgs-bg: #eff1f5;
100
+ --inputbox-bg: #dce0e8;
101
+ --menu-bg: var(--bg-elev2);
102
+ }
103
+
104
+ /* ---- syntax highlighting (Catppuccin Latte) ---- */
105
+ .hljs {
106
+ color: #4c4f69;
107
+ background: #e6e9ef;
108
+ }
109
+ .hljs-doctag,
110
+ .hljs-keyword,
111
+ .hljs-meta .hljs-keyword {
112
+ color: #8839ef;
113
+ }
114
+ .hljs-title,
115
+ .hljs-title.class_,
116
+ .hljs-title.function_ {
117
+ color: #1e66f5;
118
+ }
119
+ .hljs-attr,
120
+ .hljs-attribute,
121
+ .hljs-literal,
122
+ .hljs-number {
123
+ color: #fe640b;
124
+ }
125
+ .hljs-string,
126
+ .hljs-regexp {
127
+ color: #40a02b;
128
+ }
129
+ .hljs-built_in,
130
+ .hljs-type {
131
+ color: #df8e1d;
132
+ }
133
+ .hljs-comment,
134
+ .hljs-code {
135
+ color: #7c7f93;
136
+ }
@@ -0,0 +1,140 @@
1
+ /* theme-name: Catppuccin */
2
+ /* theme-name-en: Catppuccin Mocha */
3
+ /* theme-group: classic */
4
+ :root {
5
+ color-scheme: dark;
6
+ --bg: #1e1e2e;
7
+ --bg-elev: #24273a;
8
+ --bg-elev2: #313244;
9
+ --border: #45475a;
10
+ --border-soft: #363a4f;
11
+ --text: #cdd6f4;
12
+ --text-dim: #a6adc8;
13
+ --text-faint: #6c7086;
14
+ --accent: #89b4fa;
15
+ --accent-soft: rgba(137, 180, 250, 0.14);
16
+ --green: #a6e3a1;
17
+ --green-soft: rgba(166, 227, 161, 0.12);
18
+ --red: #f38ba8;
19
+ --red-soft: rgba(243, 139, 168, 0.12);
20
+ --amber: #f9e2af;
21
+ --term-bg: #181825;
22
+ --term-fg: #cdd6f4;
23
+ --term-cursor: #f5e0dc;
24
+ --term-cursor-accent: #181825;
25
+ --term-selection: rgba(88, 91, 112, 0.4);
26
+ --term-black: #45475a;
27
+ --term-red: #f38ba8;
28
+ --term-green: #a6e3a1;
29
+ --term-yellow: #f9e2af;
30
+ --term-blue: #89b4fa;
31
+ --term-magenta: #cba6f7;
32
+ --term-cyan: #89dceb;
33
+ --term-white: #bac2de;
34
+ --term-bright-black: #585b70;
35
+ --term-bright-red: #f38ba8;
36
+ --term-bright-green: #a6e3a1;
37
+ --term-bright-yellow: #f9e2af;
38
+ --term-bright-blue: #89b4fa;
39
+ --term-bright-magenta: #cba6f7;
40
+ --term-bright-cyan: #89dceb;
41
+ --term-bright-white: #a6adc8;
42
+ --mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
43
+ --mermaid-font-size: 12px;
44
+ --tooltip-bg: #313244;
45
+ --code-bg: #181825;
46
+ --code-text: #cdd6f4;
47
+ --code-border: var(--border-soft);
48
+ --code-pad: 8px 10px;
49
+ --card-body-pad: 4px 14px 12px;
50
+ --err-text: #f38ba8;
51
+ --red-text: #f38ba8;
52
+ --amber-text: #f9e2af;
53
+ --info-blue: #89dceb;
54
+ --link: #89b4fa;
55
+ --link-hover: #b4befe;
56
+ --link-soft: #89b4fa;
57
+ --md-strong: #cdd6f4;
58
+ --skill-blue: #89b4fa;
59
+ --plugin-purple: #b58cff;
60
+ --auth-green: #a6e3a1;
61
+ --scroll-thumb: #45475a;
62
+ --scroll-thumb-hover: #585b70;
63
+ --notice-err-bg: #401d23;
64
+ --notice-warn-bg: #38251f;
65
+ --notice-info-bg: #1b2544;
66
+ --notice-err-border: #ef4444;
67
+ --notice-warn-border: #f59e0b;
68
+ --notice-info-border: #3b82f6;
69
+ --send-blue: #89b4fa;
70
+ --send-blue-hover: #b4befe;
71
+ --brand-grad-a: #89b4fa;
72
+ --brand-grad-b: #cba6f7;
73
+ --on-amber: #1a1a1a;
74
+ --search-active-fg: #1a1d26;
75
+ --switch-knob: #ffffff;
76
+ --bg-elev3: rgba(255, 255, 255, 0.06);
77
+ --sunken-bg: rgba(0, 0, 0, 0.15);
78
+ --glow-015: rgba(255, 255, 255, 0.015);
79
+ --glow-025: rgba(255, 255, 255, 0.025);
80
+ --glow-03: rgba(255, 255, 255, 0.03);
81
+ --glow-04: rgba(255, 255, 255, 0.04);
82
+ --glow-05: rgba(255, 255, 255, 0.05);
83
+ --glow-12: rgba(255, 255, 255, 0.12);
84
+ --glow-18: rgba(255, 255, 255, 0.18);
85
+ --glow-22: rgba(255, 255, 255, 0.22);
86
+ --glow-38: rgba(255, 255, 255, 0.38);
87
+ --control-fg: #a6adc8;
88
+ --control-bg: #313244;
89
+ --control-border: #45475a;
90
+ --bg-image: none;
91
+ --bg-image-dim: 0.78;
92
+ --bg-image-blur: 0px;
93
+ --wallpaper-panel-alpha: 100%;
94
+ --topbar-bg: #24273a;
95
+ --statusbar-bg: #181825;
96
+ --panel-bg: #24273a;
97
+ --card-bg: #24273a;
98
+ --chip-bg: #313244;
99
+ --msgs-bg: #1e1e2e;
100
+ --inputbox-bg: #313244;
101
+ --menu-bg: var(--bg-elev2);
102
+ }
103
+
104
+ /* ---- syntax highlighting (Catppuccin Mocha) ---- */
105
+ .hljs {
106
+ color: #cdd6f4;
107
+ background: #181825;
108
+ }
109
+ .hljs-doctag,
110
+ .hljs-keyword,
111
+ .hljs-meta .hljs-keyword {
112
+ color: #cba6f7;
113
+ }
114
+ .hljs-title,
115
+ .hljs-title.class_,
116
+ .hljs-title.function_ {
117
+ color: #89b4fa;
118
+ }
119
+ .hljs-attr,
120
+ .hljs-attribute,
121
+ .hljs-literal,
122
+ .hljs-number {
123
+ color: #fab387;
124
+ }
125
+ .hljs-string,
126
+ .hljs-regexp {
127
+ color: #a6e3a1;
128
+ }
129
+ .hljs-built_in,
130
+ .hljs-type {
131
+ color: #f9e2af;
132
+ }
133
+ .hljs-comment,
134
+ .hljs-code {
135
+ color: #6c7086;
136
+ }
137
+ .hljs-tag,
138
+ .hljs-name {
139
+ color: #89dceb;
140
+ }
@@ -0,0 +1,130 @@
1
+ /* theme-name: 北欧极光 */
2
+ /* theme-name-en: Nord */
3
+ /* theme-group: classic */
4
+ :root {
5
+ color-scheme: dark;
6
+ --bg: #2e3440;
7
+ --bg-elev: #3b4252;
8
+ --bg-elev2: #434c5e;
9
+ --border: #4c566a;
10
+ --border-soft: #3b4252;
11
+ --text: #d8dee9;
12
+ --text-dim: #e5e9f0;
13
+ --text-faint: #818c9f;
14
+ --accent: #88c0d0;
15
+ --accent-soft: rgba(136, 192, 208, 0.14);
16
+ --green: #a3be8c;
17
+ --green-soft: rgba(163, 190, 140, 0.12);
18
+ --red: #bf616a;
19
+ --red-soft: rgba(191, 97, 106, 0.12);
20
+ --amber: #ebcb8b;
21
+ --term-bg: #242933;
22
+ --term-fg: #d8dee9;
23
+ --term-cursor: #88c0d0;
24
+ --term-cursor-accent: #242933;
25
+ --term-selection: rgba(67, 76, 94, 0.5);
26
+ --term-black: #3b4252;
27
+ --term-red: #bf616a;
28
+ --term-green: #a3be8c;
29
+ --term-yellow: #ebcb8b;
30
+ --term-blue: #81a1c1;
31
+ --term-magenta: #b48ead;
32
+ --term-cyan: #88c0d0;
33
+ --term-white: #e5e9f0;
34
+ --term-bright-black: #4c566a;
35
+ --term-bright-red: #bf616a;
36
+ --term-bright-green: #a3be8c;
37
+ --term-bright-yellow: #ebcb8b;
38
+ --term-bright-blue: #81a1c1;
39
+ --term-bright-magenta: #b48ead;
40
+ --term-bright-cyan: #8fbcbb;
41
+ --term-bright-white: #eceff4;
42
+ --mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
43
+ --mermaid-font-size: 12px;
44
+ --tooltip-bg: #3b4252;
45
+ --code-bg: #242933;
46
+ --code-text: #d8dee9;
47
+ --code-border: var(--border-soft);
48
+ --code-pad: 8px 10px;
49
+ --card-body-pad: 4px 14px 12px;
50
+ --err-text: #bf616a;
51
+ --red-text: #bf616a;
52
+ --amber-text: #ebcb8b;
53
+ --info-blue: #81a1c1;
54
+ --link: #88c0d0;
55
+ --link-hover: #81a1c1;
56
+ --link-soft: #88c0d0;
57
+ --md-strong: #eceff4;
58
+ --skill-blue: #88c0d0;
59
+ --plugin-purple: #b58cff;
60
+ --auth-green: #a3be8c;
61
+ --scroll-thumb: #434c5e;
62
+ --scroll-thumb-hover: #4c566a;
63
+ --notice-err-bg: #401d23;
64
+ --notice-warn-bg: #38251f;
65
+ --notice-info-bg: #1b2544;
66
+ --notice-err-border: #ef4444;
67
+ --notice-warn-border: #f59e0b;
68
+ --notice-info-border: #3b82f6;
69
+ --send-blue: #88c0d0;
70
+ --send-blue-hover: #81a1c1;
71
+ --brand-grad-a: #88c0d0;
72
+ --brand-grad-b: #81a1c1;
73
+ --on-amber: #1a1a1a;
74
+ --search-active-fg: #1a1d26;
75
+ --switch-knob: #ffffff;
76
+ --bg-elev3: rgba(255, 255, 255, 0.06);
77
+ --sunken-bg: rgba(0, 0, 0, 0.15);
78
+ --glow-015: rgba(255, 255, 255, 0.015);
79
+ --glow-025: rgba(255, 255, 255, 0.025);
80
+ --glow-03: rgba(255, 255, 255, 0.03);
81
+ --glow-04: rgba(255, 255, 255, 0.04);
82
+ --glow-05: rgba(255, 255, 255, 0.05);
83
+ --glow-12: rgba(255, 255, 255, 0.12);
84
+ --glow-18: rgba(255, 255, 255, 0.18);
85
+ --glow-22: rgba(255, 255, 255, 0.22);
86
+ --glow-38: rgba(255, 255, 255, 0.38);
87
+ --control-fg: #d8dee9;
88
+ --control-bg: #3b4252;
89
+ --control-border: #4c566a;
90
+ --bg-image: none;
91
+ --bg-image-dim: 0.78;
92
+ --bg-image-blur: 0px;
93
+ --wallpaper-panel-alpha: 100%;
94
+ --topbar-bg: #3b4252;
95
+ --statusbar-bg: #242933;
96
+ --panel-bg: #3b4252;
97
+ --card-bg: #3b4252;
98
+ --chip-bg: #434c5e;
99
+ --msgs-bg: #2e3440;
100
+ --inputbox-bg: #434c5e;
101
+ --menu-bg: var(--bg-elev2);
102
+ }
103
+
104
+ /* ---- syntax highlighting (Nord) ---- */
105
+ .hljs {
106
+ color: #d8dee9;
107
+ background: #242933;
108
+ }
109
+ .hljs-keyword,
110
+ .hljs-meta .hljs-keyword {
111
+ color: #81a1c1;
112
+ }
113
+ .hljs-title,
114
+ .hljs-title.function_ {
115
+ color: #88c0d0;
116
+ }
117
+ .hljs-number,
118
+ .hljs-literal {
119
+ color: #b48ead;
120
+ }
121
+ .hljs-string {
122
+ color: #a3be8c;
123
+ }
124
+ .hljs-built_in,
125
+ .hljs-type {
126
+ color: #ebcb8b;
127
+ }
128
+ .hljs-comment {
129
+ color: #616e88;
130
+ }
@@ -0,0 +1,131 @@
1
+ /* theme-name: One Dark */
2
+ /* theme-name-en: One Dark Pro */
3
+ /* theme-group: classic */
4
+ :root {
5
+ color-scheme: dark;
6
+ --bg: #282c34;
7
+ --bg-elev: #21252b;
8
+ --bg-elev2: #2c313a;
9
+ --border: #3e4451;
10
+ --border-soft: #31363f;
11
+ --text: #abb2bf;
12
+ --text-dim: #828997;
13
+ --text-faint: #5c6370;
14
+ --accent: #61afef;
15
+ --accent-soft: rgba(97, 175, 239, 0.14);
16
+ --green: #98c379;
17
+ --green-soft: rgba(152, 195, 121, 0.12);
18
+ --red: #e06c75;
19
+ --red-soft: rgba(224, 108, 117, 0.12);
20
+ --amber: #e5c07b;
21
+ --term-bg: #1e2227;
22
+ --term-fg: #abb2bf;
23
+ --term-cursor: #528bff;
24
+ --term-cursor-accent: #1e2227;
25
+ --term-selection: rgba(62, 68, 81, 0.5);
26
+ --term-black: #282c34;
27
+ --term-red: #e06c75;
28
+ --term-green: #98c379;
29
+ --term-yellow: #e5c07b;
30
+ --term-blue: #61afef;
31
+ --term-magenta: #c678dd;
32
+ --term-cyan: #56b6c2;
33
+ --term-white: #abb2bf;
34
+ --term-bright-black: #5c6370;
35
+ --term-bright-red: #e06c75;
36
+ --term-bright-green: #98c379;
37
+ --term-bright-yellow: #e5c07b;
38
+ --term-bright-blue: #61afef;
39
+ --term-bright-magenta: #c678dd;
40
+ --term-bright-cyan: #56b6c2;
41
+ --term-bright-white: #ffffff;
42
+ --mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
43
+ --mermaid-font-size: 12px;
44
+ --tooltip-bg: #21252b;
45
+ --code-bg: #1e2227;
46
+ --code-text: #abb2bf;
47
+ --code-border: var(--border-soft);
48
+ --code-pad: 8px 10px;
49
+ --card-body-pad: 4px 14px 12px;
50
+ --err-text: #e06c75;
51
+ --red-text: #e06c75;
52
+ --amber-text: #e5c07b;
53
+ --info-blue: #56b6c2;
54
+ --link: #61afef;
55
+ --link-hover: #528bff;
56
+ --link-soft: #61afef;
57
+ --md-strong: #ffffff;
58
+ --skill-blue: #61afef;
59
+ --plugin-purple: #b58cff;
60
+ --auth-green: #98c379;
61
+ --scroll-thumb: #3e4451;
62
+ --scroll-thumb-hover: #4b5263;
63
+ --notice-err-bg: #401d23;
64
+ --notice-warn-bg: #38251f;
65
+ --notice-info-bg: #1b2544;
66
+ --notice-err-border: #ef4444;
67
+ --notice-warn-border: #f59e0b;
68
+ --notice-info-border: #3b82f6;
69
+ --send-blue: #61afef;
70
+ --send-blue-hover: #528bff;
71
+ --brand-grad-a: #61afef;
72
+ --brand-grad-b: #c678dd;
73
+ --on-amber: #1a1a1a;
74
+ --search-active-fg: #1a1d26;
75
+ --switch-knob: #ffffff;
76
+ --bg-elev3: rgba(255, 255, 255, 0.06);
77
+ --sunken-bg: rgba(0, 0, 0, 0.15);
78
+ --glow-015: rgba(255, 255, 255, 0.015);
79
+ --glow-025: rgba(255, 255, 255, 0.025);
80
+ --glow-03: rgba(255, 255, 255, 0.03);
81
+ --glow-04: rgba(255, 255, 255, 0.04);
82
+ --glow-05: rgba(255, 255, 255, 0.05);
83
+ --glow-12: rgba(255, 255, 255, 0.12);
84
+ --glow-18: rgba(255, 255, 255, 0.18);
85
+ --glow-22: rgba(255, 255, 255, 0.22);
86
+ --glow-38: rgba(255, 255, 255, 0.38);
87
+ --control-fg: #828997;
88
+ --control-bg: #21252b;
89
+ --control-border: #3e4451;
90
+ --bg-image: none;
91
+ --bg-image-dim: 0.78;
92
+ --bg-image-blur: 0px;
93
+ --wallpaper-panel-alpha: 100%;
94
+ --topbar-bg: #21252b;
95
+ --statusbar-bg: #1e2227;
96
+ --panel-bg: #21252b;
97
+ --card-bg: #21252b;
98
+ --chip-bg: #2c313a;
99
+ --msgs-bg: #282c34;
100
+ --inputbox-bg: #2c313a;
101
+ --menu-bg: var(--bg-elev2);
102
+ }
103
+
104
+ /* ---- syntax highlighting (One Dark Pro) ---- */
105
+ .hljs {
106
+ color: #abb2bf;
107
+ background: #1e2227;
108
+ }
109
+ .hljs-keyword,
110
+ .hljs-meta .hljs-keyword {
111
+ color: #c678dd;
112
+ }
113
+ .hljs-title,
114
+ .hljs-title.function_ {
115
+ color: #61afef;
116
+ }
117
+ .hljs-number,
118
+ .hljs-literal {
119
+ color: #d19a66;
120
+ }
121
+ .hljs-string {
122
+ color: #98c379;
123
+ }
124
+ .hljs-built_in,
125
+ .hljs-type {
126
+ color: #e5c07b;
127
+ }
128
+ .hljs-comment {
129
+ color: #5c6370;
130
+ font-style: italic;
131
+ }