dsh-pixel-ui 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 zhang66633
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # 🪵 dsh-pixel-ui
2
+
3
+ > DeepSeek Harness 像素皮肤(Agent Xi 风格):四个主题一键切换——像素·木屋 / 像素·羊皮纸 / 像素·暖阳 / 像素·终端绿,随时可切回现代默认 UI。
4
+
5
+ ![License: MIT](https://img.shields.io/badge/license-MIT-brightgreen)
6
+ ![dsh](https://img.shields.io/badge/dsh-0.1.0--rc.6-blue)
7
+ ![version](https://img.shields.io/badge/version-1.0.0-F4D03F)
8
+ ![themes](https://img.shields.io/badge/themes-4-orange)
9
+
10
+ ---
11
+
12
+ ## Overview
13
+
14
+ `dsh-pixel-ui` 是一个**皮肤插件**,把 dsh Web GUI 重皮肤成像素 RPG 风:
15
+
16
+ 1. **四个主题**:像素·木屋(深木 + 金)、像素·羊皮纸(浅色纸面 + 金棕)、像素·暖阳(暖橙木)、像素·终端绿(CRT 绿字),色板与 Agent Xi 主题系统同源;
17
+ 2. **像素质感**:阶梯硬阴影、8-bit 凸起按钮、内凹输入框、木纹条纹、CRT 扫描线 + 暗角、像素光标;
18
+ 3. **像素字体**:标题/页签/按钮/徽章/输入框用 fusion-pixel(中文)+ Press Start 2P(英文数字),正文与代码走 mono,长文不累眼。
19
+
20
+ **适合谁**:想要像素风 / 星露谷风 / 复古终端外观的 dsh 用户;想给会话截图加一点氛围感的博主和开发者。
21
+
22
+ <p align="center">
23
+ <img src="./assets/screenshot-wood.png" alt="像素·木屋(默认主题)" width="760" />
24
+ </p>
25
+
26
+ ## Themes
27
+
28
+ ### 像素·木屋 · `pixel-wood`
29
+
30
+ > 深色 · 深木 `#1A0F06` + 金 `#F4D03F`(默认主题)
31
+
32
+ <img src="./assets/screenshot-wood.png" alt="像素·木屋" width="100%" />
33
+
34
+ ### 像素·羊皮纸 · `pixel-paper`
35
+
36
+ > 浅色 · 纸面 `#F0E8D8` + 金棕 `#C8960C`
37
+
38
+ <img src="./assets/screenshot-paper.png" alt="像素·羊皮纸" width="100%" />
39
+
40
+ ### 像素·暖阳 · `pixel-warm`
41
+
42
+ > 深色 · 暖木 `#1E0E04` + 橙 `#FF8C42`
43
+
44
+ <img src="./assets/screenshot-warm.png" alt="像素·暖阳" width="100%" />
45
+
46
+ ### 像素·终端绿 · `pixel-retro`
47
+
48
+ > 深色 · 墨绿 `#0A0E0A` + 绿 `#33FF33`
49
+
50
+ <img src="./assets/screenshot-retro.png" alt="像素·终端绿" width="100%" />
51
+
52
+ <details>
53
+ <summary>📷 对话页与输入框(展开查看四主题截图)</summary>
54
+
55
+ <img src="./assets/screenshot-wood-chat.png" alt="木屋对话页" width="100%" />
56
+ <img src="./assets/screenshot-paper-chat.png" alt="羊皮纸对话页" width="100%" />
57
+ <img src="./assets/screenshot-warm-chat.png" alt="暖阳对话页" width="100%" />
58
+ <img src="./assets/screenshot-retro-chat.png" alt="终端绿对话页" width="100%" />
59
+
60
+ </details>
61
+
62
+ ## Compatibility
63
+
64
+ | 项 | 支持范围 |
65
+ | --- | --- |
66
+ | dsh 生态 | `0.1.0-rc.6`(ThemeService `register`/`setTheme` + `settings.general.item` 槽位;最后验证 2026-08-14) |
67
+ | 模式 | 三深色 + 一浅色(`colorScheme` 按主题声明) |
68
+ | 浏览器 | 现代 Chromium / Firefox(`localStorage` + CSS 变量 + SVG 光标) |
69
+ | 字体 | fusion-pixel 12px zh_hans(MIT)+ Press Start 2P(OFL),随包分发 |
70
+
71
+ ## Install / Uninstall
72
+
73
+ ### Install
74
+
75
+ npm(推荐):
76
+
77
+ ```bash
78
+ dsh plugin --profile web add dsh-pixel-ui
79
+ ```
80
+
81
+ GitHub 源码(clone 后按本地 link 方式接入,同样无需构建——构建产物已随仓库提交):
82
+
83
+ ```bash
84
+ git clone --depth 1 https://github.com/zhang66633/dsh-pixel-ui
85
+ ```
86
+
87
+ 本地开发(link 方式):
88
+
89
+ ```jsonc
90
+ // ~/.dsh/profiles/web/package.json
91
+ {
92
+ "dependencies": { "dsh-pixel-ui": "link:<仓库路径>" },
93
+ "dsh": { "profile": { "bundles": ["dsh-pixel-ui"] } }
94
+ }
95
+ ```
96
+
97
+ ```bash
98
+ cd ~/.dsh/profiles/web && pnpm install
99
+ ```
100
+
101
+ ### Upgrade
102
+
103
+ - npm:重新运行 `dsh plugin add`(固定版本号);
104
+ - 本地 link:`git pull` 后重新构建(`npm run build`),刷新浏览器。
105
+
106
+ ### Disable
107
+
108
+ 只从 `dsh.profile.bundles` 移除 `dsh-pixel-ui`(依赖可以保留)——皮肤不再注入,UI 回到现代默认。
109
+
110
+ ### Uninstall
111
+
112
+ 从 profile `package.json` 移除依赖与 bundles 条目,`pnpm install`。
113
+
114
+ ## Quick start
115
+
116
+ 1. 安装后重启 `dsh web`;
117
+ 2. 首次加载自动激活默认主题「像素·木屋」;
118
+ 3. 设置 → 通用 → **像素主题**,五个按钮一键切换四个皮肤和「现代默认」;
119
+ 4. 选「现代默认」(或外观行选 浅色 / 深色 / 跟随系统)即整体退出皮肤,选择会被记住,下次打开不复活。
120
+
121
+ 最小可复现示例:安装 → 重启 → 木屋主题上身 → 切换到「像素·羊皮纸」→ 输入框文字清晰可读 → 点「现代默认」→ 页面立即回到现代 UI → 刷新页面仍是现代 UI。
122
+
123
+ ## Configuration
124
+
125
+ - **无配置项**:四个主题的 13 个 `--dsw-alias-*` token 定义在 `src/client/index.js` 的 `THEMES`,像素质感样式在 `src/client/pixel.css`;
126
+ - **默认主题**:`pixel-wood`(仅首次安装时自动激活,之后尊重你的选择);
127
+ - **持久化**:最后的选择存于浏览器 `localStorage` 的 `dsh-pixel-ui:theme`;
128
+ - 无环境变量、无敏感项。
129
+
130
+ ## Permissions & data
131
+
132
+ - 宿主进程:**只读**本包内字体文件,仅注册一个 `/dsh-pixel-ui/fonts/*` 路由(文件名白名单,无路径穿越);
133
+ - 浏览器半边:注册主题 + 注入样式表 + 一个设置行;无网络请求、无遥测、不读凭据,只在 `localStorage` 存一个主题 id。
134
+
135
+ ## Troubleshooting
136
+
137
+ | 现象 | 处理 |
138
+ | --- | --- |
139
+ | 皮肤没生效 | `dsh --profile web --dump-config` 确认 `dsh-pixel-ui` 在树;设置 → 通用 → 像素主题 里选一个主题;重启 |
140
+ | 想回现代默认 | 设置 → 通用 → 像素主题 → 点「现代默认」(或外观行选 浅色/深色/跟随系统) |
141
+ | 字体没加载 | 浏览器控制台(F12 → Network)看 `/dsh-pixel-ui/fonts/*` 是否 200 |
142
+ | 主题没记住 | 确认浏览器未禁用 `localStorage` |
143
+ | 回滚 | 从 `dsh.profile.bundles` 移除插件条目并 `pnpm install` —— profile 其余部分不受影响 |
144
+
145
+ ## Development
146
+
147
+ ```bash
148
+ npm install
149
+ npm run build # 构建 lib/client.js(wire 格式,CSS 以文本内联)
150
+ ```
151
+
152
+ 改动皮肤后重新构建并刷新浏览器即可(link 安装方式下无需重启 dsh)。欢迎 PR;行为变更请同步更新 README。
153
+
154
+ ## License & security
155
+
156
+ [MIT](./LICENSE) © 2026 zhang66633 · 字体:fusion-pixel(MIT)、Press Start 2P(SIL OFL)。
157
+
158
+ 安全问题请通过 GitHub **security advisory** 私下报告,不要发公开 issue。
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,7 @@
1
+ # dsh-pixel-ui bundle patch: inserts the dual-face plugin row into the web
2
+ # profile roster. Node half (exports ".") serves the bundled pixel fonts;
3
+ # the `dsh.client` declaration makes the browser half (exports "./client")
4
+ # load in the web GUI and register the pixel theme.
5
+ - insert:
6
+ - id: dsh-pixel-ui
7
+ name: dsh-pixel-ui
package/lib/client.js ADDED
@@ -0,0 +1,768 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-pixel-ui", factory: (require) => { var module = { exports: {} }; var exports = module.exports;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name2 in all)
8
+ __defProp(target, name2, { get: all[name2], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client/index.js
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ apply: () => apply,
24
+ inject: () => inject,
25
+ name: () => name
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+ var import_react = require("react");
29
+ var import_client = require("@deepseek-ai/dsh-client-runtime/client");
30
+
31
+ // src/client/pixel.css
32
+ var pixel_default = `/* dsh-pixel-ui — 星露谷风像素皮肤(木屋/羊皮纸/暖阳/终端绿四主题)\r
33
+ * 全面对标 Agent Xi 前端像素语言(web/src/styles/main.css):\r
34
+ * - 木色/金色/羊皮纸三系色板 + 阶梯硬阴影 + 内凹/凸起 bevel\r
35
+ * - 像素字体做界面装饰(标题/页签/按钮/徽章/输入框),正文与代码走 mono\r
36
+ * - 木纹条纹纹理、CRT 扫描线 + 暗角 + 微闪烁、像素光标、像素按压动效\r
37
+ * 作用域 html[data-pixel-ui]:任一像素主题激活时生效,\r
38
+ * data-pixel-theme 区分四种配色。切回 现代默认/浅色/深色 即整体退出。\r
39
+ * 原则:颜色尽量交给主题 token,本表负责 token 表达不了的像素质感。 */\r
40
+ \r
41
+ @font-face {\r
42
+ font-family: 'Fusion Pixel 12';\r
43
+ src: url('/dsh-pixel-ui/fonts/fusion-pixel-12px.woff2') format('woff2');\r
44
+ font-weight: 400;\r
45
+ font-style: normal;\r
46
+ font-display: swap;\r
47
+ }\r
48
+ @font-face {\r
49
+ font-family: 'Press Start 2P';\r
50
+ src: url('/dsh-pixel-ui/fonts/PressStart2P-Regular.ttf') format('truetype');\r
51
+ font-weight: 400;\r
52
+ font-style: normal;\r
53
+ font-display: swap;\r
54
+ }\r
55
+ \r
56
+ html[data-pixel-ui] {\r
57
+ /* ── Xi 同款色板 ─────────────────────────────────────── */\r
58
+ --px-wood-darkest: #1A0F06;\r
59
+ --px-wood-dark: #2C1A0C;\r
60
+ --px-wood-mid: #3A2515;\r
61
+ --px-wood-warm: #4A3020;\r
62
+ --px-wood-light: #6B4C2E;\r
63
+ --px-wood-pale: #8B6B45;\r
64
+ --px-gold: #F4D03F;\r
65
+ --px-gold-bright: #FFE066;\r
66
+ --px-gold-dark: #C99A00;\r
67
+ --px-gold-deep: #8B6B00;\r
68
+ --px-parchment: #F5E6C8;\r
69
+ --px-text-on-dark: #E8D5B0;\r
70
+ --px-text-light: #9B7B5B;\r
71
+ \r
72
+ /* 输入框专用色(各主题单独覆盖,保证任何底色下文字可见) */\r
73
+ --px-input-bg: #1A0F06;\r
74
+ --px-input-text: #FFFDF5;\r
75
+ --px-input-caret: #F4D03F;\r
76
+ --px-input-ph: #9B7B5B;\r
77
+ \r
78
+ /* 文字阴影强度:暗色主题用 2px 像素硬阴影,浅色主题收敛防重影 */\r
79
+ --px-ts-chrome: 2px 2px 0 rgba(26, 15, 6, 0.6), -1px -1px 0 rgba(26, 15, 6, 0.4);\r
80
+ --px-ts-btn: 1px 1px 0 rgba(0, 0, 0, 0.4);\r
81
+ \r
82
+ /* 像素字体栈:中文/全角走 fusion-pixel(12px 原生),英文数字兜底 Press Start 2P */\r
83
+ --px-font: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r
84
+ --px-mono: 'Cascadia Code', 'Consolas', 'Courier New', monospace;\r
85
+ }\r
86
+ \r
87
+ /* ── 四主题色板(Agent Xi 同款)────────────────────────── */\r
88
+ html[data-pixel-theme='pixel-paper'] {\r
89
+ --px-wood-darkest: #F0E8D8;\r
90
+ --px-wood-dark: #E8DCC8;\r
91
+ --px-wood-mid: #DDD0B8;\r
92
+ --px-wood-warm: #D4C4A8;\r
93
+ --px-wood-light: #B8A080;\r
94
+ --px-wood-pale: #9B8B6B;\r
95
+ --px-gold: #C8960C;\r
96
+ --px-gold-bright: #E0A800;\r
97
+ --px-gold-dark: #A07000;\r
98
+ --px-gold-deep: #805000;\r
99
+ --px-parchment: #FFFDF5;\r
100
+ --px-text-on-dark: #3A2A10;\r
101
+ --px-text-light: #8B7040;\r
102
+ --px-input-bg: #FFFDF5;\r
103
+ --px-input-text: #3A2A10;\r
104
+ --px-input-caret: #C8960C;\r
105
+ --px-input-ph: #8B7040;\r
106
+ /* 浅色底上 2px 硬阴影会变重影:去掉文字阴影,靠字体本身 */\r
107
+ --px-ts-chrome: none;\r
108
+ --px-ts-btn: none;\r
109
+ }\r
110
+ html[data-pixel-theme='pixel-warm'] {\r
111
+ --px-wood-darkest: #1E0E04;\r
112
+ --px-wood-dark: #34180A;\r
113
+ --px-wood-mid: #4A2210;\r
114
+ --px-wood-warm: #5C2E16;\r
115
+ --px-wood-light: #8B4A28;\r
116
+ --px-wood-pale: #A86B40;\r
117
+ --px-gold: #FF8C42;\r
118
+ --px-gold-bright: #FFA64D;\r
119
+ --px-gold-dark: #D96E30;\r
120
+ --px-gold-deep: #A05020;\r
121
+ --px-parchment: #FFF0E0;\r
122
+ --px-text-on-dark: #F0C8A0;\r
123
+ --px-text-light: #A86B40;\r
124
+ --px-input-bg: #1E0E04;\r
125
+ --px-input-text: #FFFBF5;\r
126
+ --px-input-caret: #FF8C42;\r
127
+ --px-input-ph: #A86B40;\r
128
+ }\r
129
+ html[data-pixel-theme='pixel-retro'] {\r
130
+ --px-wood-darkest: #0A0E0A;\r
131
+ --px-wood-dark: #0E140E;\r
132
+ --px-wood-mid: #121A12;\r
133
+ --px-wood-warm: #162016;\r
134
+ --px-wood-light: #2A402A;\r
135
+ --px-wood-pale: #3A5A3A;\r
136
+ --px-gold: #33FF33;\r
137
+ --px-gold-bright: #66FF66;\r
138
+ --px-gold-dark: #00CC00;\r
139
+ --px-gold-deep: #009900;\r
140
+ --px-parchment: #0A1A0A;\r
141
+ --px-text-on-dark: #33FF33;\r
142
+ --px-text-light: #118811;\r
143
+ --px-input-bg: #0A0E0A;\r
144
+ --px-input-text: #33FF33;\r
145
+ --px-input-caret: #33FF33;\r
146
+ --px-input-ph: #118811;\r
147
+ }\r
148
+ \r
149
+ /* ── 全局质感:禁次像素平滑(像素字体的灵魂)、位图三件套、方形化 ── */\r
150
+ html[data-pixel-ui] body {\r
151
+ -webkit-font-smoothing: none;\r
152
+ -moz-osx-font-smoothing: grayscale;\r
153
+ text-rendering: geometricPrecision;\r
154
+ font-family: var(--px-font) !important;\r
155
+ letter-spacing: 0.01em;\r
156
+ }\r
157
+ \r
158
+ html[data-pixel-ui] img,\r
159
+ html[data-pixel-ui] canvas,\r
160
+ html[data-pixel-ui] video {\r
161
+ image-rendering: -moz-crisp-edges;\r
162
+ image-rendering: crisp-edges;\r
163
+ image-rendering: pixelated;\r
164
+ }\r
165
+ \r
166
+ /* 一切皆方角(像素风第一原则) */\r
167
+ html[data-pixel-ui] * {\r
168
+ border-radius: 0 !important;\r
169
+ }\r
170
+ \r
171
+ html[data-pixel-ui] ::selection {\r
172
+ background: var(--px-gold);\r
173
+ color: var(--px-wood-darkest);\r
174
+ }\r
175
+ \r
176
+ html[data-pixel-ui] :focus-visible {\r
177
+ outline: 2px solid var(--px-gold) !important;\r
178
+ outline-offset: 1px;\r
179
+ }\r
180
+ \r
181
+ /* ── 像素滚动条:方形、木色 ────────────────────────────── */\r
182
+ html[data-pixel-ui] ::-webkit-scrollbar { width: 10px; height: 10px; }\r
183
+ html[data-pixel-ui] ::-webkit-scrollbar-track {\r
184
+ background: var(--px-wood-darkest);\r
185
+ border-left: 2px solid var(--px-wood-dark);\r
186
+ }\r
187
+ html[data-pixel-ui] ::-webkit-scrollbar-thumb {\r
188
+ background: var(--px-wood-light);\r
189
+ border: 2px solid var(--px-wood-darkest);\r
190
+ }\r
191
+ html[data-pixel-ui] ::-webkit-scrollbar-thumb:hover { background: var(--px-wood-pale); }\r
192
+ \r
193
+ /* ── 排版:装饰性 UI 用像素字体,正文/代码用 mono(Xi 的信息分层) ── */\r
194
+ html[data-pixel-ui] h1,\r
195
+ html[data-pixel-ui] h2,\r
196
+ html[data-pixel-ui] h3,\r
197
+ html[data-pixel-ui] [class*='title'],\r
198
+ html[data-pixel-ui] [class*='label'],\r
199
+ html[data-pixel-ui] [class*='tab'],\r
200
+ html[data-pixel-ui] [class*='badge'],\r
201
+ html[data-pixel-ui] [class*='chip'],\r
202
+ html[data-pixel-ui] [class*='Tag'],\r
203
+ html[data-pixel-ui] [class*='pill'] {\r
204
+ font-family: var(--px-font) !important;\r
205
+ text-shadow: var(--px-ts-chrome);\r
206
+ }\r
207
+ \r
208
+ /* 标题/页签取金色(Xi .panel-title 语义) */\r
209
+ html[data-pixel-ui] h1,\r
210
+ html[data-pixel-ui] h2,\r
211
+ html[data-pixel-ui] h3,\r
212
+ html[data-pixel-ui] [class*='title'] {\r
213
+ color: var(--px-gold-bright) !important;\r
214
+ letter-spacing: 0.02em;\r
215
+ }\r
216
+ \r
217
+ /* 页签:选中态金色下划线 */\r
218
+ html[data-pixel-ui] [class*='tab'],\r
219
+ html[data-pixel-ui] [aria-selected='true'] {\r
220
+ font-size: 12px;\r
221
+ }\r
222
+ html[data-pixel-ui] [class*='tab'][class*='active'],\r
223
+ html[data-pixel-ui] [aria-selected='true'] {\r
224
+ box-shadow: inset 0 -3px 0 var(--px-gold) !important;\r
225
+ }\r
226
+ \r
227
+ /* 徽章/小标签:切角 + 内凹高光(小元素才有资格切角,避免大块裁阴影) */\r
228
+ html[data-pixel-ui] [class*='badge'],\r
229
+ html[data-pixel-ui] [class*='chip'],\r
230
+ html[data-pixel-ui] [class*='Tag'],\r
231
+ html[data-pixel-ui] [class*='pill'] {\r
232
+ font-size: 11px;\r
233
+ line-height: 1.5;\r
234
+ border: 1px solid #000 !important;\r
235
+ box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.3) !important;\r
236
+ clip-path: polygon(\r
237
+ 0 2px, 2px 2px, 2px 0,\r
238
+ calc(100% - 2px) 0, calc(100% - 2px) 2px, 100% 2px,\r
239
+ 100% calc(100% - 2px), calc(100% - 2px) calc(100% - 2px), calc(100% - 2px) 100%,\r
240
+ 2px 100%, 2px calc(100% - 2px), 0 calc(100% - 2px)\r
241
+ );\r
242
+ }\r
243
+ \r
244
+ /* ── 正文/消息/代码:mono 内容层(Xi log 区用 Fira Code 的忠实移植) ── */\r
245
+ html[data-pixel-ui] [class*='message'],\r
246
+ html[data-pixel-ui] [class*='bubble'],\r
247
+ html[data-pixel-ui] [class*='markdown'],\r
248
+ html[data-pixel-ui] [class*='content'],\r
249
+ html[data-pixel-ui] pre,\r
250
+ html[data-pixel-ui] code,\r
251
+ html[data-pixel-ui] [class*='code'] {\r
252
+ font-family: var(--px-mono) !important;\r
253
+ letter-spacing: 0;\r
254
+ text-shadow: none;\r
255
+ }\r
256
+ \r
257
+ /* 消息行:左侧木色竖条(Xi .log-row 色带,统一木色) */\r
258
+ html[data-pixel-ui] [class*='message'],\r
259
+ html[data-pixel-ui] [class*='bubble'] {\r
260
+ border-left: 3px solid var(--px-wood-warm) !important;\r
261
+ }\r
262
+ \r
263
+ /* 代码块:黑底木边(Xi .log-code-wrap) */\r
264
+ html[data-pixel-ui] pre,\r
265
+ html[data-pixel-ui] [class*='code'] {\r
266
+ background: var(--px-wood-darkest) !important;\r
267
+ color: var(--px-text-on-dark) !important;\r
268
+ border: 2px solid var(--px-wood-light) !important;\r
269
+ box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.4) !important;\r
270
+ }\r
271
+ /* 行内代码:暗底金字 */\r
272
+ html[data-pixel-ui] code {\r
273
+ background: rgba(0, 0, 0, 0.4) !important;\r
274
+ color: var(--px-gold-bright) !important;\r
275
+ border: 1px solid rgba(0, 0, 0, 0.12) !important;\r
276
+ padding: 0 4px;\r
277
+ }\r
278
+ html[data-pixel-ui] pre code {\r
279
+ background: transparent !important;\r
280
+ color: inherit !important;\r
281
+ border: none !important;\r
282
+ padding: 0;\r
283
+ }\r
284
+ \r
285
+ /* ── 按钮:8-bit 凸起 + 阶梯硬阴影 + 悬停抬升 + 按压沉底 ── */\r
286
+ html[data-pixel-ui] button,\r
287
+ html[data-pixel-ui] [role='button'],\r
288
+ html[data-pixel-ui] [class*='btn'],\r
289
+ html[data-pixel-ui] [class*='Button'] {\r
290
+ font-family: var(--px-font) !important;\r
291
+ font-size: 12px;\r
292
+ letter-spacing: 0.02em;\r
293
+ border: 2px solid #000 !important;\r
294
+ box-shadow:\r
295
+ inset 2px 2px 0 rgba(255, 248, 231, 0.22),\r
296
+ inset -2px -2px 0 rgba(0, 0, 0, 0.5),\r
297
+ 2px 2px 0 #000,\r
298
+ 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r
299
+ text-shadow: var(--px-ts-btn);\r
300
+ transition: transform 0.08s steps(2), box-shadow 0.08s steps(2), filter 0.08s steps(2);\r
301
+ }\r
302
+ html[data-pixel-ui] button:hover,\r
303
+ html[data-pixel-ui] [role='button']:hover,\r
304
+ html[data-pixel-ui] [class*='btn']:hover,\r
305
+ html[data-pixel-ui] [class*='Button']:hover {\r
306
+ filter: brightness(1.1);\r
307
+ transform: translate(-2px, -2px);\r
308
+ box-shadow:\r
309
+ inset 2px 2px 0 rgba(255, 248, 231, 0.25),\r
310
+ inset -2px -2px 0 rgba(0, 0, 0, 0.4),\r
311
+ 4px 4px 0 #000,\r
312
+ 5px 5px 0 rgba(0, 0, 0, 0.6) !important;\r
313
+ }\r
314
+ html[data-pixel-ui] button:active,\r
315
+ html[data-pixel-ui] [role='button']:active,\r
316
+ html[data-pixel-ui] [class*='btn']:active,\r
317
+ html[data-pixel-ui] [class*='Button']:active {\r
318
+ transform: translate(2px, 2px);\r
319
+ box-shadow:\r
320
+ inset 2px 2px 0 rgba(0, 0, 0, 0.5),\r
321
+ inset -2px -2px 0 rgba(255, 248, 231, 0.1) !important;\r
322
+ }\r
323
+ \r
324
+ /* 主按钮(品牌色)金边 */\r
325
+ html[data-pixel-ui] button[class*='primary'],\r
326
+ html[data-pixel-ui] [class*='btn-primary'] {\r
327
+ border-color: var(--px-gold-deep) !important;\r
328
+ box-shadow:\r
329
+ inset 2px 2px 0 rgba(255, 224, 102, 0.5),\r
330
+ inset -2px -2px 0 rgba(0, 0, 0, 0.5),\r
331
+ 2px 2px 0 #000,\r
332
+ 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r
333
+ }\r
334
+ \r
335
+ /* ── 输入框:黑木底 + 羊皮纸文字 + 金色光标(修复文字不可见) ──\r
336
+ * 关键:必须显式给文字颜色。Xi #command-input:cream 字 / wood-darkest 底 /\r
337
+ * gold-deep 边 / 3px 内凹,聚焦金边光环。 */\r
338
+ html[data-pixel-ui] input,\r
339
+ html[data-pixel-ui] textarea,\r
340
+ html[data-pixel-ui] select,\r
341
+ html[data-pixel-ui] [contenteditable='true'] {\r
342
+ font-family: var(--px-font) !important;\r
343
+ font-size: 12px;\r
344
+ letter-spacing: 0;\r
345
+ color: var(--px-input-text) !important;\r
346
+ -webkit-text-fill-color: var(--px-input-text) !important;\r
347
+ caret-color: var(--px-input-caret) !important;\r
348
+ background-color: var(--px-input-bg) !important;\r
349
+ border: 2px solid var(--px-gold-deep) !important;\r
350
+ box-shadow:\r
351
+ inset 3px 3px 0 rgba(0, 0, 0, 0.6),\r
352
+ inset -1px -1px 0 rgba(244, 208, 63, 0.1),\r
353
+ 0 0 0 1px #000 !important;\r
354
+ }\r
355
+ html[data-pixel-ui] input:focus,\r
356
+ html[data-pixel-ui] textarea:focus,\r
357
+ html[data-pixel-ui] select:focus,\r
358
+ html[data-pixel-ui] [contenteditable='true']:focus {\r
359
+ border-color: var(--px-gold) !important;\r
360
+ box-shadow:\r
361
+ inset 3px 3px 0 rgba(0, 0, 0, 0.6),\r
362
+ 0 0 0 2px var(--px-gold),\r
363
+ 0 0 8px rgba(244, 208, 63, 0.4) !important;\r
364
+ }\r
365
+ html[data-pixel-ui] input::placeholder,\r
366
+ html[data-pixel-ui] textarea::placeholder {\r
367
+ color: var(--px-input-ph) !important;\r
368
+ -webkit-text-fill-color: var(--px-input-ph) !important;\r
369
+ opacity: 1;\r
370
+ }\r
371
+ /* 输入框容器只做边框质感,不压背景(避免把容器文字也染黑) */\r
372
+ html[data-pixel-ui] [class*='input'] {\r
373
+ border-color: var(--px-gold-deep) !important;\r
374
+ }\r
375
+ \r
376
+ /* ── 面板/卡片/弹层:双框 + 阶梯硬阴影 + 木纹竖条 ────────── */\r
377
+ html[data-pixel-ui] [class*='panel'],\r
378
+ html[data-pixel-ui] [class*='card'],\r
379
+ html[data-pixel-ui] [class*='Card'],\r
380
+ html[data-pixel-ui] dialog,\r
381
+ html[data-pixel-ui] [role='dialog'],\r
382
+ html[data-pixel-ui] [class*='modal'],\r
383
+ html[data-pixel-ui] [class*='popover'],\r
384
+ html[data-pixel-ui] [class*='menu'],\r
385
+ html[data-pixel-ui] [class*='dropdown'],\r
386
+ html[data-pixel-ui] [class*='popup'] {\r
387
+ border: 2px solid var(--px-wood-warm) !important;\r
388
+ outline: 2px solid #000;\r
389
+ outline-offset: -2px;\r
390
+ box-shadow:\r
391
+ inset 1px 1px 0 rgba(255, 255, 255, 0.08),\r
392
+ inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r
393
+ 2px 2px 0 #000,\r
394
+ 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r
395
+ /* Xi 木纹:每 10px 一条 1px 暗竖纹 */\r
396
+ background-image:\r
397
+ repeating-linear-gradient(\r
398
+ 90deg,\r
399
+ transparent 0px,\r
400
+ transparent 10px,\r
401
+ rgba(0, 0, 0, 0.06) 10px,\r
402
+ rgba(0, 0, 0, 0.06) 11px\r
403
+ ) !important;\r
404
+ }\r
405
+ \r
406
+ /* 卡片悬停:抬升 + 阴影加厚(Xi hover 位移) */\r
407
+ html[data-pixel-ui] [class*='card']:hover,\r
408
+ html[data-pixel-ui] [class*='Card']:hover {\r
409
+ transform: translate(-2px, -2px);\r
410
+ box-shadow:\r
411
+ inset 1px 1px 0 rgba(255, 255, 255, 0.1),\r
412
+ inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r
413
+ 4px 4px 0 #000,\r
414
+ 5px 5px 0 rgba(0, 0, 0, 0.6) !important;\r
415
+ }\r
416
+ \r
417
+ /* ── 顶栏/侧栏:木纹渐变 + 黑底边 + 金色发丝 ─────────────── */\r
418
+ html[data-pixel-ui] [class*='header'],\r
419
+ html[data-pixel-ui] [class*='topbar'],\r
420
+ html[data-pixel-ui] [class*='titlebar'],\r
421
+ html[data-pixel-ui] [class*='sidebar'],\r
422
+ html[data-pixel-ui] [class*='Sidebar'] {\r
423
+ background-image: linear-gradient(180deg, var(--px-wood-warm) 0%, var(--px-wood-dark) 100%) !important;\r
424
+ border-bottom: 3px solid #000 !important;\r
425
+ box-shadow:\r
426
+ inset 0 2px 0 rgba(244, 208, 63, 0.1),\r
427
+ inset 0 -2px 0 rgba(0, 0, 0, 0.5) !important;\r
428
+ }\r
429
+ html[data-pixel-ui] [class*='sidebar'],\r
430
+ html[data-pixel-ui] [class*='Sidebar'] {\r
431
+ border-right: 3px solid #000 !important;\r
432
+ box-shadow:\r
433
+ inset -3px 0 0 rgba(0, 0, 0, 0.4),\r
434
+ inset 2px 0 0 rgba(255, 255, 255, 0.05) !important;\r
435
+ }\r
436
+ \r
437
+ /* ── 链接:金色下划线 ──────────────────────────────────── */\r
438
+ html[data-pixel-ui] a {\r
439
+ color: var(--px-gold-bright) !important;\r
440
+ text-decoration-thickness: 2px;\r
441
+ text-underline-offset: 3px;\r
442
+ }\r
443
+ \r
444
+ /* ── 进度条:刻度纹理 + 硬框(Xi .quest-progress) ──────── */\r
445
+ html[data-pixel-ui] [class*='progress'] {\r
446
+ border: 2px solid #000 !important;\r
447
+ box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.6) !important;\r
448
+ background-image: repeating-linear-gradient(\r
449
+ 90deg,\r
450
+ transparent 0px,\r
451
+ transparent 4px,\r
452
+ rgba(0, 0, 0, 0.35) 4px,\r
453
+ rgba(0, 0, 0, 0.35) 5px\r
454
+ ) !important;\r
455
+ }\r
456
+ \r
457
+ /* ── 像素光标(SVG data-URI 阶梯箭头,Xi 同款造型) ─────── */\r
458
+ html[data-pixel-ui] body {\r
459
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M2 2v17h3v-3h3v-3h3v-3h3v-3h3V2z' fill='%23FFFDF5' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E") 2 2, auto;\r
460
+ }\r
461
+ html[data-pixel-ui] button,\r
462
+ html[data-pixel-ui] [role='button'],\r
463
+ html[data-pixel-ui] a,\r
464
+ html[data-pixel-ui] [class*='card'],\r
465
+ html[data-pixel-ui] [class*='tab'],\r
466
+ html[data-pixel-ui] [class*='menu'],\r
467
+ html[data-pixel-ui] [class*='dropdown'],\r
468
+ html[data-pixel-ui] select,\r
469
+ html[data-pixel-ui] label[for] {\r
470
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M2 2v17h3v-3h3v-3h3v-3h3v-3h3V2z' fill='%23F4D03F' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E") 2 2, pointer;\r
471
+ }\r
472
+ html[data-pixel-ui] input,\r
473
+ html[data-pixel-ui] textarea,\r
474
+ html[data-pixel-ui] [contenteditable='true'] {\r
475
+ cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M5 3h4v2h2v2h2v2h2v2h2v2h2v6h-2v2h-4v2H5z' fill='%23FFFDF5' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E") 4 3, text;\r
476
+ }\r
477
+ \r
478
+ /* ── CRT 覆盖层:扫描线 + 暗角 + 微闪烁(Xi v3 滤镜) ────\r
479
+ * 盖在最顶层但不拦截任何事件;尊重系统“减少动态效果”偏好。 */\r
480
+ html[data-pixel-ui] body::after {\r
481
+ content: "";\r
482
+ position: fixed;\r
483
+ inset: 0;\r
484
+ z-index: 2147483647;\r
485
+ pointer-events: none;\r
486
+ background:\r
487
+ repeating-linear-gradient(\r
488
+ 0deg,\r
489
+ rgba(0, 0, 0, 0.1) 0px,\r
490
+ rgba(0, 0, 0, 0.1) 1px,\r
491
+ transparent 1px,\r
492
+ transparent 3px\r
493
+ ),\r
494
+ radial-gradient(ellipse at center, transparent 62%, rgba(0, 0, 0, 0.22) 100%);\r
495
+ animation: px-crt-flicker 4s steps(60) infinite;\r
496
+ }\r
497
+ @keyframes px-crt-flicker {\r
498
+ 0%, 100% { opacity: 1; }\r
499
+ 50% { opacity: 0.96; }\r
500
+ }\r
501
+ @media (prefers-reduced-motion: reduce) {\r
502
+ html[data-pixel-ui] body::after { animation: none; }\r
503
+ html[data-pixel-ui] button,\r
504
+ html[data-pixel-ui] [class*='btn'],\r
505
+ html[data-pixel-ui] [class*='Button'],\r
506
+ html[data-pixel-ui] [class*='card'] {\r
507
+ transition: none;\r
508
+ }\r
509
+ }\r
510
+ \r
511
+ /* ── 设置页「像素主题」行(不跟随皮肤作用域:现代模式下也保持可点) ── */\r
512
+ .px-theme-row {\r
513
+ display: flex;\r
514
+ flex-direction: column;\r
515
+ gap: 8px;\r
516
+ padding: 12px 0;\r
517
+ border-top: 1px solid rgba(139, 107, 69, 0.35);\r
518
+ }\r
519
+ .px-theme-row-title {\r
520
+ font-family: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r
521
+ font-size: 12px;\r
522
+ color: #F4D03F;\r
523
+ text-shadow: var(--px-ts-chrome, 2px 2px 0 rgba(26, 15, 6, 0.6));\r
524
+ letter-spacing: 0.05em;\r
525
+ }\r
526
+ .px-theme-row-cubes {\r
527
+ display: flex;\r
528
+ flex-wrap: wrap;\r
529
+ gap: 8px;\r
530
+ }\r
531
+ .px-theme-btn {\r
532
+ display: inline-flex;\r
533
+ align-items: center;\r
534
+ gap: 6px;\r
535
+ padding: 5px 10px;\r
536
+ font-family: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r
537
+ font-size: 11px;\r
538
+ color: #E8D5B0;\r
539
+ background: #2C1A0C;\r
540
+ border: 2px solid #1A0F06;\r
541
+ border-radius: 0 !important;\r
542
+ cursor: pointer;\r
543
+ box-shadow:\r
544
+ inset 1px 1px 0 rgba(255, 248, 231, 0.15),\r
545
+ inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r
546
+ 2px 2px 0 rgba(0, 0, 0, 0.5);\r
547
+ }\r
548
+ .px-theme-btn:hover {\r
549
+ filter: brightness(1.12);\r
550
+ transform: translate(-1px, -1px);\r
551
+ }\r
552
+ .px-theme-btn:active {\r
553
+ transform: translate(1px, 1px);\r
554
+ box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.4);\r
555
+ }\r
556
+ .px-theme-btn-active {\r
557
+ color: #1A0F06;\r
558
+ background: #F4D03F;\r
559
+ border-color: #8B6B00;\r
560
+ box-shadow:\r
561
+ inset 1px 1px 0 #FFE066,\r
562
+ inset -1px -1px 0 #8B6B00,\r
563
+ 2px 2px 0 rgba(0, 0, 0, 0.5);\r
564
+ }\r
565
+ .px-theme-swatch {\r
566
+ width: 10px;\r
567
+ height: 10px;\r
568
+ border: 1px solid #000;\r
569
+ box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.4);\r
570
+ }\r
571
+ `;
572
+
573
+ // src/client/index.js
574
+ var name = "dsh-pixel-ui";
575
+ var inject = ["slots", "theme"];
576
+ var THEME_STORAGE_KEY = "dsh-pixel-ui:theme";
577
+ var THEMES = [
578
+ {
579
+ id: "pixel-wood",
580
+ colorScheme: "dark",
581
+ tokens: {
582
+ "--dsw-alias-bg-base": "#1A0F06",
583
+ "--dsw-alias-bg-layer-1": "#2C1A0C",
584
+ "--dsw-alias-bg-layer-2": "#3A2515",
585
+ "--dsw-alias-bg-overlay": "#241408",
586
+ "--dsw-alias-border-l1": "#4A3020",
587
+ "--dsw-alias-border-l2": "#8B6B45",
588
+ "--dsw-alias-brand-primary": "#F4D03F",
589
+ "--dsw-alias-label-primary": "#F5E6C8",
590
+ "--dsw-alias-label-secondary": "#9B7B5B",
591
+ "--dsw-alias-state-error-primary": "#E74C3C",
592
+ "--dsw-alias-state-success-primary": "#7DCE82",
593
+ "--dsw-alias-state-warn-primary": "#F39C12",
594
+ "--dsw-specific-sidebar-fill": "#241408"
595
+ }
596
+ },
597
+ {
598
+ id: "pixel-paper",
599
+ colorScheme: "light",
600
+ tokens: {
601
+ "--dsw-alias-bg-base": "#F0E8D8",
602
+ "--dsw-alias-bg-layer-1": "#E8DCC8",
603
+ "--dsw-alias-bg-layer-2": "#DDD0B8",
604
+ "--dsw-alias-bg-overlay": "#E2D6BE",
605
+ "--dsw-alias-border-l1": "#D4C4A8",
606
+ "--dsw-alias-border-l2": "#9B8B6B",
607
+ "--dsw-alias-brand-primary": "#C8960C",
608
+ "--dsw-alias-label-primary": "#3A2A10",
609
+ "--dsw-alias-label-secondary": "#6B5020",
610
+ "--dsw-alias-state-error-primary": "#8B2020",
611
+ "--dsw-alias-state-success-primary": "#3A7A40",
612
+ "--dsw-alias-state-warn-primary": "#805000",
613
+ "--dsw-specific-sidebar-fill": "#E8DCC8"
614
+ }
615
+ },
616
+ {
617
+ id: "pixel-warm",
618
+ colorScheme: "dark",
619
+ tokens: {
620
+ "--dsw-alias-bg-base": "#1E0E04",
621
+ "--dsw-alias-bg-layer-1": "#34180A",
622
+ "--dsw-alias-bg-layer-2": "#4A2210",
623
+ "--dsw-alias-bg-overlay": "#2A1308",
624
+ "--dsw-alias-border-l1": "#5C2E16",
625
+ "--dsw-alias-border-l2": "#A86B40",
626
+ "--dsw-alias-brand-primary": "#FF8C42",
627
+ "--dsw-alias-label-primary": "#F0C8A0",
628
+ "--dsw-alias-label-secondary": "#A86B40",
629
+ "--dsw-alias-state-error-primary": "#D93B3B",
630
+ "--dsw-alias-state-success-primary": "#6DBF6D",
631
+ "--dsw-alias-state-warn-primary": "#FF8C42",
632
+ "--dsw-specific-sidebar-fill": "#2A1308"
633
+ }
634
+ },
635
+ {
636
+ id: "pixel-retro",
637
+ colorScheme: "dark",
638
+ tokens: {
639
+ "--dsw-alias-bg-base": "#0A0E0A",
640
+ "--dsw-alias-bg-layer-1": "#0E140E",
641
+ "--dsw-alias-bg-layer-2": "#121A12",
642
+ "--dsw-alias-bg-overlay": "#0C100C",
643
+ "--dsw-alias-border-l1": "#2A402A",
644
+ "--dsw-alias-border-l2": "#3A5A3A",
645
+ "--dsw-alias-brand-primary": "#33FF33",
646
+ "--dsw-alias-label-primary": "#33FF33",
647
+ "--dsw-alias-label-secondary": "#118811",
648
+ "--dsw-alias-state-error-primary": "#FF3333",
649
+ "--dsw-alias-state-success-primary": "#33FF33",
650
+ "--dsw-alias-state-warn-primary": "#FFCC33",
651
+ "--dsw-specific-sidebar-fill": "#0C100C"
652
+ }
653
+ }
654
+ ];
655
+ var PIXEL_IDS = THEMES.map((theme) => theme.id);
656
+ var RESTORABLE_IDS = /* @__PURE__ */ new Set(["light", "dark", "system", ...PIXEL_IDS]);
657
+ var THEME_CHOICES = [
658
+ { id: "pixel-wood", label: "像素·木屋", swatch: "#F4D03F" },
659
+ { id: "pixel-paper", label: "像素·羊皮纸", swatch: "#F5E6C8" },
660
+ { id: "pixel-warm", label: "像素·暖阳", swatch: "#FF8C42" },
661
+ { id: "pixel-retro", label: "像素·终端绿", swatch: "#33FF33" },
662
+ { id: "system", label: "现代默认", swatch: "#7A7A7A" }
663
+ ];
664
+ function createThemeRowStore() {
665
+ return (0, import_client.defineStore)({
666
+ init: () => ({ preference: null, revision: -1 }),
667
+ actions: {
668
+ sync: (draft, preference, revision) => {
669
+ if (revision <= draft.revision) return;
670
+ draft.preference = preference;
671
+ draft.revision = revision;
672
+ }
673
+ }
674
+ });
675
+ }
676
+ function ThemeRow(props) {
677
+ const preference = props.useStore((state) => state.preference);
678
+ return (0, import_react.createElement)(
679
+ "div",
680
+ { className: "px-theme-row" },
681
+ (0, import_react.createElement)("div", { className: "px-theme-row-title" }, "像素主题"),
682
+ (0, import_react.createElement)(
683
+ "div",
684
+ { className: "px-theme-row-cubes" },
685
+ THEME_CHOICES.map((choice) => (0, import_react.createElement)(
686
+ "button",
687
+ {
688
+ key: choice.id,
689
+ type: "button",
690
+ className: "px-theme-btn" + (preference === choice.id ? " px-theme-btn-active" : ""),
691
+ onClick: () => {
692
+ props.setTheme(choice.id);
693
+ }
694
+ },
695
+ (0, import_react.createElement)("span", { className: "px-theme-swatch", style: { background: choice.swatch } }),
696
+ choice.label
697
+ ))
698
+ )
699
+ );
700
+ }
701
+ function apply(ctx) {
702
+ const syncScope = () => {
703
+ const active = ctx.theme.getTheme().active;
704
+ const on = PIXEL_IDS.includes(active.id);
705
+ document.documentElement.toggleAttribute("data-pixel-ui", on);
706
+ if (on) document.documentElement.setAttribute("data-pixel-theme", active.id);
707
+ else document.documentElement.removeAttribute("data-pixel-theme");
708
+ };
709
+ const persist = (snapshot) => {
710
+ try {
711
+ localStorage.setItem(THEME_STORAGE_KEY, snapshot.preference);
712
+ } catch {
713
+ }
714
+ };
715
+ ctx.on("theme/change", (snapshot) => {
716
+ syncScope();
717
+ persist(snapshot);
718
+ });
719
+ ctx.effect(() => {
720
+ const disposers = THEMES.map((definition) => ctx.theme.register(definition));
721
+ return () => {
722
+ for (const dispose of disposers) dispose();
723
+ };
724
+ }, "dsh-pixel-ui: theme registration");
725
+ let saved = null;
726
+ try {
727
+ saved = localStorage.getItem(THEME_STORAGE_KEY);
728
+ } catch {
729
+ }
730
+ const target = saved !== null && RESTORABLE_IDS.has(saved) ? saved : "pixel-wood";
731
+ try {
732
+ ctx.theme.setTheme(target);
733
+ } catch {
734
+ }
735
+ syncScope();
736
+ const rowStore = createThemeRowStore();
737
+ let bound = void 0;
738
+ const syncRow = (snapshot) => {
739
+ bound?.sync(snapshot.preference, snapshot.revision);
740
+ };
741
+ ctx.on("theme/change", syncRow);
742
+ ctx.slots.inject("settings.general.item", () => ctx.slots.register({
743
+ name: "settings.general.item",
744
+ id: "pixel-theme",
745
+ order: 20,
746
+ store: rowStore,
747
+ inject: (actions) => {
748
+ bound = actions;
749
+ syncRow(ctx.theme.getTheme());
750
+ return { setTheme: (id) => {
751
+ ctx.theme.setTheme(id);
752
+ } };
753
+ }
754
+ }, ThemeRow));
755
+ ctx.effect(() => {
756
+ const style = document.createElement("style");
757
+ style.dataset.plugin = "dsh-pixel-ui";
758
+ style.textContent = pixel_default;
759
+ document.head.appendChild(style);
760
+ return () => {
761
+ style.remove();
762
+ document.documentElement.removeAttribute("data-pixel-ui");
763
+ document.documentElement.removeAttribute("data-pixel-theme");
764
+ };
765
+ }, "dsh-pixel-ui: stylesheet");
766
+ }
767
+ return module.exports; } });
768
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/client/index.js", "../src/client/pixel.css"],
4
+ "sourcesContent": ["/**\n * dsh-pixel-ui — browser half (the pixel skin).\n *\n * Registers four Agent-Xi-style pixel themes on the ThemeService seam\n * (`ctx.theme.register` with --dsw-alias-* token overrides): wood (dark),\n * paper (light), warm (dark), retro-green (dark). The stylesheet carries\n * the pixel borders, fonts, CRT overlay, and component tweaks that alias\n * tokens alone cannot express, scoped to `html[data-pixel-ui]` with a\n * `data-pixel-theme` variant attribute for the four palettes.\n *\n * The host settings scope persists only the built-in preferences\n * (light/dark/system), so this plugin persists the last choice itself\n * (localStorage) and restores it on load; the first run activates the\n * default wood skin. A settings row in the General section switches\n * between the four skins and back to the modern default (`system`).\n *\n * @module dsh-pixel-ui/client\n */\nimport { createElement as h } from 'react'\nimport { defineStore } from '@deepseek-ai/dsh-client-runtime/client'\nimport cssText from './pixel.css'\n\n/** Plugin name; also the patch row id. */\nexport const name = 'dsh-pixel-ui'\n\n/** Required services: the theme runtime and the settings item slot. */\nexport const inject = ['slots', 'theme']\n\n/** localStorage key carrying the last theme choice across loads. */\nconst THEME_STORAGE_KEY = 'dsh-pixel-ui:theme'\n\n/** The four pixel themes (Agent Xi palettes) registered on the ThemeService. */\nconst THEMES = [\n {\n id: 'pixel-wood',\n colorScheme: 'dark',\n tokens: {\n '--dsw-alias-bg-base': '#1A0F06',\n '--dsw-alias-bg-layer-1': '#2C1A0C',\n '--dsw-alias-bg-layer-2': '#3A2515',\n '--dsw-alias-bg-overlay': '#241408',\n '--dsw-alias-border-l1': '#4A3020',\n '--dsw-alias-border-l2': '#8B6B45',\n '--dsw-alias-brand-primary': '#F4D03F',\n '--dsw-alias-label-primary': '#F5E6C8',\n '--dsw-alias-label-secondary': '#9B7B5B',\n '--dsw-alias-state-error-primary': '#E74C3C',\n '--dsw-alias-state-success-primary': '#7DCE82',\n '--dsw-alias-state-warn-primary': '#F39C12',\n '--dsw-specific-sidebar-fill': '#241408',\n },\n },\n {\n id: 'pixel-paper',\n colorScheme: 'light',\n tokens: {\n '--dsw-alias-bg-base': '#F0E8D8',\n '--dsw-alias-bg-layer-1': '#E8DCC8',\n '--dsw-alias-bg-layer-2': '#DDD0B8',\n '--dsw-alias-bg-overlay': '#E2D6BE',\n '--dsw-alias-border-l1': '#D4C4A8',\n '--dsw-alias-border-l2': '#9B8B6B',\n '--dsw-alias-brand-primary': '#C8960C',\n '--dsw-alias-label-primary': '#3A2A10',\n '--dsw-alias-label-secondary': '#6B5020',\n '--dsw-alias-state-error-primary': '#8B2020',\n '--dsw-alias-state-success-primary': '#3A7A40',\n '--dsw-alias-state-warn-primary': '#805000',\n '--dsw-specific-sidebar-fill': '#E8DCC8',\n },\n },\n {\n id: 'pixel-warm',\n colorScheme: 'dark',\n tokens: {\n '--dsw-alias-bg-base': '#1E0E04',\n '--dsw-alias-bg-layer-1': '#34180A',\n '--dsw-alias-bg-layer-2': '#4A2210',\n '--dsw-alias-bg-overlay': '#2A1308',\n '--dsw-alias-border-l1': '#5C2E16',\n '--dsw-alias-border-l2': '#A86B40',\n '--dsw-alias-brand-primary': '#FF8C42',\n '--dsw-alias-label-primary': '#F0C8A0',\n '--dsw-alias-label-secondary': '#A86B40',\n '--dsw-alias-state-error-primary': '#D93B3B',\n '--dsw-alias-state-success-primary': '#6DBF6D',\n '--dsw-alias-state-warn-primary': '#FF8C42',\n '--dsw-specific-sidebar-fill': '#2A1308',\n },\n },\n {\n id: 'pixel-retro',\n colorScheme: 'dark',\n tokens: {\n '--dsw-alias-bg-base': '#0A0E0A',\n '--dsw-alias-bg-layer-1': '#0E140E',\n '--dsw-alias-bg-layer-2': '#121A12',\n '--dsw-alias-bg-overlay': '#0C100C',\n '--dsw-alias-border-l1': '#2A402A',\n '--dsw-alias-border-l2': '#3A5A3A',\n '--dsw-alias-brand-primary': '#33FF33',\n '--dsw-alias-label-primary': '#33FF33',\n '--dsw-alias-label-secondary': '#118811',\n '--dsw-alias-state-error-primary': '#FF3333',\n '--dsw-alias-state-success-primary': '#33FF33',\n '--dsw-alias-state-warn-primary': '#FFCC33',\n '--dsw-specific-sidebar-fill': '#0C100C',\n },\n },\n]\n\nconst PIXEL_IDS = THEMES.map((theme) => theme.id)\n\n/** Built-in preference ids; together with the pixel ids they are restorable. */\nconst RESTORABLE_IDS = new Set(['light', 'dark', 'system', ...PIXEL_IDS])\n\n/** Settings row choices: the four skins plus the modern default escape. */\nconst THEME_CHOICES = [\n { id: 'pixel-wood', label: '像素·木屋', swatch: '#F4D03F' },\n { id: 'pixel-paper', label: '像素·羊皮纸', swatch: '#F5E6C8' },\n { id: 'pixel-warm', label: '像素·暖阳', swatch: '#FF8C42' },\n { id: 'pixel-retro', label: '像素·终端绿', swatch: '#33FF33' },\n { id: 'system', label: '现代默认', swatch: '#7A7A7A' },\n]\n\n/**\n * Declares the theme row slot store: a mirror of the theme service\n * preference, written only by the plugin's apply-world change listener\n * (same shape as the ui-theme Appearance row store).\n * @returns the store handle.\n */\nfunction createThemeRowStore() {\n return defineStore({\n init: () => ({ preference: null, revision: -1 }),\n actions: {\n sync: (draft, preference, revision) => {\n if (revision <= draft.revision) return\n draft.preference = preference\n draft.revision = revision\n },\n },\n })\n}\n\n/**\n * General-section row: switch between the four pixel skins and back to the\n * modern default. Reads selection state through props.useStore and writes\n * through the injected setTheme callback.\n * @param props - slot shares (useStore + injected face).\n * @returns the row element tree.\n */\nfunction ThemeRow(props) {\n const preference = props.useStore((state) => state.preference)\n return h('div', { className: 'px-theme-row' },\n h('div', { className: 'px-theme-row-title' }, '像素主题'),\n h('div', { className: 'px-theme-row-cubes' },\n THEME_CHOICES.map((choice) => h('button', {\n key: choice.id,\n type: 'button',\n className: 'px-theme-btn' + (preference === choice.id ? ' px-theme-btn-active' : ''),\n onClick: () => { props.setTheme(choice.id) },\n },\n h('span', { className: 'px-theme-swatch', style: { background: choice.swatch } }),\n choice.label,\n )),\n ),\n )\n}\n\n/** Client plugin body: register the four themes, restore/persist the choice, inject CSS and the settings row. */\nexport function apply(ctx) {\n // Scope attributes mirror the active theme, so the stylesheet only shades\n // while a pixel theme is selected and the variant rules can pick the palette.\n const syncScope = () => {\n const active = ctx.theme.getTheme().active\n const on = PIXEL_IDS.includes(active.id)\n document.documentElement.toggleAttribute('data-pixel-ui', on)\n if (on) document.documentElement.setAttribute('data-pixel-theme', active.id)\n else document.documentElement.removeAttribute('data-pixel-theme')\n }\n\n // Custom theme ids do not survive the host settings scope, so carry the\n // latest preference here; built-in choices ride along too.\n const persist = (snapshot) => {\n try {\n localStorage.setItem(THEME_STORAGE_KEY, snapshot.preference)\n } catch {\n // Storage unavailable (private mode / quota): persistence is best-effort.\n }\n }\n ctx.on('theme/change', (snapshot) => { syncScope(); persist(snapshot) })\n\n ctx.effect(() => {\n const disposers = THEMES.map((definition) => ctx.theme.register(definition))\n return () => { for (const dispose of disposers) dispose() }\n }, 'dsh-pixel-ui: theme registration')\n\n // Restore the last choice; the first run wears the default wood skin.\n let saved = null\n try { saved = localStorage.getItem(THEME_STORAGE_KEY) } catch { /* storage unavailable */ }\n const target = saved !== null && RESTORABLE_IDS.has(saved) ? saved : 'pixel-wood'\n try { ctx.theme.setTheme(target) } catch { /* unknown id from an older version: keep current */ }\n syncScope()\n\n // Pixel theme row in the General settings section (alongside Appearance).\n const rowStore = createThemeRowStore()\n let bound = undefined\n const syncRow = (snapshot) => { bound?.sync(snapshot.preference, snapshot.revision) }\n ctx.on('theme/change', syncRow)\n ctx.slots.inject('settings.general.item', () => ctx.slots.register({\n name: 'settings.general.item',\n id: 'pixel-theme',\n order: 20,\n store: rowStore,\n inject: (actions) => {\n bound = actions\n // Re-sync from the getter so no event is lost between registration and\n // first render (the store's revision guard drops stale duplicates).\n syncRow(ctx.theme.getTheme())\n return { setTheme: (id) => { ctx.theme.setTheme(id) } }\n },\n }, ThemeRow))\n\n ctx.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = 'dsh-pixel-ui'\n style.textContent = cssText\n document.head.appendChild(style)\n return () => {\n style.remove()\n document.documentElement.removeAttribute('data-pixel-ui')\n document.documentElement.removeAttribute('data-pixel-theme')\n }\n }, 'dsh-pixel-ui: stylesheet')\n}\n", "/* dsh-pixel-ui — 星露谷风像素皮肤(木屋/羊皮纸/暖阳/终端绿四主题)\r\n * 全面对标 Agent Xi 前端像素语言(web/src/styles/main.css):\r\n * - 木色/金色/羊皮纸三系色板 + 阶梯硬阴影 + 内凹/凸起 bevel\r\n * - 像素字体做界面装饰(标题/页签/按钮/徽章/输入框),正文与代码走 mono\r\n * - 木纹条纹纹理、CRT 扫描线 + 暗角 + 微闪烁、像素光标、像素按压动效\r\n * 作用域 html[data-pixel-ui]:任一像素主题激活时生效,\r\n * data-pixel-theme 区分四种配色。切回 现代默认/浅色/深色 即整体退出。\r\n * 原则:颜色尽量交给主题 token,本表负责 token 表达不了的像素质感。 */\r\n\r\n@font-face {\r\n font-family: 'Fusion Pixel 12';\r\n src: url('/dsh-pixel-ui/fonts/fusion-pixel-12px.woff2') format('woff2');\r\n font-weight: 400;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n@font-face {\r\n font-family: 'Press Start 2P';\r\n src: url('/dsh-pixel-ui/fonts/PressStart2P-Regular.ttf') format('truetype');\r\n font-weight: 400;\r\n font-style: normal;\r\n font-display: swap;\r\n}\r\n\r\nhtml[data-pixel-ui] {\r\n /* ── Xi 同款色板 ─────────────────────────────────────── */\r\n --px-wood-darkest: #1A0F06;\r\n --px-wood-dark: #2C1A0C;\r\n --px-wood-mid: #3A2515;\r\n --px-wood-warm: #4A3020;\r\n --px-wood-light: #6B4C2E;\r\n --px-wood-pale: #8B6B45;\r\n --px-gold: #F4D03F;\r\n --px-gold-bright: #FFE066;\r\n --px-gold-dark: #C99A00;\r\n --px-gold-deep: #8B6B00;\r\n --px-parchment: #F5E6C8;\r\n --px-text-on-dark: #E8D5B0;\r\n --px-text-light: #9B7B5B;\r\n\r\n /* 输入框专用色(各主题单独覆盖,保证任何底色下文字可见) */\r\n --px-input-bg: #1A0F06;\r\n --px-input-text: #FFFDF5;\r\n --px-input-caret: #F4D03F;\r\n --px-input-ph: #9B7B5B;\r\n\r\n /* 文字阴影强度:暗色主题用 2px 像素硬阴影,浅色主题收敛防重影 */\r\n --px-ts-chrome: 2px 2px 0 rgba(26, 15, 6, 0.6), -1px -1px 0 rgba(26, 15, 6, 0.4);\r\n --px-ts-btn: 1px 1px 0 rgba(0, 0, 0, 0.4);\r\n\r\n /* 像素字体栈:中文/全角走 fusion-pixel(12px 原生),英文数字兜底 Press Start 2P */\r\n --px-font: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r\n --px-mono: 'Cascadia Code', 'Consolas', 'Courier New', monospace;\r\n}\r\n\r\n/* ── 四主题色板(Agent Xi 同款)────────────────────────── */\r\nhtml[data-pixel-theme='pixel-paper'] {\r\n --px-wood-darkest: #F0E8D8;\r\n --px-wood-dark: #E8DCC8;\r\n --px-wood-mid: #DDD0B8;\r\n --px-wood-warm: #D4C4A8;\r\n --px-wood-light: #B8A080;\r\n --px-wood-pale: #9B8B6B;\r\n --px-gold: #C8960C;\r\n --px-gold-bright: #E0A800;\r\n --px-gold-dark: #A07000;\r\n --px-gold-deep: #805000;\r\n --px-parchment: #FFFDF5;\r\n --px-text-on-dark: #3A2A10;\r\n --px-text-light: #8B7040;\r\n --px-input-bg: #FFFDF5;\r\n --px-input-text: #3A2A10;\r\n --px-input-caret: #C8960C;\r\n --px-input-ph: #8B7040;\r\n /* 浅色底上 2px 硬阴影会变重影:去掉文字阴影,靠字体本身 */\r\n --px-ts-chrome: none;\r\n --px-ts-btn: none;\r\n}\r\nhtml[data-pixel-theme='pixel-warm'] {\r\n --px-wood-darkest: #1E0E04;\r\n --px-wood-dark: #34180A;\r\n --px-wood-mid: #4A2210;\r\n --px-wood-warm: #5C2E16;\r\n --px-wood-light: #8B4A28;\r\n --px-wood-pale: #A86B40;\r\n --px-gold: #FF8C42;\r\n --px-gold-bright: #FFA64D;\r\n --px-gold-dark: #D96E30;\r\n --px-gold-deep: #A05020;\r\n --px-parchment: #FFF0E0;\r\n --px-text-on-dark: #F0C8A0;\r\n --px-text-light: #A86B40;\r\n --px-input-bg: #1E0E04;\r\n --px-input-text: #FFFBF5;\r\n --px-input-caret: #FF8C42;\r\n --px-input-ph: #A86B40;\r\n}\r\nhtml[data-pixel-theme='pixel-retro'] {\r\n --px-wood-darkest: #0A0E0A;\r\n --px-wood-dark: #0E140E;\r\n --px-wood-mid: #121A12;\r\n --px-wood-warm: #162016;\r\n --px-wood-light: #2A402A;\r\n --px-wood-pale: #3A5A3A;\r\n --px-gold: #33FF33;\r\n --px-gold-bright: #66FF66;\r\n --px-gold-dark: #00CC00;\r\n --px-gold-deep: #009900;\r\n --px-parchment: #0A1A0A;\r\n --px-text-on-dark: #33FF33;\r\n --px-text-light: #118811;\r\n --px-input-bg: #0A0E0A;\r\n --px-input-text: #33FF33;\r\n --px-input-caret: #33FF33;\r\n --px-input-ph: #118811;\r\n}\r\n\r\n/* ── 全局质感:禁次像素平滑(像素字体的灵魂)、位图三件套、方形化 ── */\r\nhtml[data-pixel-ui] body {\r\n -webkit-font-smoothing: none;\r\n -moz-osx-font-smoothing: grayscale;\r\n text-rendering: geometricPrecision;\r\n font-family: var(--px-font) !important;\r\n letter-spacing: 0.01em;\r\n}\r\n\r\nhtml[data-pixel-ui] img,\r\nhtml[data-pixel-ui] canvas,\r\nhtml[data-pixel-ui] video {\r\n image-rendering: -moz-crisp-edges;\r\n image-rendering: crisp-edges;\r\n image-rendering: pixelated;\r\n}\r\n\r\n/* 一切皆方角(像素风第一原则) */\r\nhtml[data-pixel-ui] * {\r\n border-radius: 0 !important;\r\n}\r\n\r\nhtml[data-pixel-ui] ::selection {\r\n background: var(--px-gold);\r\n color: var(--px-wood-darkest);\r\n}\r\n\r\nhtml[data-pixel-ui] :focus-visible {\r\n outline: 2px solid var(--px-gold) !important;\r\n outline-offset: 1px;\r\n}\r\n\r\n/* ── 像素滚动条:方形、木色 ────────────────────────────── */\r\nhtml[data-pixel-ui] ::-webkit-scrollbar { width: 10px; height: 10px; }\r\nhtml[data-pixel-ui] ::-webkit-scrollbar-track {\r\n background: var(--px-wood-darkest);\r\n border-left: 2px solid var(--px-wood-dark);\r\n}\r\nhtml[data-pixel-ui] ::-webkit-scrollbar-thumb {\r\n background: var(--px-wood-light);\r\n border: 2px solid var(--px-wood-darkest);\r\n}\r\nhtml[data-pixel-ui] ::-webkit-scrollbar-thumb:hover { background: var(--px-wood-pale); }\r\n\r\n/* ── 排版:装饰性 UI 用像素字体,正文/代码用 mono(Xi 的信息分层) ── */\r\nhtml[data-pixel-ui] h1,\r\nhtml[data-pixel-ui] h2,\r\nhtml[data-pixel-ui] h3,\r\nhtml[data-pixel-ui] [class*='title'],\r\nhtml[data-pixel-ui] [class*='label'],\r\nhtml[data-pixel-ui] [class*='tab'],\r\nhtml[data-pixel-ui] [class*='badge'],\r\nhtml[data-pixel-ui] [class*='chip'],\r\nhtml[data-pixel-ui] [class*='Tag'],\r\nhtml[data-pixel-ui] [class*='pill'] {\r\n font-family: var(--px-font) !important;\r\n text-shadow: var(--px-ts-chrome);\r\n}\r\n\r\n/* 标题/页签取金色(Xi .panel-title 语义) */\r\nhtml[data-pixel-ui] h1,\r\nhtml[data-pixel-ui] h2,\r\nhtml[data-pixel-ui] h3,\r\nhtml[data-pixel-ui] [class*='title'] {\r\n color: var(--px-gold-bright) !important;\r\n letter-spacing: 0.02em;\r\n}\r\n\r\n/* 页签:选中态金色下划线 */\r\nhtml[data-pixel-ui] [class*='tab'],\r\nhtml[data-pixel-ui] [aria-selected='true'] {\r\n font-size: 12px;\r\n}\r\nhtml[data-pixel-ui] [class*='tab'][class*='active'],\r\nhtml[data-pixel-ui] [aria-selected='true'] {\r\n box-shadow: inset 0 -3px 0 var(--px-gold) !important;\r\n}\r\n\r\n/* 徽章/小标签:切角 + 内凹高光(小元素才有资格切角,避免大块裁阴影) */\r\nhtml[data-pixel-ui] [class*='badge'],\r\nhtml[data-pixel-ui] [class*='chip'],\r\nhtml[data-pixel-ui] [class*='Tag'],\r\nhtml[data-pixel-ui] [class*='pill'] {\r\n font-size: 11px;\r\n line-height: 1.5;\r\n border: 1px solid #000 !important;\r\n box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.3) !important;\r\n clip-path: polygon(\r\n 0 2px, 2px 2px, 2px 0,\r\n calc(100% - 2px) 0, calc(100% - 2px) 2px, 100% 2px,\r\n 100% calc(100% - 2px), calc(100% - 2px) calc(100% - 2px), calc(100% - 2px) 100%,\r\n 2px 100%, 2px calc(100% - 2px), 0 calc(100% - 2px)\r\n );\r\n}\r\n\r\n/* ── 正文/消息/代码:mono 内容层(Xi log 区用 Fira Code 的忠实移植) ── */\r\nhtml[data-pixel-ui] [class*='message'],\r\nhtml[data-pixel-ui] [class*='bubble'],\r\nhtml[data-pixel-ui] [class*='markdown'],\r\nhtml[data-pixel-ui] [class*='content'],\r\nhtml[data-pixel-ui] pre,\r\nhtml[data-pixel-ui] code,\r\nhtml[data-pixel-ui] [class*='code'] {\r\n font-family: var(--px-mono) !important;\r\n letter-spacing: 0;\r\n text-shadow: none;\r\n}\r\n\r\n/* 消息行:左侧木色竖条(Xi .log-row 色带,统一木色) */\r\nhtml[data-pixel-ui] [class*='message'],\r\nhtml[data-pixel-ui] [class*='bubble'] {\r\n border-left: 3px solid var(--px-wood-warm) !important;\r\n}\r\n\r\n/* 代码块:黑底木边(Xi .log-code-wrap) */\r\nhtml[data-pixel-ui] pre,\r\nhtml[data-pixel-ui] [class*='code'] {\r\n background: var(--px-wood-darkest) !important;\r\n color: var(--px-text-on-dark) !important;\r\n border: 2px solid var(--px-wood-light) !important;\r\n box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.4) !important;\r\n}\r\n/* 行内代码:暗底金字 */\r\nhtml[data-pixel-ui] code {\r\n background: rgba(0, 0, 0, 0.4) !important;\r\n color: var(--px-gold-bright) !important;\r\n border: 1px solid rgba(0, 0, 0, 0.12) !important;\r\n padding: 0 4px;\r\n}\r\nhtml[data-pixel-ui] pre code {\r\n background: transparent !important;\r\n color: inherit !important;\r\n border: none !important;\r\n padding: 0;\r\n}\r\n\r\n/* ── 按钮:8-bit 凸起 + 阶梯硬阴影 + 悬停抬升 + 按压沉底 ── */\r\nhtml[data-pixel-ui] button,\r\nhtml[data-pixel-ui] [role='button'],\r\nhtml[data-pixel-ui] [class*='btn'],\r\nhtml[data-pixel-ui] [class*='Button'] {\r\n font-family: var(--px-font) !important;\r\n font-size: 12px;\r\n letter-spacing: 0.02em;\r\n border: 2px solid #000 !important;\r\n box-shadow:\r\n inset 2px 2px 0 rgba(255, 248, 231, 0.22),\r\n inset -2px -2px 0 rgba(0, 0, 0, 0.5),\r\n 2px 2px 0 #000,\r\n 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r\n text-shadow: var(--px-ts-btn);\r\n transition: transform 0.08s steps(2), box-shadow 0.08s steps(2), filter 0.08s steps(2);\r\n}\r\nhtml[data-pixel-ui] button:hover,\r\nhtml[data-pixel-ui] [role='button']:hover,\r\nhtml[data-pixel-ui] [class*='btn']:hover,\r\nhtml[data-pixel-ui] [class*='Button']:hover {\r\n filter: brightness(1.1);\r\n transform: translate(-2px, -2px);\r\n box-shadow:\r\n inset 2px 2px 0 rgba(255, 248, 231, 0.25),\r\n inset -2px -2px 0 rgba(0, 0, 0, 0.4),\r\n 4px 4px 0 #000,\r\n 5px 5px 0 rgba(0, 0, 0, 0.6) !important;\r\n}\r\nhtml[data-pixel-ui] button:active,\r\nhtml[data-pixel-ui] [role='button']:active,\r\nhtml[data-pixel-ui] [class*='btn']:active,\r\nhtml[data-pixel-ui] [class*='Button']:active {\r\n transform: translate(2px, 2px);\r\n box-shadow:\r\n inset 2px 2px 0 rgba(0, 0, 0, 0.5),\r\n inset -2px -2px 0 rgba(255, 248, 231, 0.1) !important;\r\n}\r\n\r\n/* 主按钮(品牌色)金边 */\r\nhtml[data-pixel-ui] button[class*='primary'],\r\nhtml[data-pixel-ui] [class*='btn-primary'] {\r\n border-color: var(--px-gold-deep) !important;\r\n box-shadow:\r\n inset 2px 2px 0 rgba(255, 224, 102, 0.5),\r\n inset -2px -2px 0 rgba(0, 0, 0, 0.5),\r\n 2px 2px 0 #000,\r\n 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r\n}\r\n\r\n/* ── 输入框:黑木底 + 羊皮纸文字 + 金色光标(修复文字不可见) ──\r\n * 关键:必须显式给文字颜色。Xi #command-input:cream 字 / wood-darkest 底 /\r\n * gold-deep 边 / 3px 内凹,聚焦金边光环。 */\r\nhtml[data-pixel-ui] input,\r\nhtml[data-pixel-ui] textarea,\r\nhtml[data-pixel-ui] select,\r\nhtml[data-pixel-ui] [contenteditable='true'] {\r\n font-family: var(--px-font) !important;\r\n font-size: 12px;\r\n letter-spacing: 0;\r\n color: var(--px-input-text) !important;\r\n -webkit-text-fill-color: var(--px-input-text) !important;\r\n caret-color: var(--px-input-caret) !important;\r\n background-color: var(--px-input-bg) !important;\r\n border: 2px solid var(--px-gold-deep) !important;\r\n box-shadow:\r\n inset 3px 3px 0 rgba(0, 0, 0, 0.6),\r\n inset -1px -1px 0 rgba(244, 208, 63, 0.1),\r\n 0 0 0 1px #000 !important;\r\n}\r\nhtml[data-pixel-ui] input:focus,\r\nhtml[data-pixel-ui] textarea:focus,\r\nhtml[data-pixel-ui] select:focus,\r\nhtml[data-pixel-ui] [contenteditable='true']:focus {\r\n border-color: var(--px-gold) !important;\r\n box-shadow:\r\n inset 3px 3px 0 rgba(0, 0, 0, 0.6),\r\n 0 0 0 2px var(--px-gold),\r\n 0 0 8px rgba(244, 208, 63, 0.4) !important;\r\n}\r\nhtml[data-pixel-ui] input::placeholder,\r\nhtml[data-pixel-ui] textarea::placeholder {\r\n color: var(--px-input-ph) !important;\r\n -webkit-text-fill-color: var(--px-input-ph) !important;\r\n opacity: 1;\r\n}\r\n/* 输入框容器只做边框质感,不压背景(避免把容器文字也染黑) */\r\nhtml[data-pixel-ui] [class*='input'] {\r\n border-color: var(--px-gold-deep) !important;\r\n}\r\n\r\n/* ── 面板/卡片/弹层:双框 + 阶梯硬阴影 + 木纹竖条 ────────── */\r\nhtml[data-pixel-ui] [class*='panel'],\r\nhtml[data-pixel-ui] [class*='card'],\r\nhtml[data-pixel-ui] [class*='Card'],\r\nhtml[data-pixel-ui] dialog,\r\nhtml[data-pixel-ui] [role='dialog'],\r\nhtml[data-pixel-ui] [class*='modal'],\r\nhtml[data-pixel-ui] [class*='popover'],\r\nhtml[data-pixel-ui] [class*='menu'],\r\nhtml[data-pixel-ui] [class*='dropdown'],\r\nhtml[data-pixel-ui] [class*='popup'] {\r\n border: 2px solid var(--px-wood-warm) !important;\r\n outline: 2px solid #000;\r\n outline-offset: -2px;\r\n box-shadow:\r\n inset 1px 1px 0 rgba(255, 255, 255, 0.08),\r\n inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r\n 2px 2px 0 #000,\r\n 3px 3px 0 rgba(0, 0, 0, 0.6) !important;\r\n /* Xi 木纹:每 10px 一条 1px 暗竖纹 */\r\n background-image:\r\n repeating-linear-gradient(\r\n 90deg,\r\n transparent 0px,\r\n transparent 10px,\r\n rgba(0, 0, 0, 0.06) 10px,\r\n rgba(0, 0, 0, 0.06) 11px\r\n ) !important;\r\n}\r\n\r\n/* 卡片悬停:抬升 + 阴影加厚(Xi hover 位移) */\r\nhtml[data-pixel-ui] [class*='card']:hover,\r\nhtml[data-pixel-ui] [class*='Card']:hover {\r\n transform: translate(-2px, -2px);\r\n box-shadow:\r\n inset 1px 1px 0 rgba(255, 255, 255, 0.1),\r\n inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r\n 4px 4px 0 #000,\r\n 5px 5px 0 rgba(0, 0, 0, 0.6) !important;\r\n}\r\n\r\n/* ── 顶栏/侧栏:木纹渐变 + 黑底边 + 金色发丝 ─────────────── */\r\nhtml[data-pixel-ui] [class*='header'],\r\nhtml[data-pixel-ui] [class*='topbar'],\r\nhtml[data-pixel-ui] [class*='titlebar'],\r\nhtml[data-pixel-ui] [class*='sidebar'],\r\nhtml[data-pixel-ui] [class*='Sidebar'] {\r\n background-image: linear-gradient(180deg, var(--px-wood-warm) 0%, var(--px-wood-dark) 100%) !important;\r\n border-bottom: 3px solid #000 !important;\r\n box-shadow:\r\n inset 0 2px 0 rgba(244, 208, 63, 0.1),\r\n inset 0 -2px 0 rgba(0, 0, 0, 0.5) !important;\r\n}\r\nhtml[data-pixel-ui] [class*='sidebar'],\r\nhtml[data-pixel-ui] [class*='Sidebar'] {\r\n border-right: 3px solid #000 !important;\r\n box-shadow:\r\n inset -3px 0 0 rgba(0, 0, 0, 0.4),\r\n inset 2px 0 0 rgba(255, 255, 255, 0.05) !important;\r\n}\r\n\r\n/* ── 链接:金色下划线 ──────────────────────────────────── */\r\nhtml[data-pixel-ui] a {\r\n color: var(--px-gold-bright) !important;\r\n text-decoration-thickness: 2px;\r\n text-underline-offset: 3px;\r\n}\r\n\r\n/* ── 进度条:刻度纹理 + 硬框(Xi .quest-progress) ──────── */\r\nhtml[data-pixel-ui] [class*='progress'] {\r\n border: 2px solid #000 !important;\r\n box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.6) !important;\r\n background-image: repeating-linear-gradient(\r\n 90deg,\r\n transparent 0px,\r\n transparent 4px,\r\n rgba(0, 0, 0, 0.35) 4px,\r\n rgba(0, 0, 0, 0.35) 5px\r\n ) !important;\r\n}\r\n\r\n/* ── 像素光标(SVG data-URI 阶梯箭头,Xi 同款造型) ─────── */\r\nhtml[data-pixel-ui] body {\r\n cursor: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M2 2v17h3v-3h3v-3h3v-3h3v-3h3V2z' fill='%23FFFDF5' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E\") 2 2, auto;\r\n}\r\nhtml[data-pixel-ui] button,\r\nhtml[data-pixel-ui] [role='button'],\r\nhtml[data-pixel-ui] a,\r\nhtml[data-pixel-ui] [class*='card'],\r\nhtml[data-pixel-ui] [class*='tab'],\r\nhtml[data-pixel-ui] [class*='menu'],\r\nhtml[data-pixel-ui] [class*='dropdown'],\r\nhtml[data-pixel-ui] select,\r\nhtml[data-pixel-ui] label[for] {\r\n cursor: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M2 2v17h3v-3h3v-3h3v-3h3v-3h3V2z' fill='%23F4D03F' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E\") 2 2, pointer;\r\n}\r\nhtml[data-pixel-ui] input,\r\nhtml[data-pixel-ui] textarea,\r\nhtml[data-pixel-ui] [contenteditable='true'] {\r\n cursor: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' shape-rendering='crispEdges'%3E%3Cpath d='M5 3h4v2h2v2h2v2h2v2h2v2h2v6h-2v2h-4v2H5z' fill='%23FFFDF5' stroke='%231A0F06' stroke-width='2'/%3E%3C/svg%3E\") 4 3, text;\r\n}\r\n\r\n/* ── CRT 覆盖层:扫描线 + 暗角 + 微闪烁(Xi v3 滤镜) ────\r\n * 盖在最顶层但不拦截任何事件;尊重系统“减少动态效果”偏好。 */\r\nhtml[data-pixel-ui] body::after {\r\n content: \"\";\r\n position: fixed;\r\n inset: 0;\r\n z-index: 2147483647;\r\n pointer-events: none;\r\n background:\r\n repeating-linear-gradient(\r\n 0deg,\r\n rgba(0, 0, 0, 0.1) 0px,\r\n rgba(0, 0, 0, 0.1) 1px,\r\n transparent 1px,\r\n transparent 3px\r\n ),\r\n radial-gradient(ellipse at center, transparent 62%, rgba(0, 0, 0, 0.22) 100%);\r\n animation: px-crt-flicker 4s steps(60) infinite;\r\n}\r\n@keyframes px-crt-flicker {\r\n 0%, 100% { opacity: 1; }\r\n 50% { opacity: 0.96; }\r\n}\r\n@media (prefers-reduced-motion: reduce) {\r\n html[data-pixel-ui] body::after { animation: none; }\r\n html[data-pixel-ui] button,\r\n html[data-pixel-ui] [class*='btn'],\r\n html[data-pixel-ui] [class*='Button'],\r\n html[data-pixel-ui] [class*='card'] {\r\n transition: none;\r\n }\r\n}\r\n\r\n/* ── 设置页「像素主题」行(不跟随皮肤作用域:现代模式下也保持可点) ── */\r\n.px-theme-row {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n padding: 12px 0;\r\n border-top: 1px solid rgba(139, 107, 69, 0.35);\r\n}\r\n.px-theme-row-title {\r\n font-family: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r\n font-size: 12px;\r\n color: #F4D03F;\r\n text-shadow: var(--px-ts-chrome, 2px 2px 0 rgba(26, 15, 6, 0.6));\r\n letter-spacing: 0.05em;\r\n}\r\n.px-theme-row-cubes {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 8px;\r\n}\r\n.px-theme-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n gap: 6px;\r\n padding: 5px 10px;\r\n font-family: 'Fusion Pixel 12', 'Press Start 2P', monospace;\r\n font-size: 11px;\r\n color: #E8D5B0;\r\n background: #2C1A0C;\r\n border: 2px solid #1A0F06;\r\n border-radius: 0 !important;\r\n cursor: pointer;\r\n box-shadow:\r\n inset 1px 1px 0 rgba(255, 248, 231, 0.15),\r\n inset -1px -1px 0 rgba(0, 0, 0, 0.4),\r\n 2px 2px 0 rgba(0, 0, 0, 0.5);\r\n}\r\n.px-theme-btn:hover {\r\n filter: brightness(1.12);\r\n transform: translate(-1px, -1px);\r\n}\r\n.px-theme-btn:active {\r\n transform: translate(1px, 1px);\r\n box-shadow: inset 2px 2px 0 rgba(0, 0, 0, 0.4);\r\n}\r\n.px-theme-btn-active {\r\n color: #1A0F06;\r\n background: #F4D03F;\r\n border-color: #8B6B00;\r\n box-shadow:\r\n inset 1px 1px 0 #FFE066,\r\n inset -1px -1px 0 #8B6B00,\r\n 2px 2px 0 rgba(0, 0, 0, 0.5);\r\n}\r\n.px-theme-swatch {\r\n width: 10px;\r\n height: 10px;\r\n border: 1px solid #000;\r\n box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.4);\r\n}\r\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBA,mBAAmC;AACnC,oBAA4B;;;ACnB5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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",
6
+ "names": ["h"]
7
+ }
package/lib/index.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * dsh-pixel-ui — node half.
3
+ *
4
+ * Serves the bundled pixel fonts to the browser half under
5
+ * `/dsh-pixel-ui/fonts/<file>` (filename whitelist — no path traversal).
6
+ * The theme itself lives entirely in the browser half; this package is
7
+ * dual-face only so the fonts have a stable same-origin URL.
8
+ *
9
+ * @module dsh-pixel-ui
10
+ */
11
+ import { readFileSync } from 'node:fs'
12
+ import { join } from 'node:path'
13
+ import { fileURLToPath } from 'node:url'
14
+
15
+ /** Plugin name; also the patch row id. */
16
+ export const name = 'dsh-pixel-ui'
17
+
18
+ /** Required services: the web route registry. */
19
+ export const inject = ['webServer']
20
+
21
+ const FONTS_DIR = fileURLToPath(new URL('../assets/fonts/', import.meta.url))
22
+
23
+ const FONT_TYPES = {
24
+ 'fusion-pixel-12px.woff2': 'font/woff2',
25
+ 'PressStart2P-Regular.ttf': 'font/ttf',
26
+ }
27
+
28
+ /**
29
+ * Mount the font route.
30
+ * @param ctx - context carrying webServer.
31
+ */
32
+ export function apply(ctx) {
33
+ ctx.effect(() => ctx.webServer.register({
34
+ kind: 'prefix',
35
+ path: '/dsh-pixel-ui/fonts',
36
+ handler: (req, res) => {
37
+ const pathname = new URL(req.url ?? '/', 'http://x').pathname
38
+ const file = pathname.slice('/dsh-pixel-ui/fonts/'.length)
39
+ const type = FONT_TYPES[file]
40
+ if (type === undefined) {
41
+ res.writeHead(404)
42
+ res.end()
43
+ return
44
+ }
45
+ res.writeHead(200, {
46
+ 'content-type': type,
47
+ 'cache-control': 'public, max-age=86400',
48
+ })
49
+ res.end(readFileSync(join(FONTS_DIR, file)))
50
+ },
51
+ }), 'dsh-pixel-ui: fonts route')
52
+ }
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "dsh-pixel-ui",
3
+ "version": "1.0.0",
4
+ "description": "DSH 像素皮肤:Agent Xi 风格四主题(木屋/羊皮纸/暖阳/终端绿)+ fusion-pixel/Press Start 2P 像素字体 + CRT 扫描线,可一键切回现代默认",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "files": [
8
+ "lib",
9
+ "assets",
10
+ "cordis.patch.yml",
11
+ "README.md",
12
+ "LICENSE"
13
+ ],
14
+ "exports": {
15
+ ".": "./lib/index.js",
16
+ "./client": "./lib/client.js",
17
+ "./package.json": "./package.json"
18
+ },
19
+ "scripts": {
20
+ "build": "node scripts/build.mjs"
21
+ },
22
+ "dsh": {
23
+ "bundle": {
24
+ "patch": "./cordis.patch.yml"
25
+ },
26
+ "client": {
27
+ "inject": [
28
+ "@deepseek-ai/dsh-client-ui-theme",
29
+ "@deepseek-ai/dsh-client-ui-slots",
30
+ "@deepseek-ai/dsh-client-ui-settings-general"
31
+ ],
32
+ "platform": "web"
33
+ }
34
+ },
35
+ "peerDependencies": {
36
+ "@deepseek-ai/cordis": "^4.0.1"
37
+ },
38
+ "devDependencies": {
39
+ "esbuild": "^0.28.2"
40
+ },
41
+ "license": "MIT"
42
+ }