@1outres/dsh-plugin-background 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/lib/client.js +112 -21
  2. package/package.json +4 -1
package/lib/client.js CHANGED
@@ -104,6 +104,7 @@ window.__ModuleLoader__.load({
104
104
  title: "Background",
105
105
  description: "Paint an image behind the whole interface. Point at an absolute path on the machine running DSH, or at an https URL.",
106
106
  enable: "Enable background",
107
+ enableHint: "Turns the wallpaper off without clearing the image or the readability controls.",
107
108
  image: "Image path or URL",
108
109
  imageHint: "Absolute local path, for example /home/you/wallpaper.jpg, or an https:// URL. Local images are served through the authenticated file route, so they never leave the Host.",
109
110
  invalidImage: "Enter an absolute path or an http(s) URL.",
@@ -126,6 +127,7 @@ window.__ModuleLoader__.load({
126
127
  };
127
128
 
128
129
  // src/client/SettingsPage.tsx
130
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
129
131
  var import_react = require("react");
130
132
  var import_jsx_runtime = require("react/jsx-runtime");
131
133
  var FIELDS = ["enabled", "image", "panelOpacity", "dim", "blur"];
@@ -166,6 +168,21 @@ window.__ModuleLoader__.load({
166
168
  fontSize: 12,
167
169
  lineHeight: 1.5
168
170
  };
171
+ var switchHintStyle = {
172
+ ...hintStyle,
173
+ marginTop: 4
174
+ };
175
+ var switchRowStyle = {
176
+ display: "flex",
177
+ alignItems: "center",
178
+ justifyContent: "space-between",
179
+ gap: 24,
180
+ marginTop: 22
181
+ };
182
+ var switchTitleStyle = {
183
+ fontSize: 13,
184
+ fontWeight: 600
185
+ };
169
186
  var errorStyle = {
170
187
  margin: 0,
171
188
  color: "var(--dsw-alias-state-error-primary)",
@@ -214,6 +231,51 @@ window.__ModuleLoader__.load({
214
231
  fontSize: 13,
215
232
  lineHeight: 1.6
216
233
  };
234
+ var SLIDER_COMMIT_DELAY = 300;
235
+ function useSliderDraft(committed, commit) {
236
+ const [value, setValue] = (0, import_react.useState)(committed);
237
+ const latest = (0, import_react.useRef)(committed);
238
+ const dirty = (0, import_react.useRef)(false);
239
+ const inFlight = (0, import_react.useRef)(0);
240
+ const timer = (0, import_react.useRef)(void 0);
241
+ (0, import_react.useEffect)(() => {
242
+ if (dirty.current || inFlight.current > 0) return;
243
+ latest.current = committed;
244
+ setValue(committed);
245
+ }, [committed]);
246
+ (0, import_react.useEffect)(
247
+ () => () => {
248
+ window.clearTimeout(timer.current);
249
+ },
250
+ []
251
+ );
252
+ const send = () => {
253
+ window.clearTimeout(timer.current);
254
+ timer.current = void 0;
255
+ if (!dirty.current) return;
256
+ dirty.current = false;
257
+ const sent = latest.current;
258
+ inFlight.current += 1;
259
+ void commit(sent).then((accepted) => {
260
+ inFlight.current -= 1;
261
+ if (accepted || dirty.current || inFlight.current > 0) return;
262
+ latest.current = committed;
263
+ setValue(committed);
264
+ });
265
+ };
266
+ const change = (next) => {
267
+ if (next === latest.current) return;
268
+ latest.current = next;
269
+ dirty.current = true;
270
+ setValue(next);
271
+ window.clearTimeout(timer.current);
272
+ timer.current = window.setTimeout(send, SLIDER_COMMIT_DELAY);
273
+ };
274
+ const flush = () => {
275
+ send();
276
+ };
277
+ return { value, change, flush };
278
+ }
217
279
  function SettingsPage({ form, t }) {
218
280
  const subscribe = (0, import_react.useCallback)((listener) => form.subscribe(listener), [form]);
219
281
  const getSnapshot = (0, import_react.useCallback)(() => form.getSnapshot(), [form]);
@@ -231,12 +293,22 @@ window.__ModuleLoader__.load({
231
293
  const draftSource = resolveImageSource(draft, document.baseURI);
232
294
  const draftInvalid = draft.trim().length > 0 && draftSource === void 0;
233
295
  const previewFailed = previewFailure !== null && previewFailure.src === source && previewFailure.failed;
234
- const write = (field, value) => {
235
- void form.set(field, value).then((accepted) => setWriteError(!accepted)).catch(() => setWriteError(true));
236
- };
296
+ const write = (field, value) => form.set(field, value).then(
297
+ (accepted) => {
298
+ setWriteError(!accepted);
299
+ return accepted;
300
+ },
301
+ () => {
302
+ setWriteError(true);
303
+ return false;
304
+ }
305
+ );
306
+ const opacitySlider = useSliderDraft(config.panelOpacity, (value) => write("panelOpacity", value));
307
+ const dimSlider = useSliderDraft(config.dim, (value) => write("dim", value));
308
+ const blurSlider = useSliderDraft(config.blur, (value) => write("blur", value));
237
309
  const commitImage = () => {
238
310
  const next = draft.trim();
239
- if (next !== config.image) write("image", next);
311
+ if (next !== config.image) void write("image", next);
240
312
  };
241
313
  const onImageChange = (event) => {
242
314
  setDraft(event.target.value);
@@ -254,23 +326,30 @@ window.__ModuleLoader__.load({
254
326
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: mutedStyle, children: t("unavailable") });
255
327
  }
256
328
  const disabled = snapshot.writable === false;
257
- const dim = dimColor(config.dim);
258
- const alpha = clamp(config.panelOpacity, 0, 100) / 100;
329
+ const dim = dimColor(dimSlider.value);
330
+ const alpha = clamp(opacitySlider.value, 0, 100) / 100;
331
+ const blur = clamp(blurSlider.value, 0, 40);
259
332
  const dark = document.body.hasAttribute("data-ds-dark-theme");
260
333
  const surfaceColor = dark ? `rgba(21, 21, 23, ${alpha})` : `rgba(255, 255, 255, ${alpha})`;
261
334
  const surfaceText = dark ? "#e9ecf2" : "#0f1115";
262
335
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: sectionStyle, children: [
263
336
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: headingStyle, children: t("title") }),
264
337
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: introStyle, children: t("description") }),
265
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { ...labelRowStyle, marginTop: 22, cursor: "pointer" }, children: [
266
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("enable") }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: switchRowStyle, children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { minWidth: 0 }, children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: switchTitleStyle, children: t("enable") }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: switchHintStyle, children: t("enableHint") })
342
+ ] }),
267
343
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
268
- "input",
344
+ import_dsh_client_ui_primitives.Switch,
269
345
  {
270
- type: "checkbox",
271
346
  checked: config.enabled,
272
347
  disabled,
273
- onChange: (event) => write("enabled", event.target.checked)
348
+ label: t("enable"),
349
+ title: disabled ? t("readOnly") : void 0,
350
+ onChange: (next) => {
351
+ void write("enabled", next);
352
+ }
274
353
  }
275
354
  )
276
355
  ] }),
@@ -307,7 +386,7 @@ window.__ModuleLoader__.load({
307
386
  backgroundImage: imageCssValue(source),
308
387
  backgroundPosition: "center",
309
388
  backgroundSize: "cover",
310
- filter: `blur(${clamp(config.blur, 0, 40)}px)`,
389
+ filter: `blur(${blur}px)`,
311
390
  transform: "scale(1.06)"
312
391
  }
313
392
  }
@@ -364,7 +443,7 @@ window.__ModuleLoader__.load({
364
443
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: labelRowStyle, htmlFor: "dsh-background-panel-opacity", children: [
365
444
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("panelOpacity") }),
366
445
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: mutedStyle, children: [
367
- Math.round(config.panelOpacity),
446
+ Math.round(opacitySlider.value),
368
447
  "%"
369
448
  ] })
370
449
  ] }),
@@ -376,10 +455,14 @@ window.__ModuleLoader__.load({
376
455
  min: 0,
377
456
  max: 100,
378
457
  step: 1,
379
- value: config.panelOpacity,
458
+ value: opacitySlider.value,
380
459
  disabled,
381
460
  style: sliderStyle,
382
- onChange: (event) => write("panelOpacity", Number(event.target.value))
461
+ onChange: (event) => opacitySlider.change(Number(event.target.value)),
462
+ onPointerUp: opacitySlider.flush,
463
+ onPointerCancel: opacitySlider.flush,
464
+ onKeyUp: opacitySlider.flush,
465
+ onBlur: opacitySlider.flush
383
466
  }
384
467
  ),
385
468
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: hintStyle, children: t("panelOpacityHint") })
@@ -388,7 +471,7 @@ window.__ModuleLoader__.load({
388
471
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: labelRowStyle, htmlFor: "dsh-background-dim", children: [
389
472
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("dim") }),
390
473
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: mutedStyle, children: [
391
- Math.round(config.dim),
474
+ Math.round(dimSlider.value),
392
475
  "%"
393
476
  ] })
394
477
  ] }),
@@ -400,10 +483,14 @@ window.__ModuleLoader__.load({
400
483
  min: 0,
401
484
  max: 100,
402
485
  step: 1,
403
- value: config.dim,
486
+ value: dimSlider.value,
404
487
  disabled,
405
488
  style: sliderStyle,
406
- onChange: (event) => write("dim", Number(event.target.value))
489
+ onChange: (event) => dimSlider.change(Number(event.target.value)),
490
+ onPointerUp: dimSlider.flush,
491
+ onPointerCancel: dimSlider.flush,
492
+ onKeyUp: dimSlider.flush,
493
+ onBlur: dimSlider.flush
407
494
  }
408
495
  ),
409
496
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: hintStyle, children: t("dimHint") })
@@ -412,7 +499,7 @@ window.__ModuleLoader__.load({
412
499
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: labelRowStyle, htmlFor: "dsh-background-blur", children: [
413
500
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("blur") }),
414
501
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: mutedStyle, children: [
415
- Math.round(config.blur),
502
+ Math.round(blurSlider.value),
416
503
  " px"
417
504
  ] })
418
505
  ] }),
@@ -424,10 +511,14 @@ window.__ModuleLoader__.load({
424
511
  min: 0,
425
512
  max: 40,
426
513
  step: 1,
427
- value: config.blur,
514
+ value: blurSlider.value,
428
515
  disabled,
429
516
  style: sliderStyle,
430
- onChange: (event) => write("blur", Number(event.target.value))
517
+ onChange: (event) => blurSlider.change(Number(event.target.value)),
518
+ onPointerUp: blurSlider.flush,
519
+ onPointerCancel: blurSlider.flush,
520
+ onKeyUp: blurSlider.flush,
521
+ onBlur: blurSlider.flush
431
522
  }
432
523
  ),
433
524
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: hintStyle, children: t("blurHint") })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1outres/dsh-plugin-background",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Set a background image behind the DeepSeek Harness Web UI, with panel opacity, dim and blur controls.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -55,5 +55,8 @@
55
55
  ]
56
56
  }
57
57
  },
58
+ "devDependencies": {
59
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.5"
60
+ },
58
61
  "scripts": {}
59
62
  }