dsh-background-by-model 0.5.1 → 0.5.3
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 +22 -3
- package/README.zh.md +22 -3
- package/lib/client.js +345 -99
- package/lib/client.js.map +1 -1
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -78,7 +78,9 @@ window.__ModuleLoader__.load({
|
|
|
78
78
|
ruleEmptyHint: "这条规则还没有图片,不会被匹配到,也不会作为兜底",
|
|
79
79
|
ruleColor: "主题色",
|
|
80
80
|
ruleColorNone: "系统主题",
|
|
81
|
-
ruleColorNoneHint: "
|
|
81
|
+
ruleColorNoneHint: "未设颜色时跟随系统主题:界面用宿主的配色,壁纸与各部位的透明度、模糊照旧生效",
|
|
82
|
+
ruleColorPick: "自定义颜色",
|
|
83
|
+
ruleColorPickHint: "优先从本图取色,取不到就用默认色",
|
|
82
84
|
ruleColorExtract: "从本图提取",
|
|
83
85
|
ruleLayout: "布局模式",
|
|
84
86
|
ruleFraming: "取景",
|
|
@@ -183,7 +185,9 @@ window.__ModuleLoader__.load({
|
|
|
183
185
|
ruleEmptyHint: "This rule has no image — it can neither match nor serve as the fallback",
|
|
184
186
|
ruleColor: "Theme color",
|
|
185
187
|
ruleColorNone: "System theme",
|
|
186
|
-
ruleColorNoneHint: "Without a color this rule follows the system theme",
|
|
188
|
+
ruleColorNoneHint: "Without a color this rule follows the system theme: the host palette paints the interface while the wallpaper and every opacity/blur slider keep working",
|
|
189
|
+
ruleColorPick: "Custom color",
|
|
190
|
+
ruleColorPickHint: "Extracts from this image when it can, otherwise uses a default color",
|
|
187
191
|
ruleColorExtract: "Extract from image",
|
|
188
192
|
ruleLayout: "Layout mode",
|
|
189
193
|
ruleFraming: "Framing",
|
|
@@ -1341,6 +1345,24 @@ window.__ModuleLoader__.load({
|
|
|
1341
1345
|
}
|
|
1342
1346
|
//#endregion
|
|
1343
1347
|
//#region src/client/wallpaper.ts
|
|
1348
|
+
/**
|
|
1349
|
+
* `data-ds-dark-theme` value the plugin writes while it forces its own dark
|
|
1350
|
+
* palette. The host treats the attribute as a boolean (`toggleAttribute`), so a
|
|
1351
|
+
* plugin-specific value still matches every `body[data-ds-dark-theme]` rule
|
|
1352
|
+
* while staying distinguishable from the host's own write — which is what lets
|
|
1353
|
+
* `releaseOwnScheme` hand the flag back without clobbering the host's scheme.
|
|
1354
|
+
*/
|
|
1355
|
+
const OWN_SCHEME = "dsh-background-by-model";
|
|
1356
|
+
const DARK_ATTR = "data-ds-dark-theme";
|
|
1357
|
+
/**
|
|
1358
|
+
* Marker on <html> while the plugin owns a palette. The dialog/trajectory rules
|
|
1359
|
+
* below redirect NO-fallback tokens (`--dsw-alias-bg-layer-*`) to plugin-owned
|
|
1360
|
+
* variables, so they may only match while those variables are actually written:
|
|
1361
|
+
* without the gate a palette-less state would leave them reading a
|
|
1362
|
+
* guaranteed-invalid value (transparent panels) instead of handing the surface
|
|
1363
|
+
* back to the host untouched.
|
|
1364
|
+
*/
|
|
1365
|
+
const THEMED_ATTR = "data-dab-themed";
|
|
1344
1366
|
let wpEl = null;
|
|
1345
1367
|
let appliedTokenNames = [];
|
|
1346
1368
|
let tokenStyleEl = null;
|
|
@@ -1356,6 +1378,22 @@ window.__ModuleLoader__.load({
|
|
|
1356
1378
|
if (tokenStyleEl) tokenStyleEl.textContent = "";
|
|
1357
1379
|
for (const name of appliedTokenNames) document.body.style.removeProperty(name);
|
|
1358
1380
|
appliedTokenNames = [];
|
|
1381
|
+
baseTokenKey = "";
|
|
1382
|
+
lastBgKey = "";
|
|
1383
|
+
}
|
|
1384
|
+
/** Drop every surface the plugin owns: the variables the scoped
|
|
1385
|
+
* dialog/trajectory rules read, and the inline backgrounds written onto the
|
|
1386
|
+
* AppFrame columns. Used when no palette is available and at teardown — without
|
|
1387
|
+
* it the last color's surfaces outlive the color that produced them. */
|
|
1388
|
+
function clearOwnedSurfaces() {
|
|
1389
|
+
discoverParts();
|
|
1390
|
+
const root = document.documentElement;
|
|
1391
|
+
for (const name of OWNED_SURFACE_VARS) root.style.removeProperty(name);
|
|
1392
|
+
for (const el of [
|
|
1393
|
+
frameEl,
|
|
1394
|
+
centerEl,
|
|
1395
|
+
detailsEl
|
|
1396
|
+
]) el?.style.removeProperty("background");
|
|
1359
1397
|
}
|
|
1360
1398
|
const OPACITY_TOKEN_GROUPS = [
|
|
1361
1399
|
{
|
|
@@ -1392,6 +1430,142 @@ window.__ModuleLoader__.load({
|
|
|
1392
1430
|
"--dsw-menu-surface-fill": "--dsh-any-op-menu"
|
|
1393
1431
|
};
|
|
1394
1432
|
let baseTokenKey = "";
|
|
1433
|
+
const HOST_SURFACE_TOKENS = Object.keys(OPACITY_VARS);
|
|
1434
|
+
/** Plugin-owned variables the scoped dialog/trajectory rules read. */
|
|
1435
|
+
const SETTINGS_SURFACE_VARS = [
|
|
1436
|
+
"--dsh-any-bg-settings-surface",
|
|
1437
|
+
"--dsh-any-bg-settings-layer-1",
|
|
1438
|
+
"--dsh-any-bg-settings-layer-2",
|
|
1439
|
+
"--dsh-any-bg-settings-layer-3"
|
|
1440
|
+
];
|
|
1441
|
+
const TRAJECTORY_SURFACE_VARS = [
|
|
1442
|
+
"--dsh-any-traj-layer-1",
|
|
1443
|
+
"--dsh-any-traj-layer-2",
|
|
1444
|
+
"--dsh-any-traj-layer-3"
|
|
1445
|
+
];
|
|
1446
|
+
const OWNED_SURFACE_VARS = [...SETTINGS_SURFACE_VARS, ...TRAJECTORY_SURFACE_VARS];
|
|
1447
|
+
let hostProbe = null;
|
|
1448
|
+
/** Resolve any color the engine understands (hex, rgb()/hsl(), a var() chain,
|
|
1449
|
+
* color-mix(), …) to its USED value: only a used color can be re-emitted with
|
|
1450
|
+
* an alpha. Returns null when the engine rejects the value. */
|
|
1451
|
+
function resolveCssColor(raw) {
|
|
1452
|
+
const value = raw.trim();
|
|
1453
|
+
if (value === "") return null;
|
|
1454
|
+
if (hostProbe === null) {
|
|
1455
|
+
hostProbe = document.createElement("span");
|
|
1456
|
+
hostProbe.setAttribute("aria-hidden", "true");
|
|
1457
|
+
hostProbe.style.cssText = "position:absolute;width:0;height:0;pointer-events:none";
|
|
1458
|
+
}
|
|
1459
|
+
if (!hostProbe.isConnected) document.body.appendChild(hostProbe);
|
|
1460
|
+
hostProbe.style.color = "";
|
|
1461
|
+
hostProbe.style.color = value;
|
|
1462
|
+
if (hostProbe.style.color === "") return null;
|
|
1463
|
+
return getComputedStyle(hostProbe).color || null;
|
|
1464
|
+
}
|
|
1465
|
+
/** Read the host's own surface colors out of the live cascade. */
|
|
1466
|
+
function readHostPalette() {
|
|
1467
|
+
const sheet = tokenStyleEl;
|
|
1468
|
+
const muted = sheet !== null && sheet.isConnected && !sheet.disabled;
|
|
1469
|
+
if (muted) sheet.disabled = true;
|
|
1470
|
+
try {
|
|
1471
|
+
const computed = getComputedStyle(document.body);
|
|
1472
|
+
const tokens = {};
|
|
1473
|
+
for (const name of HOST_SURFACE_TOKENS) {
|
|
1474
|
+
const used = resolveCssColor(computed.getPropertyValue(name));
|
|
1475
|
+
if (used !== null) tokens[name] = used;
|
|
1476
|
+
}
|
|
1477
|
+
return tokens["--dsw-alias-bg-base"] === void 0 ? null : {
|
|
1478
|
+
own: false,
|
|
1479
|
+
tokens
|
|
1480
|
+
};
|
|
1481
|
+
} finally {
|
|
1482
|
+
if (muted) sheet.disabled = false;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
let hostPaletteCache = null;
|
|
1486
|
+
const HOST_PALETTE_TTL_MS = 1e3;
|
|
1487
|
+
function invalidateHostPalette() {
|
|
1488
|
+
hostPaletteCache = null;
|
|
1489
|
+
}
|
|
1490
|
+
function hostPalette() {
|
|
1491
|
+
const now = Date.now();
|
|
1492
|
+
if (hostPaletteCache !== null && now - hostPaletteCache.at < HOST_PALETTE_TTL_MS) return hostPaletteCache.palette;
|
|
1493
|
+
const read = readHostPalette();
|
|
1494
|
+
hostPaletteCache = {
|
|
1495
|
+
at: now,
|
|
1496
|
+
palette: read
|
|
1497
|
+
};
|
|
1498
|
+
return read;
|
|
1499
|
+
}
|
|
1500
|
+
/** The palette every surface is currently painted from. */
|
|
1501
|
+
function palette() {
|
|
1502
|
+
if (!rHasColor()) return hostPalette();
|
|
1503
|
+
const [h, s, l] = rColor();
|
|
1504
|
+
return {
|
|
1505
|
+
own: true,
|
|
1506
|
+
tokens: genTokens(h, s, l).tokens
|
|
1507
|
+
};
|
|
1508
|
+
}
|
|
1509
|
+
/** A resolved color with a new alpha. The plugin's own tokens are `hsl()` and
|
|
1510
|
+
* the host's alias tokens resolve to hex, both of which `toRgba` parses; a host
|
|
1511
|
+
* publishing an already-composited value (`color(…)`, `oklab(…)`, …) cannot be
|
|
1512
|
+
* parsed there, and emitting it unchanged would paint an OPAQUE surface — the
|
|
1513
|
+
* one outcome the transparent-surface design must never fall back to. Those go
|
|
1514
|
+
* through `color-mix` instead. */
|
|
1515
|
+
function withAlpha(color, alpha) {
|
|
1516
|
+
const converted = toRgba(color, alpha);
|
|
1517
|
+
if (/^(rgb|hsl)a?\(/i.test(converted)) return converted;
|
|
1518
|
+
return `color-mix(in srgb, ${color} ${Math.round(Math.max(0, Math.min(1, alpha)) * 100)}%, transparent)`;
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* The color scheme the HOST's own preference resolves to, pushed in by the
|
|
1522
|
+
* browser half (the theme service knows it, custom themes included). `null`
|
|
1523
|
+
* means "unknown", which is the only case where the plugin falls back to the
|
|
1524
|
+
* preference the host's boot script published and to the OS query itself.
|
|
1525
|
+
*/
|
|
1526
|
+
let hostSchemeDark = null;
|
|
1527
|
+
function setHostScheme(dark) {
|
|
1528
|
+
hostSchemeDark = dark;
|
|
1529
|
+
}
|
|
1530
|
+
function resolveHostDark() {
|
|
1531
|
+
if (typeof hostSchemeDark === "boolean") return hostSchemeDark;
|
|
1532
|
+
const source = document.documentElement.dataset.dsThemeSource;
|
|
1533
|
+
if (source === "dark") return true;
|
|
1534
|
+
if (source === "light") return false;
|
|
1535
|
+
try {
|
|
1536
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
1537
|
+
} catch {
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* Keep `data-ds-dark-theme` in the HOST's own form (a boolean attribute) while
|
|
1543
|
+
* the plugin does not own a palette.
|
|
1544
|
+
*
|
|
1545
|
+
* The plugin overwrites that flag whenever it owns a palette — including
|
|
1546
|
+
* REMOVING it to force a light one — and the host only re-projects the flag on a
|
|
1547
|
+
* theme change. So a flag the plugin dropped can stick: the host keeps painting
|
|
1548
|
+
* its light palette on a dark system, the readback then hands those light
|
|
1549
|
+
* surfaces back to the plugin, and the interface stays light until some
|
|
1550
|
+
* unrelated event happens to re-run an apply. Restoring the flag from the
|
|
1551
|
+
* resolved scheme closes that hole, and the write is skipped when it already
|
|
1552
|
+
* matches so this never churns the theme observer.
|
|
1553
|
+
*/
|
|
1554
|
+
function adoptHostScheme() {
|
|
1555
|
+
const dark = resolveHostDark();
|
|
1556
|
+
const current = document.body.getAttribute(DARK_ATTR);
|
|
1557
|
+
if (dark) {
|
|
1558
|
+
if (current !== "") document.body.setAttribute(DARK_ATTR, "");
|
|
1559
|
+
} else if (current !== null) document.body.removeAttribute(DARK_ATTR);
|
|
1560
|
+
}
|
|
1561
|
+
/** Re-read the host palette and repaint from it when it moved. Called while a
|
|
1562
|
+
* color-less rule is active (the host can re-project its palette at any time,
|
|
1563
|
+
* with no event of ours to hang a repaint on). */
|
|
1564
|
+
function refreshSystemTheme() {
|
|
1565
|
+
adoptHostScheme();
|
|
1566
|
+
invalidateHostPalette();
|
|
1567
|
+
applyCustomTokens(rOps());
|
|
1568
|
+
}
|
|
1395
1569
|
let pendingOps = null;
|
|
1396
1570
|
let tokensRaf = null;
|
|
1397
1571
|
function applyCustomTokens(ops) {
|
|
@@ -1407,26 +1581,38 @@ window.__ModuleLoader__.load({
|
|
|
1407
1581
|
}
|
|
1408
1582
|
let lastBgKey = "";
|
|
1409
1583
|
function applyCustomTokensNow(ops) {
|
|
1584
|
+
const src = palette();
|
|
1585
|
+
if (src === null) {
|
|
1586
|
+
clearCustomTokens();
|
|
1587
|
+
clearOwnedSurfaces();
|
|
1588
|
+
adoptHostScheme();
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
const { own, tokens } = src;
|
|
1410
1592
|
const [h, s, l] = rColor();
|
|
1411
|
-
const { tokens } = genTokens(h, s, l);
|
|
1412
1593
|
try {
|
|
1413
|
-
const forceDark = l < .55;
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
if (
|
|
1417
|
-
|
|
1418
|
-
|
|
1594
|
+
const forceDark = own && l < .55;
|
|
1595
|
+
const key = own ? `own:${h}|${s}|${l}` : `host:${HOST_SURFACE_TOKENS.map((n) => tokens[n] ?? "").join("|")}`;
|
|
1596
|
+
if (key !== baseTokenKey) {
|
|
1597
|
+
if (own) {
|
|
1598
|
+
if (forceDark) document.body.setAttribute(DARK_ATTR, OWN_SCHEME);
|
|
1599
|
+
else document.body.removeAttribute(DARK_ATTR);
|
|
1600
|
+
} else adoptHostScheme();
|
|
1601
|
+
const decls = own ? [`color-scheme:${forceDark ? "dark" : "light"}`] : [];
|
|
1419
1602
|
for (const [name, value] of Object.entries(tokens)) {
|
|
1420
1603
|
const opVar = OPACITY_VARS[name];
|
|
1421
1604
|
decls.push(`${name}:${opVar !== void 0 ? `var(${opVar})` : value}!important`);
|
|
1422
1605
|
}
|
|
1423
1606
|
ensureTokenStyle().textContent = `body{${decls.join(";")}}`;
|
|
1424
|
-
|
|
1425
|
-
|
|
1607
|
+
if (own) {
|
|
1608
|
+
for (const name of appliedTokenNames) document.body.style.removeProperty(name);
|
|
1609
|
+
appliedTokenNames = Object.keys(tokens);
|
|
1610
|
+
}
|
|
1611
|
+
baseTokenKey = key;
|
|
1426
1612
|
}
|
|
1427
1613
|
const root = document.documentElement;
|
|
1428
|
-
for (const g of OPACITY_TOKEN_GROUPS) for (const name of g.names) root.style.setProperty(OPACITY_VARS[name],
|
|
1429
|
-
root.style.setProperty("--dsh-any-op-menu-cordis",
|
|
1614
|
+
for (const g of OPACITY_TOKEN_GROUPS) for (const name of g.names) root.style.setProperty(OPACITY_VARS[name], withAlpha(tokens[name] ?? "#000", ops[g.part]));
|
|
1615
|
+
root.style.setProperty("--dsh-any-op-menu-cordis", withAlpha(tokens["--dsw-specific-menu"] ?? "#000", ops.input));
|
|
1430
1616
|
const bgKey = `${baseTokenKey}|${ops.bg}`;
|
|
1431
1617
|
if (bgKey !== lastBgKey) {
|
|
1432
1618
|
lastBgKey = bgKey;
|
|
@@ -1435,45 +1621,48 @@ window.__ModuleLoader__.load({
|
|
|
1435
1621
|
} catch {}
|
|
1436
1622
|
}
|
|
1437
1623
|
const SETTINGS_PANEL_SEL = "[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]";
|
|
1438
|
-
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)
|
|
1624
|
+
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);}html[${THEMED_ATTR}] ${SETTINGS_PANEL_SEL}{--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)}`;
|
|
1439
1625
|
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}";
|
|
1440
1626
|
function applyInputBlur(px) {
|
|
1441
1627
|
if (px > 0) document.documentElement.style.setProperty("--dsh-any-input-blur", `blur(${px}px)`);
|
|
1442
1628
|
else document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
1443
1629
|
}
|
|
1444
1630
|
function applySettingsOverrides(op) {
|
|
1445
|
-
const
|
|
1446
|
-
const
|
|
1447
|
-
const
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1631
|
+
const tokens = palette()?.tokens ?? {};
|
|
1632
|
+
const root = document.documentElement;
|
|
1633
|
+
const write = (name, token) => {
|
|
1634
|
+
const value = tokens[token];
|
|
1635
|
+
if (value === void 0) root.style.removeProperty(name);
|
|
1636
|
+
else root.style.setProperty(name, withAlpha(value, op));
|
|
1637
|
+
};
|
|
1638
|
+
write("--dsh-any-bg-settings-surface", "--dsw-alias-bg-layer-2");
|
|
1639
|
+
write("--dsh-any-bg-settings-layer-1", "--dsw-alias-bg-layer-1");
|
|
1640
|
+
write("--dsh-any-bg-settings-layer-2", "--dsw-alias-bg-layer-2");
|
|
1641
|
+
write("--dsh-any-bg-settings-layer-3", "--dsw-alias-bg-layer-3");
|
|
1642
|
+
}
|
|
1643
|
+
const TRAJECTORY_STYLE_RULE = `html[${THEMED_ATTR}] [data-conversation-composer-overlay]{--dsw-alias-bg-layer-1:var(--dsh-any-traj-layer-1);--dsw-alias-bg-layer-2:var(--dsh-any-traj-layer-2);--dsw-alias-bg-layer-3:var(--dsh-any-traj-layer-3)}`;
|
|
1456
1644
|
function applyTrajectoryOverrides(op) {
|
|
1457
|
-
const
|
|
1458
|
-
const
|
|
1459
|
-
const
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1645
|
+
const tokens = palette()?.tokens ?? {};
|
|
1646
|
+
const root = document.documentElement;
|
|
1647
|
+
const write = (name, token) => {
|
|
1648
|
+
const value = tokens[token];
|
|
1649
|
+
if (value === void 0) root.style.removeProperty(name);
|
|
1650
|
+
else root.style.setProperty(name, withAlpha(value, op));
|
|
1651
|
+
};
|
|
1652
|
+
write("--dsh-any-traj-layer-1", "--dsw-alias-bg-layer-1");
|
|
1653
|
+
write("--dsh-any-traj-layer-2", "--dsw-alias-bg-layer-2");
|
|
1654
|
+
write("--dsh-any-traj-layer-3", "--dsw-alias-bg-layer-3");
|
|
1465
1655
|
}
|
|
1466
1656
|
const RIGHTBAR_STYLE_RULE = "div[data-sidebar-right-panel]:not(:has([data-dockkit-content],[data-dockkit-empty]))[data-sidebar-right-open],div[data-sidebar-right-panel] [data-dockkit-content]:not([data-dockkit-float]),div[data-sidebar-right-panel] [data-dockkit-empty]{background:var(--dsh-any-bg-rightbar,var(--dsw-alias-bg-base))!important}div[data-sidebar-right-panel][data-sidebar-right-open]{-webkit-backdrop-filter:var(--dsh-any-blur-rightbar,none);backdrop-filter:var(--dsh-any-blur-rightbar,none)}";
|
|
1467
1657
|
/** Paint the file-preview panel's surface from its own slider. */
|
|
1468
1658
|
function applyRightbarOverrides(op) {
|
|
1469
1659
|
const root = document.documentElement;
|
|
1470
|
-
|
|
1660
|
+
const base = palette()?.tokens["--dsw-alias-bg-base"];
|
|
1661
|
+
if (base === void 0) {
|
|
1471
1662
|
root.style.removeProperty("--dsh-any-bg-rightbar");
|
|
1472
1663
|
return;
|
|
1473
1664
|
}
|
|
1474
|
-
|
|
1475
|
-
const base = genTokens(h, s, l).tokens["--dsw-alias-bg-base"];
|
|
1476
|
-
if (base !== void 0) root.style.setProperty("--dsh-any-bg-rightbar", toRgba(base, op));
|
|
1665
|
+
root.style.setProperty("--dsh-any-bg-rightbar", withAlpha(base, op));
|
|
1477
1666
|
}
|
|
1478
1667
|
/** Extra backdrop frost for the file-preview panel (0 = no frost of its own). */
|
|
1479
1668
|
function applyRightbarBlur(px) {
|
|
@@ -1542,14 +1731,20 @@ window.__ModuleLoader__.load({
|
|
|
1542
1731
|
* reducing the main-bg opacity stacked a second alpha onto the sidebar; moving
|
|
1543
1732
|
* the alpha onto the columns keeps the sidebar owned by its own slider. */
|
|
1544
1733
|
function applyPartOpacities(ops) {
|
|
1545
|
-
if (!rHasColor()) return;
|
|
1546
1734
|
discoverParts();
|
|
1547
1735
|
if (frameEl === null) return;
|
|
1548
|
-
const
|
|
1549
|
-
|
|
1736
|
+
const base = palette()?.tokens["--dsw-alias-bg-base"];
|
|
1737
|
+
if (base === void 0) {
|
|
1738
|
+
for (const el of [
|
|
1739
|
+
frameEl,
|
|
1740
|
+
centerEl,
|
|
1741
|
+
detailsEl
|
|
1742
|
+
]) el?.style.removeProperty("background");
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1550
1745
|
frameEl.style.background = "transparent";
|
|
1551
|
-
if (centerEl !== null) centerEl.style.background =
|
|
1552
|
-
if (detailsEl !== null) detailsEl.style.background =
|
|
1746
|
+
if (centerEl !== null) centerEl.style.background = withAlpha(base, ops.bg);
|
|
1747
|
+
if (detailsEl !== null) detailsEl.style.background = withAlpha(base, ops.bg);
|
|
1553
1748
|
}
|
|
1554
1749
|
/** Blur of the option panels inside the settings dialog (.dab-card), owned by
|
|
1555
1750
|
* the "dialog option panel" (card) blur slider. Written as a plugin-owned
|
|
@@ -1762,8 +1957,7 @@ window.__ModuleLoader__.load({
|
|
|
1762
1957
|
function applyViewCards() {
|
|
1763
1958
|
discoverParts();
|
|
1764
1959
|
if (centerEl === null) return;
|
|
1765
|
-
const
|
|
1766
|
-
const surface = genTokens(h, s, l).tokens["--dsw-alias-bg-layer-1"];
|
|
1960
|
+
const surface = palette()?.tokens["--dsw-alias-bg-layer-1"];
|
|
1767
1961
|
VIEW_CARDS.forEach((spec, i) => {
|
|
1768
1962
|
const target = discoverViewTarget(i, spec);
|
|
1769
1963
|
if (target === null) return;
|
|
@@ -1773,8 +1967,8 @@ window.__ModuleLoader__.load({
|
|
|
1773
1967
|
if (!plain) {
|
|
1774
1968
|
if (!target.hasAttribute(spec.mark)) stashCardPrev(target, spec.prev, false);
|
|
1775
1969
|
const borderAlpha = opacity > 0 ? Math.min(1, opacity * 1.5) : blurPx > 0 ? .35 : 0;
|
|
1776
|
-
target.style.background = surface !== void 0 ?
|
|
1777
|
-
target.style.border = surface !== void 0 ? `1px solid ${
|
|
1970
|
+
target.style.background = surface !== void 0 ? withAlpha(surface, opacity) : "transparent";
|
|
1971
|
+
target.style.border = surface !== void 0 ? `1px solid ${withAlpha(surface, borderAlpha)}` : "1px solid transparent";
|
|
1778
1972
|
target.style.borderRadius = "16px";
|
|
1779
1973
|
target.style.padding = "18px";
|
|
1780
1974
|
}
|
|
@@ -1806,31 +2000,38 @@ window.__ModuleLoader__.load({
|
|
|
1806
2000
|
let themeRaf = 0;
|
|
1807
2001
|
function reassertScheme() {
|
|
1808
2002
|
const [, , l] = rColor();
|
|
1809
|
-
if (l < .55) document.body.setAttribute(
|
|
1810
|
-
else document.body.removeAttribute(
|
|
2003
|
+
if (l < .55) document.body.setAttribute(DARK_ATTR, OWN_SCHEME);
|
|
2004
|
+
else document.body.removeAttribute(DARK_ATTR);
|
|
1811
2005
|
applyCustomTokens(rOps());
|
|
1812
2006
|
}
|
|
1813
2007
|
/** Re-assert the plugin's forced scheme whenever the host strips it, so a
|
|
1814
|
-
* refresh / cold-load / set-change never flashes a light frame.
|
|
2008
|
+
* refresh / cold-load / set-change never flashes a light frame. Also the point
|
|
2009
|
+
* where a host-side scheme flip is noticed while a color-less rule runs: that
|
|
2010
|
+
* rule paints from the host palette, so the readback is dropped and the
|
|
2011
|
+
* surfaces are re-emitted from the new one. */
|
|
1815
2012
|
function watchThemeResets() {
|
|
1816
2013
|
if (themeObserver !== null || typeof MutationObserver === "undefined") return () => void 0;
|
|
1817
2014
|
themeObserver = new MutationObserver(() => {
|
|
1818
|
-
|
|
1819
|
-
if (
|
|
2015
|
+
invalidateHostPalette();
|
|
2016
|
+
if (document.body.getAttribute(DARK_ATTR) === "dsh-background-by-model") return;
|
|
2017
|
+
if (!rHasColor()) {
|
|
2018
|
+
applyCustomTokens(rOps());
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
1820
2021
|
if (themeRaf !== 0) return;
|
|
1821
2022
|
themeRaf = requestAnimationFrame(() => {
|
|
1822
2023
|
themeRaf = 0;
|
|
1823
|
-
if (document.body.getAttribute(
|
|
2024
|
+
if (document.body.getAttribute(DARK_ATTR) === "dsh-background-by-model") return;
|
|
1824
2025
|
reassertScheme();
|
|
1825
2026
|
});
|
|
1826
2027
|
});
|
|
1827
2028
|
themeObserver.observe(document.body, {
|
|
1828
2029
|
attributes: true,
|
|
1829
|
-
attributeFilter: [
|
|
2030
|
+
attributeFilter: [DARK_ATTR]
|
|
1830
2031
|
});
|
|
1831
2032
|
themeObserver.observe(document.documentElement, {
|
|
1832
2033
|
attributes: true,
|
|
1833
|
-
attributeFilter: [
|
|
2034
|
+
attributeFilter: [DARK_ATTR]
|
|
1834
2035
|
});
|
|
1835
2036
|
return () => {
|
|
1836
2037
|
themeObserver?.disconnect();
|
|
@@ -2072,16 +2273,20 @@ window.__ModuleLoader__.load({
|
|
|
2072
2273
|
const url = rWp();
|
|
2073
2274
|
if (url) applyImageWp(url);
|
|
2074
2275
|
else if (wpEl !== null) dropWpContainer();
|
|
2075
|
-
if (rHasColor()) {
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2276
|
+
if (!rHasColor() && !baseTokenKey.startsWith("host:")) {
|
|
2277
|
+
clearCustomTokens();
|
|
2278
|
+
invalidateHostPalette();
|
|
2279
|
+
}
|
|
2280
|
+
if (!rHasColor()) adoptHostScheme();
|
|
2281
|
+
const src = palette();
|
|
2282
|
+
document.documentElement.toggleAttribute(THEMED_ATTR, src !== null);
|
|
2283
|
+
if (src === null) {
|
|
2080
2284
|
clearCustomTokens();
|
|
2081
|
-
|
|
2082
|
-
baseTokenKey = "";
|
|
2083
|
-
lastBgKey = "";
|
|
2285
|
+
clearOwnedSurfaces();
|
|
2084
2286
|
}
|
|
2287
|
+
applyCustomTokens(rOps());
|
|
2288
|
+
applySettingsOverrides(rSop());
|
|
2289
|
+
applyTrajectoryOverrides(rTrajectoryOpacity());
|
|
2085
2290
|
applyRightbarOverrides(rRightbarOpacity());
|
|
2086
2291
|
applyPartBlurs(rBlurs());
|
|
2087
2292
|
}
|
|
@@ -2091,23 +2296,17 @@ window.__ModuleLoader__.load({
|
|
|
2091
2296
|
tokenStyleEl?.remove();
|
|
2092
2297
|
tokenStyleEl = null;
|
|
2093
2298
|
removeViewCards();
|
|
2094
|
-
document.
|
|
2299
|
+
document.documentElement.removeAttribute(THEMED_ATTR);
|
|
2095
2300
|
document.body.style.removeProperty("color-scheme");
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
document.documentElement.style.removeProperty("--dsh-any-bg-settings-layer-3");
|
|
2100
|
-
document.documentElement.style.removeProperty("--dsh-any-traj-layer-1");
|
|
2101
|
-
document.documentElement.style.removeProperty("--dsh-any-traj-layer-2");
|
|
2102
|
-
document.documentElement.style.removeProperty("--dsh-any-traj-layer-3");
|
|
2301
|
+
clearOwnedSurfaces();
|
|
2302
|
+
adoptHostScheme();
|
|
2303
|
+
invalidateHostPalette();
|
|
2103
2304
|
document.documentElement.style.removeProperty("--dsh-any-blur-settings");
|
|
2104
2305
|
document.documentElement.style.removeProperty("--dsh-any-blur-card-panels");
|
|
2105
2306
|
document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
2106
2307
|
document.documentElement.style.removeProperty("--dsh-any-bg-rightbar");
|
|
2107
2308
|
document.documentElement.style.removeProperty("--dsh-any-blur-rightbar");
|
|
2108
2309
|
for (const v of Object.values(OPACITY_VARS)) document.documentElement.style.removeProperty(v);
|
|
2109
|
-
baseTokenKey = "";
|
|
2110
|
-
lastBgKey = "";
|
|
2111
2310
|
if (tokensRaf !== null) {
|
|
2112
2311
|
cancelAnimationFrame(tokensRaf);
|
|
2113
2312
|
tokensRaf = null;
|
|
@@ -2119,9 +2318,6 @@ window.__ModuleLoader__.load({
|
|
|
2119
2318
|
setBlur(sidebarEl, 0);
|
|
2120
2319
|
setBlur(centerEl, 0);
|
|
2121
2320
|
setBlur(detailsEl, 0);
|
|
2122
|
-
if (frameEl !== null) frameEl.style.removeProperty("background");
|
|
2123
|
-
if (centerEl !== null) centerEl.style.removeProperty("background");
|
|
2124
|
-
if (detailsEl !== null) detailsEl.style.removeProperty("background");
|
|
2125
2321
|
stopWatchingParts();
|
|
2126
2322
|
}
|
|
2127
2323
|
//#endregion
|
|
@@ -3919,6 +4115,23 @@ window.__ModuleLoader__.load({
|
|
|
3919
4115
|
setExtracting(false);
|
|
3920
4116
|
}
|
|
3921
4117
|
};
|
|
4118
|
+
/**
|
|
4119
|
+
* Leaving "follow the system theme" must not hand the user a color that has
|
|
4120
|
+
* nothing to do with the wallpaper they just picked, so this tries the image
|
|
4121
|
+
* first and only falls back to the seed. (`extractColor` is the same pass the
|
|
4122
|
+
* extract button runs and returns false when nothing vivid was found.)
|
|
4123
|
+
*/
|
|
4124
|
+
const onPickColor = async () => {
|
|
4125
|
+
if (url !== null) {
|
|
4126
|
+
setExtracting(true);
|
|
4127
|
+
try {
|
|
4128
|
+
if (await p.extractColor(rule.id)) return;
|
|
4129
|
+
} catch {} finally {
|
|
4130
|
+
setExtracting(false);
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
p.setRule(rule.id, { color: SEED_COLOR });
|
|
4134
|
+
};
|
|
3922
4135
|
const cls = `dab-rule${active ? " is-active" : ""}${rule.enabled ? "" : " is-off"}`;
|
|
3923
4136
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3924
4137
|
className: cls,
|
|
@@ -4110,25 +4323,34 @@ window.__ModuleLoader__.load({
|
|
|
4110
4323
|
className: "dab-rule-section-title",
|
|
4111
4324
|
children: t("ruleColor")
|
|
4112
4325
|
}),
|
|
4113
|
-
rule.color === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4326
|
+
rule.color === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4327
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4328
|
+
className: "dab-chip-row",
|
|
4329
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4330
|
+
type: "button",
|
|
4331
|
+
className: "dab-btn",
|
|
4332
|
+
disabled: extracting,
|
|
4333
|
+
onClick: () => void onPickColor(),
|
|
4334
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropletIcon, { size: 14 }), extracting ? t("extracting") : t("ruleColorPick")]
|
|
4335
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4336
|
+
type: "button",
|
|
4337
|
+
className: "dab-btn",
|
|
4338
|
+
disabled: url === null || extracting,
|
|
4339
|
+
onClick: () => void onExtract(),
|
|
4340
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SparkleIcon, { size: 14 }), extracting ? t("extracting") : t("ruleColorExtract")]
|
|
4341
|
+
})]
|
|
4342
|
+
}),
|
|
4343
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4344
|
+
className: "dab-hint",
|
|
4345
|
+
style: { marginTop: 8 },
|
|
4346
|
+
children: t("ruleColorNoneHint")
|
|
4347
|
+
}),
|
|
4348
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4349
|
+
className: "dab-hint",
|
|
4350
|
+
style: { marginTop: 6 },
|
|
4351
|
+
children: t("ruleColorPickHint")
|
|
4352
|
+
})
|
|
4353
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4132
4354
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4133
4355
|
style: {
|
|
4134
4356
|
display: "flex",
|
|
@@ -4522,7 +4744,7 @@ window.__ModuleLoader__.load({
|
|
|
4522
4744
|
const styleEl = document.createElement("style");
|
|
4523
4745
|
styleEl.dataset.plugin = "dsh-background-by-model";
|
|
4524
4746
|
markOwnSheet(styleEl);
|
|
4525
|
-
styleEl.textContent = `body[data-ds-dark-theme="
|
|
4747
|
+
styleEl.textContent = `body[data-ds-dark-theme="${OWN_SCHEME}"]::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}`;
|
|
4526
4748
|
document.head.appendChild(styleEl);
|
|
4527
4749
|
ctx.effect(() => () => {
|
|
4528
4750
|
styleEl?.parentNode?.removeChild(styleEl);
|
|
@@ -4562,20 +4784,38 @@ window.__ModuleLoader__.load({
|
|
|
4562
4784
|
rev++;
|
|
4563
4785
|
bound?.sync(rWp(), rev, rulesRev, modelLabel !== "" ? modelLabel : modelText, modelSource, modelNote, activeRuleId, activeMatched);
|
|
4564
4786
|
};
|
|
4787
|
+
/**
|
|
4788
|
+
* Publish the scheme the host's own preference resolves to. The theme service
|
|
4789
|
+
* is the only place that knows it (a custom active theme included); the
|
|
4790
|
+
* wallpaper layer needs it to hand `data-ds-dark-theme` back in the host's own
|
|
4791
|
+
* form while a color-less rule follows that theme, instead of leaving the flag
|
|
4792
|
+
* off — which pins the host to its LIGHT palette on a dark system.
|
|
4793
|
+
*/
|
|
4794
|
+
const syncHostScheme = () => {
|
|
4795
|
+
try {
|
|
4796
|
+
setHostScheme(ctx.theme.getTheme().active.colorScheme === "dark");
|
|
4797
|
+
} catch {
|
|
4798
|
+
setHostScheme(null);
|
|
4799
|
+
}
|
|
4800
|
+
};
|
|
4565
4801
|
/** Resolve the active rule for the current model and repaint everything. */
|
|
4566
4802
|
const applyActive = () => {
|
|
4567
4803
|
const { rule, matched } = matchRule(cfg.rules, modelText);
|
|
4568
4804
|
setActive(rule === null ? null : rule.id, matched);
|
|
4569
4805
|
const color = rule === null ? null : rule.color;
|
|
4570
4806
|
if (skinTimer !== null) window.clearTimeout(skinTimer);
|
|
4571
|
-
|
|
4807
|
+
if (color === null) {
|
|
4808
|
+
skinTimer = null;
|
|
4809
|
+
dropCustom();
|
|
4810
|
+
} else skinTimer = window.setTimeout(() => {
|
|
4572
4811
|
skinTimer = null;
|
|
4573
|
-
|
|
4574
|
-
else registerCustom(color[0], color[1], color[2]);
|
|
4812
|
+
registerCustom(color[0], color[1], color[2]);
|
|
4575
4813
|
}, 60);
|
|
4814
|
+
syncHostScheme();
|
|
4576
4815
|
applyWp();
|
|
4577
4816
|
sync();
|
|
4578
4817
|
};
|
|
4818
|
+
syncHostScheme();
|
|
4579
4819
|
applyWp();
|
|
4580
4820
|
sync();
|
|
4581
4821
|
watchParts();
|
|
@@ -4625,6 +4865,7 @@ window.__ModuleLoader__.load({
|
|
|
4625
4865
|
teardownWp();
|
|
4626
4866
|
}, "dsh-background-by-model: wp cleanup");
|
|
4627
4867
|
ctx.effect(() => ctx.on("theme/change", () => {
|
|
4868
|
+
syncHostScheme();
|
|
4628
4869
|
if (activeRuleColor() !== null) {
|
|
4629
4870
|
const snapshot = ctx.theme.getTheme();
|
|
4630
4871
|
if (snapshot.preference !== CUSTOM_ID && snapshot.themes.some((t) => t.id === CUSTOM_ID)) ctx.theme.setTheme(CUSTOM_ID);
|
|
@@ -4927,6 +5168,7 @@ window.__ModuleLoader__.load({
|
|
|
4927
5168
|
navIconObserver = null;
|
|
4928
5169
|
}, "dsh-background-by-model: nav icon watch");
|
|
4929
5170
|
const restoreSaved = () => {
|
|
5171
|
+
syncHostScheme();
|
|
4930
5172
|
const color = activeRuleColor();
|
|
4931
5173
|
if (color !== null) {
|
|
4932
5174
|
const snapshot = ctx.theme.getTheme();
|
|
@@ -4940,8 +5182,12 @@ window.__ModuleLoader__.load({
|
|
|
4940
5182
|
restoreTimers.forEach((id) => window.clearTimeout(id));
|
|
4941
5183
|
}, "dsh-background-by-model: boot restore");
|
|
4942
5184
|
const watchdogId = window.setInterval(() => {
|
|
5185
|
+
syncHostScheme();
|
|
4943
5186
|
const color = activeRuleColor();
|
|
4944
|
-
if (color === null)
|
|
5187
|
+
if (color === null) {
|
|
5188
|
+
refreshSystemTheme();
|
|
5189
|
+
return;
|
|
5190
|
+
}
|
|
4945
5191
|
const snapshot = ctx.theme.getTheme();
|
|
4946
5192
|
let changed = false;
|
|
4947
5193
|
if (!snapshot.themes.some((t) => t.id === CUSTOM_ID)) {
|