pi-web-ui 0.77.0 → 0.79.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.
- package/CHANGELOG.md +45 -3
- package/dist/server/index.js +82 -1
- package/package.json +4 -1
- package/themes/mist.css +179 -0
- package/themes/paper.css +179 -0
- package/themes/sakura.css +179 -0
- package/web/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/dist/assets/{TerminalPanel-CDsBHVQ5.js → TerminalPanel-BYigWYyx.js} +1 -1
- package/web/dist/assets/index-D7BpHJ59.js +347 -0
- package/web/dist/assets/index-GKv6Qo91.css +10 -0
- package/web/dist/assets/markdown-D3PKeHAZ.js +311 -0
- package/web/dist/assets/{react-CtudoG1_.js → react-w24rH0km.js} +1 -1
- package/web/dist/index.html +4 -4
- package/web/dist/assets/index-BsATrxLx.js +0 -346
- package/web/dist/assets/index-DeuPu917.css +0 -10
- package/web/dist/assets/markdown-Cpo0pNcR.js +0 -51
package/CHANGELOG.md
CHANGED
|
@@ -8,9 +8,49 @@
|
|
|
8
8
|
每个版本的内容按"实际合入该版本发布的提交"归档(以 `package.json` 的 version 变更提交为准),
|
|
9
9
|
而不是按提交日期聚类——连续快速发布的 patch 版本以此为准最准确。
|
|
10
10
|
|
|
11
|
-
## [
|
|
11
|
+
## [0.79.0] — 2026-09-11
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- 聊天消息支持渲染 LaTeX 公式(issue #116):`$...$` 行内、`$$...$$` 独立行块走 KaTeX 渲染(`remark-math + rehype-katex`,字体随包离线可用);代码围栏/行内 code 不受影响,公式写坏了只显示红色源码不打断整条消息。
|
|
16
|
+
- 排队/插队气泡新增「撤回」按钮 ↩(#118):点一下把该条消息从队列取回、文字落回输入框(输入框非空时追加到末尾,绝不覆盖正在打的字),改完直接重发;连续撤回多条按序追加。队列里只存文本,撤回只回文字(附件不恢复)。
|
|
17
|
+
- 新增 paper(暖纸)/ mist(雾蓝灰)/ sakura(樱粉)三套浅色主题:主题切换器与 `make-light-theme.mjs` 生成器同步增强,终端配色跟随主题;`vscode-editor` / `db-client` 插件同步跟随亮色(见下 Fixed)。
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- `vscode-editor` 插件跟随亮色主题:之前文件树/标签栏/弹窗底色引用了主应用不存在的 `--bg-elev0/1` 变量,亮色下永远回退到深色硬编码值;编辑器(CodeMirror `oneDark`)与底部 SSH 终端配色也是写死的深色。现在底色改走 `--bg/--bg-elev`,编辑器亮色用跟随 `--bg/--text/--accent` 的浅色壳(暗色仍是 `oneDark`,Compartment 热切换),终端读 `--term-*` 调色板;主应用切换主题时(`pi-web-ui:theme-change`)已打开的编辑器与存活终端一起换肤,无需重载。
|
|
22
|
+
- `db-client` 插件跟随亮色主题:同上,文件树/主区/表头/弹窗输入框底色引用的 `--bg-elev0/1` 改走 `--bg/--bg-elev`(该插件无自绘深色组件,一次变量映射即完整跟随)。
|
|
23
|
+
|
|
24
|
+
<!-- auto-i18n:start -->
|
|
25
|
+
### i18n
|
|
26
|
+
|
|
27
|
+
- 前端新增 key(1):`queueRecallTip`
|
|
28
|
+
<!-- auto-i18n:end -->
|
|
29
|
+
|
|
30
|
+
## [0.78.0] — 2026-09-11
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- 文件预览支持渲染 HTML(`README.html` 这类文件不再只看到源码):打开 `.html` / `.htm` / `.xhtml` 默认是**渲染视图**,工具栏的 👁/`</>` 与 Markdown 一样一键切源码,进编辑态自动落到源码。渲染走**沙箱 iframe**,页面里的 JavaScript 默认**不执行**(工具条显示「🛡 脚本已禁用(静态预览)」),要跑脚本得对**当前这个文件**点「启用脚本」显式放开(切文件即复位、不持久化、不写进任何配置);无论开关如何,iframe 一律**不带 `allow-same-origin`** —— 页面拿不到本应用的同源/DOM/cookie/存储,表单提交与顶层跳转同样被挡(脚本开时工具条换成「⚠ 脚本已启用」并说明后果)。渲染地址是新增的目录映射路由,页面里的**相对引用**(`<link href="../web/src/styles.css">`、`./app.js`、图片…)按浏览器正常语义解析加载:
|
|
35
|
+
- `/api/preview/<工作区相对路径>`(机器浏览的绝对路径用 `__abs__/` 前缀),各路径段 URI 编码;`.html` 文档下发 `Content-Security-Policy: sandbox`(`?allowJs=1` 时 `sandbox allow-scripts`,**永不**加 `allow-same-origin`)与 `X-Content-Type-Options: nosniff`,其余子资源按真实 content-type 直送;`..` 越界由 `workspacePath()` 拒绝(400 `path outside workspace`)。
|
|
36
|
+
- `/api/file` 直出的 HTML 也带上 `sandbox` CSP——把预览地址单独在新标签页打开,一样拿不到应用源。
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- 重试与提示词模板「直发」补记模型使用次数:这两个入口都是「沿用当前模型再发一轮」,之前不计入 `model-usage`,模型下拉的「按使用次数排序」会漏掉这部分(现在与正常发送一致;模板直发记的是当前模型)。
|
|
41
|
+
- `vscode-editor` 插件中止上传时临时文件可能残留(Windows):`abortUploadEntry` 旧写法是 `void fh.close()` 后立刻 `unlink` 并把错误吞掉,而 close 是异步的 —— 句柄还没关就删会 `EBUSY/EPERM`,目标目录里就留下 `.vsc-upload-*.part`。现在改成 `await close()` → `await unlink()`,且 `upload_abort` 等清理完再回响应(客户端随后就会去核验目录);定时清扫与 `deactivate` 两条路径改为不等(`void`)。
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- 排队/插队消息改成和正式用户消息**同一套气泡**(`MessageList.tsx` 的 `QueuedMessage` 复用 `.msg-user` 结构):Markdown 渲染(代码块/列表/链接等不再是一坨纯文本)、角色行显示「你」、状态 tag(插队/排队)与移除 ✕ 排在同一行;未发送仍用**虚线边框 + 0.75 透明度**区分,服务端真正下发后直接变成正常消息气泡(外观不再跳变)。`styles.css` 里旧的 `.queued-bubble` / `.queued-text` / `.queued-remove` 一套样式一并删除。
|
|
46
|
+
- 官方插件做手机竖屏(≤640px)适配,桌面端表现不变:`db-client`(连接侧栏变左滑抽屉、库表树变可折叠面板、结果表格在容器内横滑、Redis 键列表改上下排、触摸目标加大、输入框提到 16px 防 iOS 聚焦缩放)、`vscode-editor`(文件树变抽屉 + 顶栏 ☰、选中文件自动收起)、`run-trace`(三段改上下堆叠、时间轴压到 200px、回放条允许换行、触屏色块热区加大)、`webmail`、`demo-mailbox`。
|
|
47
|
+
- `docs/architecture-attachments.md` 的文件预览协议补一节「HTML 渲染走目录映射的 HTTP」(沙箱策略与相对引用语义)。
|
|
48
|
+
|
|
49
|
+
<!-- auto-i18n:start -->
|
|
50
|
+
### i18n
|
|
51
|
+
|
|
52
|
+
- 前端新增 key(8):`showHtmlSource`、`showHtmlPreview`、`htmlJsOff`、`htmlJsOffTip`、`htmlJsOn`、`htmlJsOnTip`、`htmlEnableJs`、`htmlDisableJs`
|
|
53
|
+
<!-- auto-i18n:end -->
|
|
14
54
|
|
|
15
55
|
## [0.77.0] — 2026-09-11
|
|
16
56
|
|
|
@@ -425,7 +465,9 @@
|
|
|
425
465
|
- 0.35.1(2026-08-27):编辑重问保留附件(#18)+ 全窗口拖放(#19)。
|
|
426
466
|
- 0.29.0(2026-08-23):全局搜索弹窗(Ctrl+K)+ 消息列表惰性窗口化。
|
|
427
467
|
|
|
428
|
-
[Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.
|
|
468
|
+
[Unreleased]: https://github.com/xing-shuyin/pi-web-ui/compare/v0.79.0...main
|
|
469
|
+
[0.79.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.79.0
|
|
470
|
+
[0.78.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.78.0
|
|
429
471
|
[0.77.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.77.0
|
|
430
472
|
[0.76.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.76.0
|
|
431
473
|
[0.75.0]: https://github.com/xing-shuyin/pi-web-ui/releases/tag/v0.75.0
|
package/dist/server/index.js
CHANGED
|
@@ -236,7 +236,12 @@ app.get("/api/file", async (req, res) => {
|
|
|
236
236
|
const name = basename(abs);
|
|
237
237
|
const kind = previewKind(name);
|
|
238
238
|
const isDownload = req.query.download === "1";
|
|
239
|
-
|
|
239
|
+
// HTML files preview through a sandboxed <iframe> in the file modal
|
|
240
|
+
// (FilePreview.tsx). They are text as far as previewKind goes, so
|
|
241
|
+
// allowlist them explicitly here.
|
|
242
|
+
const lower = name.toLowerCase();
|
|
243
|
+
const isHtmlPreview = lower.endsWith(".html") || lower.endsWith(".htm") || lower.endsWith(".xhtml");
|
|
244
|
+
if (!isDownload && kind !== "image" && kind !== "video" && !isHtmlPreview) {
|
|
240
245
|
res.status(400).end("not a previewable media file");
|
|
241
246
|
return;
|
|
242
247
|
}
|
|
@@ -251,6 +256,20 @@ app.get("/api/file", async (req, res) => {
|
|
|
251
256
|
res.download(abs, name);
|
|
252
257
|
}
|
|
253
258
|
else {
|
|
259
|
+
if (isHtmlPreview) {
|
|
260
|
+
// Sandbox even a top-level navigation to this URL: a workspace
|
|
261
|
+
// HTML file must never get our origin (it could otherwise read
|
|
262
|
+
// the token cookie). The modal iframe carries its own sandbox
|
|
263
|
+
// attribute as well (defense in depth).
|
|
264
|
+
//
|
|
265
|
+
// ?allowJs=1 is the explicit per-file opt-in from the preview
|
|
266
|
+
// modal ("启用脚本"): scripts run, but still in an opaque
|
|
267
|
+
// origin — no DOM/cookie/storage access to our app, no forms,
|
|
268
|
+
// no top-navigation. NEVER add allow-same-origin here.
|
|
269
|
+
const allowJs = req.query.allowJs === "1";
|
|
270
|
+
res.setHeader("Content-Security-Policy", allowJs ? "sandbox allow-scripts" : "sandbox");
|
|
271
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
272
|
+
}
|
|
254
273
|
res.sendFile(abs);
|
|
255
274
|
}
|
|
256
275
|
}
|
|
@@ -258,6 +277,68 @@ app.get("/api/file", async (req, res) => {
|
|
|
258
277
|
res.status(404).end("not found");
|
|
259
278
|
}
|
|
260
279
|
});
|
|
280
|
+
/**
|
|
281
|
+
* Directory-mapped preview: serves a workspace file at a URL that mirrors its
|
|
282
|
+
* directory location, so an HTML preview's RELATIVE subresources
|
|
283
|
+
* (<link href="../web/src/styles.css">, <img src="./x.png">, <script
|
|
284
|
+
* src="./app.js">, …) resolve and load with normal browser semantics. The
|
|
285
|
+
* iframe document URL itself carries the file's directory — no HTML rewriting.
|
|
286
|
+
*
|
|
287
|
+
* /api/preview/<workspace-rel-path>?clientId=…[&allowJs=1]
|
|
288
|
+
* /api/preview/__abs__/<absolute-wire-path>?clientId=…[&allowJs=1]
|
|
289
|
+
* (each path segment URI-encoded; ".." is normalized by the browser before
|
|
290
|
+
* the request is sent, workspace containment is still re-checked here)
|
|
291
|
+
*
|
|
292
|
+
* Same footing as /api/file: workspace containment enforced, HTML documents
|
|
293
|
+
* get a sandboxed CSP (?allowJs=1 relaxes scripts only — never same-origin),
|
|
294
|
+
* everything else streams with its real content type.
|
|
295
|
+
*/
|
|
296
|
+
app.get("/api/preview/*", async (req, res) => {
|
|
297
|
+
try {
|
|
298
|
+
const captured = String(req.params[0] ?? "");
|
|
299
|
+
const ABS_MARKER = "__abs__/";
|
|
300
|
+
const cid = typeof req.query.clientId === "string" ? req.query.clientId : "";
|
|
301
|
+
const cs = cid ? service.get(cid) : undefined;
|
|
302
|
+
const root = cs?.cwd ?? CWD;
|
|
303
|
+
// Express decodes %XX in the wildcard, so this is back to the wire
|
|
304
|
+
// form (filenames never contain "/", so per-segment encoding from
|
|
305
|
+
// the client round-trips exactly).
|
|
306
|
+
let abs;
|
|
307
|
+
if (captured === "__abs__" || captured.startsWith(ABS_MARKER)) {
|
|
308
|
+
// Machine browsing: absolute wire path ("C:/..." / "/...").
|
|
309
|
+
const wire = captured.slice(ABS_MARKER.length);
|
|
310
|
+
if (!isAbsoluteWirePath(wire)) {
|
|
311
|
+
res.status(400).end("bad absolute preview path");
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
abs = wireToAbs(wire);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
const wp = workspacePath(root, captured);
|
|
318
|
+
if (!wp) {
|
|
319
|
+
res.status(400).end("path outside workspace");
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
abs = wp.abs;
|
|
323
|
+
}
|
|
324
|
+
const name = basename(abs);
|
|
325
|
+
const st = await stat(abs);
|
|
326
|
+
if (!st.isFile()) {
|
|
327
|
+
res.status(400).end("not a file");
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
331
|
+
const lower = name.toLowerCase();
|
|
332
|
+
if (lower.endsWith(".html") || lower.endsWith(".htm") || lower.endsWith(".xhtml")) {
|
|
333
|
+
const allowJs = req.query.allowJs === "1";
|
|
334
|
+
res.setHeader("Content-Security-Policy", allowJs ? "sandbox allow-scripts" : "sandbox");
|
|
335
|
+
}
|
|
336
|
+
res.sendFile(abs);
|
|
337
|
+
}
|
|
338
|
+
catch {
|
|
339
|
+
res.status(404).end("not found");
|
|
340
|
+
}
|
|
341
|
+
});
|
|
261
342
|
// Production: serve the built frontend from web/dist. Resolve relative to this
|
|
262
343
|
// module so it works when installed as a package (global/npx/Docker), not just
|
|
263
344
|
// from the repo root. In dev, Vite serves the UI on :5173 and proxies /ws.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-web-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.79.0",
|
|
4
4
|
"description": "Web chat interface for the pi coding agent, powered by the pi SDK (@earendil-works/pi-coding-agent) — one-command run, Docker/systemd/launchd deployable",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -83,15 +83,18 @@
|
|
|
83
83
|
"compression": "^1.8.1",
|
|
84
84
|
"express": "^4.21.2",
|
|
85
85
|
"highlight.js": "^11.10.0",
|
|
86
|
+
"katex": "^0.16.47",
|
|
86
87
|
"node-pty": "^1.1.0",
|
|
87
88
|
"react": "^18.3.1",
|
|
88
89
|
"react-dom": "^18.3.1",
|
|
89
90
|
"react-icons": "^5.7.0",
|
|
90
91
|
"react-markdown": "^9.0.1",
|
|
91
92
|
"rehype-highlight": "^7.0.1",
|
|
93
|
+
"rehype-katex": "^7.0.1",
|
|
92
94
|
"rehype-raw": "^7.0.0",
|
|
93
95
|
"remark-breaks": "^4.0.0",
|
|
94
96
|
"remark-gfm": "^4.0.0",
|
|
97
|
+
"remark-math": "^6.0.0",
|
|
95
98
|
"typebox": "^1.3.14",
|
|
96
99
|
"ws": "^8.18.0"
|
|
97
100
|
},
|
package/themes/mist.css
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* theme-name: 雾蓝灰 */
|
|
2
|
+
/* theme-name-en: Misty Blue Gray */
|
|
3
|
+
:root {
|
|
4
|
+
color-scheme: light;
|
|
5
|
+
--bg: #e9eef4;
|
|
6
|
+
--bg-elev: #f8fafc;
|
|
7
|
+
--bg-elev2: #dde5ec;
|
|
8
|
+
--border: #cbd5e1;
|
|
9
|
+
--border-soft: #dde5ec;
|
|
10
|
+
--text: #1e293b;
|
|
11
|
+
--text-dim: #475569;
|
|
12
|
+
--text-faint: #94a3b8;
|
|
13
|
+
--accent: #0284c7;
|
|
14
|
+
--accent-soft: rgba(2, 132, 199, 0.12);
|
|
15
|
+
--green: #059669;
|
|
16
|
+
--green-soft: rgba(5, 150, 105, 0.12);
|
|
17
|
+
--red: #dc2626;
|
|
18
|
+
--red-soft: rgba(220, 38, 38, 0.1);
|
|
19
|
+
--amber: #d97706;
|
|
20
|
+
--term-bg: #f8fafc;
|
|
21
|
+
--term-fg: #1e293b;
|
|
22
|
+
--term-cursor: #0284c7;
|
|
23
|
+
--term-cursor-accent: #ffffff;
|
|
24
|
+
--term-selection: rgba(2, 132, 199, 0.28);
|
|
25
|
+
--term-black: #dbe3ec;
|
|
26
|
+
--term-red: #dc2626;
|
|
27
|
+
--term-green: #059669;
|
|
28
|
+
--term-yellow: #d97706;
|
|
29
|
+
--term-blue: #2563eb;
|
|
30
|
+
--term-magenta: #9333ea;
|
|
31
|
+
--term-cyan: #0e7490;
|
|
32
|
+
--term-white: #1e293b;
|
|
33
|
+
--term-bright-black: #94a3b8;
|
|
34
|
+
--term-bright-red: #dc2626;
|
|
35
|
+
--term-bright-green: #059669;
|
|
36
|
+
--term-bright-yellow: #d97706;
|
|
37
|
+
--term-bright-blue: #2563eb;
|
|
38
|
+
--term-bright-magenta: #9333ea;
|
|
39
|
+
--term-bright-cyan: #0e7490;
|
|
40
|
+
--term-bright-white: #020617;
|
|
41
|
+
--mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
|
|
42
|
+
--mermaid-font-size: 12px;
|
|
43
|
+
--tooltip-bg: #ffffff;
|
|
44
|
+
--code-bg: #dde5ec;
|
|
45
|
+
--code-text: #1e293b;
|
|
46
|
+
--code-border: var(--border-soft);
|
|
47
|
+
--code-pad: 8px 10px;
|
|
48
|
+
--card-body-pad: 4px 14px 12px;
|
|
49
|
+
--err-text: #dc2626;
|
|
50
|
+
--red-text: #dc2626;
|
|
51
|
+
--amber-text: #b45309;
|
|
52
|
+
--info-blue: #2563eb;
|
|
53
|
+
--link: #0284c7;
|
|
54
|
+
--link-hover: #0369a1;
|
|
55
|
+
--link-soft: #0284c7;
|
|
56
|
+
--md-strong: #0f172a;
|
|
57
|
+
--skill-blue: #0284c7;
|
|
58
|
+
--plugin-purple: #b58cff;
|
|
59
|
+
--auth-green: #059669;
|
|
60
|
+
--scroll-thumb: #b6c2d1;
|
|
61
|
+
--scroll-thumb-hover: #94a3b8;
|
|
62
|
+
--notice-err-bg: #f9dee0;
|
|
63
|
+
--notice-warn-bg: #f0e6cb;
|
|
64
|
+
--notice-info-bg: #d9e6f5;
|
|
65
|
+
--notice-err-border: #dc2626;
|
|
66
|
+
--notice-warn-border: #b45309;
|
|
67
|
+
--notice-info-border: #2563eb;
|
|
68
|
+
--send-blue: #0284c7;
|
|
69
|
+
--send-blue-hover: #0369a1;
|
|
70
|
+
--brand-grad-a: #38bdf8;
|
|
71
|
+
--brand-grad-b: #0284c7;
|
|
72
|
+
--on-amber: #1a1a1a;
|
|
73
|
+
--search-active-fg: #1a1d26;
|
|
74
|
+
--switch-knob: #ffffff;
|
|
75
|
+
--bg-elev3: rgba(30, 58, 95, 0.05);
|
|
76
|
+
--glow-015: rgba(30, 58, 95, 0.02);
|
|
77
|
+
--glow-025: rgba(30, 58, 95, 0.02);
|
|
78
|
+
--glow-03: rgba(30, 58, 95, 0.02);
|
|
79
|
+
--glow-04: rgba(30, 58, 95, 0.03);
|
|
80
|
+
--glow-05: rgba(30, 58, 95, 0.03);
|
|
81
|
+
--glow-12: rgba(30, 58, 95, 0.08);
|
|
82
|
+
--glow-18: rgba(30, 58, 95, 0.12);
|
|
83
|
+
--glow-22: rgba(30, 58, 95, 0.15);
|
|
84
|
+
--glow-38: rgba(30, 58, 95, 0.25);
|
|
85
|
+
--control-fg: #475569;
|
|
86
|
+
--control-bg: #dde5ec;
|
|
87
|
+
--control-border: #cbd5e1;
|
|
88
|
+
--bg-image: none;
|
|
89
|
+
--bg-image-dim: 0.78;
|
|
90
|
+
--bg-image-blur: 0px;
|
|
91
|
+
--wallpaper-panel-alpha: 62%;
|
|
92
|
+
--topbar-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
93
|
+
--statusbar-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
94
|
+
--panel-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
95
|
+
--card-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
96
|
+
--chip-bg: color-mix(in srgb, var(--bg-elev2) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
97
|
+
--msgs-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
98
|
+
--inputbox-bg: color-mix(in srgb, var(--bg-elev2) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
99
|
+
--menu-bg: var(--bg-elev2);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* ---- syntax highlighting (overrides static github-dark import) ---- */
|
|
103
|
+
.hljs {
|
|
104
|
+
color: #1e293b;
|
|
105
|
+
background: #dde5ec;
|
|
106
|
+
}
|
|
107
|
+
.hljs-doctag,
|
|
108
|
+
.hljs-keyword,
|
|
109
|
+
.hljs-meta .hljs-keyword,
|
|
110
|
+
.hljs-template-tag,
|
|
111
|
+
.hljs-template-variable,
|
|
112
|
+
.hljs-type,
|
|
113
|
+
.hljs-variable.language_ {
|
|
114
|
+
color: #cf222e;
|
|
115
|
+
}
|
|
116
|
+
.hljs-title,
|
|
117
|
+
.hljs-title.class_,
|
|
118
|
+
.hljs-title.class_.inherited__,
|
|
119
|
+
.hljs-title.function_ {
|
|
120
|
+
color: #8250df;
|
|
121
|
+
}
|
|
122
|
+
.hljs-attr,
|
|
123
|
+
.hljs-attribute,
|
|
124
|
+
.hljs-literal,
|
|
125
|
+
.hljs-meta,
|
|
126
|
+
.hljs-number,
|
|
127
|
+
.hljs-operator,
|
|
128
|
+
.hljs-variable,
|
|
129
|
+
.hljs-selector-attr,
|
|
130
|
+
.hljs-selector-class,
|
|
131
|
+
.hljs-selector-id {
|
|
132
|
+
color: #0550ae;
|
|
133
|
+
}
|
|
134
|
+
.hljs-regexp,
|
|
135
|
+
.hljs-string,
|
|
136
|
+
.hljs-meta .hljs-string {
|
|
137
|
+
color: #0a3069;
|
|
138
|
+
}
|
|
139
|
+
.hljs-built_in,
|
|
140
|
+
.hljs-symbol {
|
|
141
|
+
color: #953800;
|
|
142
|
+
}
|
|
143
|
+
.hljs-comment,
|
|
144
|
+
.hljs-code,
|
|
145
|
+
.hljs-formula {
|
|
146
|
+
color: #7c8da0;
|
|
147
|
+
}
|
|
148
|
+
.hljs-name,
|
|
149
|
+
.hljs-quote,
|
|
150
|
+
.hljs-selector-tag,
|
|
151
|
+
.hljs-selector-pseudo {
|
|
152
|
+
color: #116329;
|
|
153
|
+
}
|
|
154
|
+
.hljs-subst {
|
|
155
|
+
color: #1e293b;
|
|
156
|
+
}
|
|
157
|
+
.hljs-section {
|
|
158
|
+
color: #0550ae;
|
|
159
|
+
font-weight: 700;
|
|
160
|
+
}
|
|
161
|
+
.hljs-bullet {
|
|
162
|
+
color: #0550ae;
|
|
163
|
+
}
|
|
164
|
+
.hljs-emphasis {
|
|
165
|
+
color: #1e293b;
|
|
166
|
+
font-style: italic;
|
|
167
|
+
}
|
|
168
|
+
.hljs-strong {
|
|
169
|
+
color: #1e293b;
|
|
170
|
+
font-weight: 700;
|
|
171
|
+
}
|
|
172
|
+
.hljs-addition {
|
|
173
|
+
color: #116329;
|
|
174
|
+
background: #d7e9db;
|
|
175
|
+
}
|
|
176
|
+
.hljs-deletion {
|
|
177
|
+
color: #82071e;
|
|
178
|
+
background: #f2d3d6;
|
|
179
|
+
}
|
package/themes/paper.css
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* theme-name: 暖纸 */
|
|
2
|
+
/* theme-name-en: Warm Paper */
|
|
3
|
+
:root {
|
|
4
|
+
color-scheme: light;
|
|
5
|
+
--bg: #f7f1e3;
|
|
6
|
+
--bg-elev: #fffdf6;
|
|
7
|
+
--bg-elev2: #efe7d3;
|
|
8
|
+
--border: #ddcfae;
|
|
9
|
+
--border-soft: #e7dcc2;
|
|
10
|
+
--text: #3f372c;
|
|
11
|
+
--text-dim: #6f6250;
|
|
12
|
+
--text-faint: #a2937a;
|
|
13
|
+
--accent: #b45309;
|
|
14
|
+
--accent-soft: rgba(180, 83, 9, 0.12);
|
|
15
|
+
--green: #15803d;
|
|
16
|
+
--green-soft: rgba(21, 128, 61, 0.12);
|
|
17
|
+
--red: #b91c1c;
|
|
18
|
+
--red-soft: rgba(185, 28, 28, 0.1);
|
|
19
|
+
--amber: #d97706;
|
|
20
|
+
--term-bg: #f7f1e3;
|
|
21
|
+
--term-fg: #3f372c;
|
|
22
|
+
--term-cursor: #b45309;
|
|
23
|
+
--term-cursor-accent: #fffdf6;
|
|
24
|
+
--term-selection: rgba(180, 83, 9, 0.28);
|
|
25
|
+
--term-black: #e2d5b8;
|
|
26
|
+
--term-red: #b91c1c;
|
|
27
|
+
--term-green: #15803d;
|
|
28
|
+
--term-yellow: #a16207;
|
|
29
|
+
--term-blue: #1d4ed8;
|
|
30
|
+
--term-magenta: #9333ea;
|
|
31
|
+
--term-cyan: #0e7490;
|
|
32
|
+
--term-white: #3f372c;
|
|
33
|
+
--term-bright-black: #a2937a;
|
|
34
|
+
--term-bright-red: #b91c1c;
|
|
35
|
+
--term-bright-green: #15803d;
|
|
36
|
+
--term-bright-yellow: #a16207;
|
|
37
|
+
--term-bright-blue: #1d4ed8;
|
|
38
|
+
--term-bright-magenta: #9333ea;
|
|
39
|
+
--term-bright-cyan: #0e7490;
|
|
40
|
+
--term-bright-white: #1c1917;
|
|
41
|
+
--mono: "SF Mono", "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;
|
|
42
|
+
--mermaid-font-size: 12px;
|
|
43
|
+
--tooltip-bg: #fffdf6;
|
|
44
|
+
--code-bg: #efe7d3;
|
|
45
|
+
--code-text: #43382c;
|
|
46
|
+
--code-border: var(--border-soft);
|
|
47
|
+
--code-pad: 8px 10px;
|
|
48
|
+
--card-body-pad: 4px 14px 12px;
|
|
49
|
+
--err-text: #b91c1c;
|
|
50
|
+
--red-text: #b91c1c;
|
|
51
|
+
--amber-text: #92400e;
|
|
52
|
+
--info-blue: #1d4ed8;
|
|
53
|
+
--link: #9a3412;
|
|
54
|
+
--link-hover: #7c2d12;
|
|
55
|
+
--link-soft: #9a3412;
|
|
56
|
+
--md-strong: #292019;
|
|
57
|
+
--skill-blue: #b45309;
|
|
58
|
+
--plugin-purple: #b58cff;
|
|
59
|
+
--auth-green: #15803d;
|
|
60
|
+
--scroll-thumb: #d3c4a3;
|
|
61
|
+
--scroll-thumb-hover: #b8a67f;
|
|
62
|
+
--notice-err-bg: #f5dcd2;
|
|
63
|
+
--notice-warn-bg: #f0e5c8;
|
|
64
|
+
--notice-info-bg: #e6dfc9;
|
|
65
|
+
--notice-err-border: #b91c1c;
|
|
66
|
+
--notice-warn-border: #b45309;
|
|
67
|
+
--notice-info-border: #57534e;
|
|
68
|
+
--send-blue: #b45309;
|
|
69
|
+
--send-blue-hover: #92400e;
|
|
70
|
+
--brand-grad-a: #d97706;
|
|
71
|
+
--brand-grad-b: #b45309;
|
|
72
|
+
--on-amber: #1a1a1a;
|
|
73
|
+
--search-active-fg: #1a1d26;
|
|
74
|
+
--switch-knob: #ffffff;
|
|
75
|
+
--bg-elev3: rgba(120, 90, 30, 0.06);
|
|
76
|
+
--glow-015: rgba(120, 90, 30, 0.02);
|
|
77
|
+
--glow-025: rgba(120, 90, 30, 0.02);
|
|
78
|
+
--glow-03: rgba(120, 90, 30, 0.02);
|
|
79
|
+
--glow-04: rgba(120, 90, 30, 0.03);
|
|
80
|
+
--glow-05: rgba(120, 90, 30, 0.03);
|
|
81
|
+
--glow-12: rgba(120, 90, 30, 0.08);
|
|
82
|
+
--glow-18: rgba(120, 90, 30, 0.12);
|
|
83
|
+
--glow-22: rgba(120, 90, 30, 0.15);
|
|
84
|
+
--glow-38: rgba(120, 90, 30, 0.25);
|
|
85
|
+
--control-fg: #6f6250;
|
|
86
|
+
--control-bg: #efe7d3;
|
|
87
|
+
--control-border: #ddcfae;
|
|
88
|
+
--bg-image: none;
|
|
89
|
+
--bg-image-dim: 0.78;
|
|
90
|
+
--bg-image-blur: 0px;
|
|
91
|
+
--wallpaper-panel-alpha: 62%;
|
|
92
|
+
--topbar-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
93
|
+
--statusbar-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
94
|
+
--panel-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
95
|
+
--card-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
96
|
+
--chip-bg: color-mix(in srgb, var(--bg-elev2) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
97
|
+
--msgs-bg: color-mix(in srgb, var(--bg-elev) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
98
|
+
--inputbox-bg: color-mix(in srgb, var(--bg-elev2) var(--wallpaper-panel-alpha, 62%), transparent);
|
|
99
|
+
--menu-bg: var(--bg-elev2);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* ---- syntax highlighting (overrides static github-dark import) ---- */
|
|
103
|
+
.hljs {
|
|
104
|
+
color: #3f372c;
|
|
105
|
+
background: #efe7d3;
|
|
106
|
+
}
|
|
107
|
+
.hljs-doctag,
|
|
108
|
+
.hljs-keyword,
|
|
109
|
+
.hljs-meta .hljs-keyword,
|
|
110
|
+
.hljs-template-tag,
|
|
111
|
+
.hljs-template-variable,
|
|
112
|
+
.hljs-type,
|
|
113
|
+
.hljs-variable.language_ {
|
|
114
|
+
color: #cf222e;
|
|
115
|
+
}
|
|
116
|
+
.hljs-title,
|
|
117
|
+
.hljs-title.class_,
|
|
118
|
+
.hljs-title.class_.inherited__,
|
|
119
|
+
.hljs-title.function_ {
|
|
120
|
+
color: #8250df;
|
|
121
|
+
}
|
|
122
|
+
.hljs-attr,
|
|
123
|
+
.hljs-attribute,
|
|
124
|
+
.hljs-literal,
|
|
125
|
+
.hljs-meta,
|
|
126
|
+
.hljs-number,
|
|
127
|
+
.hljs-operator,
|
|
128
|
+
.hljs-variable,
|
|
129
|
+
.hljs-selector-attr,
|
|
130
|
+
.hljs-selector-class,
|
|
131
|
+
.hljs-selector-id {
|
|
132
|
+
color: #0550ae;
|
|
133
|
+
}
|
|
134
|
+
.hljs-regexp,
|
|
135
|
+
.hljs-string,
|
|
136
|
+
.hljs-meta .hljs-string {
|
|
137
|
+
color: #0a3069;
|
|
138
|
+
}
|
|
139
|
+
.hljs-built_in,
|
|
140
|
+
.hljs-symbol {
|
|
141
|
+
color: #953800;
|
|
142
|
+
}
|
|
143
|
+
.hljs-comment,
|
|
144
|
+
.hljs-code,
|
|
145
|
+
.hljs-formula {
|
|
146
|
+
color: #8a7d64;
|
|
147
|
+
}
|
|
148
|
+
.hljs-name,
|
|
149
|
+
.hljs-quote,
|
|
150
|
+
.hljs-selector-tag,
|
|
151
|
+
.hljs-selector-pseudo {
|
|
152
|
+
color: #116329;
|
|
153
|
+
}
|
|
154
|
+
.hljs-subst {
|
|
155
|
+
color: #3f372c;
|
|
156
|
+
}
|
|
157
|
+
.hljs-section {
|
|
158
|
+
color: #0550ae;
|
|
159
|
+
font-weight: 700;
|
|
160
|
+
}
|
|
161
|
+
.hljs-bullet {
|
|
162
|
+
color: #0550ae;
|
|
163
|
+
}
|
|
164
|
+
.hljs-emphasis {
|
|
165
|
+
color: #3f372c;
|
|
166
|
+
font-style: italic;
|
|
167
|
+
}
|
|
168
|
+
.hljs-strong {
|
|
169
|
+
color: #3f372c;
|
|
170
|
+
font-weight: 700;
|
|
171
|
+
}
|
|
172
|
+
.hljs-addition {
|
|
173
|
+
color: #116329;
|
|
174
|
+
background: #dfe8cf;
|
|
175
|
+
}
|
|
176
|
+
.hljs-deletion {
|
|
177
|
+
color: #82071e;
|
|
178
|
+
background: #f0d4c4;
|
|
179
|
+
}
|