dsh-background-by-model 0.3.1 → 0.4.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.
- package/README.md +255 -236
- package/README.zh.md +255 -236
- package/lib/client.js +343 -188
- package/lib/client.js.map +1 -1
- package/lib/index.js +160 -97
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -32,29 +32,30 @@ window.__ModuleLoader__.load({
|
|
|
32
32
|
uiOpacity: "透明度",
|
|
33
33
|
uiBlur: "模糊度",
|
|
34
34
|
uiOpacityBg: "主背景",
|
|
35
|
-
uiOpacitySide: "
|
|
35
|
+
uiOpacitySide: "左侧栏",
|
|
36
36
|
uiOpacityCard: "对话框中选项面板",
|
|
37
37
|
uiOpacityInput: "输入框与控件",
|
|
38
38
|
uiSop: "设置界面透明度",
|
|
39
39
|
uiChatRegion: "对话文本框",
|
|
40
40
|
uiTrajectory: "轨迹页",
|
|
41
|
-
|
|
42
|
-
statusTitle: "当前生效",
|
|
43
|
-
statusModel: "当前模型",
|
|
44
|
-
statusUnknown: "未检测到当前模型",
|
|
41
|
+
uiPreview: "右侧栏",
|
|
45
42
|
statusUnknownHint: "检测不到时一律使用第 1 条可用规则;切换一次模型或稍等片刻会自动重试",
|
|
46
|
-
statusSourceDefault: "宿主默认",
|
|
47
43
|
statusSourceDefaultHint: "只读到宿主默认模型,它不是本会话当前选择的模型;本会话的模型选择可用后会自动纠正",
|
|
48
44
|
statusNoteNoService: "仍未拿到会话服务(会话控制器晚于本插件加载),正在自动重试",
|
|
49
45
|
statusNoteNoSession: "会话服务已就绪,但还没有当前会话 id",
|
|
50
46
|
statusNoteNoProjection: "拿不到本会话的模型选择投影(binding / projections 不可用)",
|
|
51
47
|
statusNoteEmptySelection: "本会话的模型选择投影还没有值(切一次模型即可写入)",
|
|
52
|
-
statusNone: "还没有可用规则(规则需要启用并选择图片)",
|
|
53
|
-
statusHit: "命中",
|
|
54
|
-
statusFallback: "未命中 · 使用兜底",
|
|
55
|
-
statusRule: "规则",
|
|
56
48
|
rulesTitle: "规则列表",
|
|
57
49
|
rulesHint: "从上到下即为优先级。规则 1 同时兼任兜底:所有匹配串都没命中时使用它",
|
|
50
|
+
tryoutTitle: "匹配试跑",
|
|
51
|
+
tryoutPlaceholder: "输入模型名,如 deepseek-flash",
|
|
52
|
+
tryoutUseCurrent: "填入当前模型",
|
|
53
|
+
tryoutHit: "命中规则",
|
|
54
|
+
tryoutFallback: "无匹配 · 走兜底规则",
|
|
55
|
+
tryoutNone: "没有可用规则(规则需要启用并有图片)",
|
|
56
|
+
tryoutEmpty: "输入模型名即可试跑",
|
|
57
|
+
autoExtract: "选图后自动取主题色",
|
|
58
|
+
autoExtractHint: "只在规则还没有颜色时自动取色,绝不覆盖你手动选的颜色",
|
|
58
59
|
ruleAdd: "新增规则",
|
|
59
60
|
ruleFallbackBadge: "兜底",
|
|
60
61
|
ruleMatchLabel: "匹配串",
|
|
@@ -102,7 +103,7 @@ window.__ModuleLoader__.load({
|
|
|
102
103
|
extractColor: "从图片提取主题色",
|
|
103
104
|
extracting: "取色中…",
|
|
104
105
|
extractNoWp: "请先为该规则选择图片",
|
|
105
|
-
extractDone: "
|
|
106
|
+
extractDone: "已应用图片配色",
|
|
106
107
|
extractFail: "未在这张图里找到鲜明的颜色,请换一张",
|
|
107
108
|
eyedropper: "从图片取色",
|
|
108
109
|
pickerTitle: "从图片取色",
|
|
@@ -136,29 +137,30 @@ window.__ModuleLoader__.load({
|
|
|
136
137
|
uiOpacity: "Opacity",
|
|
137
138
|
uiBlur: "Blur",
|
|
138
139
|
uiOpacityBg: "Main background",
|
|
139
|
-
uiOpacitySide: "
|
|
140
|
+
uiOpacitySide: "Left panel",
|
|
140
141
|
uiOpacityCard: "Cards & panels",
|
|
141
142
|
uiOpacityInput: "Input & controls",
|
|
142
143
|
uiSop: "Settings interface opacity",
|
|
143
144
|
uiChatRegion: "Conversation text frame",
|
|
144
145
|
uiTrajectory: "Trajectory view",
|
|
145
|
-
|
|
146
|
-
statusTitle: "Active now",
|
|
147
|
-
statusModel: "Current model",
|
|
148
|
-
statusUnknown: "No model detected",
|
|
146
|
+
uiPreview: "Right panel",
|
|
149
147
|
statusUnknownHint: "Without a detected model rule 1 is always used; switching the model once or waiting a moment retries automatically",
|
|
150
|
-
statusSourceDefault: "host default",
|
|
151
148
|
statusSourceDefaultHint: "Only the host-wide default model could be read — that is not necessarily this session's selection. It self-corrects once this session's model selection is available.",
|
|
152
149
|
statusNoteNoService: "The sessions service is not available yet (the session controller loads after this plugin); retrying automatically",
|
|
153
150
|
statusNoteNoSession: "The sessions service is up but reports no current session yet",
|
|
154
151
|
statusNoteNoProjection: "This session's model-selection projection is unreachable (no binding / projections)",
|
|
155
152
|
statusNoteEmptySelection: "The model-selection projection exists but carries no value yet (selecting a model once writes it)",
|
|
156
|
-
statusNone: "No usable rule yet (a rule needs to be enabled and have an image)",
|
|
157
|
-
statusHit: "matched",
|
|
158
|
-
statusFallback: "no match · using the fallback",
|
|
159
|
-
statusRule: "Rule",
|
|
160
153
|
rulesTitle: "Rules",
|
|
161
154
|
rulesHint: "Top to bottom is the priority. Rule 1 doubles as the fallback — it is used when no match string hits",
|
|
155
|
+
tryoutTitle: "Match test",
|
|
156
|
+
tryoutPlaceholder: "Type a model name, e.g. deepseek-flash",
|
|
157
|
+
tryoutUseCurrent: "Use current model",
|
|
158
|
+
tryoutHit: "matches rule",
|
|
159
|
+
tryoutFallback: "no match · fallback rule",
|
|
160
|
+
tryoutNone: "No usable rule (a rule needs to be enabled and have an image)",
|
|
161
|
+
tryoutEmpty: "Type a model name to test the list",
|
|
162
|
+
autoExtract: "Extract the theme color when an image is chosen",
|
|
163
|
+
autoExtractHint: "Only fills a rule that has no color yet — a color you picked is never overwritten",
|
|
162
164
|
ruleAdd: "Add rule",
|
|
163
165
|
ruleFallbackBadge: "fallback",
|
|
164
166
|
ruleMatchLabel: "Match",
|
|
@@ -206,7 +208,7 @@ window.__ModuleLoader__.load({
|
|
|
206
208
|
extractColor: "Extract from image",
|
|
207
209
|
extracting: "Extracting…",
|
|
208
210
|
extractNoWp: "Choose an image for this rule first",
|
|
209
|
-
extractDone: "Image
|
|
211
|
+
extractDone: "Image colors applied",
|
|
210
212
|
extractFail: "No vivid color found in this image, try another",
|
|
211
213
|
eyedropper: "Eyedropper",
|
|
212
214
|
pickerTitle: "Pick from image",
|
|
@@ -227,7 +229,7 @@ window.__ModuleLoader__.load({
|
|
|
227
229
|
footerTag: "Per-model wallpaper plugin"
|
|
228
230
|
};
|
|
229
231
|
//#endregion
|
|
230
|
-
//#region src/
|
|
232
|
+
//#region src/schema.ts
|
|
231
233
|
const DEFAULT_BG_STATE = {
|
|
232
234
|
zoom: 1,
|
|
233
235
|
x: 0,
|
|
@@ -235,6 +237,7 @@ window.__ModuleLoader__.load({
|
|
|
235
237
|
iw: 0,
|
|
236
238
|
ih: 0
|
|
237
239
|
};
|
|
240
|
+
/** Every accepted `bgMode`, in UI order. */
|
|
238
241
|
const BG_MODES$1 = [
|
|
239
242
|
"fit",
|
|
240
243
|
"fill",
|
|
@@ -242,6 +245,137 @@ window.__ModuleLoader__.load({
|
|
|
242
245
|
"tile",
|
|
243
246
|
"center"
|
|
244
247
|
];
|
|
248
|
+
/**
|
|
249
|
+
* Main interface opacities (0..1), global (Interface page):
|
|
250
|
+
* `bg` main background (`--dsw-alias-bg-base`)
|
|
251
|
+
* `sidebar` sidebar (`--dsw-specific-sidebar-fill`)
|
|
252
|
+
* `card` cards/panels (`--dsw-alias-bg-layer-1/2/3`, `--dsw-specific-menu`)
|
|
253
|
+
* `input` input/control surfaces (`--dsw-specific-input-major`)
|
|
254
|
+
*/
|
|
255
|
+
const PART_OPACITY_KEYS = [
|
|
256
|
+
"bg",
|
|
257
|
+
"sidebar",
|
|
258
|
+
"card",
|
|
259
|
+
"input"
|
|
260
|
+
];
|
|
261
|
+
const DEFAULT_PART_OPACITIES = {
|
|
262
|
+
bg: .85,
|
|
263
|
+
sidebar: .93,
|
|
264
|
+
card: 1,
|
|
265
|
+
input: 1
|
|
266
|
+
};
|
|
267
|
+
/**
|
|
268
|
+
* Interface blur (px, 0..60), global (Interface page):
|
|
269
|
+
* `bg` main background (AppFrame grid)
|
|
270
|
+
* `sidebar` sidebar column
|
|
271
|
+
* `card` cards/panels (center + details columns, dialog option panels)
|
|
272
|
+
* `settings` settings panel
|
|
273
|
+
* `chat` conversation text region (message column of the chat view)
|
|
274
|
+
* `trajectory` trajectory view surface
|
|
275
|
+
* `rightbar` file-preview panel — the right sidebar a file click opens
|
|
276
|
+
* `input` input/control surfaces ([data-composer-card], [data-cordis-panel])
|
|
277
|
+
*/
|
|
278
|
+
const PART_BLUR_KEYS = [
|
|
279
|
+
"bg",
|
|
280
|
+
"sidebar",
|
|
281
|
+
"card",
|
|
282
|
+
"settings",
|
|
283
|
+
"chat",
|
|
284
|
+
"trajectory",
|
|
285
|
+
"rightbar",
|
|
286
|
+
"input"
|
|
287
|
+
];
|
|
288
|
+
const DEFAULT_PART_BLURS = {
|
|
289
|
+
bg: 0,
|
|
290
|
+
sidebar: 0,
|
|
291
|
+
card: 0,
|
|
292
|
+
settings: 0,
|
|
293
|
+
chat: 0,
|
|
294
|
+
trajectory: 0,
|
|
295
|
+
rightbar: 0,
|
|
296
|
+
input: 0
|
|
297
|
+
};
|
|
298
|
+
/** A default config with independent nested objects (never hand out the shared ones). */
|
|
299
|
+
function freshThemeConfig() {
|
|
300
|
+
return {
|
|
301
|
+
rules: [],
|
|
302
|
+
opacities: { ...DEFAULT_PART_OPACITIES },
|
|
303
|
+
blurs: { ...DEFAULT_PART_BLURS },
|
|
304
|
+
settingsOpacity: 1,
|
|
305
|
+
chatTextOpacity: 0,
|
|
306
|
+
trajectoryOpacity: 1,
|
|
307
|
+
rightbarOpacity: null,
|
|
308
|
+
autoExtract: true
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/** Slot names reach the filesystem, so they are strictly whitelisted. */
|
|
312
|
+
const SLOT_RE = /^[A-Za-z0-9_-]{1,32}$/;
|
|
313
|
+
function clamp$1(n, lo, hi, def) {
|
|
314
|
+
return typeof n === "number" && isFinite(n) ? Math.min(hi, Math.max(lo, n)) : def;
|
|
315
|
+
}
|
|
316
|
+
const clamp01 = (n, def) => clamp$1(n, 0, 1, def);
|
|
317
|
+
function normalizeBgState(s) {
|
|
318
|
+
const v = s ?? {};
|
|
319
|
+
return {
|
|
320
|
+
zoom: clamp$1(v.zoom, .1, 10, 1),
|
|
321
|
+
x: typeof v.x === "number" && isFinite(v.x) ? v.x : 0,
|
|
322
|
+
y: typeof v.y === "number" && isFinite(v.y) ? v.y : 0,
|
|
323
|
+
iw: typeof v.iw === "number" && v.iw > 0 ? v.iw : 0,
|
|
324
|
+
ih: typeof v.ih === "number" && v.ih > 0 ? v.ih : 0
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/** One `[h, s, l]` triple, or null when the value is not a complete finite triple. */
|
|
328
|
+
function normalizeHsl(raw) {
|
|
329
|
+
if (!Array.isArray(raw) || raw.length !== 3) return null;
|
|
330
|
+
if (!raw.every((n) => typeof n === "number" && isFinite(n))) return null;
|
|
331
|
+
return [
|
|
332
|
+
clamp$1(raw[0], 0, 360, 220),
|
|
333
|
+
clamp$1(raw[1], 0, 1, .55),
|
|
334
|
+
clamp$1(raw[2], 0, 1, .25)
|
|
335
|
+
];
|
|
336
|
+
}
|
|
337
|
+
/** Coerce one persisted rule, or null when it lacks a usable id/slot. */
|
|
338
|
+
function normalizeRule(raw) {
|
|
339
|
+
const r = raw ?? {};
|
|
340
|
+
const id = typeof r.id === "string" && r.id !== "" ? r.id : null;
|
|
341
|
+
const slot = typeof r.slot === "string" && SLOT_RE.test(r.slot) ? r.slot : null;
|
|
342
|
+
if (id === null || slot === null) return null;
|
|
343
|
+
const mode = BG_MODES$1.includes(r.bgMode) ? r.bgMode : "fit";
|
|
344
|
+
return {
|
|
345
|
+
id,
|
|
346
|
+
slot,
|
|
347
|
+
match: typeof r.match === "string" ? r.match : "",
|
|
348
|
+
enabled: r.enabled !== false,
|
|
349
|
+
color: normalizeHsl(r.color),
|
|
350
|
+
bgMode: mode,
|
|
351
|
+
wallpaperOpacity: clamp01(r.wallpaperOpacity, 1),
|
|
352
|
+
blur: clamp$1(r.blur, 0, 60, 0),
|
|
353
|
+
bgState: normalizeBgState(r.bgState)
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/** Coerce an unknown persisted value into a valid ThemeConfig, falling back per-field. */
|
|
357
|
+
function normalizeConfig(raw) {
|
|
358
|
+
const r = raw ?? {};
|
|
359
|
+
const rules = Array.isArray(r.rules) ? r.rules.map(normalizeRule).filter((x) => x !== null) : [];
|
|
360
|
+
const ops = r.opacities ?? {};
|
|
361
|
+
const bl = r.blurs ?? {};
|
|
362
|
+
const blurs = {};
|
|
363
|
+
for (const k of PART_BLUR_KEYS) blurs[k] = clamp$1(bl[k], 0, 60, DEFAULT_PART_BLURS[k]);
|
|
364
|
+
const opacities = {};
|
|
365
|
+
for (const k of PART_OPACITY_KEYS) opacities[k] = clamp01(ops[k], DEFAULT_PART_OPACITIES[k]);
|
|
366
|
+
return {
|
|
367
|
+
rules,
|
|
368
|
+
opacities,
|
|
369
|
+
blurs,
|
|
370
|
+
settingsOpacity: clamp01(r.settingsOpacity, 1),
|
|
371
|
+
chatTextOpacity: clamp01(r.chatTextOpacity, 0),
|
|
372
|
+
trajectoryOpacity: clamp01(r.trajectoryOpacity, 1),
|
|
373
|
+
rightbarOpacity: typeof r.rightbarOpacity === "number" && isFinite(r.rightbarOpacity) ? clamp01(r.rightbarOpacity, 1) : null,
|
|
374
|
+
autoExtract: r.autoExtract !== false
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/client/state.ts
|
|
245
379
|
const PALETTE = [
|
|
246
380
|
[
|
|
247
381
|
356,
|
|
@@ -284,38 +418,8 @@ window.__ModuleLoader__.load({
|
|
|
284
418
|
.58
|
|
285
419
|
]
|
|
286
420
|
];
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
opacities: {
|
|
290
|
-
bg: .85,
|
|
291
|
-
sidebar: .93,
|
|
292
|
-
card: 1,
|
|
293
|
-
input: 1
|
|
294
|
-
},
|
|
295
|
-
blurs: {
|
|
296
|
-
bg: 0,
|
|
297
|
-
sidebar: 0,
|
|
298
|
-
card: 0,
|
|
299
|
-
settings: 0,
|
|
300
|
-
chat: 0,
|
|
301
|
-
trajectory: 0,
|
|
302
|
-
input: 0
|
|
303
|
-
},
|
|
304
|
-
settingsOpacity: 1,
|
|
305
|
-
chatTextOpacity: 0,
|
|
306
|
-
trajectoryOpacity: 1
|
|
307
|
-
};
|
|
308
|
-
function freshConfig() {
|
|
309
|
-
return {
|
|
310
|
-
rules: [],
|
|
311
|
-
opacities: { ...DEFAULT_CONFIG.opacities },
|
|
312
|
-
blurs: { ...DEFAULT_CONFIG.blurs },
|
|
313
|
-
settingsOpacity: DEFAULT_CONFIG.settingsOpacity,
|
|
314
|
-
chatTextOpacity: DEFAULT_CONFIG.chatTextOpacity,
|
|
315
|
-
trajectoryOpacity: DEFAULT_CONFIG.trajectoryOpacity
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
let cfg = freshConfig();
|
|
421
|
+
freshThemeConfig();
|
|
422
|
+
let cfg = freshThemeConfig();
|
|
319
423
|
const images = /* @__PURE__ */ new Map();
|
|
320
424
|
const displayUrls = /* @__PURE__ */ new Map();
|
|
321
425
|
function revokeDisplay(slot) {
|
|
@@ -412,8 +516,6 @@ window.__ModuleLoader__.load({
|
|
|
412
516
|
}
|
|
413
517
|
return `r${Date.now()}`;
|
|
414
518
|
}
|
|
415
|
-
const clamp01 = (n, def) => typeof n === "number" && isFinite(n) ? Math.min(1, Math.max(0, n)) : def;
|
|
416
|
-
const clamp$1 = (n, lo, hi, def) => typeof n === "number" && isFinite(n) ? Math.min(hi, Math.max(lo, n)) : def;
|
|
417
519
|
function rHasColor() {
|
|
418
520
|
return activeRule()?.color !== null && activeRule() !== null;
|
|
419
521
|
}
|
|
@@ -444,100 +546,33 @@ window.__ModuleLoader__.load({
|
|
|
444
546
|
function rOps() {
|
|
445
547
|
const o = cfg.opacities ?? {};
|
|
446
548
|
const out = {};
|
|
447
|
-
for (const k of [
|
|
448
|
-
"bg",
|
|
449
|
-
"sidebar",
|
|
450
|
-
"card",
|
|
451
|
-
"input"
|
|
452
|
-
]) out[k] = clamp01(o[k], DEFAULT_CONFIG.opacities[k]);
|
|
549
|
+
for (const k of PART_OPACITY_KEYS) out[k] = clamp01(o[k], DEFAULT_PART_OPACITIES[k]);
|
|
453
550
|
return out;
|
|
454
551
|
}
|
|
455
552
|
function rBlurs() {
|
|
456
553
|
const b = cfg.blurs ?? {};
|
|
457
554
|
const out = {};
|
|
458
|
-
for (const k of [
|
|
459
|
-
"bg",
|
|
460
|
-
"sidebar",
|
|
461
|
-
"card",
|
|
462
|
-
"settings",
|
|
463
|
-
"chat",
|
|
464
|
-
"trajectory",
|
|
465
|
-
"input"
|
|
466
|
-
]) out[k] = clamp$1(b[k], 0, 60, DEFAULT_CONFIG.blurs[k]);
|
|
555
|
+
for (const k of PART_BLUR_KEYS) out[k] = clamp$1(b[k], 0, 60, DEFAULT_PART_BLURS[k]);
|
|
467
556
|
return out;
|
|
468
557
|
}
|
|
469
558
|
function rSop() {
|
|
470
|
-
return clamp01(cfg.settingsOpacity,
|
|
559
|
+
return clamp01(cfg.settingsOpacity, 1);
|
|
471
560
|
}
|
|
472
561
|
function rChatTextOpacity() {
|
|
473
|
-
return clamp01(cfg.chatTextOpacity,
|
|
562
|
+
return clamp01(cfg.chatTextOpacity, 0);
|
|
474
563
|
}
|
|
475
564
|
function rTrajectoryOpacity() {
|
|
476
|
-
return clamp01(cfg.trajectoryOpacity,
|
|
565
|
+
return clamp01(cfg.trajectoryOpacity, 1);
|
|
477
566
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
y: typeof s.y === "number" && isFinite(s.y) ? s.y : 0,
|
|
483
|
-
iw: typeof s.iw === "number" && s.iw > 0 ? s.iw : 0,
|
|
484
|
-
ih: typeof s.ih === "number" && s.ih > 0 ? s.ih : 0
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
/** Coerce one persisted rule, or null when it lacks a usable id/slot. */
|
|
488
|
-
function normalizeRule(raw) {
|
|
489
|
-
const r = raw ?? {};
|
|
490
|
-
const id = typeof r.id === "string" && r.id !== "" ? r.id : null;
|
|
491
|
-
const slot = typeof r.slot === "string" && /^[A-Za-z0-9_-]{1,32}$/.test(r.slot) ? r.slot : null;
|
|
492
|
-
if (id === null || slot === null) return null;
|
|
493
|
-
const c = r.color;
|
|
494
|
-
const color = Array.isArray(c) && c.length === 3 && c.every((n) => typeof n === "number" && isFinite(n)) ? [
|
|
495
|
-
clamp$1(c[0], 0, 360, 220),
|
|
496
|
-
clamp$1(c[1], 0, 1, .55),
|
|
497
|
-
clamp$1(c[2], 0, 1, .25)
|
|
498
|
-
] : null;
|
|
499
|
-
return {
|
|
500
|
-
id,
|
|
501
|
-
slot,
|
|
502
|
-
match: typeof r.match === "string" ? r.match : "",
|
|
503
|
-
enabled: r.enabled !== false,
|
|
504
|
-
color,
|
|
505
|
-
bgMode: BG_MODES$1.includes(r.bgMode) ? r.bgMode : "fit",
|
|
506
|
-
wallpaperOpacity: clamp01(r.wallpaperOpacity, 1),
|
|
507
|
-
blur: clamp$1(r.blur, 0, 60, 0),
|
|
508
|
-
bgState: adoptBgState(r.bgState ?? {})
|
|
509
|
-
};
|
|
567
|
+
/** Own opacity of the file-preview panel; while unowned it IS the main background's. */
|
|
568
|
+
function rRightbarOpacity() {
|
|
569
|
+
const own = cfg.rightbarOpacity;
|
|
570
|
+
return typeof own === "number" && isFinite(own) ? clamp01(own, 1) : rOps().bg;
|
|
510
571
|
}
|
|
511
572
|
/** Move a possibly-absent partial config into the shape the UI reads. */
|
|
512
573
|
function adoptConfig(raw) {
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const ops = c.opacities ?? {};
|
|
516
|
-
const bl = c.blurs ?? {};
|
|
517
|
-
const blurs = {};
|
|
518
|
-
for (const k of [
|
|
519
|
-
"bg",
|
|
520
|
-
"sidebar",
|
|
521
|
-
"card",
|
|
522
|
-
"settings",
|
|
523
|
-
"chat",
|
|
524
|
-
"trajectory",
|
|
525
|
-
"input"
|
|
526
|
-
]) blurs[k] = clamp$1(bl[k], 0, 60, DEFAULT_CONFIG.blurs[k]);
|
|
527
|
-
cfg = {
|
|
528
|
-
rules,
|
|
529
|
-
opacities: {
|
|
530
|
-
bg: clamp01(ops.bg, DEFAULT_CONFIG.opacities.bg),
|
|
531
|
-
sidebar: clamp01(ops.sidebar, DEFAULT_CONFIG.opacities.sidebar),
|
|
532
|
-
card: clamp01(ops.card, DEFAULT_CONFIG.opacities.card),
|
|
533
|
-
input: clamp01(ops.input, DEFAULT_CONFIG.opacities.input)
|
|
534
|
-
},
|
|
535
|
-
blurs,
|
|
536
|
-
settingsOpacity: clamp01(c.settingsOpacity, DEFAULT_CONFIG.settingsOpacity),
|
|
537
|
-
chatTextOpacity: clamp01(c.chatTextOpacity, DEFAULT_CONFIG.chatTextOpacity),
|
|
538
|
-
trajectoryOpacity: clamp01(c.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity)
|
|
539
|
-
};
|
|
540
|
-
if (activeRuleId !== null && !rules.some((r) => r.id === activeRuleId)) {
|
|
574
|
+
cfg = normalizeConfig(raw);
|
|
575
|
+
if (activeRuleId !== null && !cfg.rules.some((r) => r.id === activeRuleId)) {
|
|
541
576
|
activeRuleId = null;
|
|
542
577
|
activeMatched = false;
|
|
543
578
|
}
|
|
@@ -894,7 +929,7 @@ window.__ModuleLoader__.load({
|
|
|
894
929
|
const max = Math.max(r, gg, b), min = Math.min(r, gg, b);
|
|
895
930
|
const v = max / 255;
|
|
896
931
|
const s = max === 0 ? 0 : (max - min) / max;
|
|
897
|
-
totalLum +=
|
|
932
|
+
totalLum += (.2126 * r + .7152 * gg + .0722 * b) / 255;
|
|
898
933
|
sampled++;
|
|
899
934
|
if (s < .08 || v < .12 || v > .97) continue;
|
|
900
935
|
const key = r >> 4 << 8 | gg >> 4 << 4 | b >> 4;
|
|
@@ -1133,6 +1168,23 @@ window.__ModuleLoader__.load({
|
|
|
1133
1168
|
if (layer2 !== void 0) document.documentElement.style.setProperty("--dsh-any-traj-layer-2", toRgba(layer2, op));
|
|
1134
1169
|
if (layer3 !== void 0) document.documentElement.style.setProperty("--dsh-any-traj-layer-3", toRgba(layer3, op));
|
|
1135
1170
|
}
|
|
1171
|
+
const RIGHTBAR_STYLE_RULE = "div[data-sidebar-right-panel]{background:var(--dsh-any-bg-rightbar,var(--dsw-alias-bg-base))!important;-webkit-backdrop-filter:var(--dsh-any-blur-rightbar,none);backdrop-filter:var(--dsh-any-blur-rightbar,none)}";
|
|
1172
|
+
/** Paint the file-preview panel's surface from its own slider. */
|
|
1173
|
+
function applyRightbarOverrides(op) {
|
|
1174
|
+
const root = document.documentElement;
|
|
1175
|
+
if (!rHasColor()) {
|
|
1176
|
+
root.style.removeProperty("--dsh-any-bg-rightbar");
|
|
1177
|
+
return;
|
|
1178
|
+
}
|
|
1179
|
+
const [h, s, l] = rColor();
|
|
1180
|
+
const base = genTokens(h, s, l).tokens["--dsw-alias-bg-base"];
|
|
1181
|
+
if (base !== void 0) root.style.setProperty("--dsh-any-bg-rightbar", toRgba(base, op));
|
|
1182
|
+
}
|
|
1183
|
+
/** Extra backdrop frost for the file-preview panel (0 = no frost of its own). */
|
|
1184
|
+
function applyRightbarBlur(px) {
|
|
1185
|
+
if (px > 0) document.documentElement.style.setProperty("--dsh-any-blur-rightbar", `blur(${px}px)`);
|
|
1186
|
+
else document.documentElement.style.removeProperty("--dsh-any-blur-rightbar");
|
|
1187
|
+
}
|
|
1136
1188
|
let frameEl = null;
|
|
1137
1189
|
let sidebarEl = null;
|
|
1138
1190
|
let centerEl = null;
|
|
@@ -1221,6 +1273,7 @@ window.__ModuleLoader__.load({
|
|
|
1221
1273
|
applyCardPanelsBlur(blurs.card);
|
|
1222
1274
|
applySettingsBlur(blurs.settings);
|
|
1223
1275
|
applyInputBlur(blurs.input);
|
|
1276
|
+
applyRightbarBlur(blurs.rightbar);
|
|
1224
1277
|
applyViewCards();
|
|
1225
1278
|
}
|
|
1226
1279
|
/** Live per-part blur update during slider drag (no full re-apply). */
|
|
@@ -1237,6 +1290,10 @@ window.__ModuleLoader__.load({
|
|
|
1237
1290
|
applyInputBlur(v);
|
|
1238
1291
|
return;
|
|
1239
1292
|
}
|
|
1293
|
+
if (part === "rightbar") {
|
|
1294
|
+
applyRightbarBlur(v);
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1240
1297
|
if (part === "chat" || part === "trajectory") {
|
|
1241
1298
|
applyViewCards();
|
|
1242
1299
|
return;
|
|
@@ -1728,6 +1785,7 @@ window.__ModuleLoader__.load({
|
|
|
1728
1785
|
baseTokenKey = "";
|
|
1729
1786
|
lastBgKey = "";
|
|
1730
1787
|
}
|
|
1788
|
+
applyRightbarOverrides(rRightbarOpacity());
|
|
1731
1789
|
applyPartBlurs(rBlurs());
|
|
1732
1790
|
}
|
|
1733
1791
|
function teardownWp() {
|
|
@@ -1748,6 +1806,8 @@ window.__ModuleLoader__.load({
|
|
|
1748
1806
|
document.documentElement.style.removeProperty("--dsh-any-blur-settings");
|
|
1749
1807
|
document.documentElement.style.removeProperty("--dsh-any-blur-card-panels");
|
|
1750
1808
|
document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
1809
|
+
document.documentElement.style.removeProperty("--dsh-any-bg-rightbar");
|
|
1810
|
+
document.documentElement.style.removeProperty("--dsh-any-blur-rightbar");
|
|
1751
1811
|
for (const v of Object.values(OPACITY_VARS)) document.documentElement.style.removeProperty(v);
|
|
1752
1812
|
baseTokenKey = "";
|
|
1753
1813
|
lastBgKey = "";
|
|
@@ -2149,12 +2209,6 @@ window.__ModuleLoader__.load({
|
|
|
2149
2209
|
.dab-crash-desc{font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center;line-height:1.5}
|
|
2150
2210
|
|
|
2151
2211
|
/* ── model rules ─────────────────────────────────────────────────────────── */
|
|
2152
|
-
.dab-status{display:flex;align-items:center;gap:10px;flex-wrap:wrap;font-size:12.5px;color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
2153
|
-
.dab-status-model{font-family:var(--dab-mono);font-size:12.5px;font-weight:600;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:3px 9px}
|
|
2154
|
-
.dab-status-arrow{color:var(--dsw-alias-brand-primary);font-weight:700}
|
|
2155
|
-
.dab-status-hit{color:var(--dsw-alias-brand-primary);font-weight:600}
|
|
2156
|
-
.dab-status-none{color:var(--dsw-alias-state-error-primary)}
|
|
2157
|
-
.dab-status-src{font-size:11px;font-weight:600;letter-spacing:.02em;text-transform:uppercase;color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-tertiary));background:var(--dsw-alias-interactive-bg-hover);border-radius:6px;padding:2px 7px}
|
|
2158
2212
|
.dab-rules{display:flex;flex-direction:column;gap:12px}
|
|
2159
2213
|
.dab-rule{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:16px;padding:14px;transition:border-color .25s,box-shadow .25s,opacity .25s}
|
|
2160
2214
|
.dab-rule.is-active{border-color:var(--dsw-alias-brand-primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--dsw-alias-brand-primary) 16%,transparent)}
|
|
@@ -2413,6 +2467,22 @@ window.__ModuleLoader__.load({
|
|
|
2413
2467
|
rx: "2"
|
|
2414
2468
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M6.6 2.2v11.6" })]
|
|
2415
2469
|
});
|
|
2470
|
+
/** Mirror of SidebarIcon: the file-preview panel docked to the right edge. */
|
|
2471
|
+
const PreviewIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
|
|
2472
|
+
size,
|
|
2473
|
+
className,
|
|
2474
|
+
children: [
|
|
2475
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
2476
|
+
x: "2.2",
|
|
2477
|
+
y: "2.2",
|
|
2478
|
+
width: "11.6",
|
|
2479
|
+
height: "11.6",
|
|
2480
|
+
rx: "2"
|
|
2481
|
+
}),
|
|
2482
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M9.4 2.2v11.6" }),
|
|
2483
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M11 5.6h1.2M11 8h1.2" })
|
|
2484
|
+
]
|
|
2485
|
+
});
|
|
2416
2486
|
const ChatIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Glyph, {
|
|
2417
2487
|
size,
|
|
2418
2488
|
className,
|
|
@@ -2594,6 +2664,11 @@ window.__ModuleLoader__.load({
|
|
|
2594
2664
|
labelKey: "uiOpacitySide",
|
|
2595
2665
|
Icon: SidebarIcon
|
|
2596
2666
|
},
|
|
2667
|
+
{
|
|
2668
|
+
isRightbar: true,
|
|
2669
|
+
labelKey: "uiPreview",
|
|
2670
|
+
Icon: PreviewIcon
|
|
2671
|
+
},
|
|
2597
2672
|
{
|
|
2598
2673
|
opKey: "card",
|
|
2599
2674
|
labelKey: "uiOpacityCard",
|
|
@@ -2621,7 +2696,7 @@ window.__ModuleLoader__.load({
|
|
|
2621
2696
|
}
|
|
2622
2697
|
];
|
|
2623
2698
|
function InterfacePage({ p }) {
|
|
2624
|
-
const { t, setOps, setBlurs, setSop } = p;
|
|
2699
|
+
const { t, setOps, setBlurs, setSop, setRightbarOpacity } = p;
|
|
2625
2700
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
2626
2701
|
className: "dab-head dab-rise",
|
|
2627
2702
|
style: { "--d": 0 },
|
|
@@ -2637,20 +2712,15 @@ window.__ModuleLoader__.load({
|
|
|
2637
2712
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2638
2713
|
className: "dab-desc",
|
|
2639
2714
|
children: t("descInterface")
|
|
2640
|
-
}),
|
|
2641
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2642
|
-
className: "dab-hint",
|
|
2643
|
-
style: { marginTop: 7 },
|
|
2644
|
-
children: t("uiScopeHint")
|
|
2645
2715
|
})
|
|
2646
2716
|
]
|
|
2647
2717
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2648
2718
|
className: "dab-grid-parts",
|
|
2649
2719
|
children: PARTS.map((part, i) => {
|
|
2650
|
-
const { labelKey, Icon, isSettings, isChat, isTrajectory } = part;
|
|
2720
|
+
const { labelKey, Icon, isSettings, isChat, isTrajectory, isRightbar } = part;
|
|
2651
2721
|
const opKey = part.opKey;
|
|
2652
|
-
const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : opKey;
|
|
2653
|
-
const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : rOps()[opKey];
|
|
2722
|
+
const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isRightbar ? "rightbar" : isSettings ? "settings" : opKey;
|
|
2723
|
+
const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isRightbar ? rRightbarOpacity() : isSettings ? rSop() : rOps()[opKey];
|
|
2654
2724
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
2655
2725
|
className: "dab-card dab-card-hover dab-rise",
|
|
2656
2726
|
style: { "--d": i + 1 },
|
|
@@ -2687,6 +2757,9 @@ window.__ModuleLoader__.load({
|
|
|
2687
2757
|
} else if (isTrajectory) {
|
|
2688
2758
|
cfg.trajectoryOpacity = op;
|
|
2689
2759
|
applyTrajectoryOverrides(op);
|
|
2760
|
+
} else if (isRightbar) {
|
|
2761
|
+
cfg.rightbarOpacity = op;
|
|
2762
|
+
applyRightbarOverrides(op);
|
|
2690
2763
|
} else if (isSettings) {
|
|
2691
2764
|
cfg.settingsOpacity = op;
|
|
2692
2765
|
applySettingsOverrides(op);
|
|
@@ -2708,7 +2781,8 @@ window.__ModuleLoader__.load({
|
|
|
2708
2781
|
cfg.trajectoryOpacity = op;
|
|
2709
2782
|
applyTrajectoryOverrides(op);
|
|
2710
2783
|
saveConfig();
|
|
2711
|
-
} else if (
|
|
2784
|
+
} else if (isRightbar) setRightbarOpacity(op);
|
|
2785
|
+
else if (isSettings) setSop(op);
|
|
2712
2786
|
else {
|
|
2713
2787
|
const ops = { ...rOps() };
|
|
2714
2788
|
ops[opKey] = op;
|
|
@@ -3520,7 +3594,20 @@ window.__ModuleLoader__.load({
|
|
|
3520
3594
|
const { t, useStore } = p;
|
|
3521
3595
|
const store = useStore((s) => s);
|
|
3522
3596
|
const rules = cfg.rules;
|
|
3523
|
-
const
|
|
3597
|
+
const [text, setText] = (0, react.useState)("");
|
|
3598
|
+
const [touched, setTouched] = (0, react.useState)(false);
|
|
3599
|
+
(0, react.useEffect)(() => {
|
|
3600
|
+
if (!touched) setText(store.model);
|
|
3601
|
+
}, [store.model, touched]);
|
|
3602
|
+
const probe = text.trim();
|
|
3603
|
+
const result = (() => {
|
|
3604
|
+
if (probe === "") return null;
|
|
3605
|
+
const hit = matchRule(rules, probe);
|
|
3606
|
+
const rule = hit.rule;
|
|
3607
|
+
if (rule === null) return null;
|
|
3608
|
+
const n = rules.findIndex((r) => r.id === rule.id) + 1;
|
|
3609
|
+
return `${hit.matched ? t("tryoutHit") : t("tryoutFallback")} ${n}`;
|
|
3610
|
+
})();
|
|
3524
3611
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3525
3612
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
3526
3613
|
className: "dab-head dab-rise",
|
|
@@ -3544,48 +3631,50 @@ window.__ModuleLoader__.load({
|
|
|
3544
3631
|
className: "dab-card dab-rise",
|
|
3545
3632
|
style: { "--d": 1 },
|
|
3546
3633
|
children: [
|
|
3634
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3635
|
+
className: "dab-swatch-title",
|
|
3636
|
+
children: t("tryoutTitle")
|
|
3637
|
+
}),
|
|
3547
3638
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
activeIndex + 1
|
|
3574
|
-
]
|
|
3575
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3576
|
-
className: "dab-status-none",
|
|
3577
|
-
children: t("statusNone")
|
|
3578
|
-
})
|
|
3579
|
-
]
|
|
3639
|
+
style: {
|
|
3640
|
+
marginTop: 10,
|
|
3641
|
+
display: "flex",
|
|
3642
|
+
flexWrap: "wrap",
|
|
3643
|
+
gap: 8,
|
|
3644
|
+
alignItems: "center"
|
|
3645
|
+
},
|
|
3646
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3647
|
+
type: "text",
|
|
3648
|
+
className: "dab-urlinput",
|
|
3649
|
+
value: text,
|
|
3650
|
+
placeholder: t("tryoutPlaceholder"),
|
|
3651
|
+
onChange: (e) => {
|
|
3652
|
+
setTouched(true);
|
|
3653
|
+
setText(e.target.value);
|
|
3654
|
+
}
|
|
3655
|
+
}), store.model !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3656
|
+
type: "button",
|
|
3657
|
+
className: "dab-btn",
|
|
3658
|
+
onClick: () => {
|
|
3659
|
+
setTouched(true);
|
|
3660
|
+
setText(store.model);
|
|
3661
|
+
},
|
|
3662
|
+
children: t("tryoutUseCurrent")
|
|
3663
|
+
}) : null]
|
|
3580
3664
|
}),
|
|
3581
|
-
|
|
3665
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3582
3666
|
className: "dab-hint",
|
|
3583
3667
|
style: { marginTop: 9 },
|
|
3668
|
+
children: probe === "" ? t("tryoutEmpty") : result === null ? t("tryoutNone") : result
|
|
3669
|
+
}),
|
|
3670
|
+
store.model === "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3671
|
+
className: "dab-hint",
|
|
3672
|
+
style: { marginTop: 6 },
|
|
3584
3673
|
children: t("statusUnknownHint")
|
|
3585
3674
|
}) : null,
|
|
3586
3675
|
store.model !== "" && store.modelSource === "default" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3587
3676
|
className: "dab-hint",
|
|
3588
|
-
style: { marginTop:
|
|
3677
|
+
style: { marginTop: 6 },
|
|
3589
3678
|
children: t("statusSourceDefaultHint")
|
|
3590
3679
|
}) : null,
|
|
3591
3680
|
MODEL_NOTE_KEYS[store.modelNote] !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -3608,6 +3697,30 @@ window.__ModuleLoader__.load({
|
|
|
3608
3697
|
style: { marginBottom: 11 },
|
|
3609
3698
|
children: t("rulesHint")
|
|
3610
3699
|
}),
|
|
3700
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3701
|
+
className: "dab-chip-row",
|
|
3702
|
+
style: {
|
|
3703
|
+
marginBottom: 12,
|
|
3704
|
+
alignItems: "center"
|
|
3705
|
+
},
|
|
3706
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3707
|
+
type: "button",
|
|
3708
|
+
className: `dab-toggle${cfg.autoExtract ? " is-on" : ""}`,
|
|
3709
|
+
role: "switch",
|
|
3710
|
+
"aria-checked": cfg.autoExtract,
|
|
3711
|
+
title: t("autoExtract"),
|
|
3712
|
+
onClick: () => p.setAutoExtract(!cfg.autoExtract),
|
|
3713
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dab-toggle-knob" })
|
|
3714
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3715
|
+
className: "dab-hint",
|
|
3716
|
+
children: t("autoExtract")
|
|
3717
|
+
})]
|
|
3718
|
+
}),
|
|
3719
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3720
|
+
className: "dab-hint",
|
|
3721
|
+
style: { marginBottom: 11 },
|
|
3722
|
+
children: t("autoExtractHint")
|
|
3723
|
+
}),
|
|
3611
3724
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3612
3725
|
className: "dab-rules",
|
|
3613
3726
|
children: rules.map((rule, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuleCard, {
|
|
@@ -4295,7 +4408,7 @@ window.__ModuleLoader__.load({
|
|
|
4295
4408
|
}, "dsh-background-by-model: skin dispose");
|
|
4296
4409
|
const styleEl = document.createElement("style");
|
|
4297
4410
|
styleEl.dataset.plugin = "dsh-background-by-model";
|
|
4298
|
-
styleEl.textContent = `body[data-ds-dark-theme="dsh-background-by-model"]::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}[data-composer-card] textarea::placeholder,[data-composer-card] input::placeholder,[data-composer-card] [contenteditable]::placeholder,[data-cordis-panel] input::placeholder,[data-cordis-panel] textarea::placeholder,.dab-input::placeholder,.dab-input textarea::placeholder,.dab-input input::placeholder{color:var(--dsh-any-placeholder,var(--dsw-alias-label-caption,#8a8f98))!important;font-style:italic;opacity:.85}`;
|
|
4411
|
+
styleEl.textContent = `body[data-ds-dark-theme="dsh-background-by-model"]::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}${RIGHTBAR_STYLE_RULE}${INPUT_BLUR_RULE}[data-composer-card] textarea::placeholder,[data-composer-card] input::placeholder,[data-composer-card] [contenteditable]::placeholder,[data-cordis-panel] input::placeholder,[data-cordis-panel] textarea::placeholder,.dab-input::placeholder,.dab-input textarea::placeholder,.dab-input input::placeholder{color:var(--dsh-any-placeholder,var(--dsw-alias-label-caption,#8a8f98))!important;font-style:italic;opacity:.85}`;
|
|
4299
4412
|
document.head.appendChild(styleEl);
|
|
4300
4413
|
ctx.effect(() => () => {
|
|
4301
4414
|
styleEl?.parentNode?.removeChild(styleEl);
|
|
@@ -4428,6 +4541,36 @@ window.__ModuleLoader__.load({
|
|
|
4428
4541
|
zh,
|
|
4429
4542
|
en
|
|
4430
4543
|
}), "dsh-background-by-model: i18n");
|
|
4544
|
+
/**
|
|
4545
|
+
* The automatic half of "extract from image": fill a rule's theme color from
|
|
4546
|
+
* the picture it just received, but only while the rule has no color at all —
|
|
4547
|
+
* a color the user picked (or a previous extraction produced) is never
|
|
4548
|
+
* overwritten, so this cannot fight a deliberate choice.
|
|
4549
|
+
*
|
|
4550
|
+
* The decode is asynchronous, so the "still empty?" question is asked AGAIN on
|
|
4551
|
+
* arrival: a color chosen while it ran must win over the one being computed.
|
|
4552
|
+
*/
|
|
4553
|
+
const maybeAutoExtract = async (id) => {
|
|
4554
|
+
if (!cfg.autoExtract) return;
|
|
4555
|
+
const rule = ruleById(id);
|
|
4556
|
+
if (rule === null || rule.color !== null) return;
|
|
4557
|
+
const url = displayImageOf(rule.slot);
|
|
4558
|
+
if (url === null) return;
|
|
4559
|
+
let hsl = null;
|
|
4560
|
+
try {
|
|
4561
|
+
hsl = await extractWallpaperColor(url, rule.bgState);
|
|
4562
|
+
} catch {
|
|
4563
|
+
hsl = null;
|
|
4564
|
+
}
|
|
4565
|
+
if (hsl === null) return;
|
|
4566
|
+
const current = ruleById(id);
|
|
4567
|
+
if (current === null || current.color !== null) return;
|
|
4568
|
+
current.color = hsl;
|
|
4569
|
+
rulesRev++;
|
|
4570
|
+
saveConfig();
|
|
4571
|
+
if (id === activeRuleId) applyActive();
|
|
4572
|
+
else sync();
|
|
4573
|
+
};
|
|
4431
4574
|
const sectionInject = (actions) => {
|
|
4432
4575
|
bound = actions;
|
|
4433
4576
|
sync();
|
|
@@ -4482,6 +4625,7 @@ window.__ModuleLoader__.load({
|
|
|
4482
4625
|
dataUrl === null ? deleteImage(rule.slot) : writeImage(rule.slot, dataUrl);
|
|
4483
4626
|
if (id === activeRuleId) applyActive();
|
|
4484
4627
|
else sync();
|
|
4628
|
+
if (dataUrl !== null) maybeAutoExtract(id);
|
|
4485
4629
|
},
|
|
4486
4630
|
setRuleImageFromUrl: async (id, url) => {
|
|
4487
4631
|
const rule = ruleById(id);
|
|
@@ -4494,6 +4638,7 @@ window.__ModuleLoader__.load({
|
|
|
4494
4638
|
setImage(rule.slot, res.dataUrl ?? null);
|
|
4495
4639
|
if (id === activeRuleId) applyActive();
|
|
4496
4640
|
else sync();
|
|
4641
|
+
maybeAutoExtract(id);
|
|
4497
4642
|
}
|
|
4498
4643
|
return res;
|
|
4499
4644
|
},
|
|
@@ -4528,6 +4673,16 @@ window.__ModuleLoader__.load({
|
|
|
4528
4673
|
applySettingsOverrides(v);
|
|
4529
4674
|
saveConfig();
|
|
4530
4675
|
},
|
|
4676
|
+
setRightbarOpacity: (v) => {
|
|
4677
|
+
cfg.rightbarOpacity = v;
|
|
4678
|
+
applyRightbarOverrides(rRightbarOpacity());
|
|
4679
|
+
saveConfig();
|
|
4680
|
+
},
|
|
4681
|
+
setAutoExtract: (v) => {
|
|
4682
|
+
cfg.autoExtract = v;
|
|
4683
|
+
saveConfig();
|
|
4684
|
+
sync();
|
|
4685
|
+
},
|
|
4531
4686
|
exportTheme: () => {
|
|
4532
4687
|
const images = {};
|
|
4533
4688
|
for (const rule of cfg.rules) {
|