@leon___/dsh-client-liang-intensity-skin 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +144 -0
  2. package/assets/portrait-source-v2/bridge-15.webp +0 -0
  3. package/assets/portrait-source-v2/bridge-27.webp +0 -0
  4. package/assets/portrait-source-v2/level-01.webp +0 -0
  5. package/assets/portrait-source-v2/level-03.webp +0 -0
  6. package/assets/portrait-source-v2/level-04.webp +0 -0
  7. package/assets/portrait-source-v2/level-07.webp +0 -0
  8. package/assets/portrait-source-v2/level-09.webp +0 -0
  9. package/assets/portrait-source-v2/level-10.webp +0 -0
  10. package/assets/portrait-source-v2/level-13.webp +0 -0
  11. package/assets/portrait-source-v2/level-14.webp +0 -0
  12. package/assets/portrait-source-v2/level-16.webp +0 -0
  13. package/assets/portrait-source-v2/level-17.webp +0 -0
  14. package/assets/portrait-source-v2/level-19.webp +0 -0
  15. package/assets/portrait-source-v2/level-21.webp +0 -0
  16. package/assets/portrait-source-v2/level-22.webp +0 -0
  17. package/assets/portrait-source-v2/level-25.webp +0 -0
  18. package/assets/portrait-source-v2/level-28.webp +0 -0
  19. package/assets/portrait-source-v2/level-29.webp +0 -0
  20. package/assets/portrait-source-v2/stage-00.webp +0 -0
  21. package/assets/portrait-source-v2/stage-06.webp +0 -0
  22. package/assets/portrait-source-v2/stage-12.webp +0 -0
  23. package/assets/portrait-source-v2/stage-18.webp +0 -0
  24. package/assets/portrait-source-v2/stage-24.webp +0 -0
  25. package/assets/portrait-source-v2/stage-30.webp +0 -0
  26. package/cordis.patch.yml +3 -0
  27. package/lib/client.js +1353 -0
  28. package/lib/client.js.map +7 -0
  29. package/package.json +75 -0
  30. package/src/index.js +159 -0
  31. package/src/range.js +22 -0
package/lib/client.js ADDED
@@ -0,0 +1,1353 @@
1
+ window.__ModuleLoader__.load({id:"@leon___/dsh-client-liang-intensity-skin",factory:(require)=>{var module={exports:{}};var exports=module.exports;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client/index.tsx
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ apply: () => apply,
24
+ inject: () => inject
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+ var import_react = require("react");
28
+
29
+ // src/client/skin.css
30
+ var skin_default = `.liang-skin-backdrop {
31
+ position: fixed;
32
+ z-index: 0;
33
+ inset: 0;
34
+ overflow: hidden;
35
+ pointer-events: none;
36
+ background: var(--liang-page, transparent);
37
+ opacity: 0;
38
+ transition: opacity 220ms ease, background-color 180ms linear;
39
+ }
40
+
41
+ body[data-liang-skin="on"] .liang-skin-backdrop {
42
+ opacity: 1;
43
+ }
44
+
45
+ .liang-skin-backdrop img {
46
+ position: absolute;
47
+ top: 50%;
48
+ right: 0;
49
+ display: block;
50
+ width: min(42vw, 720px);
51
+ height: 100vh;
52
+ object-fit: cover;
53
+ object-position: 50% 42%;
54
+ opacity: var(--liang-portrait-opacity, 0.45);
55
+ transform: translateY(-50%);
56
+ filter: none;
57
+ mask-image: linear-gradient(90deg, transparent 0%, rgb(0 0 0 / 20%) 10%, black 30%, black 100%);
58
+ transition: filter 180ms linear;
59
+ }
60
+
61
+ .liang-skin-backdrop img {
62
+ display: none;
63
+ }
64
+
65
+ .liang-skin-backdrop[data-media="sequence"] .liang-skin-sequence-frame {
66
+ display: block;
67
+ opacity: var(--liang-portrait-opacity, 0.82);
68
+ }
69
+
70
+ .liang-skin-backdrop[data-media="color"] img {
71
+ display: none;
72
+ }
73
+
74
+ .liang-skin-backdrop::after {
75
+ position: absolute;
76
+ inset: 0;
77
+ content: "";
78
+ background: linear-gradient(90deg, var(--liang-page, transparent) 0 28%, transparent 57% 100%);
79
+ }
80
+
81
+ body[data-liang-skin="on"] {
82
+ --dsw-alias-bg-base: var(--liang-bg-base) !important;
83
+ --dsw-alias-bg-layer-1: var(--liang-layer-1) !important;
84
+ --dsw-alias-bg-layer-2: var(--liang-layer-2) !important;
85
+ --dsw-alias-bg-layer-3: var(--liang-layer-3) !important;
86
+ --dsw-specific-sidebar-fill: var(--liang-sidebar) !important;
87
+ --dsw-alias-label-primary: var(--liang-ink) !important;
88
+ --dsw-alias-label-primary-dimmed: var(--liang-ink) !important;
89
+ --dsw-alias-label-secondary: var(--liang-secondary) !important;
90
+ --dsw-alias-label-tertiary: var(--liang-tertiary) !important;
91
+ --dsw-alias-label-caption: var(--liang-tertiary) !important;
92
+ --dsw-alias-border-l1: var(--liang-border) !important;
93
+ --dsw-alias-border-l2-darkmode-thin: var(--liang-border) !important;
94
+ --dsw-alias-border-l2: var(--liang-border) !important;
95
+ --dsw-alias-border-l3: var(--liang-border) !important;
96
+ --dsw-alias-button-primary-fill: var(--liang-accent) !important;
97
+ --dsw-alias-button-primary-hover: var(--liang-accent-hover) !important;
98
+ --dsw-alias-button-info-fill: var(--liang-accent) !important;
99
+ --dsw-alias-button-info-hover: var(--liang-accent-hover) !important;
100
+ --dsw-alias-state-business-primary: var(--liang-accent) !important;
101
+ --dsw-alias-interactive-bg-hover: var(--liang-hover) !important;
102
+ --dsw-alias-interactive-bg-active: var(--liang-hover) !important;
103
+ --dsw-alias-button-elevated-fill: var(--liang-layer-1) !important;
104
+ --dsw-alias-button-floating-fill: var(--liang-layer-2) !important;
105
+ --dsw-alias-button-floating-hover: var(--liang-layer-3) !important;
106
+ --dsw-alias-interactive-bg-hover-solid: var(--liang-layer-2) !important;
107
+ --dsw-specific-bubble: var(--liang-layer-2) !important;
108
+ --dsw-specific-input-major: var(--liang-layer-1) !important;
109
+ --dsw-specific-menu: var(--liang-layer-3) !important;
110
+ --dsw-specific-selector: var(--liang-layer-2) !important;
111
+ --dsw-alias-markdown-citation: var(--liang-layer-2) !important;
112
+ --dsw-alias-markdown-code-block-banner: var(--liang-layer-1) !important;
113
+ --dsw-alias-markdown-code-block: var(--liang-layer-1) !important;
114
+ --dsw-alias-markdown-code-segment-selected: var(--liang-layer-2) !important;
115
+ --dsw-alias-markdown-code-segment-unselected: var(--liang-layer-1) !important;
116
+ --dsw-alias-markdown-inline-code: var(--liang-layer-2) !important;
117
+ --dsw-alias-markdown-placeholder: var(--liang-layer-1) !important;
118
+ --dsw-alias-markdown-tag: var(--liang-layer-2) !important;
119
+ background: var(--liang-page) !important;
120
+ }
121
+
122
+ body[data-liang-skin="on"]:is(
123
+ [data-liang-stage="0"],
124
+ [data-liang-stage="1"],
125
+ [data-liang-stage="2"],
126
+ [data-liang-stage="3"]
127
+ ) {
128
+ --dsw-alias-brand-primary-new-colorprimary-new-color: rgb(65 118 230) !important;
129
+ --dsw-alias-brand-primary: rgb(15 17 21) !important;
130
+ --dsw-alias-brand-text: rgb(15 17 21) !important;
131
+ --dsw-alias-button-primary-fill: rgb(15 17 21) !important;
132
+ --dsw-alias-button-primary-hover: rgb(53 54 56) !important;
133
+ --dsw-alias-button-info-fill: rgb(65 118 230) !important;
134
+ --dsw-alias-button-info-hover: rgb(103 158 254) !important;
135
+ --dsw-alias-state-business-primary: rgb(65 118 230) !important;
136
+ --dsw-alias-label-primary-inverted: rgb(249 250 251) !important;
137
+ --dsw-alias-button-elevated-fill: rgb(255 255 255) !important;
138
+ --dsw-alias-button-floating-fill: rgb(255 255 255) !important;
139
+ --dsw-alias-button-floating-hover: rgb(241 243 245) !important;
140
+ --dsw-alias-interactive-bg-hover-solid: rgb(241 243 245) !important;
141
+ --dsw-specific-bubble: rgb(237 243 254) !important;
142
+ --dsw-specific-input-major: rgb(255 255 255) !important;
143
+ --dsw-specific-menu: rgb(255 255 255) !important;
144
+ --dsw-specific-selector: rgb(245 246 247) !important;
145
+ }
146
+
147
+ body[data-liang-skin="on"][data-liang-stage="5"] {
148
+ --dsw-alias-brand-primary-new-colorprimary-new-color: #c19a49 !important;
149
+ --dsw-alias-brand-primary: #c19a49 !important;
150
+ --dsw-alias-brand-text: #d5b56e !important;
151
+ --dsw-alias-button-info-fill: #c19a49 !important;
152
+ --dsw-alias-button-info-hover: #d5b56e !important;
153
+ --dsw-alias-state-business-primary: #c19a49 !important;
154
+ --dsw-alias-bg-module-platform: var(--liang-layer-3) !important;
155
+ --dsw-specific-sidebar-nav-item-active: var(--liang-layer-3) !important;
156
+ --dsw-specific-sidebar-nav-item-hover: var(--liang-hover) !important;
157
+ }
158
+
159
+ /* The low-intensity skin is light by default, but it must not turn a dark
160
+ Harness document into a light surface. Keep the skin's portrait progression
161
+ while switching the shared UI layers back to a readable charcoal palette. */
162
+ body[data-liang-skin="on"][data-ds-dark-theme]:is(
163
+ [data-liang-stage="0"],
164
+ [data-liang-stage="1"],
165
+ [data-liang-stage="2"],
166
+ [data-liang-stage="3"]
167
+ ) {
168
+ --liang-page: rgb(17 17 17) !important;
169
+ --liang-bg-base: rgb(17 17 17 / 42%) !important;
170
+ --liang-layer-1: rgb(30 27 25 / 94%) !important;
171
+ --liang-layer-2: rgb(41 35 30 / 96%) !important;
172
+ --liang-layer-3: rgb(41 35 30 / 99%) !important;
173
+ --liang-sidebar: rgb(23 20 18 / 96%) !important;
174
+ --liang-ink: rgb(244 241 232) !important;
175
+ --liang-secondary: rgb(184 180 169) !important;
176
+ --liang-tertiary: rgb(137 134 126) !important;
177
+ --liang-border: rgb(244 241 232 / 15%) !important;
178
+ --liang-hover: rgb(244 241 232 / 9%) !important;
179
+ --dsw-alias-brand-primary: var(--liang-accent) !important;
180
+ --dsw-alias-brand-text: var(--liang-accent) !important;
181
+ --dsw-alias-button-primary-fill: var(--liang-accent) !important;
182
+ --dsw-alias-button-primary-hover: var(--liang-accent-hover) !important;
183
+ --dsw-alias-button-info-fill: var(--liang-accent) !important;
184
+ --dsw-alias-button-info-hover: var(--liang-accent-hover) !important;
185
+ --dsw-alias-state-business-primary: var(--liang-accent) !important;
186
+ --dsw-alias-button-elevated-fill: var(--liang-layer-1) !important;
187
+ --dsw-alias-button-floating-fill: var(--liang-layer-2) !important;
188
+ --dsw-alias-button-floating-hover: var(--liang-layer-3) !important;
189
+ --dsw-alias-interactive-bg-hover-solid: var(--liang-layer-2) !important;
190
+ --dsw-specific-bubble: var(--liang-layer-2) !important;
191
+ --dsw-specific-input-major: var(--liang-layer-1) !important;
192
+ --dsw-specific-menu: var(--liang-layer-3) !important;
193
+ --dsw-specific-selector: var(--liang-layer-2) !important;
194
+ background: var(--liang-page) !important;
195
+ }
196
+
197
+ body[data-liang-skin="on"][data-ds-dark-theme]:is(
198
+ [data-liang-stage="0"],
199
+ [data-liang-stage="1"],
200
+ [data-liang-stage="2"],
201
+ [data-liang-stage="3"]
202
+ ) .liang-skin-backdrop {
203
+ background: var(--liang-page) !important;
204
+ }
205
+
206
+ body[data-liang-skin="on"][data-ds-dark-theme]:is(
207
+ [data-liang-stage="0"],
208
+ [data-liang-stage="1"],
209
+ [data-liang-stage="2"],
210
+ [data-liang-stage="3"]
211
+ ) .liang-skin-backdrop::after {
212
+ background: linear-gradient(90deg, var(--liang-page) 0 28%, transparent 57% 100%);
213
+ }
214
+
215
+ /* The host renders the running-turn label as a clipped blue text gradient.
216
+ Retarget only that gradient's color tokens in the custom dark skin; keep
217
+ the host's text clipping and shimmer behavior, and leave light mode alone. */
218
+ body[data-liang-skin="on"][data-liang-stage="5"] [class*="_turnStatus"] {
219
+ --dsw-static-deepseek-500: #c19a49 !important;
220
+ --dsw-static-deepseek-200: #d5b56e !important;
221
+ }
222
+
223
+ body[data-liang-skin="on"][data-liang-stage="5"] [class*="_turnStatusClock"] {
224
+ color: #c19a49 !important;
225
+ -webkit-text-fill-color: #c19a49 !important;
226
+ }
227
+
228
+ /* Preserve the wordmark badge contrast in the low-intensity shell. */
229
+ body[data-liang-skin="on"]:is(
230
+ [data-liang-stage="0"],
231
+ [data-liang-stage="1"],
232
+ [data-liang-stage="2"],
233
+ [data-liang-stage="3"]
234
+ ) button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"] svg[viewBox="0 0 182 24"] > rect[width="52"] {
235
+ fill: rgb(15 17 21) !important;
236
+ }
237
+
238
+ body[data-liang-skin="on"]:is(
239
+ [data-liang-stage="0"],
240
+ [data-liang-stage="1"],
241
+ [data-liang-stage="2"],
242
+ [data-liang-stage="3"]
243
+ ) button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"] svg[viewBox="0 0 182 24"] > g[clip-path*="badge"] path {
244
+ fill: rgb(249 250 251) !important;
245
+ }
246
+
247
+ body[data-liang-skin="on"][data-liang-stage="5"] button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"] svg[viewBox="0 0 182 24"] > rect[width="52"] {
248
+ fill: #c19a49 !important;
249
+ }
250
+
251
+ body[data-liang-skin="on"][data-liang-stage="5"] button[aria-label="\u65B0\u5EFA\u4F1A\u8BDD"] svg[viewBox="0 0 182 24"] > g[clip-path*="badge"] path {
252
+ fill: #171816 !important;
253
+ }
254
+
255
+ body[data-liang-skin="on"][data-liang-stage="5"] [aria-label^="\u9009\u62E9\u6A21\u578B"] > span:nth-of-type(2) {
256
+ color: #d5b56e !important;
257
+ }
258
+
259
+ body[data-liang-skin="on"][data-liang-stage="5"] [class*="heroGlow"] ellipse {
260
+ fill: #c19a49 !important;
261
+ fill-opacity: 0.16 !important;
262
+ }
263
+
264
+ body[data-liang-skin="on"][data-liang-stage="5"] span[class*="_previewBadge"] {
265
+ color: #171816 !important;
266
+ background: #c19a49 !important;
267
+ }
268
+
269
+ body[data-liang-skin="on"][data-liang-stage="5"] button[aria-label="\u53D1\u9001\u6D88\u606F"] {
270
+ color: #171816 !important;
271
+ }
272
+
273
+ body[data-liang-skin="on"][data-liang-stage="5"] button[aria-label="\u53D1\u9001\u6D88\u606F"]:disabled {
274
+ opacity: 0.62;
275
+ }
276
+
277
+ body[data-liang-skin="on"]:is(
278
+ [data-liang-stage="0"],
279
+ [data-liang-stage="1"],
280
+ [data-liang-stage="2"],
281
+ [data-liang-stage="3"]
282
+ ) button[aria-label="\u53D1\u9001\u6D88\u606F"] {
283
+ color: #fff !important;
284
+ }
285
+
286
+ body[data-liang-skin="on"]:is(
287
+ [data-liang-stage="0"],
288
+ [data-liang-stage="1"],
289
+ [data-liang-stage="2"],
290
+ [data-liang-stage="3"]
291
+ ) button[aria-label="\u53D1\u9001\u6D88\u606F"]:disabled {
292
+ color: rgb(255 255 255 / 92%) !important;
293
+ background: rgb(65 118 230 / 42%) !important;
294
+ opacity: 1;
295
+ }
296
+
297
+ body[data-liang-skin="on"] > #root {
298
+ position: relative;
299
+ z-index: 1;
300
+ background: transparent !important;
301
+ }
302
+
303
+ body[data-liang-skin="on"] button,
304
+ body[data-liang-skin="on"] input,
305
+ body[data-liang-skin="on"] textarea {
306
+ transition: color 160ms linear, background-color 160ms linear, border-color 160ms linear;
307
+ }
308
+
309
+ /* The composer card has a native theme-mode fill, so keep its surface and
310
+ readable ink aligned with the active Liang palette. */
311
+ body[data-liang-skin="on"]:is(
312
+ [data-liang-stage="0"],
313
+ [data-liang-stage="1"],
314
+ [data-liang-stage="2"],
315
+ [data-liang-stage="3"]
316
+ ) [data-composer-card="true"] {
317
+ border-color: var(--liang-border) !important;
318
+ color: var(--liang-ink) !important;
319
+ background: var(--liang-layer-1) !important;
320
+ box-shadow: 0 8px 28px rgb(20 22 20 / 8%);
321
+ }
322
+
323
+ body[data-liang-skin="on"]:is(
324
+ [data-liang-stage="0"],
325
+ [data-liang-stage="1"],
326
+ [data-liang-stage="2"],
327
+ [data-liang-stage="3"]
328
+ ) [data-composer-card="true"] :is(textarea, button, [data-input-mirror="true"]) {
329
+ color: var(--liang-ink) !important;
330
+ caret-color: var(--liang-accent) !important;
331
+ }
332
+
333
+ body[data-liang-skin="on"]:is(
334
+ [data-liang-stage="0"],
335
+ [data-liang-stage="1"],
336
+ [data-liang-stage="2"],
337
+ [data-liang-stage="3"]
338
+ ) [data-composer-card="true"] textarea::placeholder {
339
+ color: var(--liang-tertiary) !important;
340
+ opacity: 1;
341
+ }
342
+
343
+ .liang-effort-control {
344
+ --liang-control-accent: var(--dsw-alias-brand-primary-new-colorprimary-new-color, #4176e6);
345
+ --liang-control-rail: var(--dsw-alias-border-l3, rgb(0 0 0 / 16%));
346
+ position: relative;
347
+ display: flex;
348
+ width: 124px;
349
+ height: 28px;
350
+ align-items: center;
351
+ margin: 0 3px;
352
+ overflow: visible;
353
+ }
354
+
355
+ body[data-liang-skin="on"] .liang-effort-control {
356
+ --liang-control-accent: var(--liang-secondary);
357
+ --liang-control-rail: color-mix(in srgb, var(--liang-secondary) 28%, transparent);
358
+ }
359
+
360
+ .liang-effort-control__ticks {
361
+ position: absolute;
362
+ z-index: 0;
363
+ inset: 0 10px;
364
+ pointer-events: none;
365
+ }
366
+
367
+ .liang-effort-control__ticks::before {
368
+ position: absolute;
369
+ top: 50%;
370
+ right: 0;
371
+ left: 0;
372
+ height: 1px;
373
+ content: "";
374
+ background: var(--liang-control-rail);
375
+ transform: translateY(-50%);
376
+ }
377
+
378
+ .liang-effort-control__tooltip {
379
+ position: absolute;
380
+ z-index: 4;
381
+ bottom: calc(100% + 7px);
382
+ left: calc(10px + (100% - 20px) * var(--liang-slider-ratio));
383
+ min-width: max-content;
384
+ padding: 5px 8px;
385
+ border: 1px solid var(--liang-border, rgb(0 0 0 / 12%));
386
+ border-radius: 7px;
387
+ color: var(--liang-ink, #171816);
388
+ background: var(--liang-layer-1, #fff);
389
+ box-shadow: 0 5px 16px rgb(0 0 0 / 16%);
390
+ font-size: 11px;
391
+ font-weight: 600;
392
+ line-height: 16px;
393
+ letter-spacing: 0.01em;
394
+ pointer-events: none;
395
+ transform: translateX(-50%);
396
+ white-space: nowrap;
397
+ }
398
+
399
+ .liang-effort-control__tooltip::after {
400
+ position: absolute;
401
+ top: 100%;
402
+ left: 50%;
403
+ width: 7px;
404
+ height: 7px;
405
+ content: "";
406
+ background: inherit;
407
+ transform: translate(-50%, -4px) rotate(45deg);
408
+ }
409
+
410
+ .liang-effort-control__tick {
411
+ position: absolute;
412
+ top: 50%;
413
+ width: 1px;
414
+ height: 7px;
415
+ background: var(--liang-control-accent);
416
+ opacity: 0.42;
417
+ transform: translate(-50%, -50%);
418
+ }
419
+
420
+ .liang-effort-control__range {
421
+ position: relative;
422
+ z-index: 1;
423
+ width: calc(100% - 7px);
424
+ height: 28px;
425
+ margin: 0 3.5px;
426
+ cursor: ew-resize;
427
+ appearance: none;
428
+ background: transparent;
429
+ touch-action: pan-y;
430
+ }
431
+
432
+ .liang-effort-control__range:disabled {
433
+ cursor: progress;
434
+ opacity: 0.58;
435
+ }
436
+
437
+ .liang-effort-control__range::-webkit-slider-runnable-track {
438
+ height: 1px;
439
+ border-radius: 1px;
440
+ background: transparent;
441
+ }
442
+
443
+ .liang-effort-control__range::-webkit-slider-thumb {
444
+ width: 13px;
445
+ height: 13px;
446
+ margin-top: -6px;
447
+ border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);
448
+ border-radius: 50%;
449
+ appearance: none;
450
+ background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--dsw-alias-bg-layer-1, #fff)) 2.5px);
451
+ box-shadow: 0 1px 4px rgb(0 0 0 / 14%);
452
+ }
453
+
454
+ body[data-liang-skin="on"] .liang-effort-control__range::-webkit-slider-thumb {
455
+ width: 13px;
456
+ height: 13px;
457
+ margin-top: -6px;
458
+ border-color: color-mix(in srgb, var(--liang-control-accent) 72%, transparent);
459
+ background: radial-gradient(circle, var(--liang-control-accent) 0 2px, color-mix(in srgb, var(--liang-control-accent) 22%, var(--liang-layer-1)) 2.5px);
460
+ }
461
+
462
+ .liang-effort-control__range::-moz-range-track {
463
+ height: 1px;
464
+ background: transparent;
465
+ }
466
+
467
+ .liang-effort-control__range::-moz-range-progress {
468
+ height: 1px;
469
+ background: transparent;
470
+ }
471
+
472
+ .liang-effort-control__range::-moz-range-thumb {
473
+ width: 11px;
474
+ height: 11px;
475
+ border: 1.5px solid color-mix(in srgb, var(--liang-control-accent) 72%, transparent);
476
+ border-radius: 50%;
477
+ background: color-mix(in srgb, var(--liang-control-accent) 24%, var(--dsw-alias-bg-layer-1, #fff));
478
+ }
479
+
480
+ .liang-effort-control__range:focus-visible {
481
+ outline: none;
482
+ }
483
+
484
+ .liang-effort-control[data-state="error"] {
485
+ --liang-control-accent: var(--dsw-alias-state-error-primary, #e43c3c);
486
+ }
487
+
488
+ .liang-appearance-choice {
489
+ box-sizing: border-box;
490
+ border: 1px solid var(--dsw-alias-border-l2);
491
+ flex: 180px;
492
+ flex-direction: column;
493
+ justify-content: center;
494
+ align-items: center;
495
+ gap: 4px;
496
+ padding: 20px 32px;
497
+ border-radius: 16px;
498
+ font: inherit;
499
+ color: var(--dsw-alias-label-primary);
500
+ cursor: pointer;
501
+ background: transparent;
502
+ font-size: 14px;
503
+ line-height: 22px;
504
+ display: flex;
505
+ }
506
+
507
+ [class*="_8HJdBW_cubeRow"]:has(.liang-appearance-choice) {
508
+ display: grid;
509
+ grid-template-columns: repeat(4, minmax(0, 1fr));
510
+ }
511
+
512
+ .liang-appearance-choice:hover:not([aria-pressed="true"]) {
513
+ background: var(--dsw-alias-interactive-bg-hover);
514
+ }
515
+
516
+ .liang-appearance-choice[aria-pressed="true"] {
517
+ border-color: var(--dsw-static-neutral-bluish-400);
518
+ background: var(--dsw-alias-bg-module-platform);
519
+ }
520
+
521
+ .liang-appearance-choice__icon {
522
+ display: block;
523
+ flex: 0 0 16px;
524
+ width: 16px;
525
+ height: 16px;
526
+ color: currentColor;
527
+ font-size: 16px;
528
+ line-height: 16px;
529
+ }
530
+
531
+ .liang-appearance-choice__label {
532
+ display: block;
533
+ }
534
+
535
+ /* Keep the host's three theme cubes untouched. These rules only style the
536
+ fourth button that is appended to the host cube row. */
537
+ .liang-appearance-choice:disabled {
538
+ cursor: progress;
539
+ opacity: 0.7;
540
+ }
541
+
542
+ .liang-appearance-binding {
543
+ box-sizing: border-box;
544
+ display: flex;
545
+ width: 100%;
546
+ min-height: 28px;
547
+ align-items: center;
548
+ justify-content: space-between;
549
+ gap: 16px;
550
+ padding: 4px 0 0;
551
+ color: var(--dsw-alias-label-primary);
552
+ font: inherit;
553
+ font-size: 14px;
554
+ line-height: 22px;
555
+ cursor: pointer;
556
+ }
557
+
558
+ .liang-appearance-binding__label {
559
+ display: block;
560
+ min-width: 0;
561
+ overflow: hidden;
562
+ text-overflow: ellipsis;
563
+ white-space: nowrap;
564
+ }
565
+
566
+ .liang-appearance-binding__copy {
567
+ display: flex;
568
+ min-width: 0;
569
+ flex-direction: column;
570
+ gap: 1px;
571
+ }
572
+
573
+ .liang-appearance-binding__description {
574
+ display: block;
575
+ overflow: hidden;
576
+ color: var(--dsw-alias-label-secondary);
577
+ font-size: 12px;
578
+ line-height: 18px;
579
+ text-overflow: ellipsis;
580
+ white-space: nowrap;
581
+ }
582
+
583
+ .liang-appearance-binding__input {
584
+ position: relative;
585
+ flex: 0 0 36px;
586
+ width: 36px;
587
+ height: 20px;
588
+ margin: 0;
589
+ border: 1px solid var(--dsw-alias-border-l2);
590
+ border-radius: 999px;
591
+ outline: none;
592
+ cursor: pointer;
593
+ appearance: none;
594
+ background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-module-platform));
595
+ }
596
+
597
+ .liang-appearance-binding__input::before {
598
+ position: absolute;
599
+ top: 2px;
600
+ left: 2px;
601
+ width: 14px;
602
+ height: 14px;
603
+ border-radius: 50%;
604
+ content: "";
605
+ background: var(--dsw-alias-label-primary);
606
+ box-shadow: 0 1px 3px rgb(0 0 0 / 18%);
607
+ transition: transform 160ms ease, background-color 160ms ease;
608
+ }
609
+
610
+ .liang-appearance-binding__input:checked {
611
+ border-color: var(--dsw-static-neutral-bluish-400);
612
+ background: var(--dsw-static-neutral-bluish-400);
613
+ }
614
+
615
+ .liang-appearance-binding__input:checked::before {
616
+ background: var(--dsw-alias-bg-layer-1, #fff);
617
+ transform: translateX(16px);
618
+ }
619
+
620
+ .liang-appearance-binding__input:focus-visible {
621
+ box-shadow: 0 0 0 2px var(--dsw-alias-interactive-bg-hover);
622
+ }
623
+
624
+ .liang-appearance-binding__input:disabled {
625
+ cursor: progress;
626
+ opacity: 0.7;
627
+ }
628
+
629
+ @media (max-width: 760px) {
630
+ .liang-effort-control {
631
+ width: 92px;
632
+ }
633
+
634
+ .liang-skin-backdrop img {
635
+ right: -18vw;
636
+ width: 92vw;
637
+ opacity: calc(var(--liang-portrait-opacity, 0.45) * 0.72);
638
+ }
639
+
640
+ }
641
+
642
+ @media (prefers-reduced-motion: reduce) {
643
+ .liang-skin-backdrop,
644
+ .liang-skin-backdrop img,
645
+ body[data-liang-skin="on"] button,
646
+ body[data-liang-skin="on"] input,
647
+ body[data-liang-skin="on"] textarea {
648
+ transition: none;
649
+ }
650
+ }
651
+ `;
652
+
653
+ // src/client/logic.ts
654
+ var PREVIEW_MAX_FRAME = 240;
655
+ var MAX_LEVEL = 30;
656
+ var LIANG_RANKS = ["\u5C0F\u96BE\u6881", "\u7262\u6881", "\u6881\u5B50", "\u6881\u5723", "\u6881\u795E", "\u6881\u7956"];
657
+ var STOPS = [
658
+ { at: 0, page: [232, 233, 229], surface: [248, 248, 245], surface2: [238, 239, 235], ink: [23, 24, 22], secondary: [112, 116, 111], accent: [181, 43, 36], portraitOpacity: 0.92 },
659
+ { at: 6, page: [211, 211, 206], surface: [239, 239, 234], surface2: [224, 224, 218], ink: [26, 26, 24], secondary: [101, 101, 96], accent: [181, 43, 36], portraitOpacity: 0.93 },
660
+ { at: 12, page: [171, 168, 162], surface: [211, 208, 201], surface2: [190, 186, 179], ink: [27, 26, 24], secondary: [83, 79, 74], accent: [166, 54, 42], portraitOpacity: 0.94 },
661
+ { at: 18, page: [117, 112, 106], surface: [154, 148, 140], surface2: [128, 122, 115], ink: [24, 22, 20], secondary: [65, 61, 56], accent: [154, 56, 42], portraitOpacity: 0.94 },
662
+ { at: 24, page: [43, 39, 37], surface: [48, 43, 40], surface2: [58, 51, 46], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [181, 92, 54], portraitOpacity: 0.94 },
663
+ { at: 30, page: [17, 17, 17], surface: [30, 27, 25], surface2: [41, 35, 30], ink: [244, 241, 232], secondary: [184, 180, 169], accent: [193, 154, 73], portraitOpacity: 0.94 }
664
+ ];
665
+ function clampFrame(value) {
666
+ if (!Number.isFinite(value)) return 0;
667
+ return Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(value)));
668
+ }
669
+ function frameForEffort(index, count) {
670
+ if (count <= 1 || !Number.isFinite(index)) return 0;
671
+ const safe = Math.min(count - 1, Math.max(0, Math.round(index)));
672
+ return Math.round(safe / (count - 1) * PREVIEW_MAX_FRAME);
673
+ }
674
+ function nearestEffortIndex(frame, efforts) {
675
+ if (efforts.length === 0) return -1;
676
+ const safe = clampFrame(frame);
677
+ let best = 0;
678
+ let distance = Math.abs(safe - frameForEffort(0, efforts.length));
679
+ for (let index = 1; index < efforts.length; index += 1) {
680
+ const next = Math.abs(safe - frameForEffort(index, efforts.length));
681
+ if (next < distance) {
682
+ best = index;
683
+ distance = next;
684
+ }
685
+ }
686
+ return best;
687
+ }
688
+ function selectedEffortIndex(efforts, selectedId, defaultId) {
689
+ const id = selectedId ?? defaultId;
690
+ return id === void 0 ? -1 : efforts.findIndex((effort) => effort.id === id);
691
+ }
692
+ function portraitBlendForLevel(level, anchors) {
693
+ if (anchors.length === 0) return { lowerIndex: -1, upperIndex: -1, mix: 0 };
694
+ const safeLevel = Number.isFinite(level) ? Math.min(anchors[anchors.length - 1], Math.max(anchors[0], level)) : anchors[0];
695
+ let upperIndex = anchors.findIndex((anchor) => anchor >= safeLevel);
696
+ if (upperIndex < 0) upperIndex = anchors.length - 1;
697
+ const lowerIndex = Math.max(0, upperIndex - (anchors[upperIndex] > safeLevel ? 1 : 0));
698
+ const span = anchors[upperIndex] - anchors[lowerIndex];
699
+ return {
700
+ lowerIndex,
701
+ upperIndex,
702
+ mix: span === 0 ? 0 : (safeLevel - anchors[lowerIndex]) / span
703
+ };
704
+ }
705
+ function liangRankForFrame(rawFrame) {
706
+ const level = clampFrame(rawFrame) / PREVIEW_MAX_FRAME * MAX_LEVEL;
707
+ const index = level >= MAX_LEVEL ? LIANG_RANKS.length - 1 : Math.floor(level / 6);
708
+ return LIANG_RANKS[Math.min(LIANG_RANKS.length - 1, Math.max(0, index))];
709
+ }
710
+ function indicatorLabel(rawFrame, efforts) {
711
+ const effort = efforts[nearestEffortIndex(rawFrame, efforts)];
712
+ return effort === void 0 ? liangRankForFrame(rawFrame) : `${liangRankForFrame(rawFrame)} \xB7 ${effort.name}`;
713
+ }
714
+ function lerp(a, b, amount) {
715
+ return a + (b - a) * amount;
716
+ }
717
+ function mix(a, b, amount) {
718
+ return [
719
+ Math.round(lerp(a[0], b[0], amount)),
720
+ Math.round(lerp(a[1], b[1], amount)),
721
+ Math.round(lerp(a[2], b[2], amount))
722
+ ];
723
+ }
724
+ function rgb(value, alpha = 1) {
725
+ return alpha === 1 ? `rgb(${value[0]} ${value[1]} ${value[2]})` : `rgb(${value[0]} ${value[1]} ${value[2]} / ${alpha})`;
726
+ }
727
+ function paletteForFrame(rawFrame) {
728
+ const frame = clampFrame(rawFrame);
729
+ const level = frame / PREVIEW_MAX_FRAME * MAX_LEVEL;
730
+ const portraitStage = Math.min(5, Math.floor(level / 6));
731
+ const portraitFrom = STOPS[portraitStage];
732
+ const portraitTo = STOPS[Math.min(5, portraitStage + 1)];
733
+ const portraitAmount = portraitFrom === portraitTo ? 0 : (level - portraitFrom.at) / (portraitTo.at - portraitFrom.at);
734
+ const dark = level >= 24;
735
+ const stage = dark ? 5 : 0;
736
+ const ui = dark ? STOPS[5] : STOPS[0];
737
+ const page = ui.page;
738
+ const surface = ui.surface;
739
+ const surface2 = ui.surface2;
740
+ const sidebar = mix(page, surface2, 0.25);
741
+ const ink = ui.ink;
742
+ const secondary = ui.secondary;
743
+ const accent = dark ? [193, 154, 73] : [65, 118, 230];
744
+ const accentHover = mix(accent, ink, 0.13);
745
+ return {
746
+ level,
747
+ stage,
748
+ strength: level / MAX_LEVEL,
749
+ page: rgb(page),
750
+ // Keep the shell readable while allowing the right-side portrait to remain
751
+ // visibly present. Dense controls use the opaque layer tokens below.
752
+ base: rgb(page, dark ? 0.42 : 0.28),
753
+ layer1: rgb(surface, 0.94),
754
+ layer2: rgb(surface2, 0.96),
755
+ layer3: rgb(surface2, 0.99),
756
+ sidebar: rgb(sidebar, 0.96),
757
+ ink: rgb(ink),
758
+ secondary: rgb(secondary),
759
+ tertiary: rgb(mix(secondary, page, 0.28)),
760
+ border: rgb(ink, dark ? 0.15 : 0.12),
761
+ accent: rgb(accent),
762
+ accentHover: rgb(accentHover),
763
+ hover: rgb(ink, dark ? 0.09 : 0.07),
764
+ portraitOpacity: String(lerp(
765
+ portraitFrom.portraitOpacity,
766
+ portraitTo.portraitOpacity,
767
+ portraitAmount
768
+ ))
769
+ };
770
+ }
771
+
772
+ // src/client/index.tsx
773
+ var import_jsx_runtime = require("react/jsx-runtime");
774
+ var PACKAGE_ID = "dsh-client-liang-intensity-skin";
775
+ var LOCALE_NAMESPACE = "liang.skin";
776
+ var ASSET_PREFIX = `/plugins/${PACKAGE_ID}/assets`;
777
+ var FIRST_PORTRAIT_FILE = "portrait-source-v2/stage-00.webp";
778
+ var BIND_EFFORT_KEY = "dsh-liang-intensity-skin.bind-effort";
779
+ var PORTRAIT_ANCHORS = [
780
+ { level: 0, file: "stage-00.webp" },
781
+ { level: 1, file: "level-01.webp" },
782
+ { level: 3, file: "level-03.webp" },
783
+ { level: 4, file: "level-04.webp" },
784
+ { level: 6, file: "stage-06.webp" },
785
+ { level: 7, file: "level-07.webp" },
786
+ { level: 9, file: "level-09.webp" },
787
+ { level: 10, file: "level-10.webp" },
788
+ { level: 12, file: "stage-12.webp" },
789
+ { level: 13, file: "level-13.webp" },
790
+ { level: 14, file: "level-14.webp" },
791
+ { level: 15, file: "bridge-15.webp" },
792
+ { level: 16, file: "level-16.webp" },
793
+ { level: 17, file: "level-17.webp" },
794
+ { level: 18, file: "stage-18.webp" },
795
+ { level: 19, file: "level-19.webp" },
796
+ { level: 21, file: "level-21.webp" },
797
+ { level: 22, file: "level-22.webp" },
798
+ { level: 24, file: "stage-24.webp" },
799
+ { level: 25, file: "level-25.webp" },
800
+ { level: 27, file: "bridge-27.webp" },
801
+ { level: 28, file: "level-28.webp" },
802
+ { level: 29, file: "level-29.webp" },
803
+ { level: 30, file: "stage-30.webp" }
804
+ ];
805
+ var ANCHOR_LEVELS = PORTRAIT_ANCHORS.map((anchor) => anchor.level);
806
+ var cssVariables = [
807
+ "--liang-strength",
808
+ "--liang-page",
809
+ "--liang-bg-base",
810
+ "--liang-layer-1",
811
+ "--liang-layer-2",
812
+ "--liang-layer-3",
813
+ "--liang-sidebar",
814
+ "--liang-ink",
815
+ "--liang-secondary",
816
+ "--liang-tertiary",
817
+ "--liang-border",
818
+ "--liang-accent",
819
+ "--liang-accent-hover",
820
+ "--liang-hover",
821
+ "--liang-portrait-opacity"
822
+ ];
823
+ var SkinPresenter = class {
824
+ scope;
825
+ theme;
826
+ root;
827
+ portrait;
828
+ preloads;
829
+ portraitReady = false;
830
+ enabled = true;
831
+ // Default to the max frame so the first paint after load is the dark shell;
832
+ // starting at 0 flashed the light palette before the directory resolved.
833
+ frame = PREVIEW_MAX_FRAME;
834
+ pendingFrame = PREVIEW_MAX_FRAME;
835
+ raf = 0;
836
+ disposed = false;
837
+ unsubscribe;
838
+ constructor(scope, theme) {
839
+ this.scope = scope;
840
+ this.theme = theme;
841
+ this.root = document.createElement("div");
842
+ this.root.className = "liang-skin-backdrop";
843
+ this.root.dataset.plugin = PACKAGE_ID;
844
+ this.root.dataset.media = "sequence";
845
+ this.root.setAttribute("aria-hidden", "true");
846
+ this.portrait = document.createElement("img");
847
+ this.portrait.className = "liang-skin-sequence-frame";
848
+ this.portrait.alt = "";
849
+ this.portrait.draggable = false;
850
+ this.portrait.decoding = "async";
851
+ this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;
852
+ this.portrait.addEventListener("error", this.handleSequenceError);
853
+ this.preloads = PORTRAIT_ANCHORS.map(({ file }) => {
854
+ const image = new Image();
855
+ image.loading = "eager";
856
+ image.decoding = "async";
857
+ image.src = `${ASSET_PREFIX}/portrait-source-v2/${file}`;
858
+ return image;
859
+ });
860
+ void Promise.all(this.preloads.map((image) => image.decode())).then(
861
+ () => {
862
+ if (this.disposed) return;
863
+ this.portraitReady = true;
864
+ this.root.dataset.media = "sequence";
865
+ this.updatePortrait(paletteForFrame(this.frame).level);
866
+ },
867
+ () => {
868
+ }
869
+ );
870
+ this.root.append(this.portrait);
871
+ document.body.prepend(this.root);
872
+ this.unsubscribe = scope.subscribe(() => this.syncSettings());
873
+ this.syncSettings();
874
+ }
875
+ handleSequenceError = () => {
876
+ if (this.portrait.src.endsWith(FIRST_PORTRAIT_FILE)) {
877
+ this.root.dataset.media = "color";
878
+ return;
879
+ }
880
+ this.portraitReady = false;
881
+ this.portrait.src = `${ASSET_PREFIX}/${FIRST_PORTRAIT_FILE}`;
882
+ this.root.dataset.media = "sequence";
883
+ };
884
+ syncSettings() {
885
+ this.setEnabled(this.scope.getSnapshot().enabled);
886
+ }
887
+ isEnabled() {
888
+ return this.enabled;
889
+ }
890
+ getFrame() {
891
+ return this.frame;
892
+ }
893
+ setEnabled(enabled) {
894
+ this.enabled = enabled;
895
+ if (enabled) {
896
+ if (!this.root.isConnected) document.body.prepend(this.root);
897
+ document.body.dataset.liangSkin = "on";
898
+ this.applyFrame();
899
+ } else {
900
+ this.root.remove();
901
+ delete document.body.dataset.liangSkin;
902
+ delete document.body.dataset.liangStage;
903
+ for (const name of cssVariables) document.body.style.removeProperty(name);
904
+ }
905
+ }
906
+ setFrame(frame) {
907
+ this.pendingFrame = Math.min(PREVIEW_MAX_FRAME, Math.max(0, Math.round(frame)));
908
+ this.frame = this.pendingFrame;
909
+ if (!this.enabled) return;
910
+ if (this.raf !== 0) return;
911
+ this.raf = requestAnimationFrame(() => {
912
+ this.raf = 0;
913
+ this.frame = this.pendingFrame;
914
+ this.applyFrame();
915
+ });
916
+ }
917
+ applyFrame() {
918
+ const palette = paletteForFrame(this.frame);
919
+ const body = document.body;
920
+ this.syncNativeTheme(palette.stage === 5 ? "dark" : "light");
921
+ body.dataset.liangStage = String(palette.stage);
922
+ body.style.setProperty("--liang-strength", String(palette.strength));
923
+ body.style.setProperty("--liang-page", palette.page);
924
+ body.style.setProperty("--liang-bg-base", palette.base);
925
+ body.style.setProperty("--liang-layer-1", palette.layer1);
926
+ body.style.setProperty("--liang-layer-2", palette.layer2);
927
+ body.style.setProperty("--liang-layer-3", palette.layer3);
928
+ body.style.setProperty("--liang-sidebar", palette.sidebar);
929
+ body.style.setProperty("--liang-ink", palette.ink);
930
+ body.style.setProperty("--liang-secondary", palette.secondary);
931
+ body.style.setProperty("--liang-tertiary", palette.tertiary);
932
+ body.style.setProperty("--liang-border", palette.border);
933
+ body.style.setProperty("--liang-accent", palette.accent);
934
+ body.style.setProperty("--liang-accent-hover", palette.accentHover);
935
+ body.style.setProperty("--liang-hover", palette.hover);
936
+ body.style.setProperty("--liang-portrait-opacity", palette.portraitOpacity);
937
+ this.updatePortrait(palette.level);
938
+ }
939
+ syncNativeTheme(theme = paletteForFrame(this.frame).stage === 5 ? "dark" : "light") {
940
+ if (!this.enabled || this.theme.getTheme().preference === theme) return;
941
+ this.theme.setTheme(theme);
942
+ }
943
+ updatePortrait(level) {
944
+ if (!this.portraitReady) return;
945
+ const { lowerIndex, upperIndex, mix: mix2 } = portraitBlendForLevel(
946
+ level,
947
+ ANCHOR_LEVELS
948
+ );
949
+ const lower = PORTRAIT_ANCHORS[lowerIndex];
950
+ const upper = PORTRAIT_ANCHORS[upperIndex];
951
+ const selected = mix2 >= 0.5 ? upper : lower;
952
+ const source = `${ASSET_PREFIX}/portrait-source-v2/${selected.file}`;
953
+ if (this.portrait.getAttribute("src") !== source) this.portrait.src = source;
954
+ }
955
+ async choose(enabled) {
956
+ this.setEnabled(enabled);
957
+ try {
958
+ await this.scope.set(enabled);
959
+ } catch (error) {
960
+ this.syncSettings();
961
+ throw error;
962
+ }
963
+ }
964
+ dispose() {
965
+ if (this.disposed) return;
966
+ this.disposed = true;
967
+ this.unsubscribe();
968
+ if (this.raf !== 0) cancelAnimationFrame(this.raf);
969
+ this.portrait.removeEventListener("error", this.handleSequenceError);
970
+ for (const image of this.preloads) image.src = "";
971
+ this.root.remove();
972
+ document.body.removeAttribute("data-liang-skin");
973
+ delete document.body.dataset.liangStage;
974
+ for (const name of cssVariables) document.body.style.removeProperty(name);
975
+ }
976
+ };
977
+ function modelReasoning(state) {
978
+ const current = state.current;
979
+ if (current === null) return null;
980
+ const group = state.groups.find((item) => item.id === current.provider);
981
+ const model = group?.models.find((item) => item.id === current.model);
982
+ if (model?.reasoning === void 0) return null;
983
+ return {
984
+ selection: current,
985
+ efforts: model.reasoning.efforts,
986
+ defaultEffort: model.reasoning.defaultEffort
987
+ };
988
+ }
989
+ function LiangEffortSlider({ directory, load, select, presenter, scope }) {
990
+ const state = (0, import_react.useSyncExternalStore)(
991
+ (listener) => directory.subscribe(listener),
992
+ () => directory.getSnapshot()
993
+ );
994
+ const skin = (0, import_react.useSyncExternalStore)(
995
+ (listener) => scope.subscribe(listener),
996
+ () => scope.getSnapshot()
997
+ );
998
+ const reasoning = (0, import_react.useMemo)(() => modelReasoning(state), [state]);
999
+ const efforts = reasoning?.efforts ?? [];
1000
+ const committedIndex = selectedEffortIndex(
1001
+ efforts,
1002
+ reasoning?.selection.reasoningEffort,
1003
+ reasoning?.defaultEffort
1004
+ );
1005
+ const committedFrame = committedIndex < 0 ? PREVIEW_MAX_FRAME : frameForEffort(committedIndex, efforts.length);
1006
+ const bindEffort = skin.bindEffort;
1007
+ const [frame, setFrame] = (0, import_react.useState)(() => bindEffort ? committedFrame : presenter.getFrame());
1008
+ const [pending, setPending] = (0, import_react.useState)(false);
1009
+ const [failed, setFailed] = (0, import_react.useState)(false);
1010
+ const [interacting, setInteracting] = (0, import_react.useState)(false);
1011
+ const dragging = (0, import_react.useRef)(false);
1012
+ const dragStartFrame = (0, import_react.useRef)(frame);
1013
+ const enabled = skin.enabled;
1014
+ (0, import_react.useEffect)(() => {
1015
+ if (enabled) load();
1016
+ }, [enabled, load]);
1017
+ (0, import_react.useEffect)(() => {
1018
+ if (!bindEffort || dragging.current || pending) return;
1019
+ setFrame(committedFrame);
1020
+ presenter.setFrame(committedFrame);
1021
+ }, [bindEffort, committedFrame, pending, presenter]);
1022
+ if (!enabled) return null;
1023
+ if (bindEffort && (reasoning === null || efforts.length < 2)) return null;
1024
+ const previewIndex = nearestEffortIndex(frame, efforts);
1025
+ const previewEffort = efforts[previewIndex];
1026
+ const progressRatio = frame / PREVIEW_MAX_FRAME;
1027
+ const tooltipLabel = indicatorLabel(frame, bindEffort ? efforts : []);
1028
+ const commit = async (rawFrame) => {
1029
+ if (!bindEffort) {
1030
+ dragging.current = false;
1031
+ setFrame(rawFrame);
1032
+ presenter.setFrame(rawFrame);
1033
+ return;
1034
+ }
1035
+ const targetIndex = nearestEffortIndex(rawFrame, efforts);
1036
+ const target = efforts[targetIndex];
1037
+ if (target === void 0) return;
1038
+ const targetFrame = frameForEffort(targetIndex, efforts.length);
1039
+ dragging.current = false;
1040
+ setFrame(targetFrame);
1041
+ presenter.setFrame(targetFrame);
1042
+ if (targetIndex === committedIndex || pending) return;
1043
+ setPending(true);
1044
+ setFailed(false);
1045
+ const accepted = await select({
1046
+ provider: reasoning.selection.provider,
1047
+ model: reasoning.selection.model,
1048
+ reasoningEffort: target.id
1049
+ });
1050
+ setPending(false);
1051
+ if (!accepted) {
1052
+ setFailed(true);
1053
+ setFrame(committedFrame);
1054
+ presenter.setFrame(committedFrame);
1055
+ }
1056
+ };
1057
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1058
+ "div",
1059
+ {
1060
+ className: "liang-effort-control",
1061
+ "data-plugin": PACKAGE_ID,
1062
+ "data-state": failed ? "error" : pending ? "pending" : "ready",
1063
+ title: bindEffort ? previewEffort?.name : void 0,
1064
+ children: [
1065
+ interacting && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1066
+ "output",
1067
+ {
1068
+ className: "liang-effort-control__tooltip",
1069
+ style: { "--liang-slider-ratio": progressRatio },
1070
+ children: tooltipLabel
1071
+ }
1072
+ ),
1073
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "liang-effort-control__ticks", "aria-hidden": "true", children: efforts.map((effort, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1074
+ "i",
1075
+ {
1076
+ className: "liang-effort-control__tick",
1077
+ style: { left: `${frameForEffort(index, efforts.length) / PREVIEW_MAX_FRAME * 100}%` }
1078
+ },
1079
+ effort.id
1080
+ )) }),
1081
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1082
+ "input",
1083
+ {
1084
+ className: "liang-effort-control__range",
1085
+ type: "range",
1086
+ min: 0,
1087
+ max: PREVIEW_MAX_FRAME,
1088
+ step: 1,
1089
+ value: frame,
1090
+ disabled: pending || state.status === "selecting",
1091
+ "aria-label": bindEffort ? "\u601D\u8003\u7B49\u7EA7" : "\u76AE\u80A4\u8FDB\u5EA6",
1092
+ "aria-valuetext": bindEffort ? previewEffort?.name ?? "" : tooltipLabel,
1093
+ onPointerDown: () => {
1094
+ dragging.current = true;
1095
+ dragStartFrame.current = frame;
1096
+ setInteracting(true);
1097
+ },
1098
+ onInput: (event) => {
1099
+ dragging.current = true;
1100
+ const next = Number(event.currentTarget.value);
1101
+ setFrame(next);
1102
+ presenter.setFrame(next);
1103
+ },
1104
+ onPointerUp: (event) => {
1105
+ setInteracting(false);
1106
+ void commit(Number(event.currentTarget.value));
1107
+ },
1108
+ onPointerCancel: () => {
1109
+ setInteracting(false);
1110
+ dragging.current = false;
1111
+ setFrame(dragStartFrame.current);
1112
+ presenter.setFrame(dragStartFrame.current);
1113
+ },
1114
+ onKeyUp: (event) => {
1115
+ setInteracting(false);
1116
+ if (event.key !== "Escape") void commit(Number(event.currentTarget.value));
1117
+ },
1118
+ onBlur: (event) => {
1119
+ setInteracting(false);
1120
+ if (dragging.current) void commit(Number(event.currentTarget.value));
1121
+ },
1122
+ onKeyDown: (event) => {
1123
+ setInteracting(true);
1124
+ if (event.key === "Escape" && !pending) {
1125
+ setInteracting(false);
1126
+ dragging.current = false;
1127
+ setFrame(dragStartFrame.current);
1128
+ presenter.setFrame(dragStartFrame.current);
1129
+ }
1130
+ }
1131
+ }
1132
+ )
1133
+ ]
1134
+ }
1135
+ );
1136
+ }
1137
+ var NATIVE_APPEARANCE_GROUP = '[class*="_8HJdBW_group"]';
1138
+ var NATIVE_APPEARANCE_ROW = '[class*="_8HJdBW_cubeRow"]';
1139
+ var LIANG_APPEARANCE_BUTTON = "liang-appearance-choice";
1140
+ var LIANG_BINDING_CONTROL = "liang-appearance-binding";
1141
+ var LIANG_BINDING_INPUT = "liang-appearance-binding__input";
1142
+ function installLiangAppearanceButton(scope, presenter) {
1143
+ let pending = false;
1144
+ const hookedNativeButtons = /* @__PURE__ */ new Set();
1145
+ const nativeClickHandlers = /* @__PURE__ */ new Map();
1146
+ const sync = () => {
1147
+ const group = [...document.querySelectorAll(NATIVE_APPEARANCE_GROUP)].find((node) => node.querySelector('[class*="_8HJdBW_themeCube"]'));
1148
+ const row = group?.querySelector(NATIVE_APPEARANCE_ROW);
1149
+ if (row === void 0 || row === null) return;
1150
+ let customButton = row.querySelector(`.${LIANG_APPEARANCE_BUTTON}`);
1151
+ if (customButton === null) {
1152
+ customButton = document.createElement("button");
1153
+ customButton.className = LIANG_APPEARANCE_BUTTON;
1154
+ customButton.type = "button";
1155
+ customButton.dataset.plugin = PACKAGE_ID;
1156
+ customButton.setAttribute("aria-label", "\u6ED1\u52A8\u53D8\u7956");
1157
+ const icon = document.createElement("span");
1158
+ icon.className = "liang-appearance-choice__icon";
1159
+ icon.setAttribute("aria-hidden", "true");
1160
+ icon.textContent = "\u25C8";
1161
+ const label = document.createElement("span");
1162
+ label.className = "liang-appearance-choice__label";
1163
+ label.textContent = document.documentElement.lang.toLowerCase().startsWith("en") ? "Slider" : "\u6ED1\u52A8\u53D8\u7956";
1164
+ customButton.append(icon, label);
1165
+ customButton.addEventListener("click", () => {
1166
+ if (pending || scope.getSnapshot().enabled) return;
1167
+ pending = true;
1168
+ sync();
1169
+ void presenter.choose(true).finally(() => {
1170
+ pending = false;
1171
+ sync();
1172
+ });
1173
+ });
1174
+ }
1175
+ if (customButton.parentElement !== row) row.append(customButton);
1176
+ const snapshot = scope.getSnapshot();
1177
+ customButton.disabled = pending;
1178
+ customButton.setAttribute("aria-pressed", String(snapshot.enabled));
1179
+ let bindingControl = group.querySelector(`.${LIANG_BINDING_CONTROL}`);
1180
+ if (!snapshot.enabled) {
1181
+ bindingControl?.remove();
1182
+ bindingControl = null;
1183
+ } else if (bindingControl === null) {
1184
+ bindingControl = document.createElement("label");
1185
+ bindingControl.className = LIANG_BINDING_CONTROL;
1186
+ bindingControl.dataset.plugin = PACKAGE_ID;
1187
+ const bindingCopy = document.createElement("span");
1188
+ bindingCopy.className = "liang-appearance-binding__copy";
1189
+ const bindingLabel = document.createElement("span");
1190
+ bindingLabel.className = "liang-appearance-binding__label";
1191
+ const bindingText = document.documentElement.lang.toLowerCase().startsWith("en") ? "Bind slider to reasoning level" : "\u6ED1\u52A8\u53D8\u7956\u7ED1\u5B9A\u601D\u8003\u7B49\u7EA7";
1192
+ bindingLabel.textContent = bindingText;
1193
+ const bindingDescription = document.createElement("span");
1194
+ bindingDescription.className = "liang-appearance-binding__description";
1195
+ bindingDescription.id = "liang-appearance-binding-description";
1196
+ bindingDescription.textContent = document.documentElement.lang.toLowerCase().startsWith("en") ? "When off, the slider does not change the reasoning level." : "\u5173\u95ED\u4E4B\u540E\u6ED1\u5757\u4E0D\u8054\u52A8\u601D\u8003\u7B49\u7EA7";
1197
+ bindingCopy.append(bindingLabel, bindingDescription);
1198
+ const bindingInput = document.createElement("input");
1199
+ bindingInput.className = LIANG_BINDING_INPUT;
1200
+ bindingInput.type = "checkbox";
1201
+ bindingInput.setAttribute("role", "switch");
1202
+ bindingInput.setAttribute("aria-label", bindingText);
1203
+ bindingInput.setAttribute("aria-describedby", bindingDescription.id);
1204
+ bindingInput.addEventListener("change", () => {
1205
+ void scope.setBindEffort(bindingInput.checked).catch(() => sync());
1206
+ });
1207
+ bindingControl.append(bindingCopy, bindingInput);
1208
+ group.append(bindingControl);
1209
+ }
1210
+ if (bindingControl !== null) {
1211
+ const bindingInput = bindingControl.querySelector(`.${LIANG_BINDING_INPUT}`);
1212
+ if (bindingInput !== null) {
1213
+ bindingInput.checked = snapshot.bindEffort;
1214
+ bindingInput.setAttribute("aria-checked", String(snapshot.bindEffort));
1215
+ bindingInput.disabled = pending;
1216
+ }
1217
+ }
1218
+ for (const nativeButton of row.querySelectorAll('[class*="_8HJdBW_themeCube"]')) {
1219
+ if (hookedNativeButtons.has(nativeButton)) continue;
1220
+ hookedNativeButtons.add(nativeButton);
1221
+ const handleNativeClick = () => {
1222
+ if (pending || !scope.getSnapshot().enabled) return;
1223
+ pending = true;
1224
+ sync();
1225
+ void presenter.choose(false).finally(() => {
1226
+ pending = false;
1227
+ sync();
1228
+ });
1229
+ };
1230
+ nativeClickHandlers.set(nativeButton, handleNativeClick);
1231
+ nativeButton.addEventListener("click", handleNativeClick, { capture: true });
1232
+ }
1233
+ };
1234
+ const observer = new MutationObserver(sync);
1235
+ observer.observe(document.body, { childList: true, subtree: true });
1236
+ const unsubscribe = scope.subscribe(sync);
1237
+ sync();
1238
+ return () => {
1239
+ observer.disconnect();
1240
+ unsubscribe();
1241
+ for (const [nativeButton, handleNativeClick] of nativeClickHandlers) {
1242
+ nativeButton.removeEventListener("click", handleNativeClick, { capture: true });
1243
+ }
1244
+ document.querySelectorAll(`.${LIANG_APPEARANCE_BUTTON}`).forEach((button) => button.remove());
1245
+ document.querySelectorAll(`.${LIANG_BINDING_CONTROL}`).forEach((control) => control.remove());
1246
+ };
1247
+ }
1248
+ var inject = [
1249
+ "slots",
1250
+ "sessions",
1251
+ "modelDirectories",
1252
+ "locale",
1253
+ "theme"
1254
+ ];
1255
+ function createPreferenceStore() {
1256
+ try {
1257
+ localStorage.removeItem("dsh-liang-intensity-skin.enabled");
1258
+ } catch {
1259
+ }
1260
+ let snapshot = {
1261
+ enabled: true,
1262
+ bindEffort: localStorage.getItem(BIND_EFFORT_KEY) !== "0"
1263
+ };
1264
+ const listeners = /* @__PURE__ */ new Set();
1265
+ const onStorage = (event) => {
1266
+ if (event.key !== BIND_EFFORT_KEY) return;
1267
+ const next = {
1268
+ enabled: snapshot.enabled,
1269
+ bindEffort: event.newValue !== "0"
1270
+ };
1271
+ if (next.enabled === snapshot.enabled && next.bindEffort === snapshot.bindEffort) return;
1272
+ snapshot = next;
1273
+ for (const listener of listeners) listener();
1274
+ };
1275
+ window.addEventListener("storage", onStorage);
1276
+ return {
1277
+ getSnapshot: () => snapshot,
1278
+ subscribe(listener) {
1279
+ listeners.add(listener);
1280
+ return () => listeners.delete(listener);
1281
+ },
1282
+ async set(enabled) {
1283
+ if (enabled === snapshot.enabled) return;
1284
+ snapshot = { ...snapshot, enabled };
1285
+ for (const listener of listeners) listener();
1286
+ },
1287
+ async setBindEffort(bindEffort) {
1288
+ if (bindEffort === snapshot.bindEffort) return;
1289
+ localStorage.setItem(BIND_EFFORT_KEY, bindEffort ? "1" : "0");
1290
+ snapshot = { ...snapshot, bindEffort };
1291
+ for (const listener of listeners) listener();
1292
+ },
1293
+ dispose() {
1294
+ window.removeEventListener("storage", onStorage);
1295
+ listeners.clear();
1296
+ }
1297
+ };
1298
+ }
1299
+ function apply(ctx) {
1300
+ const style = document.createElement("style");
1301
+ style.dataset.plugin = PACKAGE_ID;
1302
+ style.textContent = skin_default;
1303
+ document.head.append(style);
1304
+ ctx.effect(() => () => style.remove(), "liang-intensity-skin: scoped styles");
1305
+ const scope = createPreferenceStore();
1306
+ ctx.effect(() => () => scope.dispose(), "liang-intensity-skin: appearance preference");
1307
+ const theme = ctx.get("theme");
1308
+ const presenter = new SkinPresenter(scope, theme);
1309
+ ctx.effect(() => () => presenter.dispose(), "liang-intensity-skin: backdrop presenter");
1310
+ ctx.effect(
1311
+ () => installLiangAppearanceButton(scope, presenter),
1312
+ "liang-intensity-skin: native appearance extension"
1313
+ );
1314
+ ctx.effect(
1315
+ () => ctx.locale.register(LOCALE_NAMESPACE, {
1316
+ zh: {
1317
+ "appearance.title": "\u5916\u89C2",
1318
+ "appearance.light": "\u6D45\u8272",
1319
+ "appearance.dark": "\u6DF1\u8272",
1320
+ "appearance.system": "\u8DDF\u968F\u7CFB\u7EDF",
1321
+ "appearance.liang": "\u6ED1\u52A8\u53D8\u7956"
1322
+ },
1323
+ en: {
1324
+ "appearance.title": "Appearance",
1325
+ "appearance.light": "Light",
1326
+ "appearance.dark": "Dark",
1327
+ "appearance.system": "System",
1328
+ "appearance.liang": "Slider"
1329
+ }
1330
+ }),
1331
+ "liang-intensity-skin: settings locale"
1332
+ );
1333
+ ctx.slots.inject("conversation.input.right", () => ctx.slots.register({
1334
+ name: "conversation.input.right",
1335
+ id: "liang-intensity-control",
1336
+ order: 10,
1337
+ inject: (sessionId) => {
1338
+ const available = ctx.sessions.subagentAddress(sessionId) === void 0;
1339
+ const directory = ctx.modelDirectories.directoryFor(sessionId);
1340
+ return {
1341
+ directory: directory.store,
1342
+ presenter,
1343
+ scope,
1344
+ load: () => {
1345
+ if (available) void directory.load().catch(() => void 0);
1346
+ },
1347
+ select: (selection) => available ? directory.select(selection).then((result) => result.ok, () => false) : Promise.resolve(false)
1348
+ };
1349
+ }
1350
+ }, LiangEffortSlider));
1351
+ }
1352
+ return module.exports;}});
1353
+ //# sourceMappingURL=client.js.map