deepseek-harness-background 0.5.6 → 0.6.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 +7 -5
- package/README.zh.md +7 -5
- package/icon.svg +8 -0
- package/lib/client.js +485 -52
- package/lib/client.js.map +1 -1
- package/lib/index.js +16 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +12 -8
package/lib/client.js
CHANGED
|
@@ -104,6 +104,11 @@ window.__ModuleLoader__.load({
|
|
|
104
104
|
.dsh-bg-layer .dsh-bg-image {
|
|
105
105
|
width: 100%; height: 100%; display: block; border: 0; background: transparent;
|
|
106
106
|
object-fit: var(--bg-object-fit, cover);
|
|
107
|
+
/* Normalized crop framing: percent object-position is the position of the
|
|
108
|
+
image inside its own overflow, so one stored 0..1 value holds for every
|
|
109
|
+
window size and every source. Both axes are always written; the axis
|
|
110
|
+
with no overflow simply ignores its value. */
|
|
111
|
+
object-position: calc(var(--bg-offset-x, 0.5) * 100%) calc(var(--bg-offset-y, 0.5) * 100%);
|
|
107
112
|
opacity: var(--bg-opacity, 1);
|
|
108
113
|
filter: blur(var(--bg-wallpaper-blur, 0px));
|
|
109
114
|
/* Blur thins the edges; scale the image up to hide the fringe. */
|
|
@@ -120,6 +125,30 @@ window.__ModuleLoader__.load({
|
|
|
120
125
|
body[data-ds-dark-theme] .dsh-bg-scrim {
|
|
121
126
|
background: rgba(0, 0, 0, var(--bg-scrim, 0.25));
|
|
122
127
|
}
|
|
128
|
+
/* Desktop window drag: the shell marks a chrome row \`data-window-drag\` and
|
|
129
|
+
one rule subtracts every other body-level box
|
|
130
|
+
(\`html[data-platform='darwin'] body > :not(#root) { -webkit-app-region:
|
|
131
|
+
no-drag; }\`, ui-web base.css). Chromium collects app-region boxes by
|
|
132
|
+
geometry in DOM order and the LAST box containing a point decides, so
|
|
133
|
+
these two decorative layers — body children that follow #root — would
|
|
134
|
+
swallow the drag surface of the whole window (traffic-light strip,
|
|
135
|
+
conversation header, dock strip, and on Windows the caption strip that
|
|
136
|
+
owns drag and double-click maximize). They never take the pointer, so they
|
|
137
|
+
must not join the composition at all.
|
|
138
|
+
|
|
139
|
+
The value that achieves that is \`initial\`, NOT \`none\`: Chromium maps the
|
|
140
|
+
\`none\` keyword onto \`no-drag\`, so a \`-webkit-app-region: none\` layer IS
|
|
141
|
+
collected and DOES punch a hole exactly like \`no-drag\` does. Measured, not
|
|
142
|
+
assumed — getComputedStyle on the Windows 0.2.0-rc.2 desktop build returns
|
|
143
|
+
"no-drag" for it, and with these two full-viewport layers in that state the
|
|
144
|
+
whole window stopped dragging and double-click maximize stopped working;
|
|
145
|
+
\`initial\` is the one declaration that reads back as "none" and leaves the
|
|
146
|
+
composition. The shell rule carries #root's id specificity, so a plain
|
|
147
|
+
declaration cannot outrank it — this needs \`!important\`. */
|
|
148
|
+
body > .dsh-bg-layer,
|
|
149
|
+
body > .dsh-bg-scrim {
|
|
150
|
+
-webkit-app-region: initial !important;
|
|
151
|
+
}
|
|
123
152
|
|
|
124
153
|
/* Active: make the app frame + sidebar background transparent so all columns
|
|
125
154
|
share the same wallpaper + scrim backdrop. */
|
|
@@ -136,7 +165,6 @@ window.__ModuleLoader__.load({
|
|
|
136
165
|
light glass slightly DIMS, dark glass keeps a slight lift. Gated on the
|
|
137
166
|
GLASS ATTR (wallpaper active AND panelOpacity < 1): maxing the panel
|
|
138
167
|
slider returns these surfaces to the exact official paints. */
|
|
139
|
-
body[data-dsh-bg-glass] [data-composer-card],
|
|
140
168
|
body[data-dsh-bg-glass] [class*="_bubble"]:not([role="tooltip"]),
|
|
141
169
|
/* The read_image toolview (dsh >= 0.1.2-rc.1 ToolRow) collapses its result
|
|
142
170
|
into an image body card; glass it like the other content blocks. */
|
|
@@ -160,6 +188,37 @@ window.__ModuleLoader__.load({
|
|
|
160
188
|
0 12px 40px rgba(0, 0, 0, 0.12);
|
|
161
189
|
}
|
|
162
190
|
|
|
191
|
+
/* ---- Composer card: the filter rides a pseudo-element ------------------
|
|
192
|
+
Chromium makes every element that carries a backdrop-filter a Backdrop
|
|
193
|
+
Root, and a filter inside one can only sample what that element itself
|
|
194
|
+
paints. The composer hosts the picker menu as an absolutely positioned
|
|
195
|
+
child ([data-composer-card] > … conversation.input.overlay), so with the
|
|
196
|
+
filter on the card itself that menu sampled the card's own paint only and
|
|
197
|
+
read as flat transparency over the wallpaper. Moving the filter to a
|
|
198
|
+
positioned ::before breaks the root — the pseudo-element is not an
|
|
199
|
+
ancestor of the menu, so the menu blurs the wallpaper again. The card
|
|
200
|
+
keeps its own frost (the ::before supplies it) and needs no layout change:
|
|
201
|
+
ui-conversation already declares it position: relative as the overlay
|
|
202
|
+
anchor context. */
|
|
203
|
+
body[data-dsh-bg-glass] [data-composer-card] {
|
|
204
|
+
background-color: var(--dsw-specific-input-major);
|
|
205
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
206
|
+
box-shadow:
|
|
207
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.32),
|
|
208
|
+
inset 0 -1px 0 rgba(255, 255, 255, 0.08),
|
|
209
|
+
inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),
|
|
210
|
+
0 12px 40px rgba(0, 0, 0, 0.12);
|
|
211
|
+
}
|
|
212
|
+
body[data-dsh-bg-glass] [data-composer-card]::before {
|
|
213
|
+
content: '';
|
|
214
|
+
position: absolute;
|
|
215
|
+
inset: 0;
|
|
216
|
+
z-index: -1;
|
|
217
|
+
border-radius: inherit;
|
|
218
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
219
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
220
|
+
}
|
|
221
|
+
|
|
163
222
|
/* The sticky code-block header officially occludes scrolled code with
|
|
164
223
|
bg-base (transparent under a wallpaper): refill it with the banner token
|
|
165
224
|
(itself translucent glass) so code stays hidden beneath the sticky bar. */
|
|
@@ -308,6 +367,78 @@ window.__ModuleLoader__.load({
|
|
|
308
367
|
box-shadow: var(--dsw-elevation-panel, 0 4px 14px rgba(0, 0, 0, 0.08));
|
|
309
368
|
}
|
|
310
369
|
|
|
370
|
+
/* The card's header paints the official opaque fill (--changes-fill is a
|
|
371
|
+
static neutral), so the glass card underneath never shows through: hand
|
|
372
|
+
that one surface back to the card by clearing its fill, and give the
|
|
373
|
+
header's own hover/focus feedback the translucent interactive token the
|
|
374
|
+
card's rows already use. The anchor is the header ELEMENT, not the card's
|
|
375
|
+
first child: a single-file turn renders that same header through the
|
|
376
|
+
HoverCard primitive, which wraps its anchor in a span (ui-primitives
|
|
377
|
+
HoverCard.tsx), so a child-position anchor reached only that wrapper and
|
|
378
|
+
left the real header's fill in place — the whole card stayed opaque. */
|
|
379
|
+
body[data-dsh-bg-glass] [data-changed-files] button[class*="_header"] {
|
|
380
|
+
background-color: transparent;
|
|
381
|
+
}
|
|
382
|
+
body[data-dsh-bg-glass] [data-changed-files] button[class*="_header"]:hover:not(:disabled),
|
|
383
|
+
body[data-dsh-bg-glass] [data-changed-files] button[class*="_header"]:focus-visible {
|
|
384
|
+
background-color: var(--dsw-alias-interactive-bg-hover);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/* ---- Delivered file cards ([data-presented-file]) ---------------------
|
|
388
|
+
The deliverable grid's file card paints --deliverable-fill, a static
|
|
389
|
+
neutral (--dsw-static-neutral-50, or 850 in dark) that no overridden token
|
|
390
|
+
reaches, so it stayed fully opaque over every wallpaper. It takes the same
|
|
391
|
+
explicit-fill recipe as the changed-files card, plus its own hover state:
|
|
392
|
+
the module's .file:hover repaints the fill with --deliverable-hover, the
|
|
393
|
+
other static neutral. This rule outranks it (two attributes + body against
|
|
394
|
+
one class + pseudo-class), so the fill and the sheen both survive hover.
|
|
395
|
+
The card's inner tile and icon already paint with translucent color-mix
|
|
396
|
+
fills and need nothing here. */
|
|
397
|
+
body[data-dsh-bg-glass] [data-presented-file] {
|
|
398
|
+
background-color: var(--dsw-specific-input-major);
|
|
399
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
400
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
401
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
402
|
+
box-shadow:
|
|
403
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.32),
|
|
404
|
+
inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),
|
|
405
|
+
0 4px 14px rgba(0, 0, 0, 0.08);
|
|
406
|
+
}
|
|
407
|
+
body[data-dsh-bg-glass] [data-presented-file]:hover {
|
|
408
|
+
background-color: color-mix(in srgb, rgb(255 255 255) calc(var(--bg-glass-alpha-strong, 0.8) * 100%), transparent);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* ---- Docked stat dialogs (turn time, session stats, token usage) -------
|
|
412
|
+
These portal to document.body, so unlike the picker menu above they do
|
|
413
|
+
reach the wallpaper; their official menu skin is a 40px blur under a flat
|
|
414
|
+
58% fill, which on a soft wallpaper still reads as plain transparency. The
|
|
415
|
+
official fill and its readable contrast stay, and the shared sheen +
|
|
416
|
+
exposure chain joins them to the same glass family as every other panel —
|
|
417
|
+
including the user's blur slider (--bg-glass-blur). Anchors are the
|
|
418
|
+
panels' own detail lists: class hashes are never structural hooks. */
|
|
419
|
+
body[data-dsh-bg-glass] [role="dialog"]:has([data-turn-usage-details]),
|
|
420
|
+
body[data-dsh-bg-glass] [role="dialog"]:has([data-session-stats-details]),
|
|
421
|
+
body[data-dsh-bg-glass] [role="dialog"]:has([data-session-stats-usage]) {
|
|
422
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
423
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
424
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ---- Sidebar bonus notice (the account notice card) -------------------
|
|
428
|
+
The account notice portals an aside straight onto document.body and paints
|
|
429
|
+
--dsw-specific-input-major — a token the painter DOES turn translucent —
|
|
430
|
+
but its own module adds no backdrop-filter, so over a wallpaper it reads as
|
|
431
|
+
flat transparency instead of frosted glass. Same shape as the dock family
|
|
432
|
+
above: token fill + the shared sheen and exposure chain. The anchor is that
|
|
433
|
+
aside with its own role="status" child (the notice copy); the host ships no
|
|
434
|
+
data attribute for the card, and the direct-child step keeps the rule on
|
|
435
|
+
the portaled body child rather than any nested status region. */
|
|
436
|
+
body[data-dsh-bg-glass] > aside:has(> [role="status"]) {
|
|
437
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
438
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
439
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
440
|
+
}
|
|
441
|
+
|
|
311
442
|
/* ---- Official turn rail (dsh >= 0.1.2, TurnNavigator) -----------------
|
|
312
443
|
The enhance mode borrows the kernel's rail untouched, so its hover
|
|
313
444
|
preview card keeps the OFFICIAL opaque fill (bg-layer-1, not mediated
|
|
@@ -330,6 +461,106 @@ window.__ModuleLoader__.load({
|
|
|
330
461
|
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
331
462
|
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
332
463
|
}
|
|
464
|
+
|
|
465
|
+
/* ---- Transcript tool cards the whitelist missed -----------------------
|
|
466
|
+
Three tool-row surfaces still painted an opaque ground over a wallpaper.
|
|
467
|
+
Two of them carry a fill no overridden token reaches: the present tool's
|
|
468
|
+
result box paints --dsw-alias-bg-layer-1 (the token the painter keeps
|
|
469
|
+
opaque on purpose, because it backs the settings UI and the dialogs), and
|
|
470
|
+
the schedule_create card reuses the delivery card's static neutral
|
|
471
|
+
(--card-fill = --dsw-static-neutral-50 / 850 — its own module header says
|
|
472
|
+
the box is the delivery card). Both need an explicit fill on top of
|
|
473
|
+
the shared sheen chain, and the schedule card's own hover repaints from the
|
|
474
|
+
other static neutral, so the glass fill has to be restated there.
|
|
475
|
+
|
|
476
|
+
The turn-trigger card is the odd one out: 0.2.0-rc.2 split its fill per
|
|
477
|
+
scheme (--dsw-alias-turn-trigger-bg, set to the painter's
|
|
478
|
+
--dsw-alias-markdown-code-block in light but to an untouched
|
|
479
|
+
--dsw-alias-interactive-bg-hover in dark), which left the very same card
|
|
480
|
+
translucent in light and fully opaque in dark. One explicit fill — the
|
|
481
|
+
painter's composer token, the same one every other glass surface uses —
|
|
482
|
+
ends that split, for the resting and the hover state alike.
|
|
483
|
+
|
|
484
|
+
Anchors are the rows' own data-tool / data-turn-trigger marks; class hashes
|
|
485
|
+
never are. */
|
|
486
|
+
body[data-dsh-bg-glass] [data-tool="present"] pre,
|
|
487
|
+
body[data-dsh-bg-glass] [data-tool="schedule_create"],
|
|
488
|
+
body[data-dsh-bg-glass] [data-turn-trigger] {
|
|
489
|
+
background-color: var(--dsw-specific-input-major);
|
|
490
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
491
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
492
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
493
|
+
box-shadow:
|
|
494
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.32),
|
|
495
|
+
inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),
|
|
496
|
+
0 4px 14px rgba(0, 0, 0, 0.08);
|
|
497
|
+
}
|
|
498
|
+
body[data-dsh-bg-glass] [data-tool="schedule_create"]:hover,
|
|
499
|
+
body[data-dsh-bg-glass] [data-turn-trigger]:hover {
|
|
500
|
+
background-color: color-mix(in srgb, rgb(255 255 255) calc(var(--bg-glass-alpha-strong, 0.8) * 100%), transparent);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/* ---- Platform overlay return bar (Account settings -> usage / top-up) --
|
|
504
|
+
The isolated native Platform view paints its whole surface with
|
|
505
|
+
--dsw-alias-bg-base, the very token the painter sets to transparent while a
|
|
506
|
+
wallpaper is active, so the 48px return bar went see-through even though
|
|
507
|
+
the native child below it is opaque. dsh itself calls this surface the
|
|
508
|
+
opaque native Platform page (ui-chat README), so the ground comes back
|
|
509
|
+
here, from the two literals --dsw-alias-bg-base is defined with in
|
|
510
|
+
ui-theme, one per scheme. The anchor is the overlay's own aria-modal dialog
|
|
511
|
+
with the Platform return bar as a direct child: no other dialog carries
|
|
512
|
+
data-window-drag. Gated on data-dsh-bg (a wallpaper is active), NOT on the
|
|
513
|
+
glass gate — a fully opaque panel setting must not hand this surface back
|
|
514
|
+
to transparency. */
|
|
515
|
+
body[data-dsh-bg] [role="dialog"][aria-modal="true"]:has(> header[data-window-drag]) {
|
|
516
|
+
background-color: var(--dsw-static-neutral-bluish-00);
|
|
517
|
+
}
|
|
518
|
+
body[data-ds-dark-theme][data-dsh-bg] [role="dialog"][aria-modal="true"]:has(> header[data-window-drag]) {
|
|
519
|
+
background-color: var(--dsw-static-neutral-bluish-950);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* ---- Other surfaces that lean on the base token for their ground ------
|
|
523
|
+
The same mechanism as the Platform overlay above, in three more places.
|
|
524
|
+
dsh paints each of these with --dsw-alias-bg-base and leans on that fill:
|
|
525
|
+
- a Reasoning row's pinned disclosure header masks the thinking prose
|
|
526
|
+
scrolling under it (the sheet's own selector is
|
|
527
|
+
.root[data-expanded] [data-open] [data-disclosure-row]);
|
|
528
|
+
- the compaction marker's pinned toggle masks the summary prose under it
|
|
529
|
+
(its sheet says so out loud: the fill is what masks the prose);
|
|
530
|
+
- the inspect buttons of the tool rows and of the skill row are quiet
|
|
531
|
+
in-flow affordances that deliberately take the base ground instead of
|
|
532
|
+
the heavier overlay token.
|
|
533
|
+
With the base token transparent they lose that ground and the prose they
|
|
534
|
+
are supposed to mask shows through. The literals below are the token's own
|
|
535
|
+
two definitions, one per scheme; the anchors are ReasoningRow's own
|
|
536
|
+
data-variant mark, the compaction icon the marker ships, and the class
|
|
537
|
+
suffix those inspect buttons share across three packages. */
|
|
538
|
+
body[data-dsh-bg] [data-variant="think"][data-expanded] [data-open] [data-disclosure-row],
|
|
539
|
+
body[data-dsh-bg] [class*="_compactionButton"]:has([data-compaction-icon="context"]),
|
|
540
|
+
body[data-dsh-bg] [class*="_inspectButton"] {
|
|
541
|
+
background-color: var(--dsw-static-neutral-bluish-00);
|
|
542
|
+
}
|
|
543
|
+
body[data-ds-dark-theme][data-dsh-bg] [data-variant="think"][data-expanded] [data-open] [data-disclosure-row],
|
|
544
|
+
body[data-ds-dark-theme][data-dsh-bg] [class*="_compactionButton"]:has([data-compaction-icon="context"]),
|
|
545
|
+
body[data-ds-dark-theme][data-dsh-bg] [class*="_inspectButton"] {
|
|
546
|
+
background-color: var(--dsw-static-neutral-bluish-950);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/* ---- The ask-user transcript card -------------------------------------
|
|
550
|
+
A message-flow card like the changed-files one, but its ground is
|
|
551
|
+
--dsw-alias-bg-base rather than an opaque-token family the painter never
|
|
552
|
+
overrides — so with the base transparent the card had no ground at all and
|
|
553
|
+
its question/answer text sat straight on the wallpaper. It takes the
|
|
554
|
+
shared frosted recipe. The anchor is the tool row's own mark plus the card
|
|
555
|
+
class, because the card element itself carries no data attribute; the
|
|
556
|
+
class is matched by SUFFIX, so a sibling class such as _cardBody can never
|
|
557
|
+
be swept in. */
|
|
558
|
+
body[data-dsh-bg-glass] [data-tool="ask_user_question"] [class$="_card"] {
|
|
559
|
+
background-color: var(--dsw-specific-input-major);
|
|
560
|
+
background-image: linear-gradient(180deg, rgba(255, 255, 255, var(--bg-glass-sheen, 0.07)), rgba(255, 255, 255, var(--bg-glass-sheen-mid, 0.02)) 38%, rgba(255, 255, 255, 0.01));
|
|
561
|
+
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
562
|
+
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
563
|
+
}
|
|
333
564
|
`;
|
|
334
565
|
/**
|
|
335
566
|
* Inject the backdrop stylesheet once. Safe to call repeatedly; a second call
|
|
@@ -355,6 +586,8 @@ window.__ModuleLoader__.load({
|
|
|
355
586
|
const DEFAULT_FIT = "cover";
|
|
356
587
|
/** Image positioning modes. `cover` fills the frame (cropping as needed); `contain` fits the whole image inside the frame (letterboxing). */
|
|
357
588
|
const FIT_MODES = ["cover", "contain"];
|
|
589
|
+
/** Default framing offset — the image sits centered on both axes. */
|
|
590
|
+
const DEFAULT_OFFSET = .5;
|
|
358
591
|
//#endregion
|
|
359
592
|
//#region src/client/backdrop.ts
|
|
360
593
|
/**
|
|
@@ -559,6 +792,8 @@ window.__ModuleLoader__.load({
|
|
|
559
792
|
this.hasSource = true;
|
|
560
793
|
document.body.style;
|
|
561
794
|
this.setVar("--bg-object-fit", settings.fit);
|
|
795
|
+
this.setVar("--bg-offset-x", String(settings.offsetX));
|
|
796
|
+
this.setVar("--bg-offset-y", String(settings.offsetY));
|
|
562
797
|
this.setVar("--bg-opacity", String(settings.opacity));
|
|
563
798
|
this.setVar("--bg-wallpaper-blur", `${settings.wallpaperBlur}px`);
|
|
564
799
|
this.setVar("--bg-wallpaper-scale", (1 + settings.wallpaperBlur * .006).toFixed(4));
|
|
@@ -626,7 +861,13 @@ window.__ModuleLoader__.load({
|
|
|
626
861
|
this.setVar("--bg-wallpaper-blur", `${value}px`);
|
|
627
862
|
this.setVar("--bg-wallpaper-scale", (1 + Number(value) * .006).toFixed(4));
|
|
628
863
|
break;
|
|
629
|
-
case "fit":
|
|
864
|
+
case "fit":
|
|
865
|
+
this.setVar("--bg-object-fit", String(value));
|
|
866
|
+
break;
|
|
867
|
+
case "offsetX":
|
|
868
|
+
this.setVar("--bg-offset-x", String(value));
|
|
869
|
+
break;
|
|
870
|
+
case "offsetY": this.setVar("--bg-offset-y", String(value));
|
|
630
871
|
}
|
|
631
872
|
}
|
|
632
873
|
/**
|
|
@@ -723,6 +964,8 @@ window.__ModuleLoader__.load({
|
|
|
723
964
|
"--bg-opacity",
|
|
724
965
|
"--bg-scrim",
|
|
725
966
|
"--bg-object-fit",
|
|
967
|
+
"--bg-offset-x",
|
|
968
|
+
"--bg-offset-y",
|
|
726
969
|
"--bg-wallpaper-blur",
|
|
727
970
|
"--bg-wallpaper-scale",
|
|
728
971
|
"--bg-glass-blur",
|
|
@@ -740,6 +983,8 @@ window.__ModuleLoader__.load({
|
|
|
740
983
|
function paintPreviewSurface(el, settings) {
|
|
741
984
|
const s = el.style;
|
|
742
985
|
s.setProperty("--bg-object-fit", settings.fit);
|
|
986
|
+
s.setProperty("--bg-offset-x", String(settings.offsetX));
|
|
987
|
+
s.setProperty("--bg-offset-y", String(settings.offsetY));
|
|
743
988
|
s.setProperty("--bg-opacity", String(settings.opacity));
|
|
744
989
|
s.setProperty("--bg-scrim", String(settings.scrim));
|
|
745
990
|
s.setProperty("--bg-wallpaper-blur", `${settings.wallpaperBlur}px`);
|
|
@@ -985,6 +1230,8 @@ window.__ModuleLoader__.load({
|
|
|
985
1230
|
"background.fit": "填充方式",
|
|
986
1231
|
"background.cover": "铺满",
|
|
987
1232
|
"background.contain": "完整",
|
|
1233
|
+
"background.previewPanHint": "拖动预览可调整图片位置,双击居中",
|
|
1234
|
+
"background.repositionReset": "重置位置",
|
|
988
1235
|
"background.clear": "清除背景",
|
|
989
1236
|
"background.uploadFailed": "上传失败,请重试",
|
|
990
1237
|
"background.saveFailed": "保存失败,请重试",
|
|
@@ -1016,6 +1263,8 @@ window.__ModuleLoader__.load({
|
|
|
1016
1263
|
"background.fit": "Fit",
|
|
1017
1264
|
"background.cover": "Cover",
|
|
1018
1265
|
"background.contain": "Contain",
|
|
1266
|
+
"background.previewPanHint": "Drag the preview to reposition the image; double-click to recenter",
|
|
1267
|
+
"background.repositionReset": "Reset position",
|
|
1019
1268
|
"background.clear": "Clear background",
|
|
1020
1269
|
"background.uploadFailed": "Upload failed, try again",
|
|
1021
1270
|
"background.saveFailed": "Save failed, try again",
|
|
@@ -1149,7 +1398,7 @@ window.__ModuleLoader__.load({
|
|
|
1149
1398
|
const settingsClient = new SettingsClient();
|
|
1150
1399
|
//#endregion
|
|
1151
1400
|
//#region \0dsh-css:D:\Project\deepseek-harness-background\src\client\SettingsRow.module.css.mjs
|
|
1152
|
-
const css = ".-ozqdq_row{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;padding:16px 0;display:flex}.-ozqdq_header{flex-direction:column;gap:4px;display:flex}.-ozqdq_titleRow{justify-content:space-between;align-items:center;gap:12px;min-height:22px;display:flex}.-ozqdq_clearBtn{border-radius:12px;flex:none;height:24px;padding:0 10px;font-size:12px;line-height:24px}.-ozqdq_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.-ozqdq_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.-ozqdq_notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 12px;display:flex}.-ozqdq_noticeText{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.-ozqdq_noticeBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-size:12px;line-height:18px;text-decoration:underline}.-ozqdq_noticeBtn:hover{color:var(--dsw-alias-label-primary)}.-ozqdq_preview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;height:132px;position:relative;overflow:hidden}.-ozqdq_previewImg{object-fit:var(--bg-object-fit,cover);width:100%;height:100%;opacity:var(--bg-opacity,1);filter:blur(var(--bg-wallpaper-blur,0px));transform:scale(var(--bg-wallpaper-scale,1));display:block;position:absolute;inset:0}.-ozqdq_previewScrim{background:rgba(255, 255, 255, var(--bg-scrim,.25));position:absolute;inset:0}body[data-ds-dark-theme] .-ozqdq_previewScrim{background:rgba(0, 0, 0, var(--bg-scrim,.25))}.-ozqdq_previewGlass{background:var(--bg-preview-glass,#ffffff24);width:44%;height:46px;backdrop-filter:blur(var(--bg-glass-blur,16px)) saturate(var(--bg-glass-saturate,1.42)) brightness(var(--bg-glass-brightness,1));border:1px solid #ffffff38;border-radius:10px;justify-content:center;align-items:center;display:flex;position:absolute;bottom:16px;left:16px;box-shadow:inset 0 1px #ffffff4d}.-ozqdq_previewGlassText{color:#0f172ac7;text-shadow:0 1px 2px #fff6;white-space:nowrap;font-size:11px;line-height:1}body[data-ds-dark-theme] .-ozqdq_previewGlassText{color:#ffffffd9;text-shadow:0 1px 2px #00000059}.-ozqdq_previewEmpty{color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;font-size:12px;line-height:1.5;display:flex;position:absolute;inset:0}.-ozqdq_section{flex-direction:column;gap:8px;display:flex}.-ozqdq_sectionLabel{color:var(--dsw-alias-label-tertiary);letter-spacing:.01em;font-size:12px;font-weight:500;line-height:18px}.-ozqdq_sourceRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-ozqdq_urlRow{align-items:center;gap:8px;display:flex}.-ozqdq_urlInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 10px;font-size:13px;line-height:1.5}.-ozqdq_urlInput::placeholder{color:var(--dsw-alias-label-dimmed)}.-ozqdq_urlInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.-ozqdq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.-ozqdq_enabledBadge{white-space:nowrap;background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary);border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.-ozqdq_btn{border:1px solid var(--dsw-alias-border-l2);height:28px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:14px;justify-content:center;align-items:center;padding:0 12px;font-size:12px;line-height:18px;transition:background-color .15s,border-color .15s,color .15s;display:inline-flex}.-ozqdq_btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.-ozqdq_btn:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.-ozqdq_btn:disabled{opacity:.45;cursor:default}.-ozqdq_btnPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.-ozqdq_btnPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.-ozqdq_btnDanger{color:var(--dsw-alias-label-error)}.-ozqdq_btnDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.-ozqdq_sliderRow{align-items:center;gap:10px;display:flex}.-ozqdq_sliderLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_slider{-webkit-appearance:none;appearance:none;cursor:pointer;background:0 0;flex:1;min-width:0;height:18px;margin:0}.-ozqdq_slider::-webkit-slider-runnable-track{background:linear-gradient(90deg, var(--dsw-alias-brand-primary) var(--bg-fill,0%), var(--dsw-alias-border-l3) var(--bg-fill,0%));border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-track{background:var(--dsw-alias-border-l3);border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-progress{background:var(--dsw-alias-brand-primary);border-radius:2px;height:4px}.-ozqdq_slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%;margin-top:-5px}.-ozqdq_slider::-moz-range-thumb{border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%}.-ozqdq_slider:hover::-webkit-slider-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:hover::-moz-range-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:active::-webkit-slider-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:active::-moz-range-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:focus-visible{outline:none}.-ozqdq_slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_slider:focus-visible::-moz-range-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_sliderValue{text-align:right;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);flex:0 0 52px;font-size:13px;line-height:1.5}.-ozqdq_segRow{align-items:center;gap:10px;display:flex}.-ozqdq_segLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_segGroup{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:9px;flex:1;gap:2px;min-width:0;padding:2px;display:inline-flex}.-ozqdq_segBtn{height:24px;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:7px;flex:1;padding:0 16px;font-size:12px;line-height:24px}.-ozqdq_segBtn:hover:not(.-ozqdq_segActive){color:var(--dsw-alias-label-primary)}.-ozqdq_segActive{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font-weight:500}.-ozqdq_error{color:var(--dsw-alias-label-error);font-size:12px;line-height:1.5}.-ozqdq_clearRow{align-items:center;gap:10px;display:flex}.-ozqdq_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background-color .15s;position:relative}.-ozqdq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.-ozqdq_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_switchKnob{background:#fff;border-radius:50%;width:16px;height:16px;transition:transform .15s;position:absolute;top:3px;left:3px;box-shadow:0 1px 3px #00000047}.-ozqdq_switch[aria-checked=true] .-ozqdq_switchKnob{transform:translate(18px)}@media (prefers-reduced-motion:reduce){.-ozqdq_btn,.-ozqdq_switch,.-ozqdq_switchKnob{transition:none}}";
|
|
1401
|
+
const css = ".-ozqdq_row{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;padding:16px 0;display:flex}.-ozqdq_header{flex-direction:column;gap:4px;display:flex}.-ozqdq_titleRow{justify-content:space-between;align-items:center;gap:12px;min-height:22px;display:flex}.-ozqdq_clearBtn{border-radius:12px;flex:none;height:24px;padding:0 10px;font-size:12px;line-height:24px}.-ozqdq_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.-ozqdq_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.-ozqdq_notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 12px;display:flex}.-ozqdq_noticeText{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.-ozqdq_noticeBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-size:12px;line-height:18px;text-decoration:underline}.-ozqdq_noticeBtn:hover{color:var(--dsw-alias-label-primary)}.-ozqdq_ratioFrame{justify-content:center;display:flex}.-ozqdq_preview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;flex:none;width:100%;height:132px;position:relative;overflow:hidden}.-ozqdq_preview[data-pan]{cursor:move;touch-action:none}.-ozqdq_preview:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_previewImg{object-fit:var(--bg-object-fit,cover);object-position:calc(var(--bg-offset-x,.5) * 100%) calc(var(--bg-offset-y,.5) * 100%);width:100%;height:100%;opacity:var(--bg-opacity,1);filter:blur(var(--bg-wallpaper-blur,0px));transform:scale(var(--bg-wallpaper-scale,1));display:block;position:absolute;inset:0}.-ozqdq_previewScrim{background:rgba(255, 255, 255, var(--bg-scrim,.25));position:absolute;inset:0}body[data-ds-dark-theme] .-ozqdq_previewScrim{background:rgba(0, 0, 0, var(--bg-scrim,.25))}.-ozqdq_previewGlass{background:var(--bg-preview-glass,#ffffff24);width:44%;height:46px;backdrop-filter:blur(var(--bg-glass-blur,16px)) saturate(var(--bg-glass-saturate,1.42)) brightness(var(--bg-glass-brightness,1));border:1px solid #ffffff38;border-radius:10px;justify-content:center;align-items:center;display:flex;position:absolute;bottom:16px;left:16px;box-shadow:inset 0 1px #ffffff4d}.-ozqdq_previewGlassText{color:#0f172ac7;text-shadow:0 1px 2px #fff6;white-space:nowrap;font-size:11px;line-height:1}body[data-ds-dark-theme] .-ozqdq_previewGlassText{color:#ffffffd9;text-shadow:0 1px 2px #00000059}.-ozqdq_previewEmpty{color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;font-size:12px;line-height:1.5;display:flex;position:absolute;inset:0}.-ozqdq_previewReset{z-index:2;height:22px;font:inherit;color:#fff;cursor:pointer;backdrop-filter:blur(4px);background:#0f172a73;border:none;border-radius:11px;padding:0 9px;font-size:11px;line-height:22px;transition:background-color .15s;position:absolute;top:8px;right:8px}.-ozqdq_previewReset:hover{background:#0f172aa6}.-ozqdq_section{flex-direction:column;gap:8px;display:flex}.-ozqdq_sectionLabel{color:var(--dsw-alias-label-tertiary);letter-spacing:.01em;font-size:12px;font-weight:500;line-height:18px}.-ozqdq_sourceRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-ozqdq_urlRow{align-items:center;gap:8px;display:flex}.-ozqdq_urlInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 10px;font-size:13px;line-height:1.5}.-ozqdq_urlInput::placeholder{color:var(--dsw-alias-label-dimmed)}.-ozqdq_urlInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.-ozqdq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.-ozqdq_enabledBadge{white-space:nowrap;background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary);border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.-ozqdq_btn{border:1px solid var(--dsw-alias-border-l2);height:28px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:14px;justify-content:center;align-items:center;padding:0 12px;font-size:12px;line-height:18px;transition:background-color .15s,border-color .15s,color .15s;display:inline-flex}.-ozqdq_btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.-ozqdq_btn:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.-ozqdq_btn:disabled{opacity:.45;cursor:default}.-ozqdq_btnPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.-ozqdq_btnPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.-ozqdq_btnDanger{color:var(--dsw-alias-label-error)}.-ozqdq_btnDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.-ozqdq_sliderRow{align-items:center;gap:10px;display:flex}.-ozqdq_sliderLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_slider{-webkit-appearance:none;appearance:none;cursor:pointer;background:0 0;flex:1;min-width:0;height:18px;margin:0}.-ozqdq_slider::-webkit-slider-runnable-track{background:linear-gradient(90deg, var(--dsw-alias-brand-primary) var(--bg-fill,0%), var(--dsw-alias-border-l3) var(--bg-fill,0%));border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-track{background:var(--dsw-alias-border-l3);border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-progress{background:var(--dsw-alias-brand-primary);border-radius:2px;height:4px}.-ozqdq_slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%;margin-top:-5px}.-ozqdq_slider::-moz-range-thumb{border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%}.-ozqdq_slider:hover::-webkit-slider-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:hover::-moz-range-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:active::-webkit-slider-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:active::-moz-range-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:focus-visible{outline:none}.-ozqdq_slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_slider:focus-visible::-moz-range-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_sliderValue{text-align:right;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);flex:0 0 52px;font-size:13px;line-height:1.5}.-ozqdq_segRow{align-items:center;gap:10px;display:flex}.-ozqdq_segLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_segGroup{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:9px;flex:1;gap:2px;min-width:0;padding:2px;display:inline-flex}.-ozqdq_segBtn{height:24px;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:7px;flex:1;padding:0 16px;font-size:12px;line-height:24px}.-ozqdq_segBtn:hover:not(.-ozqdq_segActive){color:var(--dsw-alias-label-primary)}.-ozqdq_segActive{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font-weight:500}.-ozqdq_error{color:var(--dsw-alias-label-error);font-size:12px;line-height:1.5}.-ozqdq_clearRow{align-items:center;gap:10px;display:flex}.-ozqdq_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background-color .15s;position:relative}.-ozqdq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.-ozqdq_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_switchKnob{background:#fff;border-radius:50%;width:16px;height:16px;transition:transform .15s;position:absolute;top:3px;left:3px;box-shadow:0 1px 3px #00000047}.-ozqdq_switch[aria-checked=true] .-ozqdq_switchKnob{transform:translate(18px)}@media (prefers-reduced-motion:reduce){.-ozqdq_btn,.-ozqdq_switch,.-ozqdq_switchKnob{transition:none}}";
|
|
1153
1402
|
const tagId = "deepseek-harness-background/SettingsRow.module.css";
|
|
1154
1403
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1155
1404
|
const tag = document.createElement("style");
|
|
@@ -1159,44 +1408,46 @@ window.__ModuleLoader__.load({
|
|
|
1159
1408
|
document.head.appendChild(tag);
|
|
1160
1409
|
}
|
|
1161
1410
|
var SettingsRow_module_css_default = {
|
|
1162
|
-
"
|
|
1411
|
+
"preview": "-ozqdq_preview",
|
|
1412
|
+
"notice": "-ozqdq_notice",
|
|
1163
1413
|
"row": "-ozqdq_row",
|
|
1414
|
+
"section": "-ozqdq_section",
|
|
1415
|
+
"slider": "-ozqdq_slider",
|
|
1416
|
+
"clearRow": "-ozqdq_clearRow",
|
|
1164
1417
|
"previewGlass": "-ozqdq_previewGlass",
|
|
1165
|
-
"
|
|
1166
|
-
"
|
|
1418
|
+
"previewReset": "-ozqdq_previewReset",
|
|
1419
|
+
"btnDanger": "-ozqdq_btnDanger",
|
|
1167
1420
|
"segRow": "-ozqdq_segRow",
|
|
1168
|
-
"
|
|
1169
|
-
"sourceRow": "-ozqdq_sourceRow",
|
|
1170
|
-
"btnPrimary": "-ozqdq_btnPrimary",
|
|
1421
|
+
"ratioFrame": "-ozqdq_ratioFrame",
|
|
1171
1422
|
"titleRow": "-ozqdq_titleRow",
|
|
1172
|
-
"
|
|
1173
|
-
"
|
|
1423
|
+
"header": "-ozqdq_header",
|
|
1424
|
+
"title": "-ozqdq_title",
|
|
1425
|
+
"clearBtn": "-ozqdq_clearBtn",
|
|
1426
|
+
"btnPrimary": "-ozqdq_btnPrimary",
|
|
1174
1427
|
"sliderRow": "-ozqdq_sliderRow",
|
|
1175
|
-
"enabledBadge": "-ozqdq_enabledBadge",
|
|
1176
|
-
"noticeText": "-ozqdq_noticeText",
|
|
1177
|
-
"urlRow": "-ozqdq_urlRow",
|
|
1178
|
-
"previewScrim": "-ozqdq_previewScrim",
|
|
1179
|
-
"sliderLabel": "-ozqdq_sliderLabel",
|
|
1180
1428
|
"sliderValue": "-ozqdq_sliderValue",
|
|
1181
|
-
"
|
|
1429
|
+
"segActive": "-ozqdq_segActive",
|
|
1430
|
+
"switch": "-ozqdq_switch",
|
|
1431
|
+
"switchKnob": "-ozqdq_switchKnob",
|
|
1432
|
+
"desc": "-ozqdq_desc",
|
|
1182
1433
|
"error": "-ozqdq_error",
|
|
1183
|
-
"urlInput": "-ozqdq_urlInput",
|
|
1184
1434
|
"hint": "-ozqdq_hint",
|
|
1185
|
-
"
|
|
1186
|
-
"
|
|
1187
|
-
"previewImg": "-ozqdq_previewImg",
|
|
1188
|
-
"segLabel": "-ozqdq_segLabel",
|
|
1189
|
-
"switch": "-ozqdq_switch",
|
|
1190
|
-
"preview": "-ozqdq_preview",
|
|
1191
|
-
"segGroup": "-ozqdq_segGroup",
|
|
1435
|
+
"sourceRow": "-ozqdq_sourceRow",
|
|
1436
|
+
"enabledBadge": "-ozqdq_enabledBadge",
|
|
1192
1437
|
"previewGlassText": "-ozqdq_previewGlassText",
|
|
1193
|
-
"
|
|
1194
|
-
"
|
|
1195
|
-
"clearRow": "-ozqdq_clearRow",
|
|
1196
|
-
"notice": "-ozqdq_notice",
|
|
1197
|
-
"segBtn": "-ozqdq_segBtn",
|
|
1438
|
+
"segLabel": "-ozqdq_segLabel",
|
|
1439
|
+
"sliderLabel": "-ozqdq_sliderLabel",
|
|
1198
1440
|
"previewEmpty": "-ozqdq_previewEmpty",
|
|
1199
|
-
"
|
|
1441
|
+
"noticeBtn": "-ozqdq_noticeBtn",
|
|
1442
|
+
"sectionLabel": "-ozqdq_sectionLabel",
|
|
1443
|
+
"noticeText": "-ozqdq_noticeText",
|
|
1444
|
+
"previewImg": "-ozqdq_previewImg",
|
|
1445
|
+
"previewScrim": "-ozqdq_previewScrim",
|
|
1446
|
+
"btn": "-ozqdq_btn",
|
|
1447
|
+
"urlRow": "-ozqdq_urlRow",
|
|
1448
|
+
"segGroup": "-ozqdq_segGroup",
|
|
1449
|
+
"urlInput": "-ozqdq_urlInput",
|
|
1450
|
+
"segBtn": "-ozqdq_segBtn"
|
|
1200
1451
|
};
|
|
1201
1452
|
//#endregion
|
|
1202
1453
|
//#region src/client/SettingsRow.tsx
|
|
@@ -1229,6 +1480,8 @@ window.__ModuleLoader__.load({
|
|
|
1229
1480
|
blur: 16,
|
|
1230
1481
|
wallpaperBlur: 0,
|
|
1231
1482
|
fit: DEFAULT_FIT,
|
|
1483
|
+
offsetX: DEFAULT_OFFSET,
|
|
1484
|
+
offsetY: DEFAULT_OFFSET,
|
|
1232
1485
|
timeline: true
|
|
1233
1486
|
};
|
|
1234
1487
|
/** Per-field slider geometry: 5% steps for ratios, fine px steps for radii so
|
|
@@ -1271,13 +1524,26 @@ window.__ModuleLoader__.load({
|
|
|
1271
1524
|
const prefix = `${BACKGROUND_API_PREFIX}/image/`;
|
|
1272
1525
|
return url.startsWith(prefix) ? url.slice(prefix.length) : "";
|
|
1273
1526
|
}
|
|
1527
|
+
/** Cap on the preview card's height. Past it the card shrinks as a whole —
|
|
1528
|
+
* width follows the ratio — and centers, so a very tall (or very wide) window
|
|
1529
|
+
* keeps the exact viewport ratio instead of squashing the crop. */
|
|
1530
|
+
const PREVIEW_MAX_HEIGHT = 360;
|
|
1531
|
+
/** Clamp a framing offset into its schema domain, trimming the float dust the
|
|
1532
|
+
* pointer-delta division leaves behind (0.30000000000000004 → 0.3). */
|
|
1533
|
+
function clampOffset(value) {
|
|
1534
|
+
return Math.round((value < 0 ? 0 : value > 1 ? 1 : value) * 1e4) / 1e4;
|
|
1535
|
+
}
|
|
1536
|
+
/** Round ratio dust out of an inline px box (400 / (4/3) is 300.00000000000006). */
|
|
1537
|
+
function trimPx(value) {
|
|
1538
|
+
return Math.round(value * 100) / 100;
|
|
1539
|
+
}
|
|
1274
1540
|
/** Read the settings store (uSES-friendly). */
|
|
1275
1541
|
function readSnapshot() {
|
|
1276
1542
|
return settingsClient.getSnapshot();
|
|
1277
1543
|
}
|
|
1278
1544
|
/** Field-wise equality for distinguishing our own saves from external changes. */
|
|
1279
1545
|
function sameSettings(a, b) {
|
|
1280
|
-
return a.enabled === b.enabled && a.uploadId === b.uploadId && a.url === b.url && a.opacity === b.opacity && a.scrim === b.scrim && a.panelOpacity === b.panelOpacity && a.blur === b.blur && a.wallpaperBlur === b.wallpaperBlur && a.fit === b.fit && a.timeline === b.timeline;
|
|
1546
|
+
return a.enabled === b.enabled && a.uploadId === b.uploadId && a.url === b.url && a.opacity === b.opacity && a.scrim === b.scrim && a.panelOpacity === b.panelOpacity && a.blur === b.blur && a.wallpaperBlur === b.wallpaperBlur && a.fit === b.fit && a.offsetX === b.offsetX && a.offsetY === b.offsetY && a.timeline === b.timeline;
|
|
1281
1547
|
}
|
|
1282
1548
|
/**
|
|
1283
1549
|
* A stepped range control. While dragging it re-renders only itself: the value
|
|
@@ -1371,6 +1637,14 @@ window.__ModuleLoader__.load({
|
|
|
1371
1637
|
const [noticeDismissed, setNoticeDismissed] = (0, react.useState)(false);
|
|
1372
1638
|
const fileInput = (0, react.useRef)(null);
|
|
1373
1639
|
const previewRef = (0, react.useRef)(null);
|
|
1640
|
+
const frameRef = (0, react.useRef)(null);
|
|
1641
|
+
const [viewport, setViewport] = (0, react.useState)(() => ({
|
|
1642
|
+
w: window.innerWidth,
|
|
1643
|
+
h: window.innerHeight
|
|
1644
|
+
}));
|
|
1645
|
+
const [frameWidth, setFrameWidth] = (0, react.useState)(0);
|
|
1646
|
+
const [imgMeta, setImgMeta] = (0, react.useState)(null);
|
|
1647
|
+
const panRef = (0, react.useRef)(null);
|
|
1374
1648
|
const draftRef = (0, react.useRef)(DEFAULTS);
|
|
1375
1649
|
const editingRef = (0, react.useRef)(false);
|
|
1376
1650
|
const lastSavedRef = (0, react.useRef)(null);
|
|
@@ -1428,6 +1702,36 @@ window.__ModuleLoader__.load({
|
|
|
1428
1702
|
saveNowRef.current(draftRef.current);
|
|
1429
1703
|
}, 120);
|
|
1430
1704
|
}, []);
|
|
1705
|
+
(0, react.useEffect)(() => {
|
|
1706
|
+
let raf = 0;
|
|
1707
|
+
const sync = () => {
|
|
1708
|
+
raf = 0;
|
|
1709
|
+
setViewport({
|
|
1710
|
+
w: window.innerWidth,
|
|
1711
|
+
h: window.innerHeight
|
|
1712
|
+
});
|
|
1713
|
+
};
|
|
1714
|
+
const onResize = () => {
|
|
1715
|
+
if (raf !== 0) return;
|
|
1716
|
+
raf = window.requestAnimationFrame(sync);
|
|
1717
|
+
};
|
|
1718
|
+
window.addEventListener("resize", onResize);
|
|
1719
|
+
return () => {
|
|
1720
|
+
window.removeEventListener("resize", onResize);
|
|
1721
|
+
if (raf !== 0) window.cancelAnimationFrame(raf);
|
|
1722
|
+
};
|
|
1723
|
+
}, []);
|
|
1724
|
+
(0, react.useEffect)(() => {
|
|
1725
|
+
const el = frameRef.current;
|
|
1726
|
+
if (el === null) return;
|
|
1727
|
+
if (typeof ResizeObserver === "undefined") {
|
|
1728
|
+
setFrameWidth(el.clientWidth);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
const observer = new ResizeObserver(() => setFrameWidth(el.clientWidth));
|
|
1732
|
+
observer.observe(el);
|
|
1733
|
+
return () => observer.disconnect();
|
|
1734
|
+
}, []);
|
|
1431
1735
|
(0, react.useEffect)(() => {
|
|
1432
1736
|
if (snapshot.status !== "ready" || snapshot.value === void 0) return;
|
|
1433
1737
|
const saved = lastSavedRef.current;
|
|
@@ -1528,8 +1832,109 @@ window.__ModuleLoader__.load({
|
|
|
1528
1832
|
setDraft(next);
|
|
1529
1833
|
saveNow(next);
|
|
1530
1834
|
};
|
|
1835
|
+
/** Natural aspect ratio of the loaded source (null until loaded / on error). */
|
|
1836
|
+
const imageAspect = imgMeta !== null && imgMeta.w > 0 && imgMeta.h > 0 ? imgMeta.w / imgMeta.h : null;
|
|
1837
|
+
/** Preview card box at the live viewport ratio, capped at PREVIEW_MAX_HEIGHT
|
|
1838
|
+
* (past the cap the card shrinks as a whole and the frame centers it); a
|
|
1839
|
+
* width of 0 means "not measured yet" (CSS fallbacks apply). */
|
|
1840
|
+
const cardRatio = viewport.w > 0 && viewport.h > 0 ? viewport.w / viewport.h : 16 / 9;
|
|
1841
|
+
const cardWidth = frameWidth > 0 ? trimPx(Math.min(frameWidth, PREVIEW_MAX_HEIGHT * cardRatio)) : 0;
|
|
1842
|
+
const cardHeight = cardWidth > 0 ? trimPx(cardWidth / cardRatio) : 0;
|
|
1843
|
+
/** The axis the cover crop has slack on — and therefore the only one the
|
|
1844
|
+
* user may pan. A landscape source in a portrait frame overflows sideways
|
|
1845
|
+
* (pan x); a portrait source in a landscape frame overflows vertically
|
|
1846
|
+
* (pan y). null for `contain`, an unloaded source, an unmeasured card or an
|
|
1847
|
+
* exact ratio match (nothing to pan, and no division by zero). */
|
|
1848
|
+
const panAxis = draft.fit === "cover" && imageAspect !== null && cardWidth > 0 && Math.abs(imageAspect - cardRatio) >= 1e-4 ? imageAspect > cardRatio ? "x" : "y" : null;
|
|
1849
|
+
/** Whether a pan has moved the crop off center (drives the recenter chip). */
|
|
1850
|
+
const offsetMoved = draft.offsetX !== .5 || draft.offsetY !== .5;
|
|
1851
|
+
/** Overflow (px) of the rendered image past the card on one axis, measured
|
|
1852
|
+
* from the live DOM (the same frame the wallpaper layer uses), or null when
|
|
1853
|
+
* that axis has nothing to pan. */
|
|
1854
|
+
const overflowFor = (axis) => {
|
|
1855
|
+
const el = previewRef.current;
|
|
1856
|
+
if (el === null || imgMeta === null) return null;
|
|
1857
|
+
const fw = el.clientWidth;
|
|
1858
|
+
const fh = el.clientHeight;
|
|
1859
|
+
if (fw <= 0 || fh <= 0 || imgMeta.w <= 0 || imgMeta.h <= 0) return null;
|
|
1860
|
+
const scale = Math.max(fw / imgMeta.w, fh / imgMeta.h);
|
|
1861
|
+
const overflow = axis === "x" ? imgMeta.w * scale - fw : imgMeta.h * scale - fh;
|
|
1862
|
+
return overflow > 0 ? overflow : null;
|
|
1863
|
+
};
|
|
1864
|
+
/** Write one framing offset live: CSS variables only, no React state — the
|
|
1865
|
+
* pan hot path mirrors ControlSlider's onLive. */
|
|
1866
|
+
const setOffsetLive = (key, value) => {
|
|
1867
|
+
const next = {
|
|
1868
|
+
...draftRef.current,
|
|
1869
|
+
[key]: value
|
|
1870
|
+
};
|
|
1871
|
+
draftRef.current = next;
|
|
1872
|
+
paintBackgroundKnob(key, value);
|
|
1873
|
+
if (previewRef.current) paintPreviewSurface(previewRef.current, next);
|
|
1874
|
+
};
|
|
1875
|
+
const handlePanDown = (e) => {
|
|
1876
|
+
if (panAxis === null) return;
|
|
1877
|
+
const overflow = overflowFor(panAxis);
|
|
1878
|
+
if (overflow === null) return;
|
|
1879
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
1880
|
+
e.preventDefault();
|
|
1881
|
+
markEditing();
|
|
1882
|
+
panRef.current = {
|
|
1883
|
+
axis: panAxis,
|
|
1884
|
+
startPos: panAxis === "x" ? e.clientX : e.clientY,
|
|
1885
|
+
startOffset: panAxis === "x" ? draftRef.current.offsetX : draftRef.current.offsetY,
|
|
1886
|
+
overflow
|
|
1887
|
+
};
|
|
1888
|
+
};
|
|
1889
|
+
const handlePanMove = (e) => {
|
|
1890
|
+
const pan = panRef.current;
|
|
1891
|
+
if (pan === null) return;
|
|
1892
|
+
const delta = (pan.axis === "x" ? e.clientX : e.clientY) - pan.startPos;
|
|
1893
|
+
setOffsetLive(pan.axis === "x" ? "offsetX" : "offsetY", clampOffset(pan.startOffset - delta / pan.overflow));
|
|
1894
|
+
};
|
|
1895
|
+
const handlePanUp = (e) => {
|
|
1896
|
+
if (panRef.current === null) return;
|
|
1897
|
+
panRef.current = null;
|
|
1898
|
+
if (e.currentTarget.hasPointerCapture(e.pointerId)) e.currentTarget.releasePointerCapture(e.pointerId);
|
|
1899
|
+
setDraft({ ...draftRef.current });
|
|
1900
|
+
onCommit();
|
|
1901
|
+
};
|
|
1902
|
+
/** Arrow-key pan on the movable axis (Shift = coarse step). */
|
|
1903
|
+
const nudgeOffset = (axis, direction, coarse) => {
|
|
1904
|
+
const key = axis === "x" ? "offsetX" : "offsetY";
|
|
1905
|
+
setOffsetLive(key, clampOffset(draftRef.current[key] + direction * (coarse ? .1 : .02)));
|
|
1906
|
+
setDraft({ ...draftRef.current });
|
|
1907
|
+
onCommit();
|
|
1908
|
+
};
|
|
1909
|
+
const handlePanKeyDown = (e) => {
|
|
1910
|
+
if (panAxis === null) return;
|
|
1911
|
+
if (panAxis === "x" && (e.key === "ArrowLeft" || e.key === "ArrowRight")) {
|
|
1912
|
+
e.preventDefault();
|
|
1913
|
+
nudgeOffset("x", e.key === "ArrowLeft" ? -1 : 1, e.shiftKey);
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
if (panAxis === "y" && (e.key === "ArrowUp" || e.key === "ArrowDown")) {
|
|
1917
|
+
e.preventDefault();
|
|
1918
|
+
nudgeOffset("y", e.key === "ArrowUp" ? -1 : 1, e.shiftKey);
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
/** Recenter the crop on both axes (recenter chip / double-click). */
|
|
1922
|
+
const handleResetOffset = () => {
|
|
1923
|
+
const next = {
|
|
1924
|
+
...draftRef.current,
|
|
1925
|
+
offsetX: DEFAULT_OFFSET,
|
|
1926
|
+
offsetY: DEFAULT_OFFSET
|
|
1927
|
+
};
|
|
1928
|
+
draftRef.current = next;
|
|
1929
|
+
setDraft(next);
|
|
1930
|
+
paintLive(next);
|
|
1931
|
+
saveNow(next);
|
|
1932
|
+
};
|
|
1531
1933
|
const sourceUrl = draft.uploadId ? `${BACKGROUND_API_PREFIX}/image/${draft.uploadId}` : draft.url;
|
|
1532
1934
|
const hasImage = sourceUrl !== "";
|
|
1935
|
+
(0, react.useEffect)(() => {
|
|
1936
|
+
setImgMeta(null);
|
|
1937
|
+
}, [sourceUrl]);
|
|
1533
1938
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1534
1939
|
className: SettingsRow_module_css_default.row,
|
|
1535
1940
|
children: [
|
|
@@ -1565,27 +1970,55 @@ window.__ModuleLoader__.load({
|
|
|
1565
1970
|
})]
|
|
1566
1971
|
}),
|
|
1567
1972
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1568
|
-
className: SettingsRow_module_css_default.
|
|
1569
|
-
ref:
|
|
1570
|
-
children:
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1973
|
+
className: SettingsRow_module_css_default.ratioFrame,
|
|
1974
|
+
ref: frameRef,
|
|
1975
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1976
|
+
className: SettingsRow_module_css_default.preview,
|
|
1977
|
+
ref: previewRef,
|
|
1978
|
+
"data-pan": panAxis ?? void 0,
|
|
1979
|
+
style: cardHeight > 0 ? {
|
|
1980
|
+
width: `${cardWidth}px`,
|
|
1981
|
+
height: `${cardHeight}px`
|
|
1982
|
+
} : void 0,
|
|
1983
|
+
tabIndex: panAxis === null ? void 0 : 0,
|
|
1984
|
+
"aria-label": panAxis === null ? void 0 : t("background.previewPanHint"),
|
|
1985
|
+
onPointerDown: handlePanDown,
|
|
1986
|
+
onPointerMove: handlePanMove,
|
|
1987
|
+
onPointerUp: handlePanUp,
|
|
1988
|
+
onPointerCancel: handlePanUp,
|
|
1989
|
+
onKeyDown: handlePanKeyDown,
|
|
1990
|
+
onDoubleClick: panAxis === null ? void 0 : handleResetOffset,
|
|
1991
|
+
children: [hasImage ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1992
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
1993
|
+
className: SettingsRow_module_css_default.previewImg,
|
|
1994
|
+
src: sourceUrl,
|
|
1995
|
+
alt: "",
|
|
1996
|
+
draggable: false,
|
|
1997
|
+
referrerPolicy: "no-referrer",
|
|
1998
|
+
onLoad: (e) => setImgMeta({
|
|
1999
|
+
w: e.currentTarget.naturalWidth,
|
|
2000
|
+
h: e.currentTarget.naturalHeight
|
|
2001
|
+
}),
|
|
2002
|
+
onError: () => setImgMeta(null)
|
|
2003
|
+
}),
|
|
2004
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: SettingsRow_module_css_default.previewScrim }),
|
|
2005
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2006
|
+
className: SettingsRow_module_css_default.previewGlass,
|
|
2007
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2008
|
+
className: SettingsRow_module_css_default.previewGlassText,
|
|
2009
|
+
children: t("background.previewGlass")
|
|
2010
|
+
})
|
|
1584
2011
|
})
|
|
1585
|
-
})
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
2012
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2013
|
+
className: SettingsRow_module_css_default.previewEmpty,
|
|
2014
|
+
children: t("background.noPreview")
|
|
2015
|
+
}), panAxis !== null && offsetMoved && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2016
|
+
type: "button",
|
|
2017
|
+
className: SettingsRow_module_css_default.previewReset,
|
|
2018
|
+
onPointerDown: (e) => e.stopPropagation(),
|
|
2019
|
+
onClick: handleResetOffset,
|
|
2020
|
+
children: t("background.repositionReset")
|
|
2021
|
+
})]
|
|
1589
2022
|
})
|
|
1590
2023
|
}),
|
|
1591
2024
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|