dsh-pixel-ui 1.0.0 → 1.5.1
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/README.md +180 -158
- package/assets/cover.jpg +0 -0
- package/assets/screenshot-paper.png +0 -0
- package/assets/screenshot-retro.png +0 -0
- package/assets/screenshot-warm.png +0 -0
- package/assets/screenshot-wood.png +0 -0
- package/lib/client.js +157 -576
- package/lib/client.js.map +3 -3
- package/lib/index.js +120 -5
- package/package.json +44 -5
- package/assets/screenshot-paper-chat.png +0 -0
- package/assets/screenshot-retro-chat.png +0 -0
- package/assets/screenshot-warm-chat.png +0 -0
- package/assets/screenshot-wood-chat.png +0 -0
package/lib/client.js
CHANGED
|
@@ -26,554 +26,18 @@ __export(index_exports, {
|
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
28
|
var import_react = require("react");
|
|
29
|
-
var
|
|
29
|
+
var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
30
30
|
|
|
31
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
|
-
`;
|
|
32
|
+
var pixel_default = "/* dsh-pixel-ui — 星露谷风像素皮肤(木屋/羊皮纸/暖阳/终端绿四主题)\n *\n * 设计原则(v1.5.0 重写,依据是桌面端实测):\n *\n * 1. **完全平面(flat)**。用户 2026-10-01 的决定:不要立体效果。\n * 所以本表里**没有任何 box-shadow / text-shadow**——凸起、凹陷、浮雕、\n * 文字投影全部取消。像素的层次改由三样东西表达:\n * ① 整像素描边(2px,内容层 1px);\n * ② 平涂色块之间的一档明度差(主题色板自带);\n * ③ 2px 棋盘抖动(--px-dither)与手绘 SVG 像素图形。\n * 历史上用半透明 inset/outset 做 bevel,在 1.25 DPR 上会渲染成亚像素\n * 灰阶毛边,那正是用户最早报的「伪像素」。\n *\n * 2. **只做 token 表达不了的事**。颜色、背景、文字色交给主题 token;本表负责\n * 方角、2px 整像素描边、像素字体、位图缩放、像素光标、像素滚动条。\n *\n * 3. **选择器必须是「确定的类型」,不许再用 `[class*='card']` 这种子串扫射**。\n * v1.4 的 `[class*=...]` 规则命中了宿主大量它没打算命中的元素(`.xz4KEq_*`、\n * `.Dc7zOa_*`、`.Hqq-bq_*`、图标类…),结果整个界面被盖上一层厚重黑框,\n * 读起来像「处处凹陷的印章」——用户报的「伪像素 / 凹陷」就是它。\n * 这里只保留三类选择器:\n * a) 真正的 HTML 语义(button/input/table/pre/hr/…);\n * b) 稳定的 ARIA 与 data 属性([role=tab]、[aria-selected]、[data-theme]);\n * c) 本插件自己的类名(.px-*)与宿主主题 token(--dsw-*)。\n *\n * 4. **1px 细线只在内容层出现**(表格内线),装饰框一律 2px 起:\n * 像素风里 1px 装饰线在非整数缩放下必然糊成灰线。\n *\n * 作用域 html[data-pixel-ui]:任一像素主题激活时生效,data-pixel-theme 区分配色。\n */\n\n@font-face {\n font-family: 'Fusion Pixel 12';\n src: url('/dsh-pixel-ui/fonts/fusion-pixel-12px.woff2') format('woff2');\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: 'Press Start 2P';\n src: url('/dsh-pixel-ui/fonts/PressStart2P-Regular.ttf') format('truetype');\n font-weight: 400;\n font-style: normal;\n font-display: swap;\n}\n\n/* ── 基础令牌(木屋=暗色基准,其余主题覆盖配色) ─────────────────── */\nhtml[data-pixel-ui] {\n /* 木色阶 */\n --px-wood-darkest: #1A0F06;\n --px-wood-dark: #2C1A0C;\n --px-wood-mid: #3A2515;\n --px-wood-warm: #4A3020;\n --px-wood-light: #6B4C2E;\n --px-wood-pale: #8B6B45;\n /* 金色阶 */\n --px-gold: #F4D03F;\n --px-gold-bright: #FFE066;\n --px-gold-dark: #C99A00;\n --px-gold-deep: #8B6B00;\n --px-parchment: #F5E6C8;\n --px-text-on-dark: #E8D5B0;\n --px-text-light: #AC8A63;\n /* 输入件 */\n --px-input-bg: #1A0F06;\n --px-input-text: #FFFDF5;\n --px-input-caret: #F4D03F;\n --px-input-ph: #B08A5E;\n /* 代码 */\n --px-code-bg: #241408;\n --px-code-ink: #FFE066;\n /* 提示框 */\n --px-tooltip-bg: #1A0F06;\n /* 强调面 */\n --px-accent-bg: #F4D03F;\n --px-accent-ink: #1A0F06;\n --px-ink-on-mid: #F5E6C8;\n /* 描边色:平面皮肤唯一的「线」色,2px 整像素 */\n --px-line: #140B04;\n /* 纹理:2px 棋盘抖动 */\n --px-dither: #241408;\n /* 暗角(CRT 只保留暗角,扫描线在非整数 DPR 上必糊) */\n --px-vignette: rgba(0, 0, 0, 0.2);\n /* 内容列宽:宿主把 --dsh-conversation-column-width 写死成 0,\n * clamp(680px, 0 * .64, 920px) 恒取 680px 下限 → 宽屏上正文只占中间一条\n * (踩坑 #7)。这里补上那个变量应有的值:正文随视口撑开。 */\n --px-chat-width: clamp(680px, calc(64vw - 140px), 1200px);\n /* 侧栏 / 顶栏底 */\n --px-sidebar-fill: #241408;\n --px-topbar-fill: #2C1A0C;\n /* 字体栈 */\n --px-font: 'Fusion Pixel 12', 'Press Start 2P', monospace;\n --px-mono: 'Cascadia Code', 'Consolas', 'Courier New', monospace;\n}\n\n/* ── 四主题配色(Agent Xi 同款) ─────────────────────────────────── */\nhtml[data-pixel-theme='pixel-paper'] {\n --px-wood-darkest: #F0E8D8;\n --px-wood-dark: #E8DCC8;\n --px-wood-mid: #DDD0B8;\n --px-wood-warm: #D4C4A8;\n --px-wood-light: #B8A080;\n --px-wood-pale: #9B8B6B;\n --px-gold: #A07000;\n --px-gold-bright: #6B4F00;\n --px-gold-dark: #8A6400;\n --px-gold-deep: #7A5A00;\n --px-parchment: #FFFDF5;\n --px-text-on-dark: #3A2A10;\n --px-text-light: #6B5020;\n --px-input-bg: #FFFDF5;\n --px-input-text: #3A2A10;\n --px-input-caret: #8A6400;\n --px-input-ph: #8B7040;\n --px-code-bg: #E0D4BC;\n --px-code-ink: #5C4400;\n --px-tooltip-bg: #2A1B08;\n --px-accent-bg: #7A5A00;\n --px-accent-ink: #FFFDF5;\n --px-ink-on-mid: #3A2A10;\n --px-line: #8B7040;\n --px-dither: #D8C9AC;\n --px-vignette: rgba(0, 0, 0, 0.07);\n --px-sidebar-fill: #E8DCC8;\n --px-topbar-fill: #E8DCC8;\n}\nhtml[data-pixel-theme='pixel-warm'] {\n --px-wood-darkest: #1E0E04;\n --px-wood-dark: #34180A;\n --px-wood-mid: #4A2210;\n --px-wood-warm: #5C2E16;\n --px-wood-light: #8B4A28;\n --px-wood-pale: #A86B40;\n --px-gold: #FF8C42;\n --px-gold-bright: #FFA64D;\n --px-gold-dark: #D96E30;\n --px-gold-deep: #A05020;\n --px-parchment: #FFF0E0;\n --px-text-on-dark: #F0C8A0;\n --px-text-light: #C08A5C;\n --px-input-bg: #1E0E04;\n --px-input-text: #FFFBF5;\n --px-input-caret: #FF8C42;\n --px-input-ph: #C08A5C;\n --px-code-bg: #2A1308;\n --px-code-ink: #FFA64D;\n --px-tooltip-bg: #1E0E04;\n --px-accent-bg: #FF8C42;\n --px-accent-ink: #1E0E04;\n --px-ink-on-mid: #FFF0E0;\n --px-line: #150801;\n --px-dither: #2A1308;\n --px-sidebar-fill: #2A1308;\n --px-topbar-fill: #34180A;\n}\nhtml[data-pixel-theme='pixel-retro'] {\n --px-wood-darkest: #0A0E0A;\n --px-wood-dark: #0E140E;\n --px-wood-mid: #121A12;\n --px-wood-warm: #162016;\n --px-wood-light: #2A402A;\n --px-wood-pale: #3A5A3A;\n --px-gold: #33FF33;\n --px-gold-bright: #66FF66;\n --px-gold-dark: #00CC00;\n --px-gold-deep: #009900;\n --px-parchment: #B8F0B8;\n --px-text-on-dark: #33FF33;\n --px-text-light: #22AA22;\n --px-input-bg: #0A0E0A;\n --px-input-text: #33FF33;\n --px-input-caret: #33FF33;\n --px-input-ph: #22AA22;\n --px-code-bg: #0E140E;\n --px-code-ink: #66FF66;\n --px-tooltip-bg: #0A0E0A;\n --px-accent-bg: #33FF33;\n --px-accent-ink: #0A0E0A;\n --px-ink-on-mid: #B8F0B8;\n --px-line: #040704;\n --px-dither: #101A10;\n --px-sidebar-fill: #0C100C;\n --px-topbar-fill: #0E140E;\n}\n\n/* ── 内容列宽(桌面端「一半一半」的修正,踩坑 #7) ──────────────────\n * 宿主只在样式表里声明 `--dsh-chat-content-width: var(--dsh-chat-user-width,\n * clamp(680px, calc(var(--dsh-conversation-column-width, 0px) * .64), 920px))`,\n * 而 `--dsh-conversation-column-width` 全仓无人赋值 → clamp 恒取 680px。\n * 在根作用域用 !important 把两个变量补上(宿主会把 user-width 以内联样式写在\n * 容器上,只有 !important 能压过内联)。 */\nhtml[data-pixel-ui] {\n --dsh-conversation-column-width: calc(100vw - 280px) !important;\n --dsh-chat-user-width: var(--px-chat-width) !important;\n --dsh-chat-content-width: var(--px-chat-width) !important;\n}\n/* 兜底:万一宿主把列宽写死在自己的样式层,这里同权重覆盖。 */\nhtml[data-pixel-ui] [class*='xz4KEq_column'] {\n max-width: var(--px-chat-width);\n}\n\n/* ── 全局:方角、禁次像素平滑、位图缩放 ─────────────────────────── */\nhtml[data-pixel-ui] * {\n border-radius: 0 !important;\n}\nhtml[data-pixel-ui] body {\n -webkit-font-smoothing: none;\n -moz-osx-font-smoothing: grayscale;\n text-rendering: geometricPrecision;\n font-family: var(--px-font) !important;\n /* 0.01em 会把字形推到半像素 → 灰边;像素字体必须整像素落位 */\n letter-spacing: 0;\n}\nhtml[data-pixel-ui] img,\nhtml[data-pixel-ui] canvas,\nhtml[data-pixel-ui] video {\n image-rendering: pixelated;\n}\nhtml[data-pixel-ui] ::selection {\n background: var(--px-accent-bg);\n color: var(--px-accent-ink);\n}\nhtml[data-pixel-ui] :focus-visible {\n outline: 2px solid var(--px-gold) !important;\n outline-offset: 1px;\n}\n\n/* 暗角:只保留径向暗角(扫描线在 1.25 DPR 上必糊成灰膜)。 */\nhtml[data-pixel-ui] body::after {\n content: \"\";\n position: fixed;\n inset: 0;\n z-index: 2147483647;\n pointer-events: none;\n background: radial-gradient(ellipse at center, transparent 70%, var(--px-vignette) 100%);\n}\n@media (prefers-reduced-motion: reduce) {\n html[data-pixel-ui] * {\n transition: none !important;\n animation: none !important;\n }\n}\n\n/* ── 像素滚动条:方、10px、木色 ─────────────────────────────────── */\nhtml[data-pixel-ui] {\n scrollbar-color: var(--px-wood-light) var(--px-wood-darkest);\n}\nhtml[data-pixel-ui] ::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\nhtml[data-pixel-ui] ::-webkit-scrollbar-track {\n background: var(--px-wood-darkest);\n border-left: 2px solid var(--px-wood-dark);\n}\nhtml[data-pixel-ui] ::-webkit-scrollbar-thumb {\n background: var(--px-wood-light);\n border: 2px solid var(--px-wood-darkest);\n}\nhtml[data-pixel-ui] ::-webkit-scrollbar-thumb:hover {\n background: var(--px-wood-pale);\n}\nhtml[data-pixel-ui] ::-webkit-scrollbar-corner {\n background: var(--px-wood-darkest);\n}\n\n/* ── 排版:装饰性文字走像素字体;正文/代码走 mono ────────────────── */\nhtml[data-pixel-ui] h1,\nhtml[data-pixel-ui] h2,\nhtml[data-pixel-ui] h3,\nhtml[data-pixel-ui] h4,\nhtml[data-pixel-ui] summary,\nhtml[data-pixel-ui] button,\nhtml[data-pixel-ui] label,\nhtml[data-pixel-ui] legend,\nhtml[data-pixel-ui] [role='tab'],\nhtml[data-pixel-ui] [role='menuitem'],\nhtml[data-pixel-ui] [role='tooltip'],\nhtml[data-pixel-ui] [role='switch'] {\n font-family: var(--px-font) !important;\n}\nhtml[data-pixel-ui] h1,\nhtml[data-pixel-ui] h2,\nhtml[data-pixel-ui] h3 {\n color: var(--px-gold-bright) !important;\n}\n/* 正文/代码层:mono、不加字阴影、长 token 允许断行(像素字体更宽) */\nhtml[data-pixel-ui] pre,\nhtml[data-pixel-ui] code,\nhtml[data-pixel-ui] kbd,\nhtml[data-pixel-ui] textarea,\nhtml[data-pixel-ui] input,\nhtml[data-pixel-ui] p,\nhtml[data-pixel-ui] li,\nhtml[data-pixel-ui] td,\nhtml[data-pixel-ui] th {\n font-family: var(--px-mono) !important;\n}\nhtml[data-pixel-ui] p,\nhtml[data-pixel-ui] li {\n overflow-wrap: anywhere;\n}\n\n/* ── 按钮:默认只继承宿主的底与形(宿主大量图标按钮本来就是透明的),\n * 只把方角、像素字与「按下去掉一档」的反馈补齐;实心块只在悬停/选中时出现。\n * v1.4 给**所有** button 套 2px 黑框 + 内阴影,图标按钮全变成厚盒子,\n * 这是用户报「处处凹陷」的主因之一。 ─────────────────────────────── */\nhtml[data-pixel-ui] button {\n font-size: 12px;\n letter-spacing: 0;\n border: none !important;\n transition: background-color 0.06s steps(2), transform 0.06s steps(2);\n}\nhtml[data-pixel-ui] button:not(:disabled):hover {\n background-color: var(--px-wood-dark) !important;\n}\n/* 实心块按钮(工具栏/主按钮)才用整圈 2px bevel,列表行只用金色左条 */\nhtml[data-pixel-ui] button[class*='primary']:hover,\nhtml[data-pixel-ui] button[class*='Primary']:hover,\nhtml[data-pixel-ui] button[class*='danger']:hover,\n\nhtml[data-pixel-ui] button:not(:disabled):active {\n transform: translateY(1px);\n}\n/* 宿主已经画成「实心块」的按钮(主按钮/危险按钮)才补像素描边 */\nhtml[data-pixel-ui] button[class*='primary'],\nhtml[data-pixel-ui] button[class*='Primary'],\nhtml[data-pixel-ui] button[class*='danger'],\nhtml[data-pixel-ui] button[class*='Danger'] {\n border: 2px solid var(--px-line) !important;\n}\nhtml[data-pixel-ui] button:disabled {\n opacity: 0.55;\n cursor: not-allowed;\n}\n\n/* ── 页签(对话/轨迹/记忆):文字 + 金下沿,**不加边框**\n * v1.4 给页签套了 2px 黑框,整条读起来像凹陷的输入框(用户报「凹陷了」)。\n * 平面皮肤里「选中」只用颜色 + 一条整像素下边线表达,不做凹凸。 */\nhtml[data-pixel-ui] [role='tab'] {\n font-size: 13px;\n border: none !important;\n border-bottom: 3px solid transparent !important;\n background-color: transparent !important;\n color: var(--px-text-light) !important;\n}\nhtml[data-pixel-ui] [role='tab']:hover {\n color: var(--px-text-on-dark) !important;\n}\nhtml[data-pixel-ui] [role='tab'][aria-selected='true'] {\n color: var(--px-gold-bright) !important;\n background-color: transparent !important;\n border-bottom-color: var(--px-gold) !important;\n}\n\n/* ── 输入件:黑木底 + 羊皮纸字 + 金框,聚焦金环 ───────────────────\n * 只给「真正的输入面」上底和框,`select` 与只读输入保留宿主的形,\n * 否则设置页里成排的选择器全变成黑盒子。 */\nhtml[data-pixel-ui] input:not([type='checkbox']):not([type='radio']),\nhtml[data-pixel-ui] textarea,\nhtml[data-pixel-ui] [contenteditable='true'] {\n font-size: 12px;\n letter-spacing: 0;\n color: var(--px-input-text) !important;\n -webkit-text-fill-color: var(--px-input-text) !important;\n caret-color: var(--px-input-caret) !important;\n background-color: var(--px-input-bg) !important;\n border: 2px solid var(--px-gold-deep) !important;\n}\nhtml[data-pixel-ui] input:focus,\nhtml[data-pixel-ui] textarea:focus,\nhtml[data-pixel-ui] [contenteditable='true']:focus {\n border-color: var(--px-gold) !important;\n outline: none !important;\n}\nhtml[data-pixel-ui] select {\n color: var(--px-input-text) !important;\n background-color: transparent !important;\n border: 2px solid var(--px-gold-deep) !important;\n}\nhtml[data-pixel-ui] select:focus {\n border-color: var(--px-gold) !important;\n outline: none !important;\n}\nhtml[data-pixel-ui] input::placeholder,\nhtml[data-pixel-ui] textarea::placeholder {\n color: var(--px-input-ph) !important;\n -webkit-text-fill-color: var(--px-input-ph) !important;\n opacity: 1;\n}\nhtml[data-pixel-ui] [contenteditable='true']:empty::before {\n color: var(--px-input-ph) !important;\n -webkit-text-fill-color: var(--px-input-ph) !important;\n}\n\n/* ── 选择件:复选框 / 单选 / 开关 / 滑块 ───────────────────────── */\nhtml[data-pixel-ui] input[type='checkbox'],\nhtml[data-pixel-ui] input[type='radio'] {\n appearance: none;\n -webkit-appearance: none;\n width: 14px;\n height: 14px;\n padding: 0;\n flex-shrink: 0;\n background-color: var(--px-input-bg) !important;\n border: 2px solid var(--px-line) !important;\n}\nhtml[data-pixel-ui] input[type='checkbox']:checked {\n background-color: var(--px-gold) !important;\n /* 12×12 手绘像素对勾(2px 阶梯),定位取整像素 */\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' shape-rendering='crispEdges'%3E%3Cg fill='%231A0F06'%3E%3Crect x='0' y='4' width='2' height='2'/%3E%3Crect x='0' y='6' width='2' height='2'/%3E%3Crect x='2' y='6' width='2' height='2'/%3E%3Crect x='2' y='8' width='2' height='2'/%3E%3Crect x='4' y='4' width='2' height='2'/%3E%3Crect x='4' y='6' width='2' height='2'/%3E%3Crect x='4' y='8' width='2' height='2'/%3E%3Crect x='4' y='10' width='2' height='2'/%3E%3Crect x='6' y='2' width='2' height='2'/%3E%3Crect x='6' y='4' width='2' height='2'/%3E%3Crect x='6' y='6' width='2' height='2'/%3E%3Crect x='6' y='8' width='2' height='2'/%3E%3Crect x='8' y='0' width='2' height='2'/%3E%3Crect x='8' y='2' width='2' height='2'/%3E%3Crect x='8' y='4' width='2' height='2'/%3E%3Crect x='8' y='6' width='2' height='2'/%3E%3Crect x='10' y='0' width='2' height='2'/%3E%3Crect x='10' y='2' width='2' height='2'/%3E%3Crect x='10' y='4' width='2' height='2'/%3E%3C/g%3E%3C/svg%3E\") !important;\n background-repeat: no-repeat !important;\n background-position: 3px 1px !important;\n border: 2px solid var(--px-line) !important;\n}\nhtml[data-pixel-ui] input[type='radio']:checked {\n background-color: var(--px-gold) !important;\n /* 平色时代没有 inset 灰阶可用:8×8 手绘像素方点,整像素定位 */\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' shape-rendering='crispEdges'%3E%3Crect x='0' y='0' width='8' height='8' fill='%231A0F06'/%3E%3C/svg%3E\") !important;\n background-size: 6px 6px !important;\n background-position: 2px 2px !important;\n background-repeat: no-repeat !important;\n}\nhtml[data-pixel-ui] select {\n appearance: none;\n -webkit-appearance: none;\n padding-right: 28px !important;\n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8' shape-rendering='crispEdges'%3E%3Crect x='0' y='0' width='8' height='2'/%3E%3Crect x='1' y='2' width='6' height='2'/%3E%3Crect x='2' y='4' width='4' height='2'/%3E%3Crect x='3' y='6' width='2' height='2'/%3E%3C/svg%3E\") !important;\n background-repeat: no-repeat !important;\n background-position: right 8px center !important;\n}\nhtml[data-pixel-ui] select option {\n background-color: var(--px-input-bg);\n color: var(--px-input-text);\n}\nhtml[data-pixel-ui] [role='switch'] {\n border: 2px solid var(--px-line) !important;\n background-color: var(--px-wood-dark) !important;\n}\nhtml[data-pixel-ui] input[type='range'] {\n appearance: none;\n -webkit-appearance: none;\n height: 14px;\n padding: 0;\n border: none !important;\n background: transparent !important;\n}\nhtml[data-pixel-ui] input[type='range']::-webkit-slider-runnable-track {\n height: 8px;\n border: 2px solid var(--px-line);\n background-color: var(--px-wood-mid);\n}\nhtml[data-pixel-ui] input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 12px;\n height: 14px;\n margin-top: -5px;\n background-color: var(--px-gold);\n border: 2px solid var(--px-line);\n}\nhtml[data-pixel-ui] input[type='range']::-moz-range-track {\n height: 8px;\n border: 2px solid var(--px-line);\n background: var(--px-wood-mid);\n}\nhtml[data-pixel-ui] input[type='range']::-moz-range-thumb {\n width: 12px;\n height: 14px;\n background-color: var(--px-gold);\n border: 2px solid var(--px-line);\n border-radius: 0;\n}\n\n/* ── 内容层:代码块 / 行内代码 / 引用 / 表格 / 分隔线 ─────────────── */\nhtml[data-pixel-ui] pre {\n background: var(--px-code-bg) !important;\n color: var(--px-text-on-dark) !important;\n border: 2px solid var(--px-wood-light) !important;\n}\nhtml[data-pixel-ui] code {\n background: var(--px-code-bg) !important;\n color: var(--px-code-ink) !important;\n border: none !important;\n padding: 0 3px;\n}\nhtml[data-pixel-ui] pre code {\n background: transparent !important;\n color: inherit !important;\n padding: 0;\n}\nhtml[data-pixel-ui] blockquote {\n border-left: 4px solid var(--px-gold) !important;\n background-color: var(--px-wood-dark) !important;\n color: var(--px-text-on-dark) !important;\n padding: 6px 10px;\n}\nhtml[data-pixel-ui] hr {\n border: none !important;\n height: 2px;\n background: var(--px-wood-light) !important;\n}\nhtml[data-pixel-ui] table {\n border: 2px solid var(--px-wood-warm) !important;\n border-collapse: collapse;\n}\nhtml[data-pixel-ui] th {\n background-color: var(--px-wood-warm) !important;\n color: var(--px-ink-on-mid) !important;\n font-family: var(--px-font) !important;\n font-size: 12px;\n border: 1px solid var(--px-wood-light) !important;\n}\nhtml[data-pixel-ui] td {\n border: 1px solid var(--px-wood-light) !important;\n}\nhtml[data-pixel-ui] a {\n color: var(--px-gold-bright) !important;\n text-decoration-thickness: 2px;\n text-underline-offset: 3px;\n}\nhtml[data-pixel-ui] summary {\n cursor: pointer;\n color: var(--px-gold-bright) !important;\n}\n\n/* ── 工具提示 ───────────────────────────────────────────────────── */\nhtml[data-pixel-ui] [role='tooltip'] {\n font-size: 11px;\n line-height: 1.6;\n color: var(--px-parchment) !important;\n background: var(--px-tooltip-bg) !important;\n border: 2px solid var(--px-gold-deep) !important;\n}\nhtml[data-pixel-ui] [role='menuitem']:hover,\nhtml[data-pixel-ui] [role='option']:hover {\n background-color: var(--px-wood-mid) !important;\n}\n\n/* ── 像素光标(SVG data-URI 阶梯箭头) ──────────────────────────── */\nhtml[data-pixel-ui] body {\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;\n}\nhtml[data-pixel-ui] button,\nhtml[data-pixel-ui] a,\nhtml[data-pixel-ui] select,\nhtml[data-pixel-ui] [role='tab'],\nhtml[data-pixel-ui] [role='menuitem'],\nhtml[data-pixel-ui] [role='switch'] {\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;\n}\nhtml[data-pixel-ui] input,\nhtml[data-pixel-ui] textarea,\nhtml[data-pixel-ui] [contenteditable='true'] {\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;\n}\n\n/* ── 设置页「像素主题」行 ─────────────────────────────────────────\n * 这一段**不跟随皮肤作用域**:像素主题激活时用 --px-* 值,\n * 现代默认(浅色/深色/跟随系统)回落到 --dsw-alias-* 宿主 token,\n * 保证行在任何外观下都清晰可点、对比度达标。\n * 触摸目标 ≥32px(WCAG 2.2 web 目标 24px 之上留手感余量)。 */\n.px-theme-row {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px 0;\n border-top: 1px solid var(--px-wood-pale, var(--dsw-alias-border-l2, #6b5a3a));\n}\n.px-theme-row-title {\n font-family: var(--px-font, inherit);\n font-size: 12px;\n color: var(--px-gold-bright, var(--dsw-alias-label-primary));\n}\n.px-theme-row-desc {\n font-size: 11px;\n line-height: 1.6;\n color: var(--px-text-light, var(--dsw-alias-label-secondary));\n}\n.px-theme-row-cubes {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.px-theme-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-height: 32px;\n padding: 6px 12px;\n font-family: var(--px-font, inherit);\n font-size: 11px;\n color: var(--px-text-on-dark, var(--dsw-alias-label-primary));\n background: var(--px-wood-dark, var(--dsw-alias-bg-layer-1));\n border: 2px solid var(--px-wood-darkest, var(--dsw-alias-border-l1));\n border-radius: 0 !important;\n cursor: pointer;\n transition: transform 0.06s steps(2), background-color 0.06s steps(2);\n}\n.px-theme-btn:hover {\n background: var(--px-wood-mid, var(--dsw-alias-bg-layer-2));\n}\n.px-theme-btn:active {\n transform: translateY(2px);\n}\n.px-theme-btn:focus-visible {\n outline: 2px solid var(--px-gold, var(--dsw-alias-state-business-primary, currentColor));\n outline-offset: 2px;\n}\n.px-theme-btn-active {\n color: var(--px-accent-ink, var(--dsw-alias-label-on-accent, #fff));\n background: var(--px-accent-bg, var(--dsw-alias-brand-primary));\n border-color: var(--px-gold-deep, var(--dsw-alias-border-l2));\n}\n.px-theme-swatch {\n width: 10px;\n height: 10px;\n border: 2px solid #000;\n flex-shrink: 0;\n}\n";
|
|
572
33
|
|
|
573
34
|
// src/client/index.js
|
|
574
35
|
var name = "dsh-pixel-ui";
|
|
575
|
-
var inject = ["slots", "theme"];
|
|
36
|
+
var inject = ["slots", "theme", "locale"];
|
|
576
37
|
var THEME_STORAGE_KEY = "dsh-pixel-ui:theme";
|
|
38
|
+
var PREFERENCE_URL = "/dsh-pixel-ui/preference";
|
|
39
|
+
var BOOTSTRAP_GLOBAL = "__DSH_PIXEL_UI__";
|
|
40
|
+
var DEFAULT_SKIN = "pixel-wood";
|
|
577
41
|
var THEMES = [
|
|
578
42
|
{
|
|
579
43
|
id: "pixel-wood",
|
|
@@ -587,10 +51,11 @@ var THEMES = [
|
|
|
587
51
|
"--dsw-alias-border-l2": "#8B6B45",
|
|
588
52
|
"--dsw-alias-brand-primary": "#F4D03F",
|
|
589
53
|
"--dsw-alias-label-primary": "#F5E6C8",
|
|
590
|
-
"--dsw-alias-label-secondary": "#
|
|
54
|
+
"--dsw-alias-label-secondary": "#AC8A63",
|
|
591
55
|
"--dsw-alias-state-error-primary": "#E74C3C",
|
|
592
56
|
"--dsw-alias-state-success-primary": "#7DCE82",
|
|
593
57
|
"--dsw-alias-state-warn-primary": "#F39C12",
|
|
58
|
+
"--dsw-alias-state-idle-primary": "#7A5C3E",
|
|
594
59
|
"--dsw-specific-sidebar-fill": "#241408"
|
|
595
60
|
}
|
|
596
61
|
},
|
|
@@ -603,13 +68,14 @@ var THEMES = [
|
|
|
603
68
|
"--dsw-alias-bg-layer-2": "#DDD0B8",
|
|
604
69
|
"--dsw-alias-bg-overlay": "#E2D6BE",
|
|
605
70
|
"--dsw-alias-border-l1": "#D4C4A8",
|
|
606
|
-
"--dsw-alias-border-l2": "#
|
|
607
|
-
"--dsw-alias-brand-primary": "#
|
|
71
|
+
"--dsw-alias-border-l2": "#7A6A4A",
|
|
72
|
+
"--dsw-alias-brand-primary": "#8A6400",
|
|
608
73
|
"--dsw-alias-label-primary": "#3A2A10",
|
|
609
74
|
"--dsw-alias-label-secondary": "#6B5020",
|
|
610
75
|
"--dsw-alias-state-error-primary": "#8B2020",
|
|
611
76
|
"--dsw-alias-state-success-primary": "#3A7A40",
|
|
612
77
|
"--dsw-alias-state-warn-primary": "#805000",
|
|
78
|
+
"--dsw-alias-state-idle-primary": "#847458",
|
|
613
79
|
"--dsw-specific-sidebar-fill": "#E8DCC8"
|
|
614
80
|
}
|
|
615
81
|
},
|
|
@@ -625,10 +91,11 @@ var THEMES = [
|
|
|
625
91
|
"--dsw-alias-border-l2": "#A86B40",
|
|
626
92
|
"--dsw-alias-brand-primary": "#FF8C42",
|
|
627
93
|
"--dsw-alias-label-primary": "#F0C8A0",
|
|
628
|
-
"--dsw-alias-label-secondary": "#
|
|
94
|
+
"--dsw-alias-label-secondary": "#C08A5C",
|
|
629
95
|
"--dsw-alias-state-error-primary": "#D93B3B",
|
|
630
96
|
"--dsw-alias-state-success-primary": "#6DBF6D",
|
|
631
97
|
"--dsw-alias-state-warn-primary": "#FF8C42",
|
|
98
|
+
"--dsw-alias-state-idle-primary": "#8A5A38",
|
|
632
99
|
"--dsw-specific-sidebar-fill": "#2A1308"
|
|
633
100
|
}
|
|
634
101
|
},
|
|
@@ -641,28 +108,51 @@ var THEMES = [
|
|
|
641
108
|
"--dsw-alias-bg-layer-2": "#121A12",
|
|
642
109
|
"--dsw-alias-bg-overlay": "#0C100C",
|
|
643
110
|
"--dsw-alias-border-l1": "#2A402A",
|
|
644
|
-
"--dsw-alias-border-l2": "#
|
|
111
|
+
"--dsw-alias-border-l2": "#4A7A4A",
|
|
645
112
|
"--dsw-alias-brand-primary": "#33FF33",
|
|
646
113
|
"--dsw-alias-label-primary": "#33FF33",
|
|
647
|
-
"--dsw-alias-label-secondary": "#
|
|
114
|
+
"--dsw-alias-label-secondary": "#22AA22",
|
|
648
115
|
"--dsw-alias-state-error-primary": "#FF3333",
|
|
649
116
|
"--dsw-alias-state-success-primary": "#33FF33",
|
|
650
117
|
"--dsw-alias-state-warn-primary": "#FFCC33",
|
|
118
|
+
"--dsw-alias-state-idle-primary": "#359035",
|
|
651
119
|
"--dsw-specific-sidebar-fill": "#0C100C"
|
|
652
120
|
}
|
|
653
121
|
}
|
|
654
122
|
];
|
|
655
123
|
var PIXEL_IDS = THEMES.map((theme) => theme.id);
|
|
656
124
|
var RESTORABLE_IDS = /* @__PURE__ */ new Set(["light", "dark", "system", ...PIXEL_IDS]);
|
|
125
|
+
var LOCALE_NS = "settings.pixel-ui";
|
|
126
|
+
var MESSAGES = {
|
|
127
|
+
zh: {
|
|
128
|
+
"row.title": "像素主题",
|
|
129
|
+
"row.desc": "选择后立即生效并跨重启记忆;「现代默认」回到宿主外观",
|
|
130
|
+
"theme.pixel-wood": "像素·木屋",
|
|
131
|
+
"theme.pixel-paper": "像素·羊皮纸",
|
|
132
|
+
"theme.pixel-warm": "像素·暖阳",
|
|
133
|
+
"theme.pixel-retro": "像素·终端绿",
|
|
134
|
+
"theme.system": "现代默认"
|
|
135
|
+
},
|
|
136
|
+
en: {
|
|
137
|
+
"row.title": "Pixel theme",
|
|
138
|
+
"row.desc": "Applies instantly and persists across restarts; “Modern default” returns to the host appearance",
|
|
139
|
+
"theme.pixel-wood": "Pixel · Wood",
|
|
140
|
+
"theme.pixel-paper": "Pixel · Paper",
|
|
141
|
+
"theme.pixel-warm": "Pixel · Warm",
|
|
142
|
+
"theme.pixel-retro": "Pixel · Terminal Green",
|
|
143
|
+
"theme.system": "Modern default"
|
|
144
|
+
}
|
|
145
|
+
};
|
|
657
146
|
var THEME_CHOICES = [
|
|
658
|
-
{ id: "pixel-wood",
|
|
659
|
-
{ id: "pixel-paper",
|
|
660
|
-
{ id: "pixel-warm",
|
|
661
|
-
{ id: "pixel-retro",
|
|
662
|
-
{ id: "system",
|
|
147
|
+
{ id: "pixel-wood", swatch: "#F4D03F" },
|
|
148
|
+
{ id: "pixel-paper", swatch: "#FFFDF5" },
|
|
149
|
+
{ id: "pixel-warm", swatch: "#FF8C42" },
|
|
150
|
+
{ id: "pixel-retro", swatch: "#33FF33" },
|
|
151
|
+
{ id: "system", swatch: "#7A7A7A" }
|
|
663
152
|
];
|
|
153
|
+
var fallbackT = (key) => key;
|
|
664
154
|
function createThemeRowStore() {
|
|
665
|
-
return (0,
|
|
155
|
+
return (0, import_dsh_client_store.defineStore)({
|
|
666
156
|
init: () => ({ preference: null, revision: -1 }),
|
|
667
157
|
actions: {
|
|
668
158
|
sync: (draft, preference, revision) => {
|
|
@@ -675,10 +165,12 @@ function createThemeRowStore() {
|
|
|
675
165
|
}
|
|
676
166
|
function ThemeRow(props) {
|
|
677
167
|
const preference = props.useStore((state) => state.preference);
|
|
168
|
+
const t = typeof props.t === "function" ? props.t : fallbackT;
|
|
678
169
|
return (0, import_react.createElement)(
|
|
679
170
|
"div",
|
|
680
|
-
{ className: "px-theme-row" },
|
|
681
|
-
(0, import_react.createElement)("div", { className: "px-theme-row-title" }, "
|
|
171
|
+
{ className: "px-theme-row", role: "group", "aria-label": t("row.title") },
|
|
172
|
+
(0, import_react.createElement)("div", { className: "px-theme-row-title" }, t("row.title")),
|
|
173
|
+
(0, import_react.createElement)("div", { className: "px-theme-row-desc" }, t("row.desc")),
|
|
682
174
|
(0, import_react.createElement)(
|
|
683
175
|
"div",
|
|
684
176
|
{ className: "px-theme-row-cubes" },
|
|
@@ -688,16 +180,63 @@ function ThemeRow(props) {
|
|
|
688
180
|
key: choice.id,
|
|
689
181
|
type: "button",
|
|
690
182
|
className: "px-theme-btn" + (preference === choice.id ? " px-theme-btn-active" : ""),
|
|
183
|
+
"aria-pressed": preference === choice.id,
|
|
691
184
|
onClick: () => {
|
|
692
185
|
props.setTheme(choice.id);
|
|
693
186
|
}
|
|
694
187
|
},
|
|
695
|
-
(0, import_react.createElement)("span", { className: "px-theme-swatch", style: { background: choice.swatch } }),
|
|
696
|
-
choice.
|
|
188
|
+
(0, import_react.createElement)("span", { className: "px-theme-swatch", "aria-hidden": "true", style: { background: choice.swatch } }),
|
|
189
|
+
t(`theme.${choice.id}`)
|
|
697
190
|
))
|
|
698
191
|
)
|
|
699
192
|
);
|
|
700
193
|
}
|
|
194
|
+
function readLocalTheme() {
|
|
195
|
+
try {
|
|
196
|
+
const value = localStorage.getItem(THEME_STORAGE_KEY);
|
|
197
|
+
return RESTORABLE_IDS.has(value) ? value : null;
|
|
198
|
+
} catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function writeLocalTheme(id) {
|
|
203
|
+
try {
|
|
204
|
+
localStorage.setItem(THEME_STORAGE_KEY, id);
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function readBootTheme() {
|
|
209
|
+
try {
|
|
210
|
+
const theme = globalThis[BOOTSTRAP_GLOBAL]?.theme;
|
|
211
|
+
return typeof theme === "string" && RESTORABLE_IDS.has(theme) ? theme : null;
|
|
212
|
+
} catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function readHostTheme() {
|
|
217
|
+
const injected = readBootTheme();
|
|
218
|
+
if (injected !== null) return injected;
|
|
219
|
+
try {
|
|
220
|
+
const res = await fetch(PREFERENCE_URL, { headers: { accept: "application/json" } });
|
|
221
|
+
if (!res.ok) return null;
|
|
222
|
+
const body = await res.json();
|
|
223
|
+
const theme = body?.theme;
|
|
224
|
+
return typeof theme === "string" && RESTORABLE_IDS.has(theme) ? theme : null;
|
|
225
|
+
} catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function writeHostTheme(id) {
|
|
230
|
+
try {
|
|
231
|
+
fetch(PREFERENCE_URL, {
|
|
232
|
+
method: "PUT",
|
|
233
|
+
headers: { "content-type": "application/json" },
|
|
234
|
+
body: JSON.stringify({ theme: id })
|
|
235
|
+
}).catch(() => {
|
|
236
|
+
});
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
}
|
|
701
240
|
function apply(ctx) {
|
|
702
241
|
const syncScope = () => {
|
|
703
242
|
const active = ctx.theme.getTheme().active;
|
|
@@ -705,16 +244,37 @@ function apply(ctx) {
|
|
|
705
244
|
document.documentElement.toggleAttribute("data-pixel-ui", on);
|
|
706
245
|
if (on) document.documentElement.setAttribute("data-pixel-theme", active.id);
|
|
707
246
|
else document.documentElement.removeAttribute("data-pixel-theme");
|
|
247
|
+
return on;
|
|
708
248
|
};
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
localStorage.setItem(THEME_STORAGE_KEY, snapshot.preference);
|
|
712
|
-
} catch {
|
|
713
|
-
}
|
|
714
|
-
};
|
|
249
|
+
let explicit = false;
|
|
250
|
+
let restoring = true;
|
|
715
251
|
ctx.on("theme/change", (snapshot) => {
|
|
716
252
|
syncScope();
|
|
717
|
-
|
|
253
|
+
const pref = snapshot.preference;
|
|
254
|
+
if (explicit) {
|
|
255
|
+
explicit = false;
|
|
256
|
+
writeLocalTheme(pref);
|
|
257
|
+
writeHostTheme(pref);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (PIXEL_IDS.includes(pref)) {
|
|
261
|
+
writeLocalTheme(pref);
|
|
262
|
+
writeHostTheme(pref);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const want = readLocalTheme();
|
|
266
|
+
if (want !== null && PIXEL_IDS.includes(want)) {
|
|
267
|
+
try {
|
|
268
|
+
ctx.theme.setTheme(want);
|
|
269
|
+
} catch {
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (restoring || want === null) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
writeLocalTheme(pref);
|
|
277
|
+
writeHostTheme(pref);
|
|
718
278
|
});
|
|
719
279
|
ctx.effect(() => {
|
|
720
280
|
const disposers = THEMES.map((definition) => ctx.theme.register(definition));
|
|
@@ -722,17 +282,36 @@ function apply(ctx) {
|
|
|
722
282
|
for (const dispose of disposers) dispose();
|
|
723
283
|
};
|
|
724
284
|
}, "dsh-pixel-ui: theme registration");
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
ctx.theme.
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
|
|
285
|
+
const applyTarget = (target) => {
|
|
286
|
+
try {
|
|
287
|
+
ctx.theme.setTheme(target);
|
|
288
|
+
} catch {
|
|
289
|
+
}
|
|
290
|
+
syncScope();
|
|
291
|
+
writeLocalTheme(target);
|
|
292
|
+
return ctx.theme.getTheme().active.id === target;
|
|
293
|
+
};
|
|
294
|
+
const restore = async () => {
|
|
295
|
+
const local = readLocalTheme();
|
|
296
|
+
if (local !== null) {
|
|
297
|
+
applyTarget(local);
|
|
298
|
+
const host2 = await readHostTheme();
|
|
299
|
+
if (host2 !== null && host2 !== ctx.theme.getTheme().preference) applyTarget(host2);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const host = await readHostTheme();
|
|
303
|
+
if (!applyTarget(host ?? DEFAULT_SKIN)) {
|
|
304
|
+
await new Promise((resolve) => {
|
|
305
|
+
setTimeout(resolve, 120);
|
|
306
|
+
});
|
|
307
|
+
applyTarget(host ?? DEFAULT_SKIN);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
const settle = () => {
|
|
311
|
+
restoring = false;
|
|
312
|
+
};
|
|
313
|
+
void restore().then(settle, settle);
|
|
314
|
+
ctx.effect(() => ctx.locale.register(LOCALE_NS, MESSAGES), "dsh-pixel-ui: settings row dictionaries");
|
|
736
315
|
const rowStore = createThemeRowStore();
|
|
737
316
|
let bound = void 0;
|
|
738
317
|
const syncRow = (snapshot) => {
|
|
@@ -744,10 +323,12 @@ function apply(ctx) {
|
|
|
744
323
|
id: "pixel-theme",
|
|
745
324
|
order: 20,
|
|
746
325
|
store: rowStore,
|
|
326
|
+
locale: LOCALE_NS,
|
|
747
327
|
inject: (actions) => {
|
|
748
328
|
bound = actions;
|
|
749
329
|
syncRow(ctx.theme.getTheme());
|
|
750
330
|
return { setTheme: (id) => {
|
|
331
|
+
explicit = true;
|
|
751
332
|
ctx.theme.setTheme(id);
|
|
752
333
|
} };
|
|
753
334
|
}
|