dsh-background-by-model 0.7.3 → 0.7.5
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/CHANGELOG.md +190 -171
- package/CHANGELOG.zh.md +191 -170
- package/LICENSE +21 -21
- package/README.md +294 -300
- package/README.zh.md +294 -300
- package/cordis.patch.yml +8 -8
- package/lib/client.js +261 -49
- package/lib/client.js.map +1 -1
- package/lib/index.js +46 -14
- package/package.json +4 -2
package/lib/client.js
CHANGED
|
@@ -33,6 +33,7 @@ window.__ModuleLoader__.load({
|
|
|
33
33
|
uiOpacityBg: "主背景",
|
|
34
34
|
uiOpacitySide: "左侧栏",
|
|
35
35
|
uiOpacityCard: "卡片与菜单面板",
|
|
36
|
+
uiOpacityCode: "代码块",
|
|
36
37
|
uiOpacityInput: "输入框与控件",
|
|
37
38
|
uiSop: "设置界面透明度",
|
|
38
39
|
uiChatRegion: "对话文本框",
|
|
@@ -83,6 +84,7 @@ window.__ModuleLoader__.load({
|
|
|
83
84
|
ruleColorTargetImage: "作用于选中的图片:",
|
|
84
85
|
ruleColorTargetRule: "作用于本规则(它还没有图片)",
|
|
85
86
|
ruleLayout: "布局模式",
|
|
87
|
+
ruleLayoutNoImage: "添加图片后可分别设置每张图的布局模式",
|
|
86
88
|
ruleFramingEdit: "编辑位置",
|
|
87
89
|
ruleOpacity: "背景透明度",
|
|
88
90
|
ruleBlur: "背景模糊",
|
|
@@ -141,6 +143,7 @@ window.__ModuleLoader__.load({
|
|
|
141
143
|
importDone: "已导入配置",
|
|
142
144
|
importFail: "导入失败,文件格式不正确",
|
|
143
145
|
footerTag: "按模型换背景插件",
|
|
146
|
+
repoLink: "在 GitHub 上打开仓库",
|
|
144
147
|
holidayTitle: "节日特殊背景",
|
|
145
148
|
holidayEnable: "启用节日特殊背景(中秋当天、国庆 10 月 1–7 日)",
|
|
146
149
|
trTitle: "切换效果",
|
|
@@ -174,6 +177,7 @@ window.__ModuleLoader__.load({
|
|
|
174
177
|
uiOpacityBg: "Main background",
|
|
175
178
|
uiOpacitySide: "Left panel",
|
|
176
179
|
uiOpacityCard: "Cards & menus",
|
|
180
|
+
uiOpacityCode: "Code blocks",
|
|
177
181
|
uiOpacityInput: "Input & controls",
|
|
178
182
|
uiSop: "Settings interface opacity",
|
|
179
183
|
uiChatRegion: "Conversation text frame",
|
|
@@ -224,6 +228,7 @@ window.__ModuleLoader__.load({
|
|
|
224
228
|
ruleColorTargetRule: "Applies to this rule (it has no image yet)",
|
|
225
229
|
ruleColorExtract: "Extract from image",
|
|
226
230
|
ruleLayout: "Layout mode",
|
|
231
|
+
ruleLayoutNoImage: "Add an image to give each one its own layout mode",
|
|
227
232
|
ruleFramingEdit: "Edit position",
|
|
228
233
|
ruleOpacity: "Background opacity",
|
|
229
234
|
ruleBlur: "Background blur",
|
|
@@ -282,6 +287,7 @@ window.__ModuleLoader__.load({
|
|
|
282
287
|
importDone: "Profile imported",
|
|
283
288
|
importFail: "Import failed — invalid file",
|
|
284
289
|
footerTag: "Per-model wallpaper plugin",
|
|
290
|
+
repoLink: "Open the repository on GitHub",
|
|
285
291
|
holidayTitle: "Holiday backgrounds",
|
|
286
292
|
holidayEnable: "Enable holiday backgrounds (Mid-Autumn day, Oct 1–7)",
|
|
287
293
|
trTitle: "Switch effect",
|
|
@@ -578,18 +584,22 @@ window.__ModuleLoader__.load({
|
|
|
578
584
|
* `sidebar` sidebar (`--dsw-specific-sidebar-fill`)
|
|
579
585
|
* `card` cards/panels (`--dsw-alias-bg-layer-1/2/3`, `--dsw-specific-menu`
|
|
580
586
|
* and its 0.1.7 alias `--dsw-menu-surface-fill`)
|
|
587
|
+
* `code` code blocks, banner included (`--dsw-alias-markdown-code-block`,
|
|
588
|
+
* `--dsw-alias-markdown-code-block-banner`)
|
|
581
589
|
* `input` input/control surfaces (`--dsw-specific-input-major`)
|
|
582
590
|
*/
|
|
583
591
|
const PART_OPACITY_KEYS = [
|
|
584
592
|
"bg",
|
|
585
593
|
"sidebar",
|
|
586
594
|
"card",
|
|
595
|
+
"code",
|
|
587
596
|
"input"
|
|
588
597
|
];
|
|
589
598
|
const DEFAULT_PART_OPACITIES = {
|
|
590
599
|
bg: .85,
|
|
591
600
|
sidebar: .93,
|
|
592
601
|
card: 1,
|
|
602
|
+
code: 1,
|
|
593
603
|
input: 1
|
|
594
604
|
};
|
|
595
605
|
/**
|
|
@@ -722,7 +732,9 @@ window.__ModuleLoader__.load({
|
|
|
722
732
|
*
|
|
723
733
|
* Holidays default to `fill` rather than a rule's `fit`: these are full-bleed
|
|
724
734
|
* festival wallpapers, and `fit` would letterbox them on every aspect ratio the
|
|
725
|
-
* art was not cut for.
|
|
735
|
+
* art was not cut for. The mode now lives on the IMAGE (see `BgImage.bgMode`), so
|
|
736
|
+
* that default is written there — and `fill` is what a holiday's read-back
|
|
737
|
+
* sanitizer refuses to lose (see `normalizeHolidayRule`).
|
|
726
738
|
*/
|
|
727
739
|
function defaultHolidayRule(def) {
|
|
728
740
|
const color = hexToHsl(def.color);
|
|
@@ -730,13 +742,13 @@ window.__ModuleLoader__.load({
|
|
|
730
742
|
id: def.id,
|
|
731
743
|
images: [{
|
|
732
744
|
slot: def.slot,
|
|
745
|
+
bgMode: "fill",
|
|
733
746
|
bgState: { ...DEFAULT_BG_STATE },
|
|
734
747
|
color
|
|
735
748
|
}],
|
|
736
749
|
match: "",
|
|
737
750
|
enabled: true,
|
|
738
751
|
color,
|
|
739
|
-
bgMode: "fill",
|
|
740
752
|
wallpaperOpacity: 1,
|
|
741
753
|
blur: 0,
|
|
742
754
|
rotate: defaultRotation()
|
|
@@ -867,12 +879,21 @@ window.__ModuleLoader__.load({
|
|
|
867
879
|
* same as absent: an entry with `color: null` is an image the user explicitly set
|
|
868
880
|
* to "follow the system theme", and re-inheriting the rule's color over that
|
|
869
881
|
* would undo a deliberate choice on every load.
|
|
882
|
+
*
|
|
883
|
+
* `inheritMode` is the same one-shot lift for the layout mode, and it is the
|
|
884
|
+
* caller's to resolve because the two callers answer differently: a user rule
|
|
885
|
+
* passes the mode its config carried at the RULE level (a schema-5 config, where
|
|
886
|
+
* 适应/填充 was one choice for the whole rotation), a holiday passes `fill` (its
|
|
887
|
+
* own default, which is not up for the lift to change). An entry that HAS a
|
|
888
|
+
* `bgMode` key keeps it — including one that has just been set to a value equal
|
|
889
|
+
* to the default, which is a decision and not an absence.
|
|
870
890
|
*/
|
|
871
|
-
function normalizeImage(raw, inherit = null) {
|
|
891
|
+
function normalizeImage(raw, inherit = null, inheritMode = "fit") {
|
|
872
892
|
const i = raw ?? {};
|
|
873
893
|
if (typeof i.slot !== "string" || !SLOT_RE.test(i.slot)) return null;
|
|
874
894
|
return {
|
|
875
895
|
slot: i.slot,
|
|
896
|
+
bgMode: BG_MODES$1.includes(i.bgMode) ? i.bgMode : inheritMode,
|
|
876
897
|
bgState: normalizeBgState(i.bgState),
|
|
877
898
|
color: hasOwn(i, "color") ? normalizeHsl(i.color) : inherit
|
|
878
899
|
};
|
|
@@ -892,6 +913,14 @@ window.__ModuleLoader__.load({
|
|
|
892
913
|
* it as well: it is not a default for its images at paint time any more, but it
|
|
893
914
|
* is still what the rule paints once its last picture is gone.
|
|
894
915
|
*
|
|
916
|
+
* The layout mode makes the same trip in the other direction, and this is the
|
|
917
|
+
* last release that has to: a config written before 0.8 keeps `bgMode` at the RULE
|
|
918
|
+
* level, where one value covered every picture of a rotation, so it is read here
|
|
919
|
+
* once and handed to each image as its inherited mode. What the user chose
|
|
920
|
+
* therefore survives the move the same way it survived the color's — the mode is
|
|
921
|
+
* not reset to the default on upgrade, and the field it used to live on is simply
|
|
922
|
+
* not written back.
|
|
923
|
+
*
|
|
895
924
|
* An EMPTY list is a legitimate rule, not a broken one: removing a rule's last
|
|
896
925
|
* picture has to be expressible, and forcing an entry back in is what produced a
|
|
897
926
|
* phantom blank image that took slot 1 and could never be deleted again (the next
|
|
@@ -906,11 +935,12 @@ window.__ModuleLoader__.load({
|
|
|
906
935
|
const id = typeof r.id === "string" && r.id !== "" ? r.id : null;
|
|
907
936
|
if (id === null) return null;
|
|
908
937
|
const color = normalizeHsl(r.color);
|
|
938
|
+
const mode = BG_MODES$1.includes(r.bgMode) ? r.bgMode : "fit";
|
|
909
939
|
const images = [];
|
|
910
940
|
const seen = /* @__PURE__ */ new Set();
|
|
911
941
|
const hadList = Array.isArray(r.images);
|
|
912
942
|
if (hadList) for (const entry of r.images) {
|
|
913
|
-
const image = normalizeImage(entry, color);
|
|
943
|
+
const image = normalizeImage(entry, color, mode);
|
|
914
944
|
if (image === null || seen.has(image.slot)) continue;
|
|
915
945
|
seen.add(image.slot);
|
|
916
946
|
images.push(image);
|
|
@@ -918,21 +948,22 @@ window.__ModuleLoader__.load({
|
|
|
918
948
|
const legacySlot = typeof r.slot === "string" && SLOT_RE.test(r.slot) ? r.slot : null;
|
|
919
949
|
if (images.length === 0 && legacySlot !== null) images.push({
|
|
920
950
|
slot: legacySlot,
|
|
951
|
+
bgMode: mode,
|
|
921
952
|
bgState: normalizeBgState(r.bgState),
|
|
922
953
|
color
|
|
923
954
|
});
|
|
924
955
|
if (images.length === 0 && !hadList) return null;
|
|
925
|
-
const
|
|
956
|
+
const rotate = normalizeRotation(r.rotate);
|
|
957
|
+
if (images.length < 2) rotate.enabled = false;
|
|
926
958
|
return {
|
|
927
959
|
id,
|
|
928
960
|
images,
|
|
929
961
|
match: typeof r.match === "string" ? r.match : "",
|
|
930
962
|
enabled: r.enabled !== false,
|
|
931
963
|
color,
|
|
932
|
-
bgMode: mode,
|
|
933
964
|
wallpaperOpacity: clamp01(r.wallpaperOpacity, 1),
|
|
934
965
|
blur: clamp$1(r.blur, 0, 60, 0),
|
|
935
|
-
rotate
|
|
966
|
+
rotate
|
|
936
967
|
};
|
|
937
968
|
}
|
|
938
969
|
/**
|
|
@@ -943,9 +974,12 @@ window.__ModuleLoader__.load({
|
|
|
943
974
|
* its bytes, and its theme color is a fixed part of what that holiday looks like —
|
|
944
975
|
* so a stale or hand-edited value would either orphan the wallpaper, point the
|
|
945
976
|
* holiday at a rule's image, or paint a festival in a color it does not have.
|
|
946
|
-
* Everything else is sanitized exactly like a rule's field — except
|
|
947
|
-
*
|
|
948
|
-
*
|
|
977
|
+
* Everything else is sanitized exactly like a rule's field — except three things
|
|
978
|
+
* that stay the definition's own: the image list and the rotation (so a festival
|
|
979
|
+
* can never be swapped or cycled), and the layout mode, which is the definition's
|
|
980
|
+
* `fill` for the same reason the color is its own — full-bleed art letterboxed by
|
|
981
|
+
* a stale `fit` is the one thing this feature must not do, and the mode is not
|
|
982
|
+
* editable for a holiday anywhere in the panel.
|
|
949
983
|
*/
|
|
950
984
|
function normalizeHolidayRule(def, raw) {
|
|
951
985
|
const r = raw ?? {};
|
|
@@ -953,11 +987,11 @@ window.__ModuleLoader__.load({
|
|
|
953
987
|
return {
|
|
954
988
|
...base,
|
|
955
989
|
enabled: r.enabled !== false,
|
|
956
|
-
bgMode: BG_MODES$1.includes(r.bgMode) ? r.bgMode : base.bgMode,
|
|
957
990
|
wallpaperOpacity: clamp01(r.wallpaperOpacity, base.wallpaperOpacity),
|
|
958
991
|
blur: clamp$1(r.blur, 0, 60, base.blur),
|
|
959
992
|
images: base.images.map((image) => ({
|
|
960
993
|
slot: image.slot,
|
|
994
|
+
bgMode: image.bgMode,
|
|
961
995
|
bgState: normalizeBgState(r.images?.[0]?.bgState ?? r.bgState),
|
|
962
996
|
color: image.color
|
|
963
997
|
}))
|
|
@@ -1194,7 +1228,6 @@ window.__ModuleLoader__.load({
|
|
|
1194
1228
|
match: "",
|
|
1195
1229
|
enabled: true,
|
|
1196
1230
|
color: null,
|
|
1197
|
-
bgMode: "fit",
|
|
1198
1231
|
wallpaperOpacity: 1,
|
|
1199
1232
|
blur: 0,
|
|
1200
1233
|
rotate: defaultRotation()
|
|
@@ -1255,8 +1288,17 @@ window.__ModuleLoader__.load({
|
|
|
1255
1288
|
.25
|
|
1256
1289
|
];
|
|
1257
1290
|
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Layout mode of the CURRENT image (per image, see BgImage).
|
|
1293
|
+
*
|
|
1294
|
+
* Read from the image and never from the rule, which no longer has a mode at all:
|
|
1295
|
+
* a rotation through a photo and a screenshot has to be able to letterbox one and
|
|
1296
|
+
* fill the other, and a rule-level answer would be the wrong one for half the
|
|
1297
|
+
* list. A rule with no image has nothing to place, so it answers with the
|
|
1298
|
+
* default — the renderer's null case, painted as "no wallpaper".
|
|
1299
|
+
*/
|
|
1258
1300
|
function rBgMode() {
|
|
1259
|
-
return
|
|
1301
|
+
return activeImage()?.bgMode ?? "fit";
|
|
1260
1302
|
}
|
|
1261
1303
|
function rWop() {
|
|
1262
1304
|
return clamp01(activeRule()?.wallpaperOpacity, 1);
|
|
@@ -1510,7 +1552,7 @@ window.__ModuleLoader__.load({
|
|
|
1510
1552
|
const d = data;
|
|
1511
1553
|
const slots = Array.isArray(d.slots) ? d.slots.filter((s) => typeof s === "string") : [];
|
|
1512
1554
|
const schema = typeof d.schema === "number" && isFinite(d.schema) ? d.schema : null;
|
|
1513
|
-
hostShape = schema === null ? "legacy" : schema >=
|
|
1555
|
+
hostShape = schema === null ? "legacy" : schema >= 6 ? "current" : "legacy";
|
|
1514
1556
|
if (hostShape === "legacy") holdWrite();
|
|
1515
1557
|
return {
|
|
1516
1558
|
config: d.config,
|
|
@@ -1602,9 +1644,13 @@ window.__ModuleLoader__.load({
|
|
|
1602
1644
|
const names = Object.keys(input.initial).filter((n) => n.startsWith("--"));
|
|
1603
1645
|
if (names.length === 0) return "";
|
|
1604
1646
|
const css = registrations(names, input.initial);
|
|
1605
|
-
if (!(input.durationMs > 0)
|
|
1606
|
-
const
|
|
1607
|
-
|
|
1647
|
+
if (!(input.durationMs > 0)) return css;
|
|
1648
|
+
const written = new Set(input.written);
|
|
1649
|
+
const timing = (n) => `${n} ${input.durationMs}ms ${input.easing}`;
|
|
1650
|
+
return `${css}${input.scopes.map((s) => ({
|
|
1651
|
+
selector: s.selector,
|
|
1652
|
+
transitions: [...s.tokens.filter((n) => names.includes(n) && written.has(n)), ...s.properties ?? []]
|
|
1653
|
+
})).filter((s) => s.transitions.length > 0).map((s) => `${s.selector}{transition:${s.transitions.map(timing).join(",")}}`).join("")}`;
|
|
1608
1654
|
}
|
|
1609
1655
|
/**
|
|
1610
1656
|
* The same fade for an element the plugin paints INLINE (its columns and cards).
|
|
@@ -1774,6 +1820,7 @@ window.__ModuleLoader__.load({
|
|
|
1774
1820
|
"--dsw-alias-interactive-bg-hover": rgba(h(0), s(0), l(-.3), .08),
|
|
1775
1821
|
"--dsw-alias-interactive-bg-active": rgba(h(0), s(0), l(-.3), .14),
|
|
1776
1822
|
"--dsw-alias-markdown-code-block": hsl(h(0), s(-.1), l(-.03)),
|
|
1823
|
+
"--dsw-alias-markdown-code-block-banner": hsl(h(0), s(-.1), l(-.06)),
|
|
1777
1824
|
"--dsw-alias-markdown-inline-code": hsl(h(0), s(-.08), l(.04)),
|
|
1778
1825
|
"--dsw-specific-sidebar-fill": hsl(h(0), s(-.1), l(-.03)),
|
|
1779
1826
|
"--dsw-specific-sidebar-nav-item-active": hsl(h(0), s(-.08), l(.05)),
|
|
@@ -1999,7 +2046,11 @@ window.__ModuleLoader__.load({
|
|
|
1999
2046
|
/* ── shell: nav rail + page body ─────────────────────────────────────────── */
|
|
2000
2047
|
.dab-shell{display:grid;grid-template-columns:158px minmax(0,1fr);gap:26px;align-items:start;padding-bottom:8px;width:100%;max-width:980px;margin:0 auto}
|
|
2001
2048
|
.dab-nav{position:sticky;top:0;display:flex;flex-direction:column;gap:18px}
|
|
2002
|
-
|
|
2049
|
+
/* The brand is an <a> (it opens the repository): an anchor brings its own colour
|
|
2050
|
+
and underline, so both are reset here rather than left to the host's link
|
|
2051
|
+
styles, which would repaint the tile's label. */
|
|
2052
|
+
.dab-brand{display:flex;align-items:center;gap:10px;padding:2px 6px;color:inherit;text-decoration:none}
|
|
2053
|
+
.dab-brand:hover .dab-brand-name{color:var(--dsw-alias-brand-primary)}
|
|
2003
2054
|
.dab-brand-tile{width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;color:var(--dsw-alias-label-primary-inverted);background:var(--dsw-alias-brand-primary);box-shadow:0 4px 14px -4px var(--dsw-alias-brand-primary)}
|
|
2004
2055
|
.dab-brand-name{font-size:13px;font-weight:650;letter-spacing:.01em;line-height:1.25}
|
|
2005
2056
|
.dab-brand-tag{font-size:9px;letter-spacing:.16em;font-weight:600;color:var(--dsw-alias-label-quaternary,var(--dsw-alias-label-tertiary));text-transform:uppercase}
|
|
@@ -2090,6 +2141,11 @@ window.__ModuleLoader__.load({
|
|
|
2090
2141
|
.dab-chip-row{display:flex;flex-wrap:wrap;gap:8px}
|
|
2091
2142
|
.dab-chip{height:30px;padding:0 14px;border-radius:99px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary));font-size:12px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:all .22s ease}
|
|
2092
2143
|
.dab-chip:hover{border-color:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary)}
|
|
2144
|
+
/* A mode chip on a rule with no picture: there is nothing to lay out. It reads
|
|
2145
|
+
as unavailable rather than as an active choice, and the hover that would
|
|
2146
|
+
promise otherwise is dropped with it. */
|
|
2147
|
+
.dab-chip:disabled{opacity:.45;cursor:not-allowed}
|
|
2148
|
+
.dab-chip:disabled:hover{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary,var(--dsw-alias-label-tertiary))}
|
|
2093
2149
|
.dab-chip.is-active{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-inverted);border-color:transparent}
|
|
2094
2150
|
|
|
2095
2151
|
/* ── sliders ─────────────────────────────────────────────────────────────── */
|
|
@@ -2148,6 +2204,10 @@ window.__ModuleLoader__.load({
|
|
|
2148
2204
|
.dab-profile-desc{font-size:12px;color:var(--dsw-alias-label-tertiary);line-height:1.55;margin:5px 0 15px}
|
|
2149
2205
|
.dab-footer{margin-top:6px;padding:14px 4px 0;border-top:1px solid var(--dsw-alias-border-l2);display:flex;align-items:center;justify-content:space-between;font-size:11px;color:var(--dsw-alias-label-tertiary)}
|
|
2150
2206
|
.dab-footer-mono{font-family:var(--dab-mono);letter-spacing:.02em}
|
|
2207
|
+
/* Same reset as the brand: the package name links to the repository, and the
|
|
2208
|
+
underline appears on hover where it reads as an affordance instead of chrome. */
|
|
2209
|
+
.dab-footer a{color:inherit;text-decoration:none}
|
|
2210
|
+
.dab-footer a:hover{color:var(--dsw-alias-brand-primary);text-decoration:underline}
|
|
2151
2211
|
|
|
2152
2212
|
/* ── toast ───────────────────────────────────────────────────────────────── */
|
|
2153
2213
|
.dab-toast{position:fixed;left:50%;bottom:30px;transform:translateX(-50%);display:flex;align-items:center;gap:8px;height:38px;padding:0 16px;border-radius:99px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2));border:1px solid var(--dsw-alias-border-l2);box-shadow:0 10px 30px -8px rgba(0,0,0,.38);font-size:12.5px;z-index:10001;animation:dab-toast-in .32s cubic-bezier(.22,1,.36,1) both}
|
|
@@ -2422,6 +2482,10 @@ window.__ModuleLoader__.load({
|
|
|
2422
2482
|
"--dsw-menu-surface-fill"
|
|
2423
2483
|
]
|
|
2424
2484
|
},
|
|
2485
|
+
{
|
|
2486
|
+
part: "code",
|
|
2487
|
+
names: ["--dsw-alias-markdown-code-block", "--dsw-alias-markdown-code-block-banner"]
|
|
2488
|
+
},
|
|
2425
2489
|
{
|
|
2426
2490
|
part: "input",
|
|
2427
2491
|
names: ["--dsw-specific-input-major"]
|
|
@@ -2435,7 +2499,9 @@ window.__ModuleLoader__.load({
|
|
|
2435
2499
|
"--dsw-alias-bg-layer-3": "--dsh-any-op-card-3",
|
|
2436
2500
|
"--dsw-specific-input-major": "--dsh-any-op-input",
|
|
2437
2501
|
"--dsw-specific-menu": "--dsh-any-op-menu",
|
|
2438
|
-
"--dsw-menu-surface-fill": "--dsh-any-op-menu"
|
|
2502
|
+
"--dsw-menu-surface-fill": "--dsh-any-op-menu",
|
|
2503
|
+
"--dsw-alias-markdown-code-block": "--dsh-any-op-code",
|
|
2504
|
+
"--dsw-alias-markdown-code-block-banner": "--dsh-any-op-code-banner"
|
|
2439
2505
|
};
|
|
2440
2506
|
let baseTokenKey = "";
|
|
2441
2507
|
const HOST_SURFACE_TOKENS = Object.keys(OPACITY_VARS);
|
|
@@ -2660,7 +2726,7 @@ window.__ModuleLoader__.load({
|
|
|
2660
2726
|
const scheme = own ? forceDark ? "dark" : "light" : resolveHostDark() ? "dark" : "light";
|
|
2661
2727
|
const fadeable = paletteChanged && paletteFadeAllowed(paletteScheme, scheme);
|
|
2662
2728
|
lastFadeable = fadeable;
|
|
2663
|
-
applyPaletteFade(fadeable);
|
|
2729
|
+
applyPaletteFade(fadeable, Object.keys(tokens));
|
|
2664
2730
|
if (paletteChanged) {
|
|
2665
2731
|
paletteScheme = scheme;
|
|
2666
2732
|
if (own) {
|
|
@@ -2672,7 +2738,7 @@ window.__ModuleLoader__.load({
|
|
|
2672
2738
|
const opVar = OPACITY_VARS[name];
|
|
2673
2739
|
decls.push(`${name}:${opVar !== void 0 ? `var(${opVar})` : value}!important`);
|
|
2674
2740
|
}
|
|
2675
|
-
ensureTokenStyle().textContent =
|
|
2741
|
+
ensureTokenStyle().textContent = `:root,body{${decls.join(";")}}`;
|
|
2676
2742
|
if (own) {
|
|
2677
2743
|
for (const name of appliedTokenNames) document.body.style.removeProperty(name);
|
|
2678
2744
|
appliedTokenNames = Object.keys(tokens);
|
|
@@ -2693,7 +2759,8 @@ window.__ModuleLoader__.load({
|
|
|
2693
2759
|
}
|
|
2694
2760
|
const SETTINGS_PANEL_SEL = "[role=\"dialog\"][aria-modal=\"true\"][aria-labelledby]";
|
|
2695
2761
|
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)}`;
|
|
2696
|
-
const
|
|
2762
|
+
const CORDIS_PANEL_SEL = "[data-cordis-panel]";
|
|
2763
|
+
const INPUT_BLUR_RULE = `[data-composer-card],${CORDIS_PANEL_SEL}{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}${CORDIS_PANEL_SEL}{--dsw-specific-menu:var(--dsh-any-op-menu-cordis)!important}`;
|
|
2697
2764
|
function applyInputBlur(px) {
|
|
2698
2765
|
if (px > 0) document.documentElement.style.setProperty("--dsh-any-input-blur", `blur(${px}px)`);
|
|
2699
2766
|
else document.documentElement.style.removeProperty("--dsh-any-input-blur");
|
|
@@ -2724,20 +2791,82 @@ window.__ModuleLoader__.load({
|
|
|
2724
2791
|
write("--dsh-any-traj-layer-2", "--dsw-alias-bg-layer-2");
|
|
2725
2792
|
write("--dsh-any-traj-layer-3", "--dsw-alias-bg-layer-3");
|
|
2726
2793
|
}
|
|
2794
|
+
const TRAJECTORY_ROOT_SEL = "[data-conversation-composer-overlay]";
|
|
2727
2795
|
/** Elements whose own token declarations change when the palette does: the body
|
|
2728
2796
|
* (which everything else inherits), and the two surfaces that RE-declare the
|
|
2729
|
-
* layer tokens instead of inheriting them.
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2797
|
+
* layer tokens instead of inheriting them.
|
|
2798
|
+
*
|
|
2799
|
+
* The three layer tokens are also the ONLY ones those two surfaces may carry a
|
|
2800
|
+
* transition for. Handing them the full palette is not "more of the same": a
|
|
2801
|
+
* transition on an INHERITED token makes the element interpolate towards the
|
|
2802
|
+
* stale value it saw when the fade was armed, and everything under it rides that
|
|
2803
|
+
* lagged copy — the settings dialog's own controls (the holiday switch fill, the
|
|
2804
|
+
* active chips) then hold the previous theme colour for the whole switch and jump
|
|
2805
|
+
* at the end. See ./palette-fade for the measurement. */
|
|
2806
|
+
const FADE_LAYER_TOKENS = [
|
|
2807
|
+
"--dsw-alias-bg-layer-1",
|
|
2808
|
+
"--dsw-alias-bg-layer-2",
|
|
2809
|
+
"--dsw-alias-bg-layer-3"
|
|
2734
2810
|
];
|
|
2735
|
-
/** The token names
|
|
2736
|
-
*
|
|
2737
|
-
*
|
|
2811
|
+
/** The token names a palette CAN carry — deliberately the widest branch.
|
|
2812
|
+
*
|
|
2813
|
+
* `genTokens(220, 0.55, 0.25)` resolves to the DARK branch (l = 0.25), and that
|
|
2814
|
+
* branch is the superset: the light one emits roughly thirty fewer aliases (no
|
|
2815
|
+
* bubble, selector, tip, tooltip/toast, toolbar and markdown state tokens). This
|
|
2816
|
+
* list is therefore what the REGISTRATIONS are emitted for — a later light→dark
|
|
2817
|
+
* change has to find the dark names already registered — and NOT the transition
|
|
2818
|
+
* list, which is narrowed per apply to the palette in force (`written` in
|
|
2819
|
+
* ./palette-fade). Assuming the two branches carry the same set is exactly the
|
|
2820
|
+
* mistake that let the fade animate host-owned tokens: a name only the dark
|
|
2821
|
+
* branch declares is, under a light palette, the HOST's value.
|
|
2822
|
+
*
|
|
2823
|
+
* An unknown name is only registered when the host can answer for it (see
|
|
2824
|
+
* `fadeInitials`). */
|
|
2738
2825
|
function fadeTokenNames() {
|
|
2739
2826
|
return Object.keys(genTokens(220, .55, .25).tokens);
|
|
2740
2827
|
}
|
|
2828
|
+
/** One `transition` list per element that DECLARES palette tokens, each carrying
|
|
2829
|
+
* only the tokens that element actually declares — and, at emission, only those
|
|
2830
|
+
* the palette in force writes (see `written`).
|
|
2831
|
+
*
|
|
2832
|
+
* Two of the entries carry a STANDARD property instead, because those surfaces
|
|
2833
|
+
* are not painted from a registered token: the settings dialog's plate and the
|
|
2834
|
+
* file-preview panel read a colour the plugin owns as a plain variable
|
|
2835
|
+
* (`--dsh-any-bg-settings-surface`, `--dsh-any-bg-rightbar`) and would otherwise
|
|
2836
|
+
* snap in one frame while every surface around them fades. The Cordis panel is
|
|
2837
|
+
* the third case of the same kind — it re-declares `--dsw-specific-menu` from
|
|
2838
|
+
* `--dsh-any-op-menu-cordis`, which is also unregistered, but since the token it
|
|
2839
|
+
* re-declares IS one, naming the token is what reaches it. */
|
|
2840
|
+
function fadeScopes() {
|
|
2841
|
+
return [
|
|
2842
|
+
{
|
|
2843
|
+
selector: ":root",
|
|
2844
|
+
tokens: fadeTokenNames()
|
|
2845
|
+
},
|
|
2846
|
+
{
|
|
2847
|
+
selector: "body",
|
|
2848
|
+
tokens: fadeTokenNames()
|
|
2849
|
+
},
|
|
2850
|
+
{
|
|
2851
|
+
selector: SETTINGS_PANEL_SEL,
|
|
2852
|
+
tokens: FADE_LAYER_TOKENS,
|
|
2853
|
+
properties: ["background-color"]
|
|
2854
|
+
},
|
|
2855
|
+
{
|
|
2856
|
+
selector: TRAJECTORY_ROOT_SEL,
|
|
2857
|
+
tokens: FADE_LAYER_TOKENS
|
|
2858
|
+
},
|
|
2859
|
+
{
|
|
2860
|
+
selector: RIGHTBAR_SEL,
|
|
2861
|
+
tokens: [],
|
|
2862
|
+
properties: ["background-color"]
|
|
2863
|
+
},
|
|
2864
|
+
{
|
|
2865
|
+
selector: CORDIS_PANEL_SEL,
|
|
2866
|
+
tokens: ["--dsw-specific-menu"]
|
|
2867
|
+
}
|
|
2868
|
+
];
|
|
2869
|
+
}
|
|
2741
2870
|
let fadeStyleEl = null;
|
|
2742
2871
|
let fadeInitials = null;
|
|
2743
2872
|
let fadeCssCache = "";
|
|
@@ -2801,12 +2930,21 @@ window.__ModuleLoader__.load({
|
|
|
2801
2930
|
*
|
|
2802
2931
|
* `animate` is false on every pass that only moves an alpha (a slider drag): the
|
|
2803
2932
|
* tokens are rewritten there too, and a live transition would make the surface
|
|
2804
|
-
* lag behind the pointer.
|
|
2805
|
-
|
|
2933
|
+
* lag behind the pointer.
|
|
2934
|
+
*
|
|
2935
|
+
* `written` is the token set of the palette IN FORCE — `Object.keys(tokens)` of
|
|
2936
|
+
* the very block this pass is about to write — and only those may carry a
|
|
2937
|
+
* transition: a name the palette does not write still belongs to the host, and a
|
|
2938
|
+
* transition on it animates the host's own scheme change at this plugin's
|
|
2939
|
+
* duration (see ./palette-fade for the report that shape produced). The
|
|
2940
|
+
* registrations stay on the full set, so a later palette of the other branch
|
|
2941
|
+
* still has them in place. */
|
|
2942
|
+
function applyPaletteFade(animate, written) {
|
|
2806
2943
|
const initials = fadeInitialsOf(fadeTokenNames());
|
|
2807
2944
|
const css = paletteFadeCss({
|
|
2808
|
-
|
|
2945
|
+
scopes: fadeScopes(),
|
|
2809
2946
|
initial: initials,
|
|
2947
|
+
written,
|
|
2810
2948
|
durationMs: animate ? paletteFadeMs() : 0,
|
|
2811
2949
|
easing: rTransition().easing
|
|
2812
2950
|
});
|
|
@@ -2818,7 +2956,8 @@ window.__ModuleLoader__.load({
|
|
|
2818
2956
|
function fadeInlineFor(animate) {
|
|
2819
2957
|
return paletteFadeInline(animate ? paletteFadeMs() : 0, rTransition().easing);
|
|
2820
2958
|
}
|
|
2821
|
-
const
|
|
2959
|
+
const RIGHTBAR_SEL = "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]";
|
|
2960
|
+
const RIGHTBAR_STYLE_RULE = `${RIGHTBAR_SEL}{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)}`;
|
|
2822
2961
|
/** Paint the file-preview panel's surface from its own slider. */
|
|
2823
2962
|
function applyRightbarOverrides(op) {
|
|
2824
2963
|
const root = document.documentElement;
|
|
@@ -4018,6 +4157,12 @@ window.__ModuleLoader__.load({
|
|
|
4018
4157
|
rx: "2"
|
|
4019
4158
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 6.6v2M7 8h2" })]
|
|
4020
4159
|
});
|
|
4160
|
+
/** Angle brackets: the code-block surface on the Interface page. */
|
|
4161
|
+
const CodeIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Glyph, {
|
|
4162
|
+
size,
|
|
4163
|
+
className,
|
|
4164
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M5.7 4.3 2.4 8l3.3 3.7M10.3 4.3 13.6 8l-3.3 3.7" })
|
|
4165
|
+
});
|
|
4021
4166
|
//#endregion
|
|
4022
4167
|
//#region src/client/components/ErrorBoundary.tsx
|
|
4023
4168
|
/**
|
|
@@ -4088,6 +4233,19 @@ window.__ModuleLoader__.load({
|
|
|
4088
4233
|
return target ? (0, react_dom.createPortal)(children, target) : null;
|
|
4089
4234
|
}
|
|
4090
4235
|
//#endregion
|
|
4236
|
+
//#region src/client/repo.ts
|
|
4237
|
+
/**
|
|
4238
|
+
* The project's public repository — the ONE address the shell links to.
|
|
4239
|
+
*
|
|
4240
|
+
* Both links the interface ships (the brand in the header, the package name in
|
|
4241
|
+
* the profile footer) read this constant: two literals would drift the day the
|
|
4242
|
+
* repository moves, and a link that points at the wrong place is indistinguishable
|
|
4243
|
+
* from a link that works until someone clicks it. `scripts/ui-strings-check.ts`
|
|
4244
|
+
* holds it against `package.json`'s `repository`, which is what npm and the
|
|
4245
|
+
* plugin market read.
|
|
4246
|
+
*/
|
|
4247
|
+
const REPO_URL = "https://github.com/HarmlessFunny/dsh-background-by-model";
|
|
4248
|
+
//#endregion
|
|
4091
4249
|
//#region src/client/components/LiveSlider.tsx
|
|
4092
4250
|
/**
|
|
4093
4251
|
* Zero-lag slider: the thumb and value label update through DOM refs while
|
|
@@ -4184,6 +4342,12 @@ window.__ModuleLoader__.load({
|
|
|
4184
4342
|
labelKey: "uiOpacityCard",
|
|
4185
4343
|
Icon: ChatIcon
|
|
4186
4344
|
},
|
|
4345
|
+
{
|
|
4346
|
+
opKey: "code",
|
|
4347
|
+
labelKey: "uiOpacityCode",
|
|
4348
|
+
Icon: CodeIcon,
|
|
4349
|
+
noBlur: true
|
|
4350
|
+
},
|
|
4187
4351
|
{
|
|
4188
4352
|
opKey: "input",
|
|
4189
4353
|
labelKey: "uiOpacityInput",
|
|
@@ -4227,9 +4391,9 @@ window.__ModuleLoader__.load({
|
|
|
4227
4391
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4228
4392
|
className: "dab-grid-parts",
|
|
4229
4393
|
children: PARTS.map((part, i) => {
|
|
4230
|
-
const { labelKey, Icon, isSettings, isChat, isTrajectory, isRightbar } = part;
|
|
4394
|
+
const { labelKey, Icon, isSettings, isChat, isTrajectory, isRightbar, noBlur } = part;
|
|
4231
4395
|
const opKey = part.opKey;
|
|
4232
|
-
const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isRightbar ? "rightbar" : isSettings ? "settings" : opKey;
|
|
4396
|
+
const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isRightbar ? "rightbar" : isSettings ? "settings" : noBlur ? null : opKey;
|
|
4233
4397
|
const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isRightbar ? rRightbarOpacity() : isSettings ? rSop() : rOps()[opKey];
|
|
4234
4398
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
4235
4399
|
className: "dab-card dab-card-hover dab-rise",
|
|
@@ -4300,7 +4464,7 @@ window.__ModuleLoader__.load({
|
|
|
4300
4464
|
}
|
|
4301
4465
|
}
|
|
4302
4466
|
}),
|
|
4303
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LiveSlider, {
|
|
4467
|
+
blurKey !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LiveSlider, {
|
|
4304
4468
|
label: t("uiBlur"),
|
|
4305
4469
|
min: 0,
|
|
4306
4470
|
max: 60,
|
|
@@ -4321,7 +4485,7 @@ window.__ModuleLoader__.load({
|
|
|
4321
4485
|
}
|
|
4322
4486
|
})
|
|
4323
4487
|
]
|
|
4324
|
-
}, blurKey);
|
|
4488
|
+
}, blurKey ?? opKey);
|
|
4325
4489
|
})
|
|
4326
4490
|
})] });
|
|
4327
4491
|
}
|
|
@@ -5399,6 +5563,7 @@ window.__ModuleLoader__.load({
|
|
|
5399
5563
|
const rotatable = rule.images.length >= 2;
|
|
5400
5564
|
const preset = ROTATE_PRESETS.find((x) => x.ms === rule.rotate.intervalMs);
|
|
5401
5565
|
const selSlot = image?.slot ?? null;
|
|
5566
|
+
const bgMode = image?.bgMode ?? "fit";
|
|
5402
5567
|
/** How far the pointer must travel before a click turns into a drag. */
|
|
5403
5568
|
const DRAG_SLOP = 5;
|
|
5404
5569
|
const tileDown = (i, slot) => (e) => {
|
|
@@ -5881,12 +6046,17 @@ window.__ModuleLoader__.load({
|
|
|
5881
6046
|
children: t("ruleLayout")
|
|
5882
6047
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5883
6048
|
className: "dab-chip-row",
|
|
6049
|
+
style: { marginTop: 8 },
|
|
5884
6050
|
children: [BG_MODES.map((m) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5885
6051
|
type: "button",
|
|
5886
|
-
className: `dab-chip${
|
|
5887
|
-
|
|
6052
|
+
className: `dab-chip${bgMode === m.mode ? " is-active" : ""}`,
|
|
6053
|
+
disabled: image === void 0,
|
|
6054
|
+
title: image === void 0 ? t("ruleLayoutNoImage") : void 0,
|
|
6055
|
+
onClick: () => {
|
|
6056
|
+
if (image !== void 0) p.setImageMode(rule.id, image.slot, m.mode);
|
|
6057
|
+
},
|
|
5888
6058
|
children: t(m.key)
|
|
5889
|
-
}, m.mode)), url !== null &&
|
|
6059
|
+
}, m.mode)), url !== null && bgMode === "fit" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5890
6060
|
type: "button",
|
|
5891
6061
|
className: "dab-btn",
|
|
5892
6062
|
onClick: () => setEditorOpen(true),
|
|
@@ -6219,12 +6389,7 @@ window.__ModuleLoader__.load({
|
|
|
6219
6389
|
}, easing))
|
|
6220
6390
|
})] }),
|
|
6221
6391
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6222
|
-
className: "dab-swatch-title",
|
|
6223
6392
|
style: { marginTop: 12 },
|
|
6224
|
-
children: t("trDuration")
|
|
6225
|
-
}),
|
|
6226
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6227
|
-
style: { marginTop: 2 },
|
|
6228
6393
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LiveSlider, {
|
|
6229
6394
|
label: t("trDuration"),
|
|
6230
6395
|
min: 0,
|
|
@@ -6342,8 +6507,12 @@ window.__ModuleLoader__.load({
|
|
|
6342
6507
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
|
|
6343
6508
|
className: "dab-footer dab-rise",
|
|
6344
6509
|
style: { "--d": 4 },
|
|
6345
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
6510
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
6346
6511
|
className: "dab-footer-mono",
|
|
6512
|
+
href: REPO_URL,
|
|
6513
|
+
target: "_blank",
|
|
6514
|
+
rel: "noreferrer noopener",
|
|
6515
|
+
title: t("repoLink"),
|
|
6347
6516
|
children: "dsh-background-by-model"
|
|
6348
6517
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("footerTag") })]
|
|
6349
6518
|
})
|
|
@@ -6407,8 +6576,12 @@ window.__ModuleLoader__.load({
|
|
|
6407
6576
|
className: "dab-shell",
|
|
6408
6577
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
6409
6578
|
className: "dab-nav",
|
|
6410
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
6579
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
6411
6580
|
className: "dab-brand",
|
|
6581
|
+
href: REPO_URL,
|
|
6582
|
+
target: "_blank",
|
|
6583
|
+
rel: "noreferrer noopener",
|
|
6584
|
+
title: t("repoLink"),
|
|
6412
6585
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6413
6586
|
className: "dab-brand-tile",
|
|
6414
6587
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SunIcon, { size: 15 })
|
|
@@ -6468,10 +6641,21 @@ window.__ModuleLoader__.load({
|
|
|
6468
6641
|
initRpc((endpoint, payload) => ctx.connection.rpc.call(RPC_CHANNEL, endpoint, payload).then((res) => res));
|
|
6469
6642
|
let customDispose = null;
|
|
6470
6643
|
let skinTimer = null;
|
|
6644
|
+
/** Colour scheme of the skin this plugin has registered, or null when none is. */
|
|
6645
|
+
let skinScheme = null;
|
|
6646
|
+
/** Scheme the host currently holds for our theme id; null when it is not there. */
|
|
6647
|
+
const registeredScheme = () => {
|
|
6648
|
+
const theme = ctx.theme.getTheme().themes.find((t) => t.id === CUSTOM_ID);
|
|
6649
|
+
return theme === void 0 ? null : theme.colorScheme;
|
|
6650
|
+
};
|
|
6471
6651
|
const registerCustom = (h, s, l) => {
|
|
6652
|
+
const { colorScheme, tokens } = genTokens(h, s, l);
|
|
6653
|
+
if (skinScheme === colorScheme && registeredScheme() !== null) {
|
|
6654
|
+
if (ctx.theme.getTheme().preference !== CUSTOM_ID) ctx.theme.setTheme(CUSTOM_ID);
|
|
6655
|
+
return;
|
|
6656
|
+
}
|
|
6472
6657
|
customDispose?.();
|
|
6473
6658
|
try {
|
|
6474
|
-
const { colorScheme, tokens } = genTokens(h, s, l);
|
|
6475
6659
|
customDispose = ctx.theme.register({
|
|
6476
6660
|
id: CUSTOM_ID,
|
|
6477
6661
|
colorScheme,
|
|
@@ -6480,12 +6664,14 @@ window.__ModuleLoader__.load({
|
|
|
6480
6664
|
} catch {
|
|
6481
6665
|
customDispose = null;
|
|
6482
6666
|
}
|
|
6667
|
+
skinScheme = registeredScheme() ?? colorScheme;
|
|
6483
6668
|
if (ctx.theme.getTheme().themes.some((t) => t.id === CUSTOM_ID)) ctx.theme.setTheme(CUSTOM_ID);
|
|
6484
6669
|
};
|
|
6485
6670
|
/** A rule without a saved color means "follow the system theme". */
|
|
6486
6671
|
const dropCustom = () => {
|
|
6487
6672
|
customDispose?.();
|
|
6488
6673
|
customDispose = null;
|
|
6674
|
+
skinScheme = null;
|
|
6489
6675
|
try {
|
|
6490
6676
|
if (ctx.theme.getTheme().preference === CUSTOM_ID) ctx.theme.setTheme("system");
|
|
6491
6677
|
} catch {}
|
|
@@ -7040,6 +7226,7 @@ window.__ModuleLoader__.load({
|
|
|
7040
7226
|
const slot = nextSlot();
|
|
7041
7227
|
const image = {
|
|
7042
7228
|
slot,
|
|
7229
|
+
bgMode: "fit",
|
|
7043
7230
|
bgState: { ...DEFAULT_BG_STATE },
|
|
7044
7231
|
color: null
|
|
7045
7232
|
};
|
|
@@ -7060,6 +7247,7 @@ window.__ModuleLoader__.load({
|
|
|
7060
7247
|
if (idx < 0) return;
|
|
7061
7248
|
const winner = winnerId();
|
|
7062
7249
|
rule.images.splice(idx, 1);
|
|
7250
|
+
if (rule.images.length < 2 && rule.rotate.enabled) patchRotation(rule, { enabled: false });
|
|
7063
7251
|
if (id === activeRuleId) setRotIndex(0);
|
|
7064
7252
|
rulesRev++;
|
|
7065
7253
|
persistConfig();
|
|
@@ -7100,6 +7288,29 @@ window.__ModuleLoader__.load({
|
|
|
7100
7288
|
saveConfig();
|
|
7101
7289
|
repaintIfMoved(id, winner);
|
|
7102
7290
|
},
|
|
7291
|
+
/**
|
|
7292
|
+
* Store ONE image's layout mode. Addressed by slot like `setImageFraming`,
|
|
7293
|
+
* for the same reason: how a picture meets the viewport is a property of the
|
|
7294
|
+
* picture, and 适应 on a tall screenshot says nothing about the landscape
|
|
7295
|
+
* photo beside it in the rotation.
|
|
7296
|
+
*
|
|
7297
|
+
* A mode is a placement, not a paint: it changes nothing about WHICH image is
|
|
7298
|
+
* on screen, only how it is laid out. So the patch is written, sanitized, and
|
|
7299
|
+
* the layer repainted through the same `repaintIfMoved` the framing commit
|
|
7300
|
+
* uses — that call repaints the current image whether or not the winner
|
|
7301
|
+
* moved, which is what makes the chips feel live.
|
|
7302
|
+
*/
|
|
7303
|
+
setImageMode: (id, slot, mode) => {
|
|
7304
|
+
const rule = ruleById(id);
|
|
7305
|
+
const image = rule?.images.find((i) => i.slot === slot);
|
|
7306
|
+
if (rule === null || image === void 0) return;
|
|
7307
|
+
const winner = winnerId();
|
|
7308
|
+
image.bgMode = mode;
|
|
7309
|
+
normalizeRuleInPlace(rule);
|
|
7310
|
+
rulesRev++;
|
|
7311
|
+
saveConfig();
|
|
7312
|
+
repaintIfMoved(id, winner);
|
|
7313
|
+
},
|
|
7103
7314
|
setRuleRotation: (id, patch) => {
|
|
7104
7315
|
const rule = ruleById(id);
|
|
7105
7316
|
if (rule === null) return;
|
|
@@ -7154,6 +7365,7 @@ window.__ModuleLoader__.load({
|
|
|
7154
7365
|
const winner = winnerId();
|
|
7155
7366
|
rule.images.push({
|
|
7156
7367
|
slot,
|
|
7368
|
+
bgMode: "fit",
|
|
7157
7369
|
bgState: { ...DEFAULT_BG_STATE },
|
|
7158
7370
|
color: null
|
|
7159
7371
|
});
|