dsh-dracula-theme 0.1.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/lib/client.js ADDED
@@ -0,0 +1,846 @@
1
+ // dsh-dracula-theme — browser half (client plugin bundle). GENERATED FILE:
2
+ // run `node scripts/gen-themes.mjs` to regenerate from lib/client.tpl.js.
3
+ //
4
+ // Loaded by dsh-client-modules at /plugins/dsh-dracula-theme/client.js and
5
+ // executed through the vendored cordis Loader's lazy-CJS module table
6
+ // (window.__ModuleLoader__.load). The registered id MUST be the package name
7
+ // ("dsh-dracula-theme"): client-modules keys its boot-graph rows by the
8
+ // loader entry's package name and verifies the bundle registers exactly that
9
+ // id. The factory body is plain CJS with require() resolved against the
10
+ // shell's module table — the same shape the shipped ui-* packages' tsdown
11
+ // bundles emit.
12
+ //
13
+ // Structure modeled on dsh-catppuccin (MIT, zhijun-dai) — thanks.
14
+ window.__ModuleLoader__.load({
15
+ id: "dsh-dracula-theme",
16
+ factory: (require) => {
17
+ var module = { exports: {} };
18
+ var exports = module.exports;
19
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
20
+ let react_jsx_runtime = require("react/jsx-runtime");
21
+ let _runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
22
+
23
+ //#region dsh-dracula: definitions
24
+ /** The settings row's locale namespace. */
25
+ const SETTINGS_NS = "settings.dracula";
26
+ /** localStorage key holding the selected theme id. */
27
+ const STORAGE_KEY = "dsh-dracula:skin";
28
+ /** Sentinel meaning "no custom theme — follow the built-in appearance". */
29
+ const DEFAULT_SKIN = "system";
30
+
31
+ /**
32
+ * The Dracula theme catalog, generated from palette/dracula.json.
33
+ * Each entry is a third-party theme for the built-in ThemeRuntime:
34
+ * an id, the base palette it builds on (colorScheme drives
35
+ * body[data-ds-dark-theme]), and --dsw-alias-* / --dsw-specific-* /
36
+ * --shiki-* overrides applied as inline custom properties on <body>
37
+ * by ui-layout's ThemePresenter, plus the underlying --dsw-static-*
38
+ * ramps. Values are concrete CSS colors (no var() indirection).
39
+ */
40
+ const SKINS = [
41
+ {
42
+ "id": "dracula",
43
+ "name": "Dracula",
44
+ "colorScheme": "dark",
45
+ "tokens": {
46
+ "--dsw-static-neutral-50": "#efefe9",
47
+ "--dsw-static-neutral-100": "#e2e2da",
48
+ "--dsw-static-neutral-200": "#cdcdc5",
49
+ "--dsw-static-neutral-300": "#b6b6ae",
50
+ "--dsw-static-neutral-400": "#8f8f96",
51
+ "--dsw-static-neutral-500": "#6d6d7a",
52
+ "--dsw-static-neutral-550": "#5c5c6b",
53
+ "--dsw-static-neutral-600": "#4d4d5e",
54
+ "--dsw-static-neutral-700": "#3e3e50",
55
+ "--dsw-static-neutral-800": "#30303f",
56
+ "--dsw-static-neutral-850": "#282a36",
57
+ "--dsw-static-neutral-900": "#20212b",
58
+ "--dsw-static-neutral-1000": "#191a21",
59
+ "--dsw-static-neutral-description": "Anchor stops of the neutral grayscale ramp (--dsw-static-neutral-*), lightest (00) to darkest (1000). The official port does not override this ramp; values are Dracula-gray interpolations for a self-contained theme.",
60
+ "--dsw-static-neutral-00": "#f8f8f2",
61
+ "--dsw-static-neutral-bluish-50": "#f8f8f2",
62
+ "--dsw-static-neutral-bluish-60": "#282a36",
63
+ "--dsw-static-neutral-bluish-75": "#eef0f8",
64
+ "--dsw-static-neutral-bluish-100": "#e8eaf4",
65
+ "--dsw-static-neutral-bluish-150": "#d8ddef",
66
+ "--dsw-static-neutral-bluish-200": "#ccd2e8",
67
+ "--dsw-static-neutral-bluish-250": "#c4cbe3",
68
+ "--dsw-static-neutral-bluish-300": "#bbc4de",
69
+ "--dsw-static-neutral-bluish-400": "#9ba9d0",
70
+ "--dsw-static-neutral-bluish-500": "#7b8fc4",
71
+ "--dsw-static-neutral-bluish-550": "#6f81b4",
72
+ "--dsw-static-neutral-bluish-600": "#6272a4",
73
+ "--dsw-static-neutral-bluish-700": "#6272a4",
74
+ "--dsw-static-neutral-bluish-750": "#44475a",
75
+ "--dsw-static-neutral-bluish-800": "#44475a",
76
+ "--dsw-static-neutral-bluish-850": "#2e3040",
77
+ "--dsw-static-neutral-bluish-875": "#282a36",
78
+ "--dsw-static-neutral-bluish-900": "#282a36",
79
+ "--dsw-static-neutral-bluish-950": "#20212b",
80
+ "--dsw-static-neutral-bluish-1000": "#1a1b24",
81
+ "--dsw-static-neutral-bluish-00": "#f8f8f2",
82
+ "--dsw-static-deepseek-50": "#f0eaff",
83
+ "--dsw-static-deepseek-100": "#e0d2fe",
84
+ "--dsw-static-deepseek-200": "#c8aafd",
85
+ "--dsw-static-deepseek-300": "#b088fc",
86
+ "--dsw-static-deepseek-400": "#8be9fd",
87
+ "--dsw-static-deepseek-450": "#bd93f9",
88
+ "--dsw-static-deepseek-500": "#a97dfa",
89
+ "--dsw-static-deepseek-600": "#7a5abf",
90
+ "--dsw-static-deepseek-800": "#44475a",
91
+ "--dsw-static-deepseek-900": "#383a4a",
92
+ "--dsw-static-deepseek-description": "--dsw-static-deepseek-* overrides from the official port. 400 link / brand-text → cyan, 450 brand-primary → purple, 500 hover.",
93
+ "--dsw-static-deepseek-700-delete": "#5a3e99",
94
+ "--dsw-static-blue-50": "#eafcff",
95
+ "--dsw-static-blue-75": "#c6f3fd",
96
+ "--dsw-static-blue-100": "#b0edfc",
97
+ "--dsw-static-blue-300": "#8be9fd",
98
+ "--dsw-static-blue-400": "#6fd8f0",
99
+ "--dsw-static-blue-450": "#58c6e2",
100
+ "--dsw-static-blue-500": "#41b0cf",
101
+ "--dsw-static-blue-600": "#2b94b5",
102
+ "--dsw-static-blue-800": "#1c6a86",
103
+ "--dsw-static-blue-900": "#165064",
104
+ "--dsw-static-blue-950": "#103d4d",
105
+ "--dsw-static-blue-50p": "#d9f8fe",
106
+ "--dsw-static-red-50": "#ffecec",
107
+ "--dsw-static-red-100": "#ffd9d9",
108
+ "--dsw-static-red-400": "#ff5555",
109
+ "--dsw-static-red-500": "#ec4d4d",
110
+ "--dsw-static-red-600": "#cd4141",
111
+ "--dsw-static-red-900": "#5e2727",
112
+ "--dsw-static-green-100": "#dcfce6",
113
+ "--dsw-static-green-400": "#50fa7b",
114
+ "--dsw-static-green-500": "#3fdd68",
115
+ "--dsw-static-green-900": "#205c38",
116
+ "--dsw-static-amber-100": "#fff0dc",
117
+ "--dsw-static-amber-400": "#ffb86c",
118
+ "--dsw-static-amber-500": "#f2a352",
119
+ "--dsw-static-amber-600": "#d48b43",
120
+ "--dsw-static-amber-900": "#6b4521",
121
+ "--dsw-alias-bg-base": "#20212b",
122
+ "--dsw-alias-bg-layer-1": "#282a36",
123
+ "--dsw-alias-bg-layer-2": "#2e3040",
124
+ "--dsw-alias-bg-layer-3": "#44475a",
125
+ "--dsw-alias-bg-module-platform": "#44475a",
126
+ "--dsw-alias-bg-overlay": "#44475a",
127
+ "--dsw-alias-bg-multi-select": "#44475a",
128
+ "--dsw-alias-bg-skeleton": "rgba(248, 248, 242, 0.05)",
129
+ "--dsw-alias-bg-mask-1": "rgba(0, 0, 0, 0.45)",
130
+ "--dsw-alias-bg-mask-2": "rgba(0, 0, 0, 0.55)",
131
+ "--dsw-alias-bg-mask-3": "rgba(0, 0, 0, 0.65)",
132
+ "--dsw-alias-bg-mask-photo": "rgba(0, 0, 0, 0.88)",
133
+ "--dsw-alias-bg-mask-drop": "rgba(32, 33, 43, 0.7)",
134
+ "--dsw-alias-border-l1": "color-mix(in srgb, #6272a4 30%, transparent)",
135
+ "--dsw-alias-border-l2": "color-mix(in srgb, #6272a4 45%, transparent)",
136
+ "--dsw-alias-border-l3": "color-mix(in srgb, #6272a4 60%, transparent)",
137
+ "--dsw-alias-border-l4": "color-mix(in srgb, #6272a4 75%, transparent)",
138
+ "--dsw-alias-border-inverted": "rgba(0, 0, 0, 0.08)",
139
+ "--dsw-alias-border-inverted2": "rgba(0, 0, 0, 0.12)",
140
+ "--dsw-alias-border-l2-darkmode-thin": "rgba(98, 114, 164, 0.3)",
141
+ "--dsw-alias-brand-primary": "#bd93f9",
142
+ "--dsw-alias-brand-primary-invert": "#f8f8f2",
143
+ "--dsw-alias-brand-primary-new-colorprimary-new-color": "#bd93f9",
144
+ "--dsw-alias-brand-text": "#8be9fd",
145
+ "--dsw-alias-button-contrast-fill": "#282a36",
146
+ "--dsw-alias-button-elevated-fill": "#2e3040",
147
+ "--dsw-alias-button-floating-fill": "#44475a",
148
+ "--dsw-alias-button-floating-hover": "#6272a4",
149
+ "--dsw-alias-button-ghost-active-border": "#6272a4",
150
+ "--dsw-alias-button-ghost-active-fill": "#2e3040",
151
+ "--dsw-alias-button-ghost-active-hover": "#44475a",
152
+ "--dsw-alias-button-info-fill": "#bd93f9",
153
+ "--dsw-alias-button-info-hover": "#5a3e99",
154
+ "--dsw-alias-button-primary-dimmed": "#7a5abf",
155
+ "--dsw-alias-button-primary-fill": "#bd93f9",
156
+ "--dsw-alias-button-primary-hover": "#a97dfa",
157
+ "--dsw-alias-button-tool-bar-fill": "rgba(98, 114, 164, 0.35)",
158
+ "--dsw-alias-button-tool-bar-fill-invisible": "rgba(98, 114, 164, 0.2)",
159
+ "--dsw-alias-button-tool-bar-hover": "rgba(189, 147, 249, 0.35)",
160
+ "--dsw-alias-interactive-bg-active": "rgba(248, 248, 242, 0.14)",
161
+ "--dsw-alias-interactive-bg-hover": "rgba(248, 248, 242, 0.08)",
162
+ "--dsw-alias-interactive-bg-hover-accent": "rgba(189, 147, 249, 0.16)",
163
+ "--dsw-alias-interactive-bg-hover-danger": "rgba(255, 85, 85, 0.14)",
164
+ "--dsw-alias-interactive-bg-hover-solid": "#44475a",
165
+ "--dsw-alias-label-caption": "#6272a4",
166
+ "--dsw-alias-label-dimmed": "#7b8fc4",
167
+ "--dsw-alias-label-primary": "#f8f8f2",
168
+ "--dsw-alias-label-primary-bluish": "#f8f8f2",
169
+ "--dsw-alias-label-primary-dimmed": "#9ba9d0",
170
+ "--dsw-alias-label-primary-foreground": "#282a36",
171
+ "--dsw-alias-label-primary-inverted": "#44475a",
172
+ "--dsw-alias-label-secondary": "#bbc4de",
173
+ "--dsw-alias-label-tertiary": "#9ba9d0",
174
+ "--dsw-alias-markdown-citation": "#44475a",
175
+ "--dsw-alias-markdown-code-block": "#2e3040",
176
+ "--dsw-alias-markdown-code-block-banner": "#282a36",
177
+ "--dsw-alias-markdown-code-segment-selected": "#44475a",
178
+ "--dsw-alias-markdown-code-segment-unselected": "#2e3040",
179
+ "--dsw-alias-markdown-inline-code": "#44475a",
180
+ "--dsw-alias-markdown-placeholder": "#7b8fc4",
181
+ "--dsw-alias-markdown-tag": "#bd93f9",
182
+ "--dsw-alias-scrollbar-bg-l1": "rgba(98, 114, 164, 0.4)",
183
+ "--dsw-alias-scrollbar-bg-l2": "rgba(98, 114, 164, 0.4)",
184
+ "--dsw-alias-scrollbar-hover-l1": "rgba(189, 147, 249, 0.6)",
185
+ "--dsw-alias-scrollbar-hover-l2": "rgba(189, 147, 249, 0.6)",
186
+ "--dsw-alias-separator-primary": "rgba(189, 147, 249, 0.8)",
187
+ "--dsw-alias-state-business-primary": "#8be9fd",
188
+ "--dsw-alias-state-business-tertiary": "rgba(139, 233, 253, 0.1)",
189
+ "--dsw-alias-state-error-primary": "#ff5555",
190
+ "--dsw-alias-state-error-secondary": "rgba(255, 85, 85, 0.16)",
191
+ "--dsw-alias-state-success-primary": "#50fa7b",
192
+ "--dsw-alias-state-success-secondary": "rgba(80, 250, 123, 0.16)",
193
+ "--dsw-alias-state-success-tertiary": "rgba(80, 250, 123, 0.1)",
194
+ "--dsw-alias-state-warn-label": "#ffca80",
195
+ "--dsw-alias-state-warn-primary": "#ffb86c",
196
+ "--dsw-alias-state-warn-secondary": "rgba(255, 184, 108, 0.16)",
197
+ "--dsw-alias-state-warn-tertiary": "rgba(255, 184, 108, 0.1)",
198
+ "--dsw-alias-toast-bg": "#2e3040",
199
+ "--dsw-alias-tooltip-bg": "#44475a",
200
+ "--dsw-specific-sidebar-fill": "#282a36",
201
+ "--dsw-specific-sidebar-nav-item-active": "#44475a",
202
+ "--dsw-specific-sidebar-nav-item-active-accent": "rgba(189, 147, 249, 0.25)",
203
+ "--dsw-specific-sidebar-nav-item-hover": "#2e3040",
204
+ "--dsw-specific-bubble": "#2e3040",
205
+ "--dsw-specific-bubble-highlight": "#44475a",
206
+ "--dsw-specific-input-major": "#282a36",
207
+ "--dsw-specific-login-input": "#282a36",
208
+ "--dsw-specific-menu": "#2e3040",
209
+ "--dsw-specific-selector": "#44475a",
210
+ "--dsw-specific-tip": "#2e3040",
211
+ "--shiki-description": "The official Prism token mapping, translated to the DSH shiki vocabulary: comments #6272a4, punctuation #f8f8f2, tags/parameters/this → cyan, numbers/constants/strings/inserted → yellow, keywords/operators/builtins/regex → pink, functions → green, deleted/important → red.",
212
+ "--shiki-foreground": "#f8f8f2",
213
+ "--shiki-background": "#282a36",
214
+ "--shiki-token-comment": "#6272a4",
215
+ "--shiki-token-punctuation": "#f8f8f2",
216
+ "--shiki-token-constant": "#f1fa8c",
217
+ "--shiki-token-string": "#f1fa8c",
218
+ "--shiki-token-string-expression": "#f1fa8c",
219
+ "--shiki-token-inserted": "#f1fa8c",
220
+ "--shiki-token-link": "#f1fa8c",
221
+ "--shiki-token-keyword": "#ff79c6",
222
+ "--shiki-token-parameter": "#8be9fd",
223
+ "--shiki-token-function": "#50fa7b",
224
+ "--shiki-token-deleted": "#ff5555",
225
+ "--shiki-token-changed": "#ffb86c",
226
+ "--scroll-color": "rgba(98, 114, 164, 0.4)",
227
+ "--scroll-color-hover": "rgba(189, 147, 249, 0.6)"
228
+ }
229
+ },
230
+ {
231
+ "id": "dracula-soft",
232
+ "name": "Dracula Soft",
233
+ "colorScheme": "dark",
234
+ "tokens": {
235
+ "--dsw-static-neutral-50": "#efefe9",
236
+ "--dsw-static-neutral-100": "#e2e2da",
237
+ "--dsw-static-neutral-200": "#cdcdc5",
238
+ "--dsw-static-neutral-300": "#b6b6ae",
239
+ "--dsw-static-neutral-400": "#8f8f96",
240
+ "--dsw-static-neutral-500": "#6d6d7a",
241
+ "--dsw-static-neutral-550": "#5c5c6b",
242
+ "--dsw-static-neutral-600": "#4d4d5e",
243
+ "--dsw-static-neutral-700": "#3e3e50",
244
+ "--dsw-static-neutral-800": "#30303f",
245
+ "--dsw-static-neutral-850": "#282a36",
246
+ "--dsw-static-neutral-900": "#20212b",
247
+ "--dsw-static-neutral-1000": "#191a21",
248
+ "--dsw-static-neutral-description": "Anchor stops of the neutral grayscale ramp (--dsw-static-neutral-*), lightest (00) to darkest (1000). The official port does not override this ramp; values are Dracula-gray interpolations for a self-contained theme.",
249
+ "--dsw-static-neutral-00": "#f8f8f2",
250
+ "--dsw-static-neutral-bluish-50": "#f8f8f2",
251
+ "--dsw-static-neutral-bluish-60": "#282a36",
252
+ "--dsw-static-neutral-bluish-75": "#eef0f8",
253
+ "--dsw-static-neutral-bluish-100": "#e8eaf4",
254
+ "--dsw-static-neutral-bluish-150": "#d8ddef",
255
+ "--dsw-static-neutral-bluish-200": "#ccd2e8",
256
+ "--dsw-static-neutral-bluish-250": "#c4cbe3",
257
+ "--dsw-static-neutral-bluish-300": "#bbc4de",
258
+ "--dsw-static-neutral-bluish-400": "#9ba9d0",
259
+ "--dsw-static-neutral-bluish-500": "#7b8fc4",
260
+ "--dsw-static-neutral-bluish-550": "#6f81b4",
261
+ "--dsw-static-neutral-bluish-600": "#6272a4",
262
+ "--dsw-static-neutral-bluish-700": "#6272a4",
263
+ "--dsw-static-neutral-bluish-750": "#44475a",
264
+ "--dsw-static-neutral-bluish-800": "#44475a",
265
+ "--dsw-static-neutral-bluish-850": "#343746",
266
+ "--dsw-static-neutral-bluish-875": "#2b2d3a",
267
+ "--dsw-static-neutral-bluish-900": "#2b2d3a",
268
+ "--dsw-static-neutral-bluish-950": "#262833",
269
+ "--dsw-static-neutral-bluish-1000": "#1a1b24",
270
+ "--dsw-static-neutral-bluish-00": "#f8f8f2",
271
+ "--dsw-static-deepseek-50": "#f0eaff",
272
+ "--dsw-static-deepseek-100": "#e0d2fe",
273
+ "--dsw-static-deepseek-200": "#c8aafd",
274
+ "--dsw-static-deepseek-300": "#b088fc",
275
+ "--dsw-static-deepseek-400": "#8be9fd",
276
+ "--dsw-static-deepseek-450": "#bd93f9",
277
+ "--dsw-static-deepseek-500": "#a97dfa",
278
+ "--dsw-static-deepseek-600": "#7a5abf",
279
+ "--dsw-static-deepseek-800": "#44475a",
280
+ "--dsw-static-deepseek-900": "#383a4a",
281
+ "--dsw-static-deepseek-description": "--dsw-static-deepseek-* overrides from the official port. 400 link / brand-text → cyan, 450 brand-primary → purple, 500 hover.",
282
+ "--dsw-static-deepseek-700-delete": "#5a3e99",
283
+ "--dsw-static-blue-50": "#eafcff",
284
+ "--dsw-static-blue-75": "#c6f3fd",
285
+ "--dsw-static-blue-100": "#b0edfc",
286
+ "--dsw-static-blue-300": "#8be9fd",
287
+ "--dsw-static-blue-400": "#6fd8f0",
288
+ "--dsw-static-blue-450": "#58c6e2",
289
+ "--dsw-static-blue-500": "#41b0cf",
290
+ "--dsw-static-blue-600": "#2b94b5",
291
+ "--dsw-static-blue-800": "#1c6a86",
292
+ "--dsw-static-blue-900": "#165064",
293
+ "--dsw-static-blue-950": "#103d4d",
294
+ "--dsw-static-blue-50p": "#d9f8fe",
295
+ "--dsw-static-red-50": "#ffecec",
296
+ "--dsw-static-red-100": "#ffd9d9",
297
+ "--dsw-static-red-400": "#ff5555",
298
+ "--dsw-static-red-500": "#ec4d4d",
299
+ "--dsw-static-red-600": "#cd4141",
300
+ "--dsw-static-red-900": "#5e2727",
301
+ "--dsw-static-green-100": "#dcfce6",
302
+ "--dsw-static-green-400": "#50fa7b",
303
+ "--dsw-static-green-500": "#3fdd68",
304
+ "--dsw-static-green-900": "#205c38",
305
+ "--dsw-static-amber-100": "#fff0dc",
306
+ "--dsw-static-amber-400": "#ffb86c",
307
+ "--dsw-static-amber-500": "#f2a352",
308
+ "--dsw-static-amber-600": "#d48b43",
309
+ "--dsw-static-amber-900": "#6b4521",
310
+ "--dsw-alias-bg-base": "#262833",
311
+ "--dsw-alias-bg-layer-1": "#2b2d3a",
312
+ "--dsw-alias-bg-layer-2": "#343746",
313
+ "--dsw-alias-bg-layer-3": "#44475a",
314
+ "--dsw-alias-bg-module-platform": "#44475a",
315
+ "--dsw-alias-bg-overlay": "#44475a",
316
+ "--dsw-alias-bg-multi-select": "#44475a",
317
+ "--dsw-alias-bg-skeleton": "rgba(248, 248, 242, 0.05)",
318
+ "--dsw-alias-bg-mask-1": "rgba(0, 0, 0, 0.45)",
319
+ "--dsw-alias-bg-mask-2": "rgba(0, 0, 0, 0.55)",
320
+ "--dsw-alias-bg-mask-3": "rgba(0, 0, 0, 0.65)",
321
+ "--dsw-alias-bg-mask-photo": "rgba(0, 0, 0, 0.88)",
322
+ "--dsw-alias-bg-mask-drop": "rgba(32, 33, 43, 0.7)",
323
+ "--dsw-alias-border-l1": "color-mix(in srgb, #6272a4 30%, transparent)",
324
+ "--dsw-alias-border-l2": "color-mix(in srgb, #6272a4 45%, transparent)",
325
+ "--dsw-alias-border-l3": "color-mix(in srgb, #6272a4 60%, transparent)",
326
+ "--dsw-alias-border-l4": "color-mix(in srgb, #6272a4 75%, transparent)",
327
+ "--dsw-alias-border-inverted": "rgba(0, 0, 0, 0.08)",
328
+ "--dsw-alias-border-inverted2": "rgba(0, 0, 0, 0.12)",
329
+ "--dsw-alias-border-l2-darkmode-thin": "rgba(98, 114, 164, 0.3)",
330
+ "--dsw-alias-brand-primary": "#bd93f9",
331
+ "--dsw-alias-brand-primary-invert": "#f8f8f2",
332
+ "--dsw-alias-brand-primary-new-colorprimary-new-color": "#bd93f9",
333
+ "--dsw-alias-brand-text": "#8be9fd",
334
+ "--dsw-alias-button-contrast-fill": "#282a36",
335
+ "--dsw-alias-button-elevated-fill": "#343746",
336
+ "--dsw-alias-button-floating-fill": "#44475a",
337
+ "--dsw-alias-button-floating-hover": "#59658e",
338
+ "--dsw-alias-button-ghost-active-border": "#6272a4",
339
+ "--dsw-alias-button-ghost-active-fill": "#343746",
340
+ "--dsw-alias-button-ghost-active-hover": "#44475a",
341
+ "--dsw-alias-button-info-fill": "#bd93f9",
342
+ "--dsw-alias-button-info-hover": "#5a3e99",
343
+ "--dsw-alias-button-primary-dimmed": "#7a5abf",
344
+ "--dsw-alias-button-primary-fill": "#bd93f9",
345
+ "--dsw-alias-button-primary-hover": "#a97dfa",
346
+ "--dsw-alias-button-tool-bar-fill": "rgba(98, 114, 164, 0.35)",
347
+ "--dsw-alias-button-tool-bar-fill-invisible": "rgba(98, 114, 164, 0.2)",
348
+ "--dsw-alias-button-tool-bar-hover": "rgba(189, 147, 249, 0.35)",
349
+ "--dsw-alias-interactive-bg-active": "rgba(248, 248, 242, 0.14)",
350
+ "--dsw-alias-interactive-bg-hover": "rgba(248, 248, 242, 0.08)",
351
+ "--dsw-alias-interactive-bg-hover-accent": "rgba(189, 147, 249, 0.16)",
352
+ "--dsw-alias-interactive-bg-hover-danger": "rgba(255, 85, 85, 0.14)",
353
+ "--dsw-alias-interactive-bg-hover-solid": "#59658e",
354
+ "--dsw-alias-label-caption": "#6272a4",
355
+ "--dsw-alias-label-dimmed": "#7b8fc4",
356
+ "--dsw-alias-label-primary": "#f8f8f2",
357
+ "--dsw-alias-label-primary-bluish": "#f8f8f2",
358
+ "--dsw-alias-label-primary-dimmed": "#9ba9d0",
359
+ "--dsw-alias-label-primary-foreground": "#282a36",
360
+ "--dsw-alias-label-primary-inverted": "#44475a",
361
+ "--dsw-alias-label-secondary": "#bbc4de",
362
+ "--dsw-alias-label-tertiary": "#9ba9d0",
363
+ "--dsw-alias-markdown-citation": "#44475a",
364
+ "--dsw-alias-markdown-code-block": "#343746",
365
+ "--dsw-alias-markdown-code-block-banner": "#2b2d3a",
366
+ "--dsw-alias-markdown-code-segment-selected": "#44475a",
367
+ "--dsw-alias-markdown-code-segment-unselected": "#343746",
368
+ "--dsw-alias-markdown-inline-code": "#44475a",
369
+ "--dsw-alias-markdown-placeholder": "#7b8fc4",
370
+ "--dsw-alias-markdown-tag": "#bd93f9",
371
+ "--dsw-alias-scrollbar-bg-l1": "#44475a",
372
+ "--dsw-alias-scrollbar-bg-l2": "#44475a",
373
+ "--dsw-alias-scrollbar-hover-l1": "#59658e",
374
+ "--dsw-alias-scrollbar-hover-l2": "#59658e",
375
+ "--dsw-alias-separator-primary": "rgba(189, 147, 249, 0.8)",
376
+ "--dsw-alias-state-business-primary": "#8be9fd",
377
+ "--dsw-alias-state-business-tertiary": "rgba(139, 233, 253, 0.1)",
378
+ "--dsw-alias-state-error-primary": "#ff5555",
379
+ "--dsw-alias-state-error-secondary": "rgba(255, 85, 85, 0.16)",
380
+ "--dsw-alias-state-success-primary": "#50fa7b",
381
+ "--dsw-alias-state-success-secondary": "rgba(80, 250, 123, 0.16)",
382
+ "--dsw-alias-state-success-tertiary": "rgba(80, 250, 123, 0.1)",
383
+ "--dsw-alias-state-warn-label": "#ffca80",
384
+ "--dsw-alias-state-warn-primary": "#ffb86c",
385
+ "--dsw-alias-state-warn-secondary": "rgba(255, 184, 108, 0.16)",
386
+ "--dsw-alias-state-warn-tertiary": "rgba(255, 184, 108, 0.1)",
387
+ "--dsw-alias-toast-bg": "#343746",
388
+ "--dsw-alias-tooltip-bg": "#44475a",
389
+ "--dsw-specific-sidebar-fill": "#2b2d3a",
390
+ "--dsw-specific-sidebar-nav-item-active": "#44475a",
391
+ "--dsw-specific-sidebar-nav-item-active-accent": "rgba(189, 147, 249, 0.25)",
392
+ "--dsw-specific-sidebar-nav-item-hover": "#343746",
393
+ "--dsw-specific-bubble": "#343746",
394
+ "--dsw-specific-bubble-highlight": "#44475a",
395
+ "--dsw-specific-input-major": "#2b2d3a",
396
+ "--dsw-specific-login-input": "#2b2d3a",
397
+ "--dsw-specific-menu": "#343746",
398
+ "--dsw-specific-selector": "#44475a",
399
+ "--dsw-specific-tip": "#343746",
400
+ "--shiki-description": "The official Prism token mapping, translated to the DSH shiki vocabulary: comments #6272a4, punctuation #f8f8f2, tags/parameters/this → cyan, numbers/constants/strings/inserted → yellow, keywords/operators/builtins/regex → pink, functions → green, deleted/important → red.",
401
+ "--shiki-foreground": "#f8f8f2",
402
+ "--shiki-background": "#282a36",
403
+ "--shiki-token-comment": "#6272a4",
404
+ "--shiki-token-punctuation": "#f8f8f2",
405
+ "--shiki-token-constant": "#f1fa8c",
406
+ "--shiki-token-string": "#f1fa8c",
407
+ "--shiki-token-string-expression": "#f1fa8c",
408
+ "--shiki-token-inserted": "#f1fa8c",
409
+ "--shiki-token-link": "#f1fa8c",
410
+ "--shiki-token-keyword": "#ff79c6",
411
+ "--shiki-token-parameter": "#8be9fd",
412
+ "--shiki-token-function": "#50fa7b",
413
+ "--shiki-token-deleted": "#ff5555",
414
+ "--shiki-token-changed": "#ffb86c",
415
+ "--scroll-color": "rgba(98, 114, 164, 0.4)",
416
+ "--scroll-color-hover": "rgba(189, 147, 249, 0.6)"
417
+ }
418
+ }
419
+ ];
420
+
421
+ /** Simplified Chinese dictionary (the key-set source of truth). */
422
+ const zh = {
423
+ "skin.title": "德古拉主题",
424
+ "skin.default": "默认",
425
+ "skin.dracula": "Dracula",
426
+ "skin.dracula-soft": "Dracula Soft"
427
+ };
428
+
429
+ /** English dictionary, checked complete against the zh key set. */
430
+ const en = {
431
+ "skin.title": "Dracula theme",
432
+ "skin.default": "Default",
433
+ "skin.dracula": "Dracula",
434
+ "skin.dracula-soft": "Dracula Soft"
435
+ };
436
+ //#endregion
437
+
438
+ //#region dsh-dracula: persistence
439
+ /** Read a localStorage string value (null on absence or error). */
440
+ function readStorage(key) {
441
+ try {
442
+ const value = window.localStorage.getItem(key);
443
+ return typeof value === "string" ? value : null;
444
+ } catch {
445
+ return null;
446
+ }
447
+ }
448
+
449
+ /** Write (or remove with null) a localStorage value. */
450
+ function writeStorage(key, value) {
451
+ try {
452
+ if (value === null) window.localStorage.removeItem(key);
453
+ else window.localStorage.setItem(key, value);
454
+ } catch {
455
+ // storage unavailable / quota — the preference stays process-local
456
+ }
457
+ }
458
+
459
+ /** Saved skin id (may be unknown/absent). */
460
+ function readSavedSkin() {
461
+ return readStorage(STORAGE_KEY);
462
+ }
463
+
464
+ /** Persist a skin choice; DEFAULT_SKIN clears the stored value. */
465
+ function writeSavedSkin(id) {
466
+ writeStorage(STORAGE_KEY, id === DEFAULT_SKIN ? null : id);
467
+ }
468
+ //#endregion
469
+
470
+ //#region dsh-dracula: settings row store
471
+ /**
472
+ * Skin row slot store: a mirror of the theme service snapshot. The
473
+ * plugin's apply-world change listener is the only writer; the row
474
+ * component reads via props.useStore.
475
+ */
476
+ function createSkinStore() {
477
+ return (0, _runtime_client.defineStore)({
478
+ init: () => ({
479
+ skin: DEFAULT_SKIN,
480
+ revision: -1
481
+ }),
482
+ actions: {
483
+ sync: (d, skin, revision) => {
484
+ if (revision <= d.revision) return;
485
+ d.skin = skin;
486
+ d.revision = revision;
487
+ }
488
+ }
489
+ });
490
+ }
491
+ //#endregion
492
+
493
+ //#region dsh-dracula: settings row
494
+ /** Inline style sheet for the row (kept dependency-free). */
495
+ const styles = {
496
+ group: {
497
+ borderBottom: "1px solid var(--dsw-alias-border-l2)",
498
+ display: "flex",
499
+ flexDirection: "column",
500
+ gap: "10px",
501
+ padding: "16px 0"
502
+ },
503
+ title: {
504
+ color: "var(--dsw-alias-label-primary)",
505
+ fontSize: "14px",
506
+ fontWeight: 400,
507
+ lineHeight: "22px"
508
+ },
509
+ grid: {
510
+ display: "flex",
511
+ flexWrap: "wrap",
512
+ gap: "10px"
513
+ },
514
+ card: {
515
+ display: "flex",
516
+ flexDirection: "column",
517
+ alignItems: "center",
518
+ gap: "6px",
519
+ width: "96px",
520
+ padding: "3px",
521
+ borderRadius: "10px",
522
+ // longhand on purpose: the shorthand leaves borderColor to
523
+ // fall back to currentColor once React clears the selected
524
+ // override, painting stale black/white boxes on deselect
525
+ borderWidth: "2px",
526
+ borderStyle: "solid",
527
+ borderColor: "transparent",
528
+ background: "transparent",
529
+ cursor: "pointer",
530
+ font: "inherit",
531
+ boxSizing: "border-box"
532
+ },
533
+ cardSelected: {
534
+ borderColor: "var(--dsw-alias-brand-primary)",
535
+ background: "var(--dsw-alias-interactive-bg-hover)"
536
+ },
537
+ cardLabel: {
538
+ color: "var(--dsw-alias-label-secondary)",
539
+ fontSize: "12px",
540
+ lineHeight: "16px",
541
+ whiteSpace: "nowrap"
542
+ },
543
+ cardLabelSelected: {
544
+ color: "var(--dsw-alias-label-primary)"
545
+ },
546
+ swatch: {
547
+ width: "100%",
548
+ height: "52px",
549
+ borderRadius: "8px",
550
+ boxSizing: "border-box",
551
+ padding: "8px",
552
+ display: "flex",
553
+ flexDirection: "column",
554
+ justifyContent: "center",
555
+ gap: "6px"
556
+ },
557
+ swatchLine: {
558
+ height: "7px",
559
+ borderRadius: "4px"
560
+ },
561
+ defaultSwatch: {
562
+ width: "100%",
563
+ height: "52px",
564
+ borderRadius: "8px",
565
+ boxSizing: "border-box",
566
+ display: "flex",
567
+ overflow: "hidden",
568
+ border: "1px solid var(--dsw-alias-border-l2)"
569
+ }
570
+ };
571
+
572
+ /** Mini palette preview driven by one skin's token table. */
573
+ function Swatch({ tokens }) {
574
+ return (0, react_jsx_runtime.jsxs)("div", {
575
+ style: {
576
+ ...styles.swatch,
577
+ background: tokens["--dsw-alias-bg-layer-2"],
578
+ border: `1px solid ${tokens["--dsw-alias-border-l2"]}`
579
+ },
580
+ children: [
581
+ (0, react_jsx_runtime.jsx)("div", {
582
+ style: {
583
+ ...styles.swatchLine,
584
+ width: "70%",
585
+ background: tokens["--dsw-alias-label-primary"]
586
+ }
587
+ }),
588
+ (0, react_jsx_runtime.jsx)("div", {
589
+ style: {
590
+ ...styles.swatchLine,
591
+ width: "45%",
592
+ background: tokens["--dsw-alias-brand-primary"]
593
+ }
594
+ }),
595
+ (0, react_jsx_runtime.jsx)("div", {
596
+ style: {
597
+ ...styles.swatchLine,
598
+ width: "55%",
599
+ background: tokens["--dsw-alias-label-secondary"],
600
+ opacity: 0.55
601
+ }
602
+ })
603
+ ]
604
+ });
605
+ }
606
+
607
+ /** "Default" chip: follow the built-in appearance (light + dark halves). */
608
+ function DefaultSwatch() {
609
+ return (0, react_jsx_runtime.jsxs)("div", {
610
+ style: styles.defaultSwatch,
611
+ children: [
612
+ (0, react_jsx_runtime.jsx)("div", { style: { flex: 1, background: "#f4f4f5" } }),
613
+ (0, react_jsx_runtime.jsx)("div", { style: { flex: 1, background: "#1c1c20" } })
614
+ ]
615
+ });
616
+ }
617
+
618
+ /** One selectable skin card. */
619
+ function SkinCard({ skin, selected, onSelect, t }) {
620
+ return (0, react_jsx_runtime.jsxs)("button", {
621
+ type: "button",
622
+ onClick: (event) => {
623
+ onSelect();
624
+ // drop focus so a stale focus ring never outlives the selection
625
+ event.currentTarget.blur();
626
+ },
627
+ "aria-pressed": selected,
628
+ style: {
629
+ ...styles.card,
630
+ ...(selected ? styles.cardSelected : {})
631
+ },
632
+ children: [
633
+ (0, react_jsx_runtime.jsx)(Swatch, { tokens: skin.tokens }),
634
+ (0, react_jsx_runtime.jsx)("span", {
635
+ style: {
636
+ ...styles.cardLabel,
637
+ ...(selected ? styles.cardLabelSelected : {})
638
+ },
639
+ children: t(`skin.${skin.id}`)
640
+ })
641
+ ]
642
+ });
643
+ }
644
+
645
+ /**
646
+ * Skin picker row registered into the Settings → General item slot,
647
+ * right after the built-in Appearance row: title + a "Default" chip
648
+ * and one swatch card per Dracula variant.
649
+ */
650
+ function SkinRow({ t, setSkin, useStore }) {
651
+ const skin = useStore((s) => s.skin);
652
+ const selected = SKINS.some((candidate) => candidate.id === skin) ? skin : null;
653
+ return (0, react_jsx_runtime.jsxs)("div", {
654
+ style: styles.group,
655
+ children: [
656
+ (0, react_jsx_runtime.jsx)("div", {
657
+ style: styles.title,
658
+ children: t("skin.title")
659
+ }),
660
+ (0, react_jsx_runtime.jsxs)("div", {
661
+ style: styles.grid,
662
+ children: [
663
+ (0, react_jsx_runtime.jsxs)("button", {
664
+ type: "button",
665
+ onClick: (event) => {
666
+ setSkin(DEFAULT_SKIN);
667
+ // drop focus so a stale focus ring never outlives the selection
668
+ event.currentTarget.blur();
669
+ },
670
+ "aria-pressed": selected === null,
671
+ style: {
672
+ ...styles.card,
673
+ ...(selected === null ? styles.cardSelected : {})
674
+ },
675
+ children: [
676
+ (0, react_jsx_runtime.jsx)(DefaultSwatch, {}),
677
+ (0, react_jsx_runtime.jsx)("span", {
678
+ style: {
679
+ ...styles.cardLabel,
680
+ ...(selected === null ? styles.cardLabelSelected : {})
681
+ },
682
+ children: t("skin.default")
683
+ })
684
+ ]
685
+ }),
686
+ SKINS.map((skinDefinition) => (0, react_jsx_runtime.jsx)(SkinCard, {
687
+ skin: skinDefinition,
688
+ selected: selected === skinDefinition.id,
689
+ onSelect: () => setSkin(skinDefinition.id),
690
+ t
691
+ }, skinDefinition.id))
692
+ ]
693
+ })
694
+ ]
695
+ });
696
+ }
697
+ //#endregion
698
+
699
+ //#region dsh-dracula: client plugin body
700
+ /**
701
+ * Required services: theme runtime (skins, switching), slots/locale
702
+ * (the settings row). Persistence is localStorage, so no settings
703
+ * transport is needed.
704
+ */
705
+ const inject = [
706
+ "slots",
707
+ "locale",
708
+ "theme"
709
+ ];
710
+
711
+ /**
712
+ * Client plugin body: register the Dracula skins into the theme
713
+ * runtime, restore the saved choice, keep the row's store in sync
714
+ * with theme/change, and register the picker into Settings → General.
715
+ * @param ctx - client cordis context.
716
+ */
717
+ function apply(ctx) {
718
+ const disposers = SKINS.map((skinDefinition) => ctx.theme.register(skinDefinition));
719
+ ctx.effect(() => () => {
720
+ for (const dispose of disposers) dispose();
721
+ }, "dsh-dracula-theme: theme registration");
722
+
723
+ // Surface polish derived from the official Dracula DeepSeek port:
724
+ // user-message bubbles carry the brand tint, message reference
725
+ // chips lose the hardcoded deepseek blue, and reasoning text
726
+ // reads in the official brand cyan. Keyed on the stable
727
+ // CSS-module suffixes and colored from our own injected theme
728
+ // variables so it adapts per variant automatically.
729
+ //
730
+ // Every selector is boosted with :not(#dsh-dracula-theme): the
731
+ // shipped ui-* stylesheets are injected by React after ours, so a
732
+ // plain attribute selector loses to the equally specific module
733
+ // class and the tint silently dies. The :not(id) pseudo is a
734
+ // no-op predicate that only raises specificity (1,1,0).
735
+ //
736
+ // The sheet is mounted only while one of our skins is active and
737
+ // removed on the "Default" preference, so the built-in appearance
738
+ // stays pixel-identical unless the user picked a Dracula skin.
739
+ const boost = (selector) =>
740
+ selector.split(",").map((part) => `${part.trim()}:not(#dsh-dracula-theme)`).join(",");
741
+ const SURFACE_RULES = [
742
+ [
743
+ "[class$=\"_userStack\"] [class$=\"_bubble\"]",
744
+ " background: color-mix(in srgb, var(--dsw-alias-brand-primary) 30%, var(--dsw-alias-bg-layer-2));"
745
+ ],
746
+ [
747
+ "[class$=\"_refChip\"]",
748
+ " background: color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent);"
749
+ ],
750
+ [
751
+ "[class$=\"_thinkBody\"]",
752
+ " color: var(--dsw-alias-brand-text);"
753
+ ]
754
+ ].map(([selector, body]) => `${boost(selector)} {\n${body}\n}`).join("\n");
755
+ const style = document.createElement("style");
756
+ style.textContent = SURFACE_RULES;
757
+ const syncSurfaceTint = () => {
758
+ const active = SKINS.some((skinDefinition) => skinDefinition.id === ctx.theme.getTheme().preference);
759
+ if (active && !style.isConnected) document.head.appendChild(style);
760
+ if (!active && style.isConnected) style.remove();
761
+ };
762
+ syncSurfaceTint();
763
+ ctx.on("theme/change", syncSurfaceTint);
764
+ ctx.effect(() => () => {
765
+ style.remove();
766
+ }, "dsh-dracula-theme: surface tint lifecycle");
767
+
768
+ // Restore the saved skin. The ThemeService adopts its durable
769
+ // built-in preference ("light"/"dark"/"system") from the Host
770
+ // settings scope asynchronously after boot, which overwrites a
771
+ // third-party preference restored too early. Re-assert the saved
772
+ // skin for a short boot window (a handful of change events or a
773
+ // few seconds), then yield to subsequent user actions.
774
+ const saved = readSavedSkin();
775
+ const savedValid = typeof saved === "string" && saved !== DEFAULT_SKIN && SKINS.some((skinDefinition) => skinDefinition.id === saved);
776
+ let bootGuard = savedValid ? 3 : 0;
777
+ const reassertSaved = () => {
778
+ if (bootGuard <= 0) return;
779
+ const current = ctx.theme.getTheme().preference;
780
+ if (current === saved) return;
781
+ bootGuard -= 1;
782
+ ctx.theme.setTheme(saved);
783
+ };
784
+ reassertSaved();
785
+ const bootWindow = setTimeout(() => {
786
+ bootGuard = 0;
787
+ }, 5000);
788
+ ctx.effect(() => () => {
789
+ clearTimeout(bootWindow);
790
+ }, "dsh-dracula: boot restore window");
791
+
792
+ const skinStore = createSkinStore();
793
+ let skinBound;
794
+ const syncSkin = (snapshot) => {
795
+ skinBound?.sync(snapshot.preference, snapshot.revision);
796
+ };
797
+ ctx.on("theme/change", (snapshot) => {
798
+ syncSkin(snapshot);
799
+ // If the preference moved to another plugin's third-party theme,
800
+ // drop our stored choice so only the last-picked plugin restores
801
+ // at boot (both plugins must implement this convention).
802
+ const pref = snapshot.preference;
803
+ if (pref !== DEFAULT_SKIN && pref !== "light" && pref !== "dark" && !SKINS.some((skinDefinition) => skinDefinition.id === pref)) {
804
+ writeSavedSkin(DEFAULT_SKIN);
805
+ }
806
+ // Re-assert from a fresh task: a re-entrant setTheme inside the
807
+ // dispatch is missed by other subscribers (ui-layout's
808
+ // ThemePresenter), so the restored skin would never reach the DOM.
809
+ setTimeout(() => {
810
+ reassertSaved();
811
+ }, 0);
812
+ });
813
+
814
+ ctx.effect(() => ctx.locale.register(SETTINGS_NS, {
815
+ zh,
816
+ en
817
+ }), "dsh-dracula: settings row dictionaries");
818
+
819
+ const skinInjected = (actions) => {
820
+ skinBound = actions;
821
+ syncSkin(ctx.theme.getTheme());
822
+ return {
823
+ setSkin: (id) => {
824
+ ctx.theme.setTheme(id);
825
+ writeSavedSkin(id);
826
+ }
827
+ };
828
+ };
829
+ ctx.slots.inject("settings.general.item", () => ctx.slots.register({
830
+ name: "settings.general.item",
831
+ id: "dracula",
832
+ order: 19,
833
+ store: skinStore,
834
+ locale: SETTINGS_NS,
835
+ inject: skinInjected
836
+ }, SkinRow));
837
+ }
838
+ //#endregion
839
+
840
+ exports.SKINS = SKINS;
841
+ exports.DEFAULT_SKIN = DEFAULT_SKIN;
842
+ exports.apply = apply;
843
+ exports.inject = inject;
844
+ return module.exports;
845
+ }
846
+ });