@dfy-plugins/dsh-wallpaper 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js ADDED
@@ -0,0 +1,1245 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@dfy-plugins/dsh-wallpaper",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ "use strict";
7
+ var __create = Object.create;
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
+ var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __getProtoOf = Object.getPrototypeOf;
12
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
13
+ var __export = (target, all) => {
14
+ for (var name2 in all)
15
+ __defProp(target, name2, { get: all[name2], enumerable: true });
16
+ };
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (let key of __getOwnPropNames(from))
20
+ if (!__hasOwnProp.call(to, key) && key !== except)
21
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
33
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
+
35
+ // src/client.tsx
36
+ var client_exports = {};
37
+ __export(client_exports, {
38
+ apply: () => apply,
39
+ inject: () => inject,
40
+ name: () => name
41
+ });
42
+ module.exports = __toCommonJS(client_exports);
43
+ var import_react = __toESM(require("react"), 1);
44
+ var import_client = require("react-dom/client");
45
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
46
+
47
+ // src/logic.ts
48
+ var WALLPAPER_MODES = [
49
+ "cover",
50
+ "contain",
51
+ "stretch",
52
+ "fit-width",
53
+ "fit-height",
54
+ "center",
55
+ "tile"
56
+ ];
57
+ var WALLPAPER_POSITIONS = [
58
+ "left top",
59
+ "center top",
60
+ "right top",
61
+ "left center",
62
+ "center center",
63
+ "right center",
64
+ "left bottom",
65
+ "center bottom",
66
+ "right bottom"
67
+ ];
68
+ var WALLPAPER_REGIONS = ["settings", "sidebar"];
69
+ var DEFAULT_SURFACE_SETTINGS = {
70
+ enabled: true,
71
+ imageName: null,
72
+ mode: "cover",
73
+ position: "center center",
74
+ offsetXPercent: 0,
75
+ offsetYPercent: 0,
76
+ imageOpacity: 1,
77
+ blur: 0,
78
+ maskColor: "#000000",
79
+ maskOpacity: 0.18,
80
+ surfaceOpacity: 0.56
81
+ };
82
+ function defaultRegionSettings() {
83
+ const { enabled: _enabled, ...appearance } = DEFAULT_SURFACE_SETTINGS;
84
+ return { ...appearance, source: "none", imageOpacity: 0.45, blur: 8, maskOpacity: 0, surfaceOpacity: 0.95 };
85
+ }
86
+ var DEFAULT_SETTINGS = {
87
+ ...DEFAULT_SURFACE_SETTINGS,
88
+ regions: { settings: defaultRegionSettings(), sidebar: defaultRegionSettings() }
89
+ };
90
+ function isRecord(value) {
91
+ return typeof value === "object" && value !== null && !Array.isArray(value);
92
+ }
93
+ function clamp(value, fallback, min, max) {
94
+ const parsed = typeof value === "number" ? value : Number.NaN;
95
+ if (!Number.isFinite(parsed)) return fallback;
96
+ return Math.min(max, Math.max(min, parsed));
97
+ }
98
+ function isMode(value) {
99
+ return typeof value === "string" && WALLPAPER_MODES.includes(value);
100
+ }
101
+ function isPosition(value) {
102
+ return typeof value === "string" && WALLPAPER_POSITIONS.includes(value);
103
+ }
104
+ function normalizeHexColor(value) {
105
+ if (typeof value !== "string") return DEFAULT_SETTINGS.maskColor;
106
+ const trimmed = value.trim();
107
+ if (/^#[0-9a-f]{6}$/i.test(trimmed)) return trimmed.toLowerCase();
108
+ if (/^#[0-9a-f]{3}$/i.test(trimmed)) {
109
+ const [r, g, b] = trimmed.slice(1).split("");
110
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
111
+ }
112
+ return DEFAULT_SETTINGS.maskColor;
113
+ }
114
+ function normalizeSurface(value, maxSurfaceOpacity = 0.95) {
115
+ const input = isRecord(value) ? value : {};
116
+ const rawName = typeof input.imageName === "string" ? input.imageName.trim() : "";
117
+ return {
118
+ enabled: typeof input.enabled === "boolean" ? input.enabled : DEFAULT_SETTINGS.enabled,
119
+ imageName: rawName.length > 0 ? rawName.slice(0, 260) : null,
120
+ mode: isMode(input.mode) ? input.mode : DEFAULT_SETTINGS.mode,
121
+ position: isPosition(input.position) ? input.position : DEFAULT_SETTINGS.position,
122
+ offsetXPercent: clamp(input.offsetXPercent, DEFAULT_SETTINGS.offsetXPercent, -100, 100),
123
+ offsetYPercent: clamp(input.offsetYPercent, DEFAULT_SETTINGS.offsetYPercent, -100, 100),
124
+ imageOpacity: clamp(input.imageOpacity, DEFAULT_SETTINGS.imageOpacity, 0, 1),
125
+ blur: clamp(input.blur, DEFAULT_SETTINGS.blur, 0, 40),
126
+ maskColor: normalizeHexColor(input.maskColor),
127
+ maskOpacity: clamp(input.maskOpacity, DEFAULT_SETTINGS.maskOpacity, 0, 0.9),
128
+ surfaceOpacity: clamp(input.surfaceOpacity, DEFAULT_SETTINGS.surfaceOpacity, 0, maxSurfaceOpacity)
129
+ };
130
+ }
131
+ function normalizeSettings(value) {
132
+ const input = isRecord(value) ? value : {};
133
+ const regions = isRecord(input.regions) ? input.regions : {};
134
+ const region = (key) => {
135
+ const value2 = isRecord(regions[key]) ? regions[key] : {};
136
+ const { enabled: _enabled, ...appearance } = normalizeSurface({ ...defaultRegionSettings(), ...value2 }, 1);
137
+ return { ...appearance, source: value2.source === "global" || value2.source === "custom" ? value2.source : "none" };
138
+ };
139
+ return { ...normalizeSurface(input), regions: { settings: region("settings"), sidebar: region("sidebar") } };
140
+ }
141
+ function offsetAxis(anchor, offset, viewportUnit) {
142
+ if (offset === 0) return anchor;
143
+ const operator = offset < 0 ? "-" : "+";
144
+ return `calc(${anchor} ${operator} ${Math.abs(offset)}${viewportUnit})`;
145
+ }
146
+ function backgroundPositionWithOffset(position, offsetXPercent, offsetYPercent) {
147
+ const [horizontal, vertical] = position.split(" ");
148
+ const horizontalAnchor = { left: "0%", center: "50%", right: "100%" }[horizontal];
149
+ const verticalAnchor = { top: "0%", center: "50%", bottom: "100%" }[vertical];
150
+ return `${offsetAxis(horizontalAnchor, offsetXPercent, "vw")} ${offsetAxis(verticalAnchor, offsetYPercent, "vh")}`;
151
+ }
152
+ function modeStyle(mode) {
153
+ switch (mode) {
154
+ case "contain":
155
+ return { size: "contain", repeat: "no-repeat" };
156
+ case "stretch":
157
+ return { size: "100% 100%", repeat: "no-repeat" };
158
+ case "fit-width":
159
+ return { size: "100% auto", repeat: "no-repeat" };
160
+ case "fit-height":
161
+ return { size: "auto 100%", repeat: "no-repeat" };
162
+ case "center":
163
+ return { size: "auto", repeat: "no-repeat" };
164
+ case "tile":
165
+ return { size: "auto", repeat: "repeat" };
166
+ case "cover":
167
+ default:
168
+ return { size: "cover", repeat: "no-repeat" };
169
+ }
170
+ }
171
+ function hexToRgb(value) {
172
+ const color = normalizeHexColor(value).slice(1);
173
+ return [
174
+ Number.parseInt(color.slice(0, 2), 16),
175
+ Number.parseInt(color.slice(2, 4), 16),
176
+ Number.parseInt(color.slice(4, 6), 16)
177
+ ];
178
+ }
179
+ function surfaceLayerAlphas(base, maxOpacity = 0.95) {
180
+ const normalized = clamp(base, DEFAULT_SETTINGS.surfaceOpacity, 0, maxOpacity);
181
+ return [normalized, Math.max(normalized, Math.min(0.97, normalized + 0.1)), Math.max(normalized, Math.min(0.99, normalized + 0.2))];
182
+ }
183
+
184
+ // src/regions.ts
185
+ var REGIONS_ATTRIBUTE = "data-dsh-wallpaper-regions";
186
+ var REGION_SELECTORS = {
187
+ settings: '[role="dialog"][aria-modal="true"]:has([data-slot="settings.header"])',
188
+ sidebar: "[data-sidebar-right-panel]"
189
+ };
190
+ var PROPERTIES = ["image", "size", "repeat", "position", "opacity", "blur", "mask-rgb", "mask-opacity", "surface-1", "surface-2", "surface-3"];
191
+ var REGION_VARIABLES = WALLPAPER_REGIONS.flatMap((region) => PROPERTIES.map((property) => `--dsh-wallpaper-${region}-${property}`));
192
+ function regionVariables(settings, globalUrl, images) {
193
+ const variables = {};
194
+ for (const region of WALLPAPER_REGIONS) {
195
+ const value = settings.regions[region];
196
+ const url = value.source === "custom" ? images[region] : value.source === "global" ? globalUrl : null;
197
+ const style = modeStyle(value.mode);
198
+ const surfaces = surfaceLayerAlphas(value.surfaceOpacity, 1);
199
+ const values = [
200
+ url === null ? "none" : `url(${JSON.stringify(url)})`,
201
+ style.size,
202
+ style.repeat,
203
+ backgroundPositionWithOffset(value.position, value.offsetXPercent, value.offsetYPercent),
204
+ String(value.imageOpacity),
205
+ `${value.blur}px`,
206
+ hexToRgb(value.maskColor).join(" "),
207
+ String(url === null ? 0 : value.maskOpacity),
208
+ ...surfaces.map(String)
209
+ ];
210
+ PROPERTIES.forEach((property, index) => {
211
+ variables[`--dsh-wallpaper-${region}-${property}`] = values[index];
212
+ });
213
+ }
214
+ return variables;
215
+ }
216
+ var REGION_STYLES = `
217
+ body[${REGIONS_ATTRIBUTE}] { --dsh-wallpaper-region-rgb: 255 255 255; }
218
+ body[${REGIONS_ATTRIBUTE}][data-ds-dark-theme] { --dsh-wallpaper-region-rgb: 18 22 32; }
219
+ ${WALLPAPER_REGIONS.map((region) => {
220
+ const selector = `body[${REGIONS_ATTRIBUTE}] ${REGION_SELECTORS[region]}`;
221
+ const variable = (name2) => `var(--dsh-wallpaper-${region}-${name2})`;
222
+ return `
223
+ ${selector} {
224
+ isolation: isolate;
225
+ background: rgb(var(--dsh-wallpaper-region-rgb) / ${variable("surface-1")});
226
+ --dsh-wallpaper-local-1: rgb(var(--dsh-wallpaper-region-rgb) / ${variable("surface-1")});
227
+ --dsh-wallpaper-local-2: rgb(var(--dsh-wallpaper-region-rgb) / ${variable("surface-2")});
228
+ --dsh-wallpaper-local-3: rgb(var(--dsh-wallpaper-region-rgb) / ${variable("surface-3")});
229
+ --dsw-alias-bg-base: transparent;
230
+ --dsw-specific-sidebar-fill: transparent;
231
+ --dsw-alias-bg-layer-1: var(--dsh-wallpaper-local-1);
232
+ --dsw-alias-bg-layer-2: var(--dsh-wallpaper-local-2);
233
+ --dsw-alias-bg-layer-3: var(--dsh-wallpaper-local-3);
234
+ --dsw-alias-bg-module-platform: var(--dsh-wallpaper-local-2);
235
+ --dsw-specific-input-major: var(--dsh-wallpaper-local-2);
236
+ --dsw-specific-selector: var(--dsh-wallpaper-local-2);
237
+ --dsw-specific-tip: var(--dsh-wallpaper-local-2);
238
+ --dsw-alias-button-elevated-fill: var(--dsh-wallpaper-local-2);
239
+ --dsw-alias-button-floating-fill: var(--dsh-wallpaper-local-3);
240
+ --dsw-alias-markdown-code-block: var(--dsh-wallpaper-local-2);
241
+ --dsw-alias-markdown-code-block-banner: var(--dsh-wallpaper-local-3);
242
+ --dsw-alias-markdown-inline-code: var(--dsh-wallpaper-local-2);
243
+ }
244
+ ${selector}::before, ${selector}::after {
245
+ content: ''; position: absolute; inset: 0; pointer-events: none; border-radius: inherit;
246
+ }
247
+ ${selector}::before {
248
+ z-index: -2;
249
+ background-image: ${variable("image")};
250
+ background-size: ${variable("size")};
251
+ background-repeat: ${variable("repeat")};
252
+ background-position: ${variable("position")};
253
+ opacity: ${variable("opacity")};
254
+ filter: blur(${variable("blur")});
255
+ clip-path: inset(0);
256
+ }
257
+ ${selector}::after {
258
+ z-index: -1; background: rgb(${variable("mask-rgb")} / ${variable("mask-opacity")});
259
+ }`;
260
+ }).join("\n")}
261
+ `;
262
+
263
+ // src/client.tsx
264
+ var name = "wallpaper";
265
+ var inject = ["slots"];
266
+ var OWNER = "dsh-wallpaper";
267
+ var STYLE_ID = "@dfy-plugins/dsh-wallpaper";
268
+ var ACTIVE_ATTRIBUTE = "data-dsh-wallpaper-active";
269
+ var API_BASE = "/api/dsh-wallpaper";
270
+ var SETTINGS_DEBOUNCE_MS = 180;
271
+ var PANEL_POSITION_KEY = "dsh-wallpaper.panel-position.v1";
272
+ var PANEL_MARGIN = 12;
273
+ var PAGE_RUNTIME_KEY = "__xiao443DshWallpaperPageRuntime__";
274
+ var CLIENT_BUILD_TOKEN = Object.freeze({});
275
+ var BODY_VARIABLES = [
276
+ "--dsh-wallpaper-image-opacity",
277
+ "--dsh-wallpaper-blur",
278
+ "--dsh-wallpaper-inset",
279
+ "--dsh-wallpaper-mask-rgb",
280
+ "--dsh-wallpaper-mask-opacity",
281
+ "--dsh-wallpaper-surface-alpha-1",
282
+ "--dsh-wallpaper-surface-alpha-2",
283
+ "--dsh-wallpaper-surface-alpha-3"
284
+ ];
285
+ var MODE_OPTIONS = [
286
+ { value: "cover", label: "\u8986\u76D6\u7A97\u53E3", hint: "\u586B\u6EE1\u7A97\u53E3\uFF0C\u5FC5\u8981\u65F6\u88C1\u5207\u56FE\u7247" },
287
+ { value: "contain", label: "\u5B8C\u6574\u663E\u793A", hint: "\u663E\u793A\u5B8C\u6574\u56FE\u7247\uFF0C\u53EF\u80FD\u7559\u6709\u7A7A\u767D" },
288
+ { value: "stretch", label: "\u62C9\u4F38\u586B\u6EE1", hint: "\u5FFD\u7565\u539F\u59CB\u6BD4\u4F8B\u94FA\u6EE1\u7A97\u53E3" },
289
+ { value: "fit-width", label: "\u9002\u5E94\u5BBD\u5EA6", hint: "\u5BBD\u5EA6\u94FA\u6EE1\uFF0C\u9AD8\u5EA6\u6309\u6BD4\u4F8B\u7F29\u653E" },
290
+ { value: "fit-height", label: "\u9002\u5E94\u9AD8\u5EA6", hint: "\u9AD8\u5EA6\u94FA\u6EE1\uFF0C\u5BBD\u5EA6\u6309\u6BD4\u4F8B\u7F29\u653E" },
291
+ { value: "center", label: "\u539F\u59CB\u5927\u5C0F", hint: "\u6309\u539F\u59CB\u5C3A\u5BF8\u663E\u793A\uFF0C\u4E0D\u7F29\u653E" },
292
+ { value: "tile", label: "\u5E73\u94FA", hint: "\u6309\u539F\u59CB\u5C3A\u5BF8\u91CD\u590D\u56FE\u7247" }
293
+ ];
294
+ var POSITION_OPTIONS = [
295
+ { value: "left top", label: "\u5DE6\u4E0A" },
296
+ { value: "center top", label: "\u9876\u90E8\u5C45\u4E2D" },
297
+ { value: "right top", label: "\u53F3\u4E0A" },
298
+ { value: "left center", label: "\u5DE6\u4FA7\u5C45\u4E2D" },
299
+ { value: "center center", label: "\u6B63\u4E2D" },
300
+ { value: "right center", label: "\u53F3\u4FA7\u5C45\u4E2D" },
301
+ { value: "left bottom", label: "\u5DE6\u4E0B" },
302
+ { value: "center bottom", label: "\u5E95\u90E8\u5C45\u4E2D" },
303
+ { value: "right bottom", label: "\u53F3\u4E0B" }
304
+ ];
305
+ var STYLES = `
306
+ ${REGION_STYLES}
307
+ body[${ACTIVE_ATTRIBUTE}] {
308
+ isolation: isolate;
309
+ --dsh-wallpaper-surface-rgb: 255 255 255;
310
+ --dsh-wallpaper-surface-1: rgb(var(--dsh-wallpaper-surface-rgb) / var(--dsh-wallpaper-surface-alpha-1));
311
+ --dsh-wallpaper-surface-2: rgb(var(--dsh-wallpaper-surface-rgb) / var(--dsh-wallpaper-surface-alpha-2));
312
+ --dsh-wallpaper-surface-3: rgb(var(--dsh-wallpaper-surface-rgb) / var(--dsh-wallpaper-surface-alpha-3));
313
+ --dsw-alias-bg-base: transparent;
314
+ --dsw-specific-sidebar-fill: transparent;
315
+ --dsw-alias-bg-layer-1: var(--dsh-wallpaper-surface-1);
316
+ --dsw-alias-bg-layer-2: var(--dsh-wallpaper-surface-2);
317
+ --dsw-alias-bg-layer-3: var(--dsh-wallpaper-surface-3);
318
+ --dsw-alias-bg-module-platform: var(--dsh-wallpaper-surface-2);
319
+ --dsw-specific-input-major: var(--dsh-wallpaper-surface-2);
320
+ --dsw-specific-selector: var(--dsh-wallpaper-surface-2);
321
+ --dsw-specific-tip: var(--dsh-wallpaper-surface-2);
322
+ --dsw-alias-button-elevated-fill: var(--dsh-wallpaper-surface-2);
323
+ --dsw-alias-button-floating-fill: var(--dsh-wallpaper-surface-3);
324
+ --dsw-alias-markdown-code-block: var(--dsh-wallpaper-surface-2);
325
+ --dsw-alias-markdown-code-block-banner: var(--dsh-wallpaper-surface-3);
326
+ --dsw-alias-markdown-inline-code: var(--dsh-wallpaper-surface-2);
327
+ }
328
+ body[${ACTIVE_ATTRIBUTE}][data-ds-dark-theme] {
329
+ --dsh-wallpaper-surface-rgb: 18 22 32;
330
+ }
331
+ [data-dsh-wallpaper-owner='${OWNER}'][data-dsh-wallpaper-layer] {
332
+ display: none;
333
+ position: fixed;
334
+ pointer-events: none;
335
+ user-select: none;
336
+ }
337
+ body[${ACTIVE_ATTRIBUTE}] > [data-dsh-wallpaper-owner='${OWNER}'][data-dsh-wallpaper-layer='media'] {
338
+ display: block;
339
+ inset: var(--dsh-wallpaper-inset, 0px);
340
+ z-index: -2;
341
+ background-color: transparent;
342
+ background-position: center center;
343
+ background-repeat: no-repeat;
344
+ background-size: cover;
345
+ filter: blur(var(--dsh-wallpaper-blur, 0px));
346
+ opacity: var(--dsh-wallpaper-image-opacity, 1);
347
+ }
348
+ body[${ACTIVE_ATTRIBUTE}] > [data-dsh-wallpaper-owner='${OWNER}'][data-dsh-wallpaper-layer='mask'] {
349
+ display: block;
350
+ inset: 0;
351
+ z-index: -1;
352
+ background: rgb(var(--dsh-wallpaper-mask-rgb, 0 0 0) / var(--dsh-wallpaper-mask-opacity, .18));
353
+ }
354
+
355
+ [data-dsh-wallpaper-owner='${OWNER}'][data-dsh-wallpaper-panel-root] {
356
+ position: fixed;
357
+ inset: 0;
358
+ z-index: 900;
359
+ pointer-events: none;
360
+ }
361
+ .dsh-wallpaper-floating {
362
+ position: absolute;
363
+ display: flex;
364
+ width: min(480px, calc(100vw - 24px));
365
+ max-height: min(760px, calc(100vh - 24px));
366
+ flex-direction: column;
367
+ overflow: hidden;
368
+ border: 1px solid rgba(34, 38, 48, .14);
369
+ border-radius: 18px;
370
+ background: rgba(249, 250, 252, .91);
371
+ box-shadow: 0 22px 64px rgba(25, 31, 43, .22), 0 4px 16px rgba(25, 31, 43, .12);
372
+ color: var(--dsw-alias-label-primary);
373
+ pointer-events: auto;
374
+ backdrop-filter: blur(24px) saturate(1.18);
375
+ -webkit-backdrop-filter: blur(24px) saturate(1.18);
376
+ }
377
+ body[data-ds-dark-theme] .dsh-wallpaper-floating {
378
+ border-color: rgba(255, 255, 255, .12);
379
+ background: rgba(28, 30, 36, .91);
380
+ box-shadow: 0 24px 72px rgba(0, 0, 0, .48), 0 4px 18px rgba(0, 0, 0, .28);
381
+ }
382
+ .dsh-wallpaper-floating:focus { outline: none; }
383
+ .dsh-wallpaper-floating-header {
384
+ display: flex;
385
+ flex: none;
386
+ align-items: center;
387
+ justify-content: space-between;
388
+ gap: 16px;
389
+ padding: 14px 14px 13px 18px;
390
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
391
+ cursor: default;
392
+ touch-action: none;
393
+ user-select: none;
394
+ }
395
+ .dsh-wallpaper-floating-heading { min-width: 0; }
396
+ .dsh-wallpaper-floating-title { margin: 0; font-size: 16px; font-weight: 680; line-height: 23px; }
397
+ .dsh-wallpaper-floating-subtitle { overflow: hidden; margin: 1px 0 0; color: var(--dsw-alias-label-tertiary); font-size: 11px; line-height: 17px; text-overflow: ellipsis; white-space: nowrap; }
398
+ .dsh-wallpaper-close {
399
+ display: grid;
400
+ width: 28px;
401
+ height: 28px;
402
+ flex: none;
403
+ place-items: center;
404
+ padding: 0;
405
+ border: 0;
406
+ border-radius: 28px;
407
+ background: transparent;
408
+ color: inherit;
409
+ cursor: pointer;
410
+ }
411
+ .dsh-wallpaper-close:hover { background: var(--dsw-alias-interactive-bg-hover); }
412
+ .dsh-wallpaper-floating-body { min-height: 0; overflow: auto; overscroll-behavior: contain; }
413
+ .dsh-wallpaper-settings { padding: 16px 18px 20px; color: inherit; }
414
+ .dsh-wallpaper-targets { display:flex; gap:4px; padding:4px; margin-bottom:16px; border-radius:12px; background:var(--dsw-alias-bg-module-platform); }
415
+ .dsh-wallpaper-targets button { flex:1; padding:9px 8px; border:0; border-radius:9px; background:transparent; color:var(--dsw-alias-label-secondary); font:inherit; font-size:13px; cursor:pointer; }
416
+ .dsh-wallpaper-targets button[aria-pressed=true] { background:var(--dsw-alias-bg-layer-3); color:var(--dsw-alias-label-primary); box-shadow:0 1px 4px rgba(0,0,0,.08); font-weight:600; }
417
+ .dsh-wallpaper-targets button:focus-visible { outline:2px solid var(--dsw-alias-state-business-primary); outline-offset:1px; }
418
+ .dsh-wallpaper-region-source { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
419
+ .dsh-wallpaper-region-source .dsh-wallpaper-source-hint { margin: 0; }
420
+ .dsh-wallpaper-controls { min-width:0; margin:0; padding:0; border:0; }
421
+ .dsh-wallpaper-controls:disabled { opacity:.6; }
422
+ .dsh-wallpaper-launcher { padding: 20px; color: var(--dsw-alias-label-tertiary); font-size: 13px; }
423
+ .dsh-wallpaper-card { border: 1px solid var(--dsw-alias-border-l2); border-radius: 16px; background: rgba(127,127,127,.06); overflow: hidden; }
424
+ .dsh-wallpaper-source { display: grid; grid-template-columns: 138px minmax(0,1fr); gap: 14px; align-items: center; padding: 14px; }
425
+ .dsh-wallpaper-preview { aspect-ratio: 16 / 10; border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; background-color: rgba(127,127,127,.1); background-position: center; background-repeat: no-repeat; background-size: cover; box-shadow: inset 0 0 0 1px rgba(255,255,255,.03); }
426
+ .dsh-wallpaper-settings[data-wallpaper-target='sidebar'] .dsh-wallpaper-preview { aspect-ratio: 2 / 3; }
427
+ .dsh-wallpaper-preview[data-empty] { display: grid; place-items: center; color: var(--dsw-alias-label-tertiary); font-size: 12px; }
428
+ .dsh-wallpaper-source-copy { min-width: 0; }
429
+ .dsh-wallpaper-source-name { overflow: hidden; margin-bottom: 4px; color: var(--dsw-alias-label-primary); font-size: 14px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
430
+ .dsh-wallpaper-source-hint { margin: 0 0 12px; color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 18px; }
431
+ .dsh-wallpaper-actions { display: flex; flex-wrap: wrap; gap: 8px; }
432
+ .dsh-wallpaper-button { min-height: 34px; padding: 0 12px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; background: var(--dsw-alias-button-elevated-fill); color: inherit; font: inherit; font-size: 13px; font-weight: 600; cursor: pointer; }
433
+ .dsh-wallpaper-button:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-solid); }
434
+ .dsh-wallpaper-button:disabled { cursor: wait; opacity: .48; }
435
+ .dsh-wallpaper-button[data-danger] { color: var(--dsw-alias-state-error-primary); }
436
+ .dsh-wallpaper-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
437
+ .dsh-wallpaper-error { margin: 12px 16px 0; padding: 9px 11px; border-radius: 9px; color: var(--dsw-alias-state-error-primary); background: rgba(229,72,77,.1); font-size: 12px; line-height: 18px; }
438
+ .dsh-wallpaper-enable { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 13px 16px; border-top: 1px solid var(--dsw-alias-border-l1); }
439
+ .dsh-wallpaper-enable-copy { min-width: 0; }
440
+ .dsh-wallpaper-enable-title { font-size: 13px; font-weight: 600; line-height: 20px; }
441
+ .dsh-wallpaper-enable-hint { color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 18px; }
442
+ .dsh-wallpaper-switch { position: relative; flex: none; width: 40px; height: 22px; }
443
+ .dsh-wallpaper-switch input { position: absolute; opacity: 0; }
444
+ .dsh-wallpaper-switch span { position: absolute; inset: 0; border-radius: 999px; background: rgba(127,127,127,.32); cursor: pointer; transition: background .15s ease; }
445
+ .dsh-wallpaper-switch span::after { content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: white; box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .15s ease; }
446
+ .dsh-wallpaper-switch input:checked + span { background: var(--dsw-alias-state-business-primary); }
447
+ .dsh-wallpaper-switch input:checked + span::after { transform: translateX(18px); }
448
+ .dsh-wallpaper-switch input:disabled + span { cursor: not-allowed; opacity: .45; }
449
+ .dsh-wallpaper-section { margin-top: 20px; }
450
+ .dsh-wallpaper-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 0 2px 9px; }
451
+ .dsh-wallpaper-section-title { margin: 0; font-size: 13px; font-weight: 650; }
452
+ .dsh-wallpaper-section-note { color: var(--dsw-alias-label-tertiary); font-size: 11px; }
453
+ .dsh-wallpaper-grid { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 10px; }
454
+ .dsh-wallpaper-field { display: flex; flex-direction: column; gap: 7px; min-width: 0; padding: 12px 14px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 12px; background: rgba(127,127,127,.045); }
455
+ .dsh-wallpaper-field-label { display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--dsw-alias-label-secondary); font-size: 12px; font-weight: 600; }
456
+ .dsh-wallpaper-field-output { color: var(--dsw-alias-label-tertiary); font-variant-numeric: tabular-nums; font-weight: 500; }
457
+ .dsh-wallpaper-select-menu { display: flex; width: 100%; }
458
+ .dsh-wallpaper-select-trigger { display: flex; width: 100%; height: 36px; align-items: center; justify-content: space-between; gap: 12px; padding: 0 14px; border: 0; border-radius: 18px; outline: none; background: var(--dsw-alias-bg-module-platform); color: inherit; cursor: pointer; font: inherit; font-size: 14px; line-height: 22px; }
459
+ .dsh-wallpaper-select-trigger:hover, .dsh-wallpaper-select-trigger[aria-expanded='true'] { background: var(--dsw-alias-interactive-bg-hover); }
460
+ .dsh-wallpaper-select-trigger:focus-visible { box-shadow: 0 0 0 2px var(--dsw-alias-state-business-primary); }
461
+ .dsh-wallpaper-select-trigger svg { flex: none; }
462
+ .dsh-wallpaper-range-row { display: grid; grid-template-columns: minmax(0,1fr) 42px; gap: 10px; align-items: center; }
463
+ .dsh-wallpaper-field input[type='range'] { width: 100%; accent-color: var(--dsw-alias-state-business-primary); }
464
+ .dsh-wallpaper-number { text-align: right; color: var(--dsw-alias-label-secondary); font-size: 12px; font-variant-numeric: tabular-nums; }
465
+ .dsh-wallpaper-number-input { box-sizing: border-box; width: 64px; height: 30px; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; outline: none; background: var(--dsw-alias-bg-layer-1); color: inherit; text-align: right; font: inherit; font-size: 12px; font-variant-numeric: tabular-nums; }
466
+ .dsh-wallpaper-number-input:focus-visible { border-color: var(--dsw-alias-state-business-primary); }
467
+ .dsh-wallpaper-offset-row { grid-template-columns: minmax(0,1fr) 64px; }
468
+ .dsh-wallpaper-color-row { display: grid; grid-template-columns: 42px minmax(0,1fr); gap: 10px; align-items: center; }
469
+ .dsh-wallpaper-color { width: 42px; height: 34px; padding: 2px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 9px; background: transparent; cursor: pointer; }
470
+ .dsh-wallpaper-footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px; }
471
+ .dsh-wallpaper-footer .dsh-wallpaper-storage-note { flex: 1 1 200px; min-width: 0; }
472
+ .dsh-wallpaper-footer .dsh-wallpaper-button { flex: none; margin-left: auto; white-space: nowrap; }
473
+ .dsh-wallpaper-storage-note { color: var(--dsw-alias-label-tertiary); font-size: 11px; line-height: 17px; }
474
+ @media (max-width: 680px) {
475
+ .dsh-wallpaper-floating { border-radius: 15px; }
476
+ .dsh-wallpaper-source { grid-template-columns: 1fr; }
477
+ .dsh-wallpaper-preview { max-width: 260px; }
478
+ .dsh-wallpaper-grid { grid-template-columns: 1fr; }
479
+ .dsh-wallpaper-footer { align-items: stretch; flex-direction: column; }
480
+ .dsh-wallpaper-footer .dsh-wallpaper-storage-note { flex-basis: auto; }
481
+ }
482
+ @media (prefers-reduced-motion: reduce) {
483
+ .dsh-wallpaper-switch span, .dsh-wallpaper-switch span::after { transition: none; }
484
+ }
485
+ `;
486
+ function installStyles() {
487
+ const existing = document.querySelector(`style[data-plugin=${JSON.stringify(STYLE_ID)}]`);
488
+ const tag = document.createElement("style");
489
+ tag.dataset.plugin = STYLE_ID;
490
+ tag.textContent = STYLES;
491
+ if (existing === null) document.head.appendChild(tag);
492
+ else existing.replaceWith(tag);
493
+ return () => tag.remove();
494
+ }
495
+ async function readApiState(response) {
496
+ const payload = await response.json();
497
+ if (!response.ok) {
498
+ throw new Error(typeof payload.error === "string" ? payload.error : `HTTP ${response.status}`);
499
+ }
500
+ const settings = normalizeSettings(payload.settings);
501
+ const imageUrl = typeof payload.imageUrl === "string" ? payload.imageUrl : null;
502
+ const hasImage = payload.hasImage === true && imageUrl !== null;
503
+ const regionImage = (region) => {
504
+ const image = payload.regionImages?.[region];
505
+ return { hasImage: image?.hasImage === true, imageUrl: image?.hasImage === true && typeof image.imageUrl === "string" ? image.imageUrl : null };
506
+ };
507
+ return { settings, hasImage, imageUrl: hasImage ? imageUrl : null, regionImages: { settings: regionImage("settings"), sidebar: regionImage("sidebar") } };
508
+ }
509
+ async function validateImage(blob) {
510
+ const url = URL.createObjectURL(blob);
511
+ try {
512
+ await new Promise((resolve, reject) => {
513
+ const image = new Image();
514
+ image.onload = () => resolve();
515
+ image.onerror = () => reject(new Error("\u65E0\u6CD5\u8BFB\u53D6\u8FD9\u5F20\u56FE\u7247"));
516
+ image.src = url;
517
+ });
518
+ } finally {
519
+ URL.revokeObjectURL(url);
520
+ }
521
+ }
522
+ function cssUrl(url) {
523
+ return `url(${JSON.stringify(url)})`;
524
+ }
525
+ var WallpaperController = class {
526
+ settings = { ...DEFAULT_SETTINGS };
527
+ imageUrl = null;
528
+ regionImages = { settings: null, sidebar: null };
529
+ panelOpen = false;
530
+ mounted = false;
531
+ disposed = false;
532
+ persistTimer = null;
533
+ persistTail = Promise.resolve();
534
+ listeners = /* @__PURE__ */ new Set();
535
+ mediaLayer = null;
536
+ maskLayer = null;
537
+ panelHost = null;
538
+ panelRoot = null;
539
+ snapshot = {
540
+ settings: this.settings,
541
+ hasImage: false,
542
+ previewUrl: null,
543
+ regionImages: this.regionImages,
544
+ panelOpen: false,
545
+ loading: true,
546
+ error: null
547
+ };
548
+ subscribe = (listener) => {
549
+ this.listeners.add(listener);
550
+ return () => this.listeners.delete(listener);
551
+ };
552
+ getSnapshot = () => this.snapshot;
553
+ mount() {
554
+ if (this.mounted) return;
555
+ this.mounted = true;
556
+ this.disposed = false;
557
+ document.querySelectorAll(`[data-dsh-wallpaper-owner='${OWNER}']`).forEach((node) => node.remove());
558
+ document.body.removeAttribute(ACTIVE_ATTRIBUTE);
559
+ document.body.removeAttribute(REGIONS_ATTRIBUTE);
560
+ const media = document.createElement("div");
561
+ media.dataset.dshWallpaperOwner = OWNER;
562
+ media.dataset.dshWallpaperLayer = "media";
563
+ media.setAttribute("aria-hidden", "true");
564
+ const mask = document.createElement("div");
565
+ mask.dataset.dshWallpaperOwner = OWNER;
566
+ mask.dataset.dshWallpaperLayer = "mask";
567
+ mask.setAttribute("aria-hidden", "true");
568
+ const panelHost = document.createElement("div");
569
+ panelHost.dataset.dshWallpaperOwner = OWNER;
570
+ panelHost.dataset.dshWallpaperPanelRoot = "";
571
+ document.body.append(media, mask, panelHost);
572
+ this.mediaLayer = media;
573
+ this.maskLayer = mask;
574
+ this.panelHost = panelHost;
575
+ this.panelRoot = (0, import_client.createRoot)(panelHost);
576
+ this.panelRoot.render(/* @__PURE__ */ import_react.default.createElement(WallpaperFloatingPanel, { controller: this }));
577
+ this.applyVisualState();
578
+ void this.restoreState();
579
+ }
580
+ dispose() {
581
+ if (!this.mounted) return;
582
+ this.disposed = true;
583
+ this.mounted = false;
584
+ if (this.persistTimer !== null) {
585
+ window.clearTimeout(this.persistTimer);
586
+ this.persistTimer = null;
587
+ void this.queuePersist(this.settings);
588
+ }
589
+ this.imageUrl = null;
590
+ this.regionImages = { settings: null, sidebar: null };
591
+ this.panelOpen = false;
592
+ this.panelRoot?.unmount();
593
+ this.mediaLayer?.remove();
594
+ this.maskLayer?.remove();
595
+ this.panelHost?.remove();
596
+ this.mediaLayer = null;
597
+ this.maskLayer = null;
598
+ this.panelHost = null;
599
+ this.panelRoot = null;
600
+ document.body.removeAttribute(ACTIVE_ATTRIBUTE);
601
+ document.body.removeAttribute(REGIONS_ATTRIBUTE);
602
+ for (const variable of [...BODY_VARIABLES, ...REGION_VARIABLES]) document.body.style.removeProperty(variable);
603
+ this.listeners.clear();
604
+ }
605
+ openPanel() {
606
+ if (!this.mounted) return;
607
+ if (!this.panelOpen) {
608
+ this.panelOpen = true;
609
+ this.publish();
610
+ }
611
+ window.requestAnimationFrame(() => {
612
+ this.panelHost?.querySelector(".dsh-wallpaper-floating")?.focus({ preventScroll: true });
613
+ });
614
+ }
615
+ closePanel() {
616
+ if (!this.panelOpen) return;
617
+ this.panelOpen = false;
618
+ this.publish();
619
+ }
620
+ update(patch) {
621
+ this.settings = normalizeSettings({ ...this.settings, ...patch });
622
+ this.schedulePersist();
623
+ this.applyVisualState();
624
+ this.publish({ error: null });
625
+ }
626
+ updateRegion(region, patch) {
627
+ this.update({ regions: { ...this.settings.regions, [region]: { ...this.settings.regions[region], ...patch } } });
628
+ }
629
+ resetAppearance(target) {
630
+ if (target !== "global") {
631
+ this.updateRegion(target, { ...defaultRegionSettings(), imageName: this.settings.regions[target].imageName });
632
+ return;
633
+ }
634
+ this.settings = {
635
+ ...DEFAULT_SETTINGS,
636
+ regions: this.settings.regions,
637
+ enabled: this.settings.enabled,
638
+ imageName: this.settings.imageName
639
+ };
640
+ this.schedulePersist();
641
+ this.applyVisualState();
642
+ this.publish({ error: null });
643
+ }
644
+ async setImage(file, target) {
645
+ if (!file.type.startsWith("image/")) {
646
+ this.publish({ error: "\u8BF7\u9009\u62E9\u56FE\u7247\u6587\u4EF6\u3002" });
647
+ return;
648
+ }
649
+ this.publish({ loading: true, error: null });
650
+ try {
651
+ await validateImage(file);
652
+ await this.flushPersist();
653
+ const response = await fetch(`${API_BASE}/image?region=${target}`, {
654
+ method: "PUT",
655
+ headers: {
656
+ "Content-Type": file.type,
657
+ "X-DSH-Wallpaper-Filename": encodeURIComponent(file.name)
658
+ },
659
+ body: file
660
+ });
661
+ const state = await readApiState(response);
662
+ if (this.disposed) return;
663
+ this.acceptState(state);
664
+ this.applyVisualState();
665
+ this.publish({ loading: false, error: null });
666
+ } catch (error) {
667
+ if (!this.disposed) this.publish({ loading: false, error: String(error) });
668
+ }
669
+ }
670
+ async removeImage(target) {
671
+ this.publish({ loading: true, error: null });
672
+ try {
673
+ await this.flushPersist();
674
+ const state = await readApiState(await fetch(`${API_BASE}/image?region=${target}`, { method: "DELETE" }));
675
+ if (this.disposed) return;
676
+ this.acceptState(state);
677
+ this.applyVisualState();
678
+ this.publish({ loading: false, error: null });
679
+ } catch (error) {
680
+ if (!this.disposed) this.publish({ loading: false, error: String(error) });
681
+ }
682
+ }
683
+ clearError() {
684
+ if (this.snapshot.error !== null) this.publish({ error: null });
685
+ }
686
+ async restoreState() {
687
+ try {
688
+ const state = await readApiState(
689
+ await fetch(`${API_BASE}/state`, { method: "GET", cache: "no-store" })
690
+ );
691
+ if (this.disposed) return;
692
+ this.acceptState(state);
693
+ this.applyVisualState();
694
+ this.publish({ loading: false, error: null });
695
+ } catch (error) {
696
+ if (!this.disposed) {
697
+ this.applyVisualState();
698
+ this.publish({ loading: false, error: `\u8BFB\u53D6\u5DF2\u4FDD\u5B58\u7684\u58C1\u7EB8\u5931\u8D25\uFF1A${String(error)}` });
699
+ }
700
+ }
701
+ }
702
+ acceptState(state) {
703
+ this.settings = state.settings;
704
+ this.imageUrl = state.imageUrl;
705
+ this.regionImages = { settings: state.regionImages.settings.imageUrl, sidebar: state.regionImages.sidebar.imageUrl };
706
+ }
707
+ applyVisualState() {
708
+ if (!this.mounted) return;
709
+ const body = document.body;
710
+ const active = this.settings.enabled && this.imageUrl !== null;
711
+ const [r, g, b] = hexToRgb(this.settings.maskColor);
712
+ const [layer1, layer2, layer3] = surfaceLayerAlphas(this.settings.surfaceOpacity);
713
+ const style = modeStyle(this.settings.mode);
714
+ const overscan = Math.ceil(this.settings.blur * 2);
715
+ body.style.setProperty("--dsh-wallpaper-image-opacity", String(this.settings.imageOpacity));
716
+ body.style.setProperty("--dsh-wallpaper-blur", `${this.settings.blur}px`);
717
+ body.style.setProperty("--dsh-wallpaper-inset", `${-overscan}px`);
718
+ body.style.setProperty("--dsh-wallpaper-mask-rgb", `${r} ${g} ${b}`);
719
+ body.style.setProperty("--dsh-wallpaper-mask-opacity", String(this.settings.maskOpacity));
720
+ body.style.setProperty("--dsh-wallpaper-surface-alpha-1", String(layer1));
721
+ body.style.setProperty("--dsh-wallpaper-surface-alpha-2", String(layer2));
722
+ body.style.setProperty("--dsh-wallpaper-surface-alpha-3", String(layer3));
723
+ if (this.mediaLayer !== null) {
724
+ this.mediaLayer.style.backgroundImage = this.imageUrl === null ? "none" : cssUrl(this.imageUrl);
725
+ this.mediaLayer.style.backgroundSize = style.size;
726
+ this.mediaLayer.style.backgroundRepeat = style.repeat;
727
+ this.mediaLayer.style.backgroundPosition = backgroundPositionWithOffset(
728
+ this.settings.position,
729
+ this.settings.offsetXPercent,
730
+ this.settings.offsetYPercent
731
+ );
732
+ }
733
+ body.toggleAttribute(ACTIVE_ATTRIBUTE, active);
734
+ for (const [name2, value] of Object.entries(regionVariables(this.settings, this.imageUrl, this.regionImages))) body.style.setProperty(name2, value);
735
+ body.setAttribute(REGIONS_ATTRIBUTE, "");
736
+ }
737
+ schedulePersist() {
738
+ if (this.persistTimer !== null) window.clearTimeout(this.persistTimer);
739
+ this.persistTimer = window.setTimeout(() => {
740
+ this.persistTimer = null;
741
+ void this.queuePersist(this.settings);
742
+ }, SETTINGS_DEBOUNCE_MS);
743
+ }
744
+ flushPersist() {
745
+ if (this.persistTimer !== null) {
746
+ window.clearTimeout(this.persistTimer);
747
+ this.persistTimer = null;
748
+ return this.queuePersist(this.settings);
749
+ }
750
+ return this.persistTail;
751
+ }
752
+ queuePersist(settings) {
753
+ const payload = JSON.stringify(settings);
754
+ const persist = async () => {
755
+ try {
756
+ await readApiState(
757
+ await fetch(`${API_BASE}/settings`, {
758
+ method: "PUT",
759
+ headers: { "Content-Type": "application/json" },
760
+ body: payload
761
+ })
762
+ );
763
+ } catch (error) {
764
+ if (!this.disposed) this.publish({ error: `\u4FDD\u5B58\u8BBE\u7F6E\u5931\u8D25\uFF1A${String(error)}` });
765
+ }
766
+ };
767
+ const next = this.persistTail.then(persist, persist);
768
+ this.persistTail = next;
769
+ return next;
770
+ }
771
+ publish(patch = {}) {
772
+ this.snapshot = {
773
+ settings: this.settings,
774
+ hasImage: this.imageUrl !== null,
775
+ previewUrl: this.imageUrl,
776
+ regionImages: this.regionImages,
777
+ panelOpen: this.panelOpen,
778
+ loading: patch.loading ?? this.snapshot.loading,
779
+ error: patch.error === void 0 ? this.snapshot.error : patch.error
780
+ };
781
+ for (const listener of this.listeners) listener();
782
+ }
783
+ };
784
+ function pageController() {
785
+ const page = globalThis;
786
+ const current = page[PAGE_RUNTIME_KEY];
787
+ if (current?.buildToken === CLIENT_BUILD_TOKEN) return current.controller;
788
+ current?.controller.dispose();
789
+ const controller = new WallpaperController();
790
+ page[PAGE_RUNTIME_KEY] = { buildToken: CLIENT_BUILD_TOKEN, controller };
791
+ return controller;
792
+ }
793
+ function RangeField(props) {
794
+ return /* @__PURE__ */ import_react.default.createElement("label", { className: "dsh-wallpaper-field" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-label" }, /* @__PURE__ */ import_react.default.createElement("span", null, props.label), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-output" }, props.display)), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-range-row" }, /* @__PURE__ */ import_react.default.createElement(
795
+ "input",
796
+ {
797
+ type: "range",
798
+ min: props.min,
799
+ max: props.max,
800
+ step: props.step,
801
+ value: props.value,
802
+ onChange: (event) => props.onChange(Number(event.currentTarget.value))
803
+ }
804
+ ), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-number" }, props.display)));
805
+ }
806
+ function WallpaperSelect({
807
+ ariaLabel,
808
+ value,
809
+ options,
810
+ onChange
811
+ }) {
812
+ const [open, setOpen] = import_react.default.useState(false);
813
+ const selectedLabel = options.find((option) => option.value === value)?.label ?? value;
814
+ const items = import_react.default.useMemo(
815
+ () => options.map((option) => ({ id: option.value, label: option.label })),
816
+ [options]
817
+ );
818
+ return /* @__PURE__ */ import_react.default.createElement(
819
+ import_dsh_client_ui_primitives.Menu,
820
+ {
821
+ className: "dsh-wallpaper-select-menu",
822
+ open,
823
+ portal: true,
824
+ items,
825
+ selectedId: value,
826
+ onClose: () => setOpen(false),
827
+ onSelect: (id) => {
828
+ onChange(id);
829
+ setOpen(false);
830
+ },
831
+ anchor: /* @__PURE__ */ import_react.default.createElement(
832
+ "button",
833
+ {
834
+ type: "button",
835
+ className: "dsh-wallpaper-select-trigger",
836
+ "aria-label": `${ariaLabel}\uFF0C\u5F53\u524D\uFF1A${selectedLabel}`,
837
+ "aria-haspopup": "menu",
838
+ "aria-expanded": open,
839
+ onClick: () => setOpen((current) => !current)
840
+ },
841
+ /* @__PURE__ */ import_react.default.createElement("span", null, selectedLabel),
842
+ /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 16 })
843
+ )
844
+ }
845
+ );
846
+ }
847
+ function formatPercent(value) {
848
+ return `${Number.isInteger(value) ? value : value.toFixed(1)}%`;
849
+ }
850
+ function PercentOffsetField(props) {
851
+ return /* @__PURE__ */ import_react.default.createElement("label", { className: "dsh-wallpaper-field" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-label" }, /* @__PURE__ */ import_react.default.createElement("span", null, props.label), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-output" }, formatPercent(props.value))), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-range-row dsh-wallpaper-offset-row" }, /* @__PURE__ */ import_react.default.createElement(
852
+ "input",
853
+ {
854
+ type: "range",
855
+ min: -100,
856
+ max: 100,
857
+ step: 0.5,
858
+ value: props.value,
859
+ onChange: (event) => props.onChange(Number(event.currentTarget.value))
860
+ }
861
+ ), /* @__PURE__ */ import_react.default.createElement(
862
+ "input",
863
+ {
864
+ className: "dsh-wallpaper-number-input",
865
+ type: "number",
866
+ min: -100,
867
+ max: 100,
868
+ step: 0.5,
869
+ value: props.value,
870
+ onChange: (event) => {
871
+ const value = event.currentTarget.valueAsNumber;
872
+ if (Number.isFinite(value)) props.onChange(value);
873
+ },
874
+ "aria-label": `${props.label}\uFF08\u7A97\u53E3\u767E\u5206\u6BD4\uFF09`
875
+ }
876
+ )));
877
+ }
878
+ function WallpaperSettingsSection({ controller }) {
879
+ const snapshot = import_react.default.useSyncExternalStore(
880
+ controller.subscribe,
881
+ controller.getSnapshot,
882
+ controller.getSnapshot
883
+ );
884
+ const [target, setTarget] = import_react.default.useState("global");
885
+ const settings = target === "global" ? snapshot.settings : snapshot.settings.regions[target];
886
+ const source = target === "global" ? "custom" : snapshot.settings.regions[target].source;
887
+ const ownUrl = target === "global" ? snapshot.previewUrl : snapshot.regionImages[target];
888
+ const previewUrl = source === "global" ? snapshot.previewUrl : ownUrl;
889
+ const hasImage = ownUrl !== null;
890
+ const displayName = source === "global" ? snapshot.settings.imageName : settings.imageName;
891
+ const update = (patch) => {
892
+ if (target === "global") controller.update(patch);
893
+ else controller.updateRegion(target, patch);
894
+ };
895
+ const fileRef = import_react.default.useRef(null);
896
+ const mode = MODE_OPTIONS.find((option) => option.value === settings.mode) ?? MODE_OPTIONS[0];
897
+ const chooseImage = () => {
898
+ controller.clearError();
899
+ fileRef.current?.click();
900
+ };
901
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-settings", "data-wallpaper-target": target }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-targets", role: "group", "aria-label": "\u80CC\u666F\u8C03\u6574\u533A\u57DF" }, [["global", "\u4E3B\u754C\u9762"], ["settings", "\u8BBE\u7F6E\u9762\u677F"], ["sidebar", "\u53F3\u4FA7 Sidebar"]].map(([value, label]) => /* @__PURE__ */ import_react.default.createElement("button", { type: "button", key: value, "aria-pressed": target === value, onClick: () => setTarget(value) }, label))), /* @__PURE__ */ import_react.default.createElement("fieldset", { className: "dsh-wallpaper-controls", disabled: snapshot.loading }, target === "global" ? null : /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-region-source" }, /* @__PURE__ */ import_react.default.createElement(
902
+ WallpaperSelect,
903
+ {
904
+ ariaLabel: "\u80CC\u666F\u6765\u6E90",
905
+ value: source,
906
+ options: [
907
+ { value: "none", label: "\u4E0D\u4F7F\u7528\u58C1\u7EB8\uFF08\u9ED8\u8BA4\uFF09" },
908
+ { value: "custom", label: "\u4F7F\u7528\u72EC\u7ACB\u56FE\u7247" },
909
+ { value: "global", label: "\u4F7F\u7528\u4E3B\u754C\u9762\u56FE\u7247" }
910
+ ],
911
+ onChange: (source2) => controller.updateRegion(target, { source: source2 })
912
+ }
913
+ ), /* @__PURE__ */ import_react.default.createElement("p", { className: "dsh-wallpaper-source-hint" }, "\u53EA\u8C03\u6574", target === "settings" ? "\u5E94\u7528\u8BBE\u7F6E\u5F39\u7A97" : "\u53F3\u4FA7 Sidebar\uFF08\u5305\u62EC\u5206\u680F\u548C\u5168\u5C4F\uFF09", "\uFF0C\u4E0D\u5F71\u54CD\u5176\u4ED6\u533A\u57DF\u3002")), /* @__PURE__ */ import_react.default.createElement("section", { className: "dsh-wallpaper-card" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-source" }, /* @__PURE__ */ import_react.default.createElement(
914
+ "div",
915
+ {
916
+ className: "dsh-wallpaper-preview",
917
+ "data-empty": previewUrl === null ? true : void 0,
918
+ style: previewUrl === null ? void 0 : {
919
+ backgroundImage: cssUrl(previewUrl),
920
+ backgroundSize: modeStyle(settings.mode).size,
921
+ backgroundRepeat: modeStyle(settings.mode).repeat,
922
+ backgroundPosition: settings.position
923
+ }
924
+ },
925
+ previewUrl === null ? "\u5C1A\u672A\u9009\u62E9\u56FE\u7247" : null
926
+ ), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-source-copy" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-source-name" }, snapshot.loading ? "\u6B63\u5728\u8BFB\u53D6\u56FE\u7247\u2026" : displayName ?? "\u9009\u62E9\u4E00\u5F20\u672C\u673A\u56FE\u7247"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dsh-wallpaper-source-hint" }, "\u539F\u56FE\u4FDD\u5B58\u5728 Harness \u6570\u636E\u76EE\u5F55\u4E2D\uFF0C\u4E0D\u4F1A\u4E0A\u4F20\u5230\u5916\u90E8\u7F51\u7EDC\u3002"), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-actions" }, /* @__PURE__ */ import_react.default.createElement(
927
+ "button",
928
+ {
929
+ type: "button",
930
+ className: "dsh-wallpaper-button",
931
+ disabled: snapshot.loading,
932
+ onClick: chooseImage
933
+ },
934
+ target === "global" ? hasImage ? "\u66F4\u6362\u56FE\u7247" : "\u9009\u62E9\u56FE\u7247" : hasImage ? "\u66F4\u6362\u72EC\u7ACB\u56FE\u7247" : "\u9009\u62E9\u72EC\u7ACB\u56FE\u7247"
935
+ ), hasImage && source !== "global" ? /* @__PURE__ */ import_react.default.createElement(
936
+ "button",
937
+ {
938
+ type: "button",
939
+ className: "dsh-wallpaper-button",
940
+ "data-danger": true,
941
+ disabled: snapshot.loading,
942
+ onClick: () => void controller.removeImage(target)
943
+ },
944
+ "\u79FB\u9664"
945
+ ) : null), /* @__PURE__ */ import_react.default.createElement(
946
+ "input",
947
+ {
948
+ ref: fileRef,
949
+ className: "dsh-wallpaper-file",
950
+ type: "file",
951
+ accept: "image/*",
952
+ onChange: (event) => {
953
+ const file = event.currentTarget.files?.[0];
954
+ event.currentTarget.value = "";
955
+ if (file !== void 0) void controller.setImage(file, target);
956
+ }
957
+ }
958
+ ))), snapshot.error === null ? null : /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-error", role: "alert" }, snapshot.error), target === "global" ? /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-enable" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-enable-copy" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-enable-title" }, "\u542F\u7528\u4E3B\u754C\u9762\u58C1\u7EB8"), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-enable-hint" }, "\u5173\u95ED\u540E\u4FDD\u7559\u56FE\u7247\u548C\u6240\u6709\u8BBE\u7F6E\u3002")), /* @__PURE__ */ import_react.default.createElement("label", { className: "dsh-wallpaper-switch" }, /* @__PURE__ */ import_react.default.createElement(
959
+ "input",
960
+ {
961
+ type: "checkbox",
962
+ checked: snapshot.settings.enabled && hasImage,
963
+ disabled: !hasImage || snapshot.loading,
964
+ onChange: (event) => update({ enabled: event.currentTarget.checked }),
965
+ "aria-label": "\u542F\u7528\u4E3B\u754C\u9762\u58C1\u7EB8"
966
+ }
967
+ ), /* @__PURE__ */ import_react.default.createElement("span", null))) : null), /* @__PURE__ */ import_react.default.createElement("section", { className: "dsh-wallpaper-section" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-section-head" }, /* @__PURE__ */ import_react.default.createElement("h4", { className: "dsh-wallpaper-section-title" }, "\u56FE\u7247\u5E03\u5C40"), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-section-note" }, mode.hint)), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-grid" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-field" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-label" }, "\u9002\u5E94\u6A21\u5F0F"), /* @__PURE__ */ import_react.default.createElement(
968
+ WallpaperSelect,
969
+ {
970
+ ariaLabel: "\u9002\u5E94\u6A21\u5F0F",
971
+ value: settings.mode,
972
+ options: MODE_OPTIONS,
973
+ onChange: (mode2) => update({ mode: mode2 })
974
+ }
975
+ )), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-field" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-label" }, "\u56FE\u7247\u4F4D\u7F6E"), /* @__PURE__ */ import_react.default.createElement(
976
+ WallpaperSelect,
977
+ {
978
+ ariaLabel: "\u56FE\u7247\u4F4D\u7F6E",
979
+ value: settings.position,
980
+ options: POSITION_OPTIONS,
981
+ onChange: (position) => update({ position })
982
+ }
983
+ )), /* @__PURE__ */ import_react.default.createElement(
984
+ PercentOffsetField,
985
+ {
986
+ label: "\u6A2A\u5411\u504F\u79FB",
987
+ value: settings.offsetXPercent,
988
+ onChange: (offsetXPercent) => update({ offsetXPercent })
989
+ }
990
+ ), /* @__PURE__ */ import_react.default.createElement(
991
+ PercentOffsetField,
992
+ {
993
+ label: "\u7EB5\u5411\u504F\u79FB",
994
+ value: settings.offsetYPercent,
995
+ onChange: (offsetYPercent) => update({ offsetYPercent })
996
+ }
997
+ ))), /* @__PURE__ */ import_react.default.createElement("section", { className: "dsh-wallpaper-section" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-section-head" }, /* @__PURE__ */ import_react.default.createElement("h4", { className: "dsh-wallpaper-section-title" }, "\u56FE\u7247\u6548\u679C"), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-section-note" }, "\u5B9E\u65F6\u9884\u89C8")), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-grid" }, /* @__PURE__ */ import_react.default.createElement(
998
+ RangeField,
999
+ {
1000
+ label: "\u56FE\u7247\u4E0D\u900F\u660E\u5EA6",
1001
+ min: 0,
1002
+ max: 1,
1003
+ step: 0.01,
1004
+ value: settings.imageOpacity,
1005
+ display: `${Math.round(settings.imageOpacity * 100)}%`,
1006
+ onChange: (imageOpacity) => update({ imageOpacity })
1007
+ }
1008
+ ), /* @__PURE__ */ import_react.default.createElement(
1009
+ RangeField,
1010
+ {
1011
+ label: "\u80CC\u666F\u6A21\u7CCA",
1012
+ min: 0,
1013
+ max: 40,
1014
+ step: 1,
1015
+ value: settings.blur,
1016
+ display: `${Math.round(settings.blur)}px`,
1017
+ onChange: (blur) => update({ blur })
1018
+ }
1019
+ ))), /* @__PURE__ */ import_react.default.createElement("section", { className: "dsh-wallpaper-section" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-section-head" }, /* @__PURE__ */ import_react.default.createElement("h4", { className: "dsh-wallpaper-section-title" }, "\u906E\u7F69\u4E0E\u754C\u9762"), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-section-note" }, "\u4FDD\u6301\u6587\u5B57\u53EF\u8BFB\u6027")), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-grid" }, /* @__PURE__ */ import_react.default.createElement("label", { className: "dsh-wallpaper-field" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-label" }, /* @__PURE__ */ import_react.default.createElement("span", null, "\u906E\u7F69\u989C\u8272"), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-field-output" }, settings.maskColor)), /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-color-row" }, /* @__PURE__ */ import_react.default.createElement(
1020
+ "input",
1021
+ {
1022
+ className: "dsh-wallpaper-color",
1023
+ type: "color",
1024
+ value: settings.maskColor,
1025
+ onChange: (event) => update({ maskColor: event.currentTarget.value }),
1026
+ "aria-label": "\u906E\u7F69\u989C\u8272"
1027
+ }
1028
+ ), /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-source-hint", style: { margin: 0 } }, "\u56FE\u7247\u4E0A\u65B9\u7684\u7EDF\u4E00\u989C\u8272\u5C42"))), /* @__PURE__ */ import_react.default.createElement(
1029
+ RangeField,
1030
+ {
1031
+ label: "\u906E\u7F69\u5F3A\u5EA6",
1032
+ min: 0,
1033
+ max: 0.9,
1034
+ step: 0.01,
1035
+ value: settings.maskOpacity,
1036
+ display: `${Math.round(settings.maskOpacity * 100)}%`,
1037
+ onChange: (maskOpacity) => update({ maskOpacity })
1038
+ }
1039
+ ), target === "global" ? /* @__PURE__ */ import_react.default.createElement(
1040
+ RangeField,
1041
+ {
1042
+ label: "\u754C\u9762\u586B\u5145",
1043
+ min: 0,
1044
+ max: 0.95,
1045
+ step: 0.01,
1046
+ value: settings.surfaceOpacity,
1047
+ display: `${Math.round(settings.surfaceOpacity * 100)}%`,
1048
+ onChange: (surfaceOpacity) => update({ surfaceOpacity })
1049
+ }
1050
+ ) : /* @__PURE__ */ import_react.default.createElement(
1051
+ RangeField,
1052
+ {
1053
+ label: "\u80CC\u666F\u4E0D\u900F\u660E\u5EA6",
1054
+ min: 0,
1055
+ max: 100,
1056
+ step: 1,
1057
+ value: Math.round(settings.surfaceOpacity * 100),
1058
+ display: `${Math.round(settings.surfaceOpacity * 100)}%`,
1059
+ onChange: (opacity) => update({ surfaceOpacity: opacity / 100 })
1060
+ }
1061
+ ))), /* @__PURE__ */ import_react.default.createElement("footer", { className: "dsh-wallpaper-footer" }, /* @__PURE__ */ import_react.default.createElement("span", { className: "dsh-wallpaper-storage-note" }, "\u6A21\u7CCA\u53EA\u4F5C\u7528\u4E8E\u80CC\u666F\u56FE\u7247\uFF0C\u4E0D\u4F1A\u6539\u53D8\u6587\u5B57\u3001\u83DC\u5355\u6216\u5F39\u7A97\u7684\u5B9A\u4F4D\u3002"), /* @__PURE__ */ import_react.default.createElement("button", { type: "button", className: "dsh-wallpaper-button", onClick: () => controller.resetAppearance(target) }, "\u6062\u590D\u9ED8\u8BA4\u6548\u679C"))));
1062
+ }
1063
+ function defaultPanelPosition() {
1064
+ return {
1065
+ x: Math.max(PANEL_MARGIN, window.innerWidth - 480 - 24),
1066
+ y: Math.min(84, Math.max(PANEL_MARGIN, window.innerHeight - 240))
1067
+ };
1068
+ }
1069
+ function readPanelPosition() {
1070
+ try {
1071
+ const saved = JSON.parse(window.localStorage.getItem(PANEL_POSITION_KEY) ?? "null");
1072
+ if (saved !== null && typeof saved.x === "number" && typeof saved.y === "number" && Number.isFinite(saved.x) && Number.isFinite(saved.y)) {
1073
+ return { x: saved.x, y: saved.y };
1074
+ }
1075
+ } catch {
1076
+ }
1077
+ return defaultPanelPosition();
1078
+ }
1079
+ function savePanelPosition(position) {
1080
+ try {
1081
+ window.localStorage.setItem(PANEL_POSITION_KEY, JSON.stringify(position));
1082
+ } catch {
1083
+ }
1084
+ }
1085
+ function clampPanelPosition(position, panel) {
1086
+ const width = panel?.offsetWidth ?? Math.min(480, Math.max(0, window.innerWidth - PANEL_MARGIN * 2));
1087
+ const height = panel?.offsetHeight ?? Math.min(760, Math.max(0, window.innerHeight - PANEL_MARGIN * 2));
1088
+ const maxX = Math.max(PANEL_MARGIN, window.innerWidth - width - PANEL_MARGIN);
1089
+ const maxY = Math.max(PANEL_MARGIN, window.innerHeight - height - PANEL_MARGIN);
1090
+ return {
1091
+ x: Math.round(Math.min(maxX, Math.max(PANEL_MARGIN, position.x))),
1092
+ y: Math.round(Math.min(maxY, Math.max(PANEL_MARGIN, position.y)))
1093
+ };
1094
+ }
1095
+ function samePanelPosition(left, right) {
1096
+ return left.x === right.x && left.y === right.y;
1097
+ }
1098
+ function WallpaperFloatingPanel({ controller }) {
1099
+ const snapshot = import_react.default.useSyncExternalStore(
1100
+ controller.subscribe,
1101
+ controller.getSnapshot,
1102
+ controller.getSnapshot
1103
+ );
1104
+ const panelRef = import_react.default.useRef(null);
1105
+ const dragRef = import_react.default.useRef(null);
1106
+ const [position, setPosition] = import_react.default.useState(readPanelPosition);
1107
+ import_react.default.useLayoutEffect(() => {
1108
+ if (!snapshot.panelOpen) return;
1109
+ setPosition((current) => {
1110
+ const next = clampPanelPosition(current, panelRef.current);
1111
+ return samePanelPosition(current, next) ? current : next;
1112
+ });
1113
+ }, [snapshot.panelOpen]);
1114
+ import_react.default.useEffect(() => {
1115
+ savePanelPosition(position);
1116
+ }, [position]);
1117
+ import_react.default.useEffect(() => {
1118
+ if (!snapshot.panelOpen) return;
1119
+ const handleResize = () => {
1120
+ setPosition((current) => {
1121
+ const next = clampPanelPosition(current, panelRef.current);
1122
+ return samePanelPosition(current, next) ? current : next;
1123
+ });
1124
+ };
1125
+ window.addEventListener("resize", handleResize);
1126
+ return () => window.removeEventListener("resize", handleResize);
1127
+ }, [snapshot.panelOpen]);
1128
+ if (!snapshot.panelOpen) return null;
1129
+ const startDrag = (event) => {
1130
+ if (event.button !== 0) return;
1131
+ if (event.target.closest("button, input, select, textarea, a")) return;
1132
+ const rect = panelRef.current?.getBoundingClientRect();
1133
+ const start = clampPanelPosition(
1134
+ rect === void 0 ? position : { x: rect.left, y: rect.top },
1135
+ panelRef.current
1136
+ );
1137
+ setPosition(start);
1138
+ dragRef.current = {
1139
+ pointerId: event.pointerId,
1140
+ clientX: event.clientX,
1141
+ clientY: event.clientY,
1142
+ x: start.x,
1143
+ y: start.y
1144
+ };
1145
+ event.currentTarget.setPointerCapture(event.pointerId);
1146
+ event.preventDefault();
1147
+ };
1148
+ const moveDrag = (event) => {
1149
+ const drag = dragRef.current;
1150
+ if (drag === null || drag.pointerId !== event.pointerId) return;
1151
+ setPosition(
1152
+ clampPanelPosition(
1153
+ {
1154
+ x: drag.x + event.clientX - drag.clientX,
1155
+ y: drag.y + event.clientY - drag.clientY
1156
+ },
1157
+ panelRef.current
1158
+ )
1159
+ );
1160
+ };
1161
+ const finishDrag = (event) => {
1162
+ if (dragRef.current?.pointerId !== event.pointerId) return;
1163
+ dragRef.current = null;
1164
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
1165
+ event.currentTarget.releasePointerCapture(event.pointerId);
1166
+ }
1167
+ };
1168
+ return /* @__PURE__ */ import_react.default.createElement(
1169
+ "div",
1170
+ {
1171
+ ref: panelRef,
1172
+ className: "dsh-wallpaper-floating",
1173
+ role: "dialog",
1174
+ "aria-modal": "false",
1175
+ "aria-label": "\u56FE\u7247\u58C1\u7EB8\u8BBE\u7F6E",
1176
+ tabIndex: -1,
1177
+ style: { left: position.x, top: position.y },
1178
+ onKeyDown: (event) => {
1179
+ if (event.key === "Escape") {
1180
+ event.stopPropagation();
1181
+ controller.closePanel();
1182
+ }
1183
+ }
1184
+ },
1185
+ /* @__PURE__ */ import_react.default.createElement(
1186
+ "div",
1187
+ {
1188
+ className: "dsh-wallpaper-floating-header",
1189
+ onPointerDown: startDrag,
1190
+ onPointerMove: moveDrag,
1191
+ onPointerUp: finishDrag,
1192
+ onPointerCancel: finishDrag
1193
+ },
1194
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-floating-heading" }, /* @__PURE__ */ import_react.default.createElement("h3", { className: "dsh-wallpaper-floating-title" }, "\u56FE\u7247\u58C1\u7EB8"), /* @__PURE__ */ import_react.default.createElement("p", { className: "dsh-wallpaper-floating-subtitle" }, "\u62D6\u52A8\u6807\u9898\u680F\u79FB\u52A8 \xB7 \u8C03\u6574\u65F6\u53EF\u76F4\u63A5\u67E5\u770B\u4E3B\u754C\u9762\u6548\u679C")),
1195
+ /* @__PURE__ */ import_react.default.createElement(
1196
+ "button",
1197
+ {
1198
+ type: "button",
1199
+ className: "dsh-wallpaper-close",
1200
+ onClick: () => controller.closePanel(),
1201
+ "aria-label": "\u5173\u95ED\u58C1\u7EB8\u8BBE\u7F6E",
1202
+ title: "\u5173\u95ED"
1203
+ },
1204
+ /* @__PURE__ */ import_react.default.createElement(import_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
1205
+ )
1206
+ ),
1207
+ /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-floating-body" }, /* @__PURE__ */ import_react.default.createElement(WallpaperSettingsSection, { controller }))
1208
+ );
1209
+ }
1210
+ function WallpaperSettingsLauncher({
1211
+ controller,
1212
+ close
1213
+ }) {
1214
+ const launched = import_react.default.useRef(false);
1215
+ import_react.default.useEffect(() => {
1216
+ if (launched.current) return;
1217
+ launched.current = true;
1218
+ controller.openPanel();
1219
+ close();
1220
+ }, [close, controller]);
1221
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "dsh-wallpaper-launcher" }, "\u6B63\u5728\u6253\u5F00\u56FE\u7247\u58C1\u7EB8\u9762\u677F\u2026");
1222
+ }
1223
+ function apply(ctx) {
1224
+ ctx.effect(installStyles, "dsh-wallpaper: client styles");
1225
+ const controller = pageController();
1226
+ ctx.effect(() => {
1227
+ controller.mount();
1228
+ }, "dsh-wallpaper.page-background");
1229
+ ctx.slots.inject(
1230
+ "settings.section",
1231
+ () => ctx.slots.register(
1232
+ {
1233
+ name: "settings.section",
1234
+ id: "wallpaper",
1235
+ order: 35,
1236
+ label: "\u58C1\u7EB8"
1237
+ },
1238
+ (props) => /* @__PURE__ */ import_react.default.createElement(WallpaperSettingsLauncher, { controller, close: props.close })
1239
+ )
1240
+ );
1241
+ }
1242
+
1243
+ return module.exports;
1244
+ }
1245
+ });