dsh-any-background 0.1.9 → 0.2.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 +9 -2
- package/README.zh.md +9 -2
- package/lib/client.js +258 -43
- package/lib/client.js.map +1 -1
- package/lib/index.js +8 -4
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -65,8 +65,8 @@ A **DeepSeek Harness** appearance plugin that lets you fully customize the Web U
|
|
|
65
65
|
- **Position Editor** — One shared editor for images and videos: drag to pan, scroll to zoom, one-click reset. Image and video placements are stored separately and never overwrite each other.
|
|
66
66
|
- **Layout Modes** — Fit / Fill / Stretch / Tile / Center for both images and videos; in Fit mode the editor-committed framing stays consistent across window resizes and cross-monitor moves.
|
|
67
67
|
- **Generated Dynamic Backgrounds** — Choose mesh gradient, Shader, or geometric patterns with adjustable spread, intensity, and seed locking.
|
|
68
|
-
- **Per-part Interface Opacity** — Independent sliders for main background, sidebar, cards & panels, plus the settings panel and wallpaper.
|
|
69
|
-
- **Per-part Interface Blur** — Frosted-glass `backdrop-filter` blur (0–60 px) for each interface part.
|
|
68
|
+
- **Per-part Interface Opacity** — Independent sliders for the main background, sidebar, cards & panels (including the dropdowns and menus around the dialog), the input & controls (composer box, Cordis panel), plus the settings panel and wallpaper.
|
|
69
|
+
- **Per-part Interface Blur** — Frosted-glass `backdrop-filter` blur (0–60 px) for each interface part, including a real backdrop on the composer and Cordis panel via stable host selectors.
|
|
70
70
|
- **Conversation View Cards** — The message list is wrapped in a translucent card automatically, and the trajectory page gets whole-page opacity & blur controls, letting the wallpaper shine through the content.
|
|
71
71
|
- **Theme Export / Import** — One-click export to a self-contained `dsh-any-theme.json` (config + wallpaper, video embedded as a data URL) and import to restore it anywhere.
|
|
72
72
|
- **File-based Persistence** — All settings are stored on the filesystem under `~/.dsh/.dsh-any-background-data/`, not `localStorage`.
|
|
@@ -84,6 +84,13 @@ A **DeepSeek Harness** appearance plugin that lets you fully customize the Web U
|
|
|
84
84
|
- **Inspiration palette selection cleared** — Picking a theme color from the wheel deselects any previously selected inspiration swatch.
|
|
85
85
|
- **Debug telemetry removed** — Temporary boot-time logging and `MutationObserver` instrumentation have been cleaned out.
|
|
86
86
|
- **Per-part blur isolated** — Blur is applied on `::before` underlays so it never traps the host's fixed-position settings dialog.
|
|
87
|
+
- **New "Input & controls" part** — The composer box, slash menu, and Cordis plugin panel own a dedicated opacity slider; their translucent surfaces get real frosted-glass backdrop blur attached through stable host data attributes (`[data-composer-card]`, `[data-cordis-panel]`).
|
|
88
|
+
- **Native control contrast fixed** — Solid surface tokens (composer, menus, Cordis panel) now carry per-part alpha, and a forced `color-scheme` keeps native `<select>` popups legible — no more white-on-white when the wallpaper brightness verdict flips labels to white.
|
|
89
|
+
- **Translucency without self-damage** — The "Input & controls" opacity slider is deliberately decoupled from the settings panel's own controls (which share the same button tokens), so adjusting it can never bleach the plugin's own sliders and buttons.
|
|
90
|
+
- **Drag-time performance** — Opacity tokens are written as CSS variables on `<html>` instead of rebuilding the whole token stylesheet per tick; slider updates are coalesced to one rAF per frame; the main-background columns are only retinted when their own slider changes.
|
|
91
|
+
- **Drag-time wallpaper downscaling** — While any slider is being dragged the wallpaper swaps to a (~720px) low-res copy for cheap rasterization over large images, then restores full resolution on release.
|
|
92
|
+
- **Instant video playback on import** — A picked video starts playing immediately from a local object URL while its raw bytes stream to disk in the background; the persisted serve URL takes over on the next reload — no more upload + first-buffer wait after import.
|
|
93
|
+
- **Option boxes follow the card slider** — The dropdowns, slash-trigger menu, model selector, and popovers around the dialog now follow the "Cards & panels" opacity slider instead of "Input & controls"; the Cordis panel keeps its own input-slider binding.
|
|
87
94
|
|
|
88
95
|
## Installation
|
|
89
96
|
|
package/README.zh.md
CHANGED
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
- **位置编辑器** — 图片与视频共用同一套编辑器:拖动平移、滚轮缩放、一键重置;图片与视频的位置状态各自独立保存,互不覆盖。
|
|
66
66
|
- **布局模式** — 适应 / 填充 / 拉伸 / 平铺 / 居中五种排布,图片与视频通用;「适应」模式下编辑器提交的构图在窗口缩放、跨屏移动后保持一致。
|
|
67
67
|
- **动态生成背景** — 支持网格渐变、Shader、几何图案,可调节扩散范围、色彩强度并锁定种子。
|
|
68
|
-
- **分部位界面透明度** —
|
|
69
|
-
- **分部位界面模糊度** — 每个界面部位可独立调整毛玻璃 `backdrop-filter` 模糊(0–60 px
|
|
68
|
+
- **分部位界面透明度** — 主背景、侧边栏、卡片面板(含对话框周围的选项框/菜单)、输入框与控件(发送框、Cordis 插件面板)、设置面板与壁纸各自独立滑块。
|
|
69
|
+
- **分部位界面模糊度** — 每个界面部位可独立调整毛玻璃 `backdrop-filter` 模糊(0–60 px),并通过宿主的稳定选择器为发送框与 Cordis 面板提供真实背景模糊。
|
|
70
70
|
- **对话视图卡片** — 消息列表自动包裹为半透明卡片,轨迹页可整页调节透明度与模糊,让壁纸从内容后方透出来。
|
|
71
71
|
- **主题导出 / 导入** — 一键导出为自包含的 `dsh-any-theme.json`(配置 + 壁纸,视频以 data URL 内嵌),可随时导入还原。
|
|
72
72
|
- **文件持久化** — 所有设置保存到文件系统 `~/.dsh/.dsh-any-background-data/`,不再依赖 `localStorage`。
|
|
@@ -84,6 +84,13 @@
|
|
|
84
84
|
- **灵感色板选中重置** — 在色轮中选取主题色后,灵感色板中的之前选中状态自动清除。
|
|
85
85
|
- **移除调试埋点** — 清理了临时的启动日志与 `MutationObserver` 探针代码。
|
|
86
86
|
- **分部位模糊隔离** — 模糊效果施加在 `::before` 伪元素上,避免影响宿主固定定位的设置弹窗。
|
|
87
|
+
- **新增「输入框与控件」部件** — 发送框、斜杠菜单、Cordis 插件面板拥有独立的透明度滑块;半透明表面通过宿主的稳定 data 属性(`[data-composer-card]`、`[data-cordis-panel]`)获得真正的毛玻璃背景模糊。
|
|
88
|
+
- **修复原生控件明暗对比** — 实心表面令牌(发送框、菜单、Cordis 面板)现在参与分部位 alpha,并强制 `color-scheme` 让原生 `<select>` 弹层保持可读——消除壁纸判暗把标签转白后出现的白底白字。
|
|
89
|
+
- **透明化不反噬自身** — 「输入框与控件」透明度滑块刻意与该面板自己的控件(共享同一批按钮令牌)解绑,调节它不会把插件自身的滑块和按钮也变透明。
|
|
90
|
+
- **拖动性能优化** — 透明度令牌改为写 `<html>` 上的 CSS 变量(拖动时不再整表重建),滑块更新按 rAF 合帧为每帧一次;「主背景」列仅在自身滑块变化时才重染。
|
|
91
|
+
- **拖动时壁纸降采样** — 拖动任意滑块期间,壁纸临时切换到(~720px)低清副本以降低大图上的合成成本,松手后恢复全分辨率。
|
|
92
|
+
- **导入即播视频壁纸** — 选中的视频立即通过本地对象 URL 开始播放,原始字节在后台流式落盘,下次刷新自动切回持久化服务地址——不再有「上传 + 首帧缓冲」的等待。
|
|
93
|
+
- **选项框跟随卡片滑块** — 对话框周围的下拉菜单、斜杠命令菜单、模型选择器与弹层现在跟随「对话框中选项面板」透明度滑块,而非「输入框与控件」;Cordis 插件面板保持自己的输入滑块绑定。
|
|
87
94
|
|
|
88
95
|
## 安装
|
|
89
96
|
|
package/lib/client.js
CHANGED
|
@@ -32,6 +32,7 @@ window.__ModuleLoader__.load({
|
|
|
32
32
|
uiOpacityBg: "主背景",
|
|
33
33
|
uiOpacitySide: "侧边栏",
|
|
34
34
|
uiOpacityCard: "对话框中选项面板",
|
|
35
|
+
uiOpacityInput: "输入框与控件",
|
|
35
36
|
uiSop: "设置界面透明度",
|
|
36
37
|
uiChatRegion: "对话文本框",
|
|
37
38
|
uiTrajectory: "轨迹页",
|
|
@@ -129,6 +130,7 @@ window.__ModuleLoader__.load({
|
|
|
129
130
|
uiOpacityBg: "Main background",
|
|
130
131
|
uiOpacitySide: "Sidebar",
|
|
131
132
|
uiOpacityCard: "Cards & panels",
|
|
133
|
+
uiOpacityInput: "Input & controls",
|
|
132
134
|
uiSop: "Settings interface opacity",
|
|
133
135
|
uiChatRegion: "Conversation text frame",
|
|
134
136
|
uiTrajectory: "Trajectory view",
|
|
@@ -211,7 +213,8 @@ window.__ModuleLoader__.load({
|
|
|
211
213
|
opacities: {
|
|
212
214
|
bg: .85,
|
|
213
215
|
sidebar: .93,
|
|
214
|
-
card: 1
|
|
216
|
+
card: 1,
|
|
217
|
+
input: 1
|
|
215
218
|
},
|
|
216
219
|
blurs: {
|
|
217
220
|
bg: 0,
|
|
@@ -219,7 +222,8 @@ window.__ModuleLoader__.load({
|
|
|
219
222
|
card: 0,
|
|
220
223
|
settings: 0,
|
|
221
224
|
chat: 0,
|
|
222
|
-
trajectory: 0
|
|
225
|
+
trajectory: 0,
|
|
226
|
+
input: 0
|
|
223
227
|
},
|
|
224
228
|
settingsOpacity: 1,
|
|
225
229
|
wallpaperOpacity: 1,
|
|
@@ -259,6 +263,8 @@ window.__ModuleLoader__.load({
|
|
|
259
263
|
let wpVideoUrl = null;
|
|
260
264
|
/** Captured video frame standing in for previews/color extraction (still-image APIs). */
|
|
261
265
|
let wpVideoSnapshot = null;
|
|
266
|
+
/** Local blob URL backing an in-session video; revoked when replaced or cleared. */
|
|
267
|
+
let wpVideoObjectUrl = null;
|
|
262
268
|
function setWpImageUrl(url) {
|
|
263
269
|
wpImageUrl = url;
|
|
264
270
|
}
|
|
@@ -272,13 +278,25 @@ window.__ModuleLoader__.load({
|
|
|
272
278
|
wpVideoSnapshot = null;
|
|
273
279
|
} else {
|
|
274
280
|
videoRev++;
|
|
275
|
-
wpVideoUrl = `${url}${url.includes("?") ? "&" : "?"}r=${videoRev}`;
|
|
281
|
+
wpVideoUrl = url.startsWith("blob:") ? url : `${url}${url.includes("?") ? "&" : "?"}r=${videoRev}`;
|
|
276
282
|
}
|
|
283
|
+
if (wpVideoObjectUrl !== null && wpVideoObjectUrl !== url) {
|
|
284
|
+
URL.revokeObjectURL(wpVideoObjectUrl);
|
|
285
|
+
wpVideoObjectUrl = null;
|
|
286
|
+
}
|
|
287
|
+
if (url !== null && url.startsWith("blob:")) wpVideoObjectUrl = url;
|
|
277
288
|
cfg.videoMime = url ? mime : null;
|
|
278
289
|
}
|
|
279
290
|
function setWpVideoSnapshot(url) {
|
|
280
291
|
wpVideoSnapshot = url;
|
|
281
292
|
}
|
|
293
|
+
/** Release the in-session video object URL (plugin teardown). */
|
|
294
|
+
function disposeVideoObjectUrl() {
|
|
295
|
+
if (wpVideoObjectUrl !== null) {
|
|
296
|
+
URL.revokeObjectURL(wpVideoObjectUrl);
|
|
297
|
+
wpVideoObjectUrl = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
282
300
|
function setBgState(s) {
|
|
283
301
|
cfg.bgState = s;
|
|
284
302
|
}
|
|
@@ -326,7 +344,8 @@ window.__ModuleLoader__.load({
|
|
|
326
344
|
for (const k of [
|
|
327
345
|
"bg",
|
|
328
346
|
"sidebar",
|
|
329
|
-
"card"
|
|
347
|
+
"card",
|
|
348
|
+
"input"
|
|
330
349
|
]) out[k] = clamp01(o[k], DEFAULT_CONFIG.opacities[k]);
|
|
331
350
|
return out;
|
|
332
351
|
}
|
|
@@ -339,7 +358,8 @@ window.__ModuleLoader__.load({
|
|
|
339
358
|
"card",
|
|
340
359
|
"settings",
|
|
341
360
|
"chat",
|
|
342
|
-
"trajectory"
|
|
361
|
+
"trajectory",
|
|
362
|
+
"input"
|
|
343
363
|
]) {
|
|
344
364
|
const v = b[k];
|
|
345
365
|
out[k] = typeof v === "number" ? Math.min(60, Math.max(0, v)) : DEFAULT_CONFIG.blurs[k];
|
|
@@ -390,7 +410,8 @@ window.__ModuleLoader__.load({
|
|
|
390
410
|
"card",
|
|
391
411
|
"settings",
|
|
392
412
|
"chat",
|
|
393
|
-
"trajectory"
|
|
413
|
+
"trajectory",
|
|
414
|
+
"input"
|
|
394
415
|
]) blurs[k] = num(bl[k], DEFAULT_CONFIG.blurs[k]);
|
|
395
416
|
const bgType = [
|
|
396
417
|
"video",
|
|
@@ -412,7 +433,8 @@ window.__ModuleLoader__.load({
|
|
|
412
433
|
opacities: {
|
|
413
434
|
bg: num(ops.bg, legacy ?? DEFAULT_CONFIG.opacities.bg),
|
|
414
435
|
sidebar: num(ops.sidebar, legacy !== null ? Math.min(1, legacy + .08) : DEFAULT_CONFIG.opacities.sidebar),
|
|
415
|
-
card: num(ops.card, DEFAULT_CONFIG.opacities.card)
|
|
436
|
+
card: num(ops.card, DEFAULT_CONFIG.opacities.card),
|
|
437
|
+
input: num(ops.input, DEFAULT_CONFIG.opacities.input)
|
|
416
438
|
},
|
|
417
439
|
blurs,
|
|
418
440
|
settingsOpacity: num(c.settingsOpacity, DEFAULT_CONFIG.settingsOpacity),
|
|
@@ -601,6 +623,7 @@ window.__ModuleLoader__.load({
|
|
|
601
623
|
"--dsw-alias-button-primary-hover": hsl(h(0), s(.1), Math.max(l(.28), .58)),
|
|
602
624
|
"--dsw-alias-button-primary-dimmed": hsl(h(0), s(0), l(.07)),
|
|
603
625
|
"--dsw-alias-button-elevated-fill": hsl(h(0), s(0), l(.04)),
|
|
626
|
+
"--dsw-alias-button-floating-hover": hsl(h(0), s(0), l(.1)),
|
|
604
627
|
"--dsw-alias-interactive-bg-hover": rgba(h(0), s(0), Math.max(l(.15), .4), .12),
|
|
605
628
|
"--dsw-alias-interactive-bg-active": rgba(h(0), s(0), Math.max(l(.15), .4), .2),
|
|
606
629
|
"--dsw-alias-markdown-code-block": hsl(h(0), s(0), l(-.06)),
|
|
@@ -612,6 +635,7 @@ window.__ModuleLoader__.load({
|
|
|
612
635
|
"--dsw-specific-sidebar-nav-item-active": hsl(h(0), s(0), l(.04)),
|
|
613
636
|
"--dsw-specific-sidebar-nav-item-hover": hsl(h(0), s(0), l(0)),
|
|
614
637
|
"--dsw-specific-input-major": hsl(h(0), s(0), l(.02)),
|
|
638
|
+
"--dsw-specific-menu": hsl(h(0), s(0), l(.08)),
|
|
615
639
|
"--dsw-alias-scrollbar-bg-l1": hsl(h(0), s(-.05), l(.12)),
|
|
616
640
|
"--dsw-alias-scrollbar-bg-l2": hsl(h(0), s(-.05), l(.16)),
|
|
617
641
|
"--dsw-alias-scrollbar-hover-l1": hsl(h(0), s(-.05), l(.22)),
|
|
@@ -639,6 +663,7 @@ window.__ModuleLoader__.load({
|
|
|
639
663
|
"--dsw-alias-button-primary-hover": hsl(h(0), s(.05), Math.min(l(-.12), .5)),
|
|
640
664
|
"--dsw-alias-button-primary-dimmed": hsl(h(0), s(-.1), l(-.03)),
|
|
641
665
|
"--dsw-alias-button-elevated-fill": hsl(h(0), s(-.1), l(.1)),
|
|
666
|
+
"--dsw-alias-button-floating-hover": hsl(h(0), s(-.1), l(.16)),
|
|
642
667
|
"--dsw-alias-interactive-bg-hover": rgba(h(0), s(0), l(-.3), .08),
|
|
643
668
|
"--dsw-alias-interactive-bg-active": rgba(h(0), s(0), l(-.3), .14),
|
|
644
669
|
"--dsw-alias-markdown-code-block": hsl(h(0), s(-.1), l(-.03)),
|
|
@@ -647,6 +672,7 @@ window.__ModuleLoader__.load({
|
|
|
647
672
|
"--dsw-specific-sidebar-nav-item-active": hsl(h(0), s(-.08), l(.05)),
|
|
648
673
|
"--dsw-specific-sidebar-nav-item-hover": hsl(h(0), s(-.12), l(0)),
|
|
649
674
|
"--dsw-specific-input-major": hsl(h(0), s(-.12), l(.1)),
|
|
675
|
+
"--dsw-specific-menu": hsl(h(0), s(-.12), l(.15)),
|
|
650
676
|
"--dsw-alias-scrollbar-bg-l1": hsl(h(0), s(-.1), l(-.08)),
|
|
651
677
|
"--dsw-alias-scrollbar-bg-l2": hsl(h(0), s(-.08), l(-.12)),
|
|
652
678
|
"--dsw-alias-scrollbar-hover-l1": hsl(h(0), s(-.08), l(-.16)),
|
|
@@ -1472,7 +1498,54 @@ window.__ModuleLoader__.load({
|
|
|
1472
1498
|
"--dsw-alias-label-dimmed",
|
|
1473
1499
|
"--dsw-alias-label-quaternary"
|
|
1474
1500
|
];
|
|
1501
|
+
const OPACITY_TOKEN_GROUPS = [
|
|
1502
|
+
{
|
|
1503
|
+
part: "bg",
|
|
1504
|
+
names: ["--dsw-alias-bg-base"]
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
part: "sidebar",
|
|
1508
|
+
names: ["--dsw-specific-sidebar-fill"]
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
part: "card",
|
|
1512
|
+
names: [
|
|
1513
|
+
"--dsw-alias-bg-layer-1",
|
|
1514
|
+
"--dsw-alias-bg-layer-2",
|
|
1515
|
+
"--dsw-alias-bg-layer-3",
|
|
1516
|
+
"--dsw-specific-menu"
|
|
1517
|
+
]
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
part: "input",
|
|
1521
|
+
names: ["--dsw-specific-input-major"]
|
|
1522
|
+
}
|
|
1523
|
+
];
|
|
1524
|
+
const OPACITY_VARS = {
|
|
1525
|
+
"--dsw-alias-bg-base": "--dsh-any-op-bg",
|
|
1526
|
+
"--dsw-specific-sidebar-fill": "--dsh-any-op-sidebar",
|
|
1527
|
+
"--dsw-alias-bg-layer-1": "--dsh-any-op-card-1",
|
|
1528
|
+
"--dsw-alias-bg-layer-2": "--dsh-any-op-card-2",
|
|
1529
|
+
"--dsw-alias-bg-layer-3": "--dsh-any-op-card-3",
|
|
1530
|
+
"--dsw-specific-input-major": "--dsh-any-op-input",
|
|
1531
|
+
"--dsw-specific-menu": "--dsh-any-op-menu"
|
|
1532
|
+
};
|
|
1533
|
+
let baseTokenKey = "";
|
|
1534
|
+
let pendingOps = null;
|
|
1535
|
+
let tokensRaf = null;
|
|
1475
1536
|
function applyCustomTokens(ops) {
|
|
1537
|
+
pendingOps = ops;
|
|
1538
|
+
if (tokensRaf !== null) return;
|
|
1539
|
+
tokensRaf = requestAnimationFrame(() => {
|
|
1540
|
+
tokensRaf = null;
|
|
1541
|
+
if (pendingOps === null) return;
|
|
1542
|
+
const o = pendingOps;
|
|
1543
|
+
pendingOps = null;
|
|
1544
|
+
applyCustomTokensNow(o);
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
let lastBgKey = "";
|
|
1548
|
+
function applyCustomTokensNow(ops) {
|
|
1476
1549
|
const [h, s, l] = rColor();
|
|
1477
1550
|
let { tokens } = genTokens(h, s, l);
|
|
1478
1551
|
try {
|
|
@@ -1482,24 +1555,37 @@ window.__ModuleLoader__.load({
|
|
|
1482
1555
|
const font = dark ? "#fff" : "#000";
|
|
1483
1556
|
for (const name of LABEL_TOKENS) tokens[name] = font;
|
|
1484
1557
|
}
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1558
|
+
const forceDark = dark ?? l < .55;
|
|
1559
|
+
if (`${h}|${s}|${l}|${dark}` !== baseTokenKey) {
|
|
1560
|
+
baseTokenKey = `${h}|${s}|${l}|${dark}`;
|
|
1561
|
+
if (forceDark) document.body.setAttribute("data-ds-dark-theme", "dsh-any-background");
|
|
1562
|
+
else document.body.removeAttribute("data-ds-dark-theme");
|
|
1563
|
+
const decls = [`color-scheme:${forceDark ? "dark" : "light"}`];
|
|
1564
|
+
for (const [name, value] of Object.entries(tokens)) {
|
|
1565
|
+
const opVar = OPACITY_VARS[name];
|
|
1566
|
+
decls.push(`${name}:${opVar !== void 0 ? `var(${opVar})` : value}!important`);
|
|
1567
|
+
}
|
|
1568
|
+
ensureTokenStyle().textContent = `body{${decls.join(";")}}`;
|
|
1569
|
+
for (const name of appliedTokenNames) document.body.style.removeProperty(name);
|
|
1570
|
+
appliedTokenNames = Object.keys(tokens);
|
|
1571
|
+
}
|
|
1572
|
+
const root = document.documentElement;
|
|
1573
|
+
for (const g of OPACITY_TOKEN_GROUPS) for (const name of g.names) root.style.setProperty(OPACITY_VARS[name], toRgba(tokens[name] ?? "#000", ops[g.part]));
|
|
1574
|
+
root.style.setProperty("--dsh-any-op-menu-cordis", toRgba(tokens["--dsw-specific-menu"] ?? "#000", ops.input));
|
|
1575
|
+
const bgKey = `${baseTokenKey}|${ops.bg}`;
|
|
1576
|
+
if (bgKey !== lastBgKey) {
|
|
1577
|
+
lastBgKey = bgKey;
|
|
1578
|
+
applyPartOpacities(ops);
|
|
1494
1579
|
}
|
|
1495
|
-
ensureTokenStyle().textContent = `body{${decls.join(";")}}`;
|
|
1496
|
-
for (const name of appliedTokenNames) document.body.style.removeProperty(name);
|
|
1497
|
-
appliedTokenNames = Object.keys(tokens);
|
|
1498
|
-
applyPartOpacities(ops);
|
|
1499
1580
|
} catch {}
|
|
1500
1581
|
}
|
|
1501
1582
|
const SETTINGS_PANEL_SEL = "[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]";
|
|
1502
1583
|
const SETTINGS_STYLE_RULE = `${SETTINGS_PANEL_SEL}{background:var(--dsh-any-bg-settings-surface,var(--dsw-alias-bg-layer-2));backdrop-filter:var(--dsh-any-blur-settings,none);--dsw-alias-bg-layer-1:var(--dsh-any-bg-settings-layer-1);--dsw-alias-bg-layer-2:var(--dsh-any-bg-settings-layer-2);--dsw-alias-bg-layer-3:var(--dsh-any-bg-settings-layer-3)}${SETTINGS_PANEL_SEL} .dab-card{backdrop-filter:var(--dsh-any-blur-card-panels,none);-webkit-backdrop-filter:var(--dsh-any-blur-card-panels,none)}`;
|
|
1584
|
+
const INPUT_BLUR_RULE = "[data-composer-card],[data-cordis-panel]{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{--dsw-specific-menu:var(--dsh-any-op-menu-cordis)!important}";
|
|
1585
|
+
function applyInputBlur(px) {
|
|
1586
|
+
if (px > 0) document.documentElement.style.setProperty("--dsh-any-input-blur", `blur(${px}px)`);
|
|
1587
|
+
else document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
1588
|
+
}
|
|
1503
1589
|
function applySettingsOverrides(op) {
|
|
1504
1590
|
const [h, s, l] = rColor();
|
|
1505
1591
|
const tokens = genTokens(h, s, l).tokens;
|
|
@@ -1688,6 +1774,7 @@ window.__ModuleLoader__.load({
|
|
|
1688
1774
|
setBlur(detailsEl, blurs.bg);
|
|
1689
1775
|
applyCardPanelsBlur(blurs.card);
|
|
1690
1776
|
applySettingsBlur(blurs.settings);
|
|
1777
|
+
applyInputBlur(blurs.input);
|
|
1691
1778
|
applyViewCards();
|
|
1692
1779
|
}
|
|
1693
1780
|
/** Live per-part blur update during slider drag (no full re-apply). */
|
|
@@ -1700,6 +1787,10 @@ window.__ModuleLoader__.load({
|
|
|
1700
1787
|
applyCardPanelsBlur(v);
|
|
1701
1788
|
return;
|
|
1702
1789
|
}
|
|
1790
|
+
if (part === "input") {
|
|
1791
|
+
applyInputBlur(v);
|
|
1792
|
+
return;
|
|
1793
|
+
}
|
|
1703
1794
|
if (part === "chat" || part === "trajectory") {
|
|
1704
1795
|
applyViewCards();
|
|
1705
1796
|
return;
|
|
@@ -1923,6 +2014,78 @@ window.__ModuleLoader__.load({
|
|
|
1923
2014
|
img.onerror = () => cb(0, 0);
|
|
1924
2015
|
img.src = url;
|
|
1925
2016
|
}
|
|
2017
|
+
const DRAG_MAX_SIDE = 720;
|
|
2018
|
+
let lowResUrl = null;
|
|
2019
|
+
let lowResFor = "";
|
|
2020
|
+
let dragLow = false;
|
|
2021
|
+
function captureLowRes(url, cb) {
|
|
2022
|
+
if (lowResFor === url) {
|
|
2023
|
+
cb(lowResUrl);
|
|
2024
|
+
return;
|
|
2025
|
+
}
|
|
2026
|
+
const img = new Image();
|
|
2027
|
+
img.onload = () => {
|
|
2028
|
+
const k = Math.min(1, DRAG_MAX_SIDE / Math.max(img.naturalWidth, img.naturalHeight));
|
|
2029
|
+
if (k >= 1) {
|
|
2030
|
+
lowResFor = url;
|
|
2031
|
+
lowResUrl = null;
|
|
2032
|
+
cb(null);
|
|
2033
|
+
return;
|
|
2034
|
+
}
|
|
2035
|
+
const c = document.createElement("canvas");
|
|
2036
|
+
c.width = Math.max(1, Math.round(img.naturalWidth * k));
|
|
2037
|
+
c.height = Math.max(1, Math.round(img.naturalHeight * k));
|
|
2038
|
+
const g = c.getContext("2d");
|
|
2039
|
+
if (!g) {
|
|
2040
|
+
lowResFor = url;
|
|
2041
|
+
lowResUrl = null;
|
|
2042
|
+
cb(null);
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
g.drawImage(img, 0, 0, c.width, c.height);
|
|
2046
|
+
const low = c.toDataURL("image/jpeg", .85);
|
|
2047
|
+
lowResFor = url;
|
|
2048
|
+
lowResUrl = low;
|
|
2049
|
+
cb(low);
|
|
2050
|
+
};
|
|
2051
|
+
img.onerror = () => cb(null);
|
|
2052
|
+
img.src = url;
|
|
2053
|
+
}
|
|
2054
|
+
function setDragLow(on) {
|
|
2055
|
+
if (cfg.backgroundType !== "image" || on === dragLow || !wpEl) return;
|
|
2056
|
+
const full = rWpImage();
|
|
2057
|
+
if (!full) return;
|
|
2058
|
+
if (on) {
|
|
2059
|
+
dragLow = true;
|
|
2060
|
+
captureLowRes(full, (low) => {
|
|
2061
|
+
if (!dragLow || !wpEl || low === null) return;
|
|
2062
|
+
if (wpEl.style.backgroundImage !== `url("${low}")`) wpEl.style.backgroundImage = `url("${low}")`;
|
|
2063
|
+
});
|
|
2064
|
+
} else {
|
|
2065
|
+
dragLow = false;
|
|
2066
|
+
if (wpEl.style.backgroundImage !== `url("${full}")`) wpEl.style.backgroundImage = `url("${full}")`;
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
/** While any range slider in the app is being dragged, run the wallpaper at
|
|
2070
|
+
* reduced resolution; restore on release. Returns a disposer for teardown. */
|
|
2071
|
+
function watchWallpaperDragQuality() {
|
|
2072
|
+
const isRange = (t) => t instanceof HTMLInputElement && t.type === "range";
|
|
2073
|
+
const down = (e) => {
|
|
2074
|
+
if (isRange(e.target)) setDragLow(true);
|
|
2075
|
+
};
|
|
2076
|
+
const up = () => {
|
|
2077
|
+
if (dragLow) setDragLow(false);
|
|
2078
|
+
};
|
|
2079
|
+
window.addEventListener("pointerdown", down, true);
|
|
2080
|
+
window.addEventListener("pointerup", up, true);
|
|
2081
|
+
window.addEventListener("pointercancel", up, true);
|
|
2082
|
+
return () => {
|
|
2083
|
+
window.removeEventListener("pointerdown", down, true);
|
|
2084
|
+
window.removeEventListener("pointerup", up, true);
|
|
2085
|
+
window.removeEventListener("pointercancel", up, true);
|
|
2086
|
+
if (dragLow) setDragLow(false);
|
|
2087
|
+
};
|
|
2088
|
+
}
|
|
1926
2089
|
function applyImageWp(url) {
|
|
1927
2090
|
clearDynamicBg();
|
|
1928
2091
|
clearVideoEl();
|
|
@@ -1967,6 +2130,7 @@ window.__ModuleLoader__.load({
|
|
|
1967
2130
|
}
|
|
1968
2131
|
});
|
|
1969
2132
|
}
|
|
2133
|
+
captureLowRes(url, () => void 0);
|
|
1970
2134
|
applyWpEffects();
|
|
1971
2135
|
}
|
|
1972
2136
|
/** Video wallpaper: a muted looping <video> inside the wallpaper layer.
|
|
@@ -1982,11 +2146,12 @@ window.__ModuleLoader__.load({
|
|
|
1982
2146
|
videoEl.loop = true;
|
|
1983
2147
|
videoEl.autoplay = true;
|
|
1984
2148
|
videoEl.playsInline = true;
|
|
2149
|
+
videoEl.preload = "auto";
|
|
1985
2150
|
videoEl.setAttribute("playsinline", "");
|
|
1986
2151
|
videoEl.style.cssText = "position:absolute;inset:0;width:100%;height:100%;object-position:center;";
|
|
2152
|
+
wpEl.appendChild(videoEl);
|
|
1987
2153
|
videoEl.setAttribute("src", url);
|
|
1988
2154
|
videoEl.play().catch(() => void 0);
|
|
1989
|
-
wpEl.appendChild(videoEl);
|
|
1990
2155
|
} else if (videoEl.getAttribute("src") !== url) {
|
|
1991
2156
|
videoEl.setAttribute("src", url);
|
|
1992
2157
|
videoEl.play().catch(() => void 0);
|
|
@@ -2047,6 +2212,7 @@ window.__ModuleLoader__.load({
|
|
|
2047
2212
|
function teardownWp() {
|
|
2048
2213
|
clearDynamicBg();
|
|
2049
2214
|
clearVideoEl();
|
|
2215
|
+
disposeVideoObjectUrl();
|
|
2050
2216
|
setBgDark(null);
|
|
2051
2217
|
wpEl?.remove();
|
|
2052
2218
|
wpEl = null;
|
|
@@ -2054,6 +2220,8 @@ window.__ModuleLoader__.load({
|
|
|
2054
2220
|
tokenStyleEl?.remove();
|
|
2055
2221
|
tokenStyleEl = null;
|
|
2056
2222
|
removeViewCards();
|
|
2223
|
+
document.body.removeAttribute("data-ds-dark-theme");
|
|
2224
|
+
document.body.style.removeProperty("color-scheme");
|
|
2057
2225
|
document.documentElement.style.removeProperty("--dsh-any-bg-settings-surface");
|
|
2058
2226
|
document.documentElement.style.removeProperty("--dsh-any-bg-settings-layer-1");
|
|
2059
2227
|
document.documentElement.style.removeProperty("--dsh-any-bg-settings-layer-2");
|
|
@@ -2064,6 +2232,15 @@ window.__ModuleLoader__.load({
|
|
|
2064
2232
|
document.documentElement.style.removeProperty("--dsh-any-bg-settings-card-surface");
|
|
2065
2233
|
document.documentElement.style.removeProperty("--dsh-any-blur-settings");
|
|
2066
2234
|
document.documentElement.style.removeProperty("--dsh-any-blur-card-panels");
|
|
2235
|
+
document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
2236
|
+
for (const v of Object.values(OPACITY_VARS)) document.documentElement.style.removeProperty(v);
|
|
2237
|
+
baseTokenKey = "";
|
|
2238
|
+
lastBgKey = "";
|
|
2239
|
+
if (tokensRaf !== null) {
|
|
2240
|
+
cancelAnimationFrame(tokensRaf);
|
|
2241
|
+
tokensRaf = null;
|
|
2242
|
+
}
|
|
2243
|
+
pendingOps = null;
|
|
2067
2244
|
setBlur(frameEl, 0);
|
|
2068
2245
|
setBlur(sidebarEl, 0);
|
|
2069
2246
|
setBlur(centerEl, 0);
|
|
@@ -2589,6 +2766,17 @@ window.__ModuleLoader__.load({
|
|
|
2589
2766
|
r: "2.1"
|
|
2590
2767
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 1.7v1.8M8 12.5v1.8M1.7 8h1.8M12.5 8h1.8M3.6 3.6l1.3 1.3M11.1 11.1l1.3 1.3M12.4 3.6l-1.3 1.3M4.9 11.1l-1.3 1.3" })]
|
|
2591
2768
|
});
|
|
2769
|
+
const InputIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
|
|
2770
|
+
size,
|
|
2771
|
+
className,
|
|
2772
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
2773
|
+
x: "2.2",
|
|
2774
|
+
y: "4",
|
|
2775
|
+
width: "11.6",
|
|
2776
|
+
height: "8",
|
|
2777
|
+
rx: "2"
|
|
2778
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 6.6v2M7 8h2" })]
|
|
2779
|
+
});
|
|
2592
2780
|
//#endregion
|
|
2593
2781
|
//#region src/client/components/ErrorBoundary.tsx
|
|
2594
2782
|
/**
|
|
@@ -3482,6 +3670,11 @@ window.__ModuleLoader__.load({
|
|
|
3482
3670
|
labelKey: "uiOpacityCard",
|
|
3483
3671
|
Icon: ChatIcon
|
|
3484
3672
|
},
|
|
3673
|
+
{
|
|
3674
|
+
opKey: "input",
|
|
3675
|
+
labelKey: "uiOpacityInput",
|
|
3676
|
+
Icon: InputIcon
|
|
3677
|
+
},
|
|
3485
3678
|
{
|
|
3486
3679
|
isSettings: true,
|
|
3487
3680
|
labelKey: "uiSop",
|
|
@@ -4556,11 +4749,13 @@ window.__ModuleLoader__.load({
|
|
|
4556
4749
|
}, "dsh-any-background: skin dispose");
|
|
4557
4750
|
const styleEl = document.createElement("style");
|
|
4558
4751
|
styleEl.dataset.plugin = "dsh-any-background";
|
|
4559
|
-
styleEl.textContent = `body[data-ds-dark-theme="dsh-any-background"]::before{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(255,255,255,0.03) 0%,transparent 60%)}${SETTINGS_STYLE_RULE}${TRAJECTORY_STYLE_RULE}`;
|
|
4752
|
+
styleEl.textContent = `body[data-ds-dark-theme="dsh-any-background"]::before{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(255,255,255,0.03) 0%,transparent 60%)}${SETTINGS_STYLE_RULE}${TRAJECTORY_STYLE_RULE}${INPUT_BLUR_RULE}`;
|
|
4560
4753
|
document.head.appendChild(styleEl);
|
|
4561
4754
|
ctx.effect(() => () => {
|
|
4562
4755
|
styleEl?.parentNode?.removeChild(styleEl);
|
|
4563
4756
|
}, "dsh-any-background: gradient");
|
|
4757
|
+
const disposeDragQuality = watchWallpaperDragQuality();
|
|
4758
|
+
ctx.effect(() => () => disposeDragQuality(), "dsh-any-background: drag quality");
|
|
4564
4759
|
let rev = 0;
|
|
4565
4760
|
let colorRev = 0;
|
|
4566
4761
|
let bgRev = 0;
|
|
@@ -4675,6 +4870,25 @@ window.__ModuleLoader__.load({
|
|
|
4675
4870
|
const sectionInject = (actions) => {
|
|
4676
4871
|
bound = actions;
|
|
4677
4872
|
syncBg();
|
|
4873
|
+
const playVideoFromBlob = (blob, mime) => {
|
|
4874
|
+
const localUrl = URL.createObjectURL(blob);
|
|
4875
|
+
cfg.backgroundType = "video";
|
|
4876
|
+
setWpUrl(null);
|
|
4877
|
+
cfg.videoBgState = { ...DEFAULT_CONFIG.bgState };
|
|
4878
|
+
setWpVideoUrl(localUrl, mime ?? blob.type ?? "video/mp4");
|
|
4879
|
+
applyWp();
|
|
4880
|
+
syncBg();
|
|
4881
|
+
const applied = rWpVideo();
|
|
4882
|
+
captureVideoSnapshot(localUrl).then((snap) => {
|
|
4883
|
+
if (rWpVideo() !== applied) return;
|
|
4884
|
+
setWpVideoSnapshot(snap);
|
|
4885
|
+
applyThemeColor();
|
|
4886
|
+
syncBg();
|
|
4887
|
+
});
|
|
4888
|
+
uploadVideo(blob, mime ?? blob.type ?? "video/mp4").then((ok) => {
|
|
4889
|
+
if (ok) persistConfig();
|
|
4890
|
+
});
|
|
4891
|
+
};
|
|
4678
4892
|
const [wh, ws, wl] = rColor();
|
|
4679
4893
|
const [dh, ds, dv] = hslToHsv(wh, ws, wl);
|
|
4680
4894
|
return {
|
|
@@ -4729,15 +4943,15 @@ window.__ModuleLoader__.load({
|
|
|
4729
4943
|
saveConfig();
|
|
4730
4944
|
return;
|
|
4731
4945
|
}
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4946
|
+
if (typeof u !== "string") {
|
|
4947
|
+
playVideoFromBlob(u, mime);
|
|
4948
|
+
return;
|
|
4949
|
+
}
|
|
4950
|
+
const live = await persistVideo(u) ? VIDEO_SERVE_URL : u;
|
|
4737
4951
|
cfg.backgroundType = "video";
|
|
4738
4952
|
setWpUrl(null);
|
|
4739
4953
|
cfg.videoBgState = { ...DEFAULT_CONFIG.bgState };
|
|
4740
|
-
setWpVideoUrl(live, mime ??
|
|
4954
|
+
setWpVideoUrl(live, mime ?? null);
|
|
4741
4955
|
applyWp();
|
|
4742
4956
|
saveConfig();
|
|
4743
4957
|
syncBg();
|
|
@@ -4854,24 +5068,25 @@ window.__ModuleLoader__.load({
|
|
|
4854
5068
|
if (cfg.backgroundType === "video") {
|
|
4855
5069
|
const video = typeof d.video === "string" && /^data:video\//.test(d.video) ? d.video : null;
|
|
4856
5070
|
if (video !== null) {
|
|
4857
|
-
let
|
|
5071
|
+
let blob = null;
|
|
4858
5072
|
try {
|
|
4859
|
-
|
|
4860
|
-
ok = await uploadVideo(blob, cfg.videoMime ?? blob.type ?? "video/mp4");
|
|
5073
|
+
blob = await fetch(video).then((r) => r.blob());
|
|
4861
5074
|
} catch {
|
|
4862
|
-
|
|
5075
|
+
blob = null;
|
|
5076
|
+
}
|
|
5077
|
+
if (blob !== null) playVideoFromBlob(blob, cfg.videoMime);
|
|
5078
|
+
else {
|
|
5079
|
+
const live = await persistVideo(video) ? VIDEO_SERVE_URL : video;
|
|
5080
|
+
setWpVideoUrl(live, cfg.videoMime);
|
|
5081
|
+
applyWp();
|
|
5082
|
+
const applied = rWpVideo();
|
|
5083
|
+
captureVideoSnapshot(live).then((snap) => {
|
|
5084
|
+
if (rWpVideo() !== applied) return;
|
|
5085
|
+
setWpVideoSnapshot(snap);
|
|
5086
|
+
applyThemeColor();
|
|
5087
|
+
syncBg();
|
|
5088
|
+
});
|
|
4863
5089
|
}
|
|
4864
|
-
if (!ok) ok = await persistVideo(video);
|
|
4865
|
-
const live = ok ? VIDEO_SERVE_URL : video;
|
|
4866
|
-
setWpVideoUrl(live, cfg.videoMime);
|
|
4867
|
-
applyWp();
|
|
4868
|
-
const applied = rWpVideo();
|
|
4869
|
-
captureVideoSnapshot(live).then((snap) => {
|
|
4870
|
-
if (rWpVideo() !== applied) return;
|
|
4871
|
-
setWpVideoSnapshot(snap);
|
|
4872
|
-
applyThemeColor();
|
|
4873
|
-
syncBg();
|
|
4874
|
-
});
|
|
4875
5090
|
} else {
|
|
4876
5091
|
setWpVideoUrl(null, null);
|
|
4877
5092
|
persistVideo(null);
|