dsh-dream-skin 0.2.1 → 0.2.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.
Files changed (2) hide show
  1. package/lib/client.js +162 -11
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -36,6 +36,10 @@ window.__ModuleLoader__.load({
36
36
  const WALLPAPER_OPACITY_KEY = "dsh-dream-skin:wallpaper-opacity";
37
37
  /** localStorage key holding the wallpaper blur radius (px). */
38
38
  const WALLPAPER_BLUR_KEY = "dsh-dream-skin:wallpaper-blur";
39
+ /** localStorage key holding recent wallpaper history (JSON array of {kind,value}). */
40
+ const WALLPAPER_HISTORY_KEY = "dsh-dream-skin:wallpaper-history";
41
+ /** Max wallpaper history entries kept. */
42
+ const WALLPAPER_HISTORY_MAX = 5;
39
43
  /** Sentinel meaning "no custom skin — follow the built-in appearance". */
40
44
  const DEFAULT_SKIN = "system";
41
45
  /** Default wash opacity (0..1) applied to the translucent surfaces. */
@@ -328,7 +332,7 @@ window.__ModuleLoader__.load({
328
332
 
329
333
  /** Simplified Chinese dictionary (the key-set source of truth). */
330
334
  const zh = {
331
- "skin.title": "皮肤(Mirage 幻梦)",
335
+ "skin.title": "皮肤",
332
336
  "skin.default": "默认",
333
337
  "skin.abyss": "深海渊",
334
338
  "skin.aurora": "极光",
@@ -344,6 +348,8 @@ window.__ModuleLoader__.load({
344
348
  "background.opacity": "透明度",
345
349
  "background.blur": "模糊",
346
350
  "background.hint": "图片显示在主内容区与侧边栏的半透明底上,消息等内层表面保持不透明以保证可读性",
351
+ "background.history": "最近使用",
352
+ "background.historyApply": "点击换回这张壁纸",
347
353
  "accent.title": "强调色(Accent)",
348
354
  "accent.random": "随机",
349
355
  "accent.clear": "恢复主题色",
@@ -365,7 +371,7 @@ window.__ModuleLoader__.load({
365
371
 
366
372
  /** English dictionary, checked complete against the zh key set. */
367
373
  const en = {
368
- "skin.title": "Skins (Mirage)",
374
+ "skin.title": "Skins",
369
375
  "skin.default": "Default",
370
376
  "skin.abyss": "Abyss",
371
377
  "skin.aurora": "Aurora",
@@ -381,6 +387,8 @@ window.__ModuleLoader__.load({
381
387
  "background.opacity": "Opacity",
382
388
  "background.blur": "Blur",
383
389
  "background.hint": "The image shows through the translucent main canvas and sidebar; inner surfaces stay opaque for readability",
390
+ "background.history": "Recent",
391
+ "background.historyApply": "Click to switch back",
384
392
  "accent.title": "Accent",
385
393
  "accent.random": "Random",
386
394
  "accent.clear": "Reset to theme",
@@ -612,14 +620,16 @@ window.__ModuleLoader__.load({
612
620
  url: null,
613
621
  opacity: DEFAULT_WALLPAPER_OPACITY,
614
622
  blur: DEFAULT_WALLPAPER_BLUR,
623
+ history: [],
615
624
  revision: -1
616
625
  }),
617
626
  actions: {
618
- sync: (d, url, opacity, blur, revision) => {
627
+ sync: (d, url, opacity, blur, history, revision) => {
619
628
  if (revision <= d.revision) return;
620
629
  d.url = url;
621
630
  d.opacity = opacity;
622
631
  d.blur = blur;
632
+ d.history = history;
623
633
  d.revision = revision;
624
634
  }
625
635
  }
@@ -665,11 +675,26 @@ window.__ModuleLoader__.load({
665
675
  background: "transparent",
666
676
  cursor: "pointer",
667
677
  font: "inherit",
668
- boxSizing: "border-box"
678
+ boxSizing: "border-box",
679
+ position: "relative"
669
680
  },
670
681
  cardSelected: {
671
682
  borderColor: "var(--dsw-alias-brand-primary)",
672
- background: "var(--dsw-alias-interactive-bg-hover)"
683
+ background: "rgba(127, 127, 127, 0.10)"
684
+ },
685
+ cardCheck: {
686
+ position: "absolute",
687
+ top: "-4px",
688
+ right: "-4px",
689
+ width: "18px",
690
+ height: "18px",
691
+ borderRadius: "50%",
692
+ background: "var(--dsw-alias-brand-primary)",
693
+ color: "#ffffff",
694
+ fontSize: "12px",
695
+ lineHeight: "18px",
696
+ textAlign: "center",
697
+ fontWeight: 700
673
698
  },
674
699
  cardLabel: {
675
700
  color: "var(--dsw-alias-label-secondary)",
@@ -756,6 +781,26 @@ window.__ModuleLoader__.load({
756
781
  cursor: "pointer",
757
782
  padding: 0
758
783
  },
784
+ historyThumb: {
785
+ width: "56px",
786
+ height: "36px",
787
+ borderRadius: "8px",
788
+ border: "1px solid var(--dsw-alias-border-l2)",
789
+ cursor: "pointer",
790
+ padding: 0,
791
+ boxSizing: "border-box",
792
+ backgroundSize: "cover",
793
+ backgroundPosition: "center"
794
+ },
795
+ accentPreset: {
796
+ width: "24px",
797
+ height: "24px",
798
+ borderRadius: "50%",
799
+ border: "1px solid rgba(128,128,128,0.4)",
800
+ cursor: "pointer",
801
+ padding: 0,
802
+ boxSizing: "border-box"
803
+ },
759
804
  checkbox: {
760
805
  accentColor: "var(--dsw-alias-brand-primary)",
761
806
  width: "16px",
@@ -857,6 +902,10 @@ window.__ModuleLoader__.load({
857
902
  ...(selected ? styles.cardSelected : {})
858
903
  },
859
904
  children: [
905
+ selected ? (0, react_jsx_runtime.jsx)("span", {
906
+ style: styles.cardCheck,
907
+ children: "✓"
908
+ }) : null,
860
909
  (0, react_jsx_runtime.jsx)(Swatch, { tokens: skin.tokens }),
861
910
  (0, react_jsx_runtime.jsx)("span", {
862
911
  style: {
@@ -948,10 +997,11 @@ window.__ModuleLoader__.load({
948
997
  * Wallpaper row: choose (compressed to a data URL), preview, tune the
949
998
  * wash opacity and blur, and remove the wallpaper.
950
999
  */
951
- function WallpaperRow({ t, setWallpaper, setOpacity, setBlur, useStore }) {
1000
+ function WallpaperRow({ t, setWallpaper, setOpacity, setBlur, applyFromHistory, useStore }) {
952
1001
  const url = useStore((s) => s.url);
953
1002
  const opacity = useStore((s) => s.opacity);
954
1003
  const blur = useStore((s) => s.blur);
1004
+ const history = useStore((s) => s.history);
955
1005
  const inputRef = (0, _react.useRef)(null);
956
1006
  const onPick = () => inputRef.current?.click();
957
1007
  const onFile = (event) => {
@@ -1019,6 +1069,31 @@ window.__ModuleLoader__.load({
1019
1069
  format: (v) => `${v}px`,
1020
1070
  onChange: setBlur
1021
1071
  }),
1072
+ history && history.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
1073
+ style: { ...styles.group, padding: "8px 0", borderBottom: "none" },
1074
+ children: [
1075
+ (0, react_jsx_runtime.jsx)("div", {
1076
+ style: styles.title,
1077
+ children: t("background.history")
1078
+ }),
1079
+ (0, react_jsx_runtime.jsxs)("div", {
1080
+ style: styles.actionRow,
1081
+ children: history.map((entry, i) => {
1082
+ const isImage = entry.kind !== "gradient" && entry.kind !== "url";
1083
+ return (0, react_jsx_runtime.jsx)("button", {
1084
+ type: "button",
1085
+ title: t("background.historyApply"),
1086
+ style: {
1087
+ ...styles.historyThumb,
1088
+ background: isImage ? `url("${entry.value}") center/cover no-repeat` : entry.value
1089
+ },
1090
+ onClick: () => applyFromHistory(entry.kind, entry.value),
1091
+ children: null
1092
+ }, i);
1093
+ })
1094
+ })
1095
+ ]
1096
+ }) : null,
1022
1097
  (0, react_jsx_runtime.jsx)("div", {
1023
1098
  style: styles.hint,
1024
1099
  children: t("background.hint")
@@ -1098,6 +1173,7 @@ window.__ModuleLoader__.load({
1098
1173
  "aria-pressed": gradient === g,
1099
1174
  style: {
1100
1175
  ...styles.presetswatches,
1176
+ background: g,
1101
1177
  ...(gradient === g ? { outline: "2px solid var(--dsw-alias-brand-primary)" } : {})
1102
1178
  },
1103
1179
  onClick: () => setGradient(g),
@@ -1691,17 +1767,43 @@ window.__ModuleLoader__.load({
1691
1767
  syncWallpaper();
1692
1768
  }
1693
1769
 
1770
+ /** Read recent wallpaper history entries [{kind,value}]. */
1771
+ function readWallpaperHistory() {
1772
+ const raw = readStorage(WALLPAPER_HISTORY_KEY);
1773
+ if (raw === null) return [];
1774
+ try {
1775
+ const parsed = JSON.parse(raw);
1776
+ return Array.isArray(parsed) ? parsed.filter((e) => e && typeof e.value === "string") : [];
1777
+ } catch {
1778
+ return [];
1779
+ }
1780
+ }
1781
+
1782
+ /** Persist the wallpaper history list. */
1783
+ function writeWallpaperHistory(list) {
1784
+ writeStorage(WALLPAPER_HISTORY_KEY, JSON.stringify(list.slice(0, WALLPAPER_HISTORY_MAX)));
1785
+ }
1786
+
1787
+ /** Record a wallpaper setting into history (dedupe by kind+value, newest first). */
1788
+ function pushWallpaperHistory(kind, value) {
1789
+ if (value === null || value === undefined || value === "") return;
1790
+ const list = readWallpaperHistory();
1791
+ const deduped = list.filter((e) => !(e.kind === kind && e.value === value));
1792
+ deduped.unshift({ kind, value });
1793
+ writeWallpaperHistory(deduped);
1794
+ }
1795
+
1694
1796
  /** Set a wallpaper by kind and value. */
1695
1797
  function setWallpaperKind(ctx, kind, value) {
1696
1798
  writeStorage(WALLPAPER_KIND_KEY, kind);
1697
1799
  if (kind === "gradient") {
1698
1800
  writeStorage(WALLPAPER_GRADIENT_KEY, value);
1699
- if (value === null) writeStorage(WALLPAPER_GRADIENT_KEY, null);
1700
1801
  } else if (kind === "url") {
1701
1802
  writeStorage(WALLPAPER_URL_KEY, value);
1702
1803
  } else {
1703
1804
  writeStorage(WALLPAPER_KEY, value);
1704
1805
  }
1806
+ pushWallpaperHistory(kind, value);
1705
1807
  applyWallpaper2(ctx);
1706
1808
  syncWallpaper();
1707
1809
  }
@@ -1734,6 +1836,13 @@ window.__ModuleLoader__.load({
1734
1836
  //#endregion
1735
1837
 
1736
1838
  //#region dsh-dream-skin: P0 UI rows (accent + packs)
1839
+ /** Curated accent presets users can pick with one click. */
1840
+ const ACCENT_PRESETS = [
1841
+ "#4f83f2", "#2563eb", "#34d399", "#22d3ee", "#a78bfa",
1842
+ "#fb923c", "#f87171", "#fbbf24", "#e879f9", "#f472b6",
1843
+ "#2dd4bf", "#a3e635"
1844
+ ];
1845
+
1737
1846
  /**
1738
1847
  * Accent row: pick an arbitrary brand-accent color (or clear to follow
1739
1848
  * the active theme). Uses an `<input type="color">` + the current accent
@@ -1777,6 +1886,21 @@ window.__ModuleLoader__.load({
1777
1886
  }) : null
1778
1887
  ]
1779
1888
  }),
1889
+ (0, react_jsx_runtime.jsxs)("div", {
1890
+ style: styles.actionRow,
1891
+ children: ACCENT_PRESETS.map((hex) => (0, react_jsx_runtime.jsx)("button", {
1892
+ type: "button",
1893
+ title: hex,
1894
+ "aria-pressed": activeValue === hex,
1895
+ style: {
1896
+ ...styles.accentPreset,
1897
+ background: hex,
1898
+ ...(activeValue === hex ? { outline: "2px solid var(--dsw-alias-label-primary)", outlineOffset: "1px" } : {})
1899
+ },
1900
+ onClick: () => setAccent(hex),
1901
+ children: null
1902
+ }, hex))
1903
+ }),
1780
1904
  (0, react_jsx_runtime.jsx)("div", {
1781
1905
  style: styles.hint,
1782
1906
  children: t("accent.hint")
@@ -1967,7 +2091,13 @@ window.__ModuleLoader__.load({
1967
2091
  wallpaperRevision += 1;
1968
2092
  // Store the raw data URL (not the CSS url(...) wrapper) so the
1969
2093
  // Wallpaper row can render an <img> preview and test `url !== null`.
1970
- wallpaperBound?.sync(readWallpaper(), readWallpaperOpacity(), readWallpaperBlur(), wallpaperRevision);
2094
+ wallpaperBound?.sync(
2095
+ readWallpaper(),
2096
+ readWallpaperOpacity(),
2097
+ readWallpaperBlur(),
2098
+ readWallpaperHistory(),
2099
+ wallpaperRevision
2100
+ );
1971
2101
  };
1972
2102
  applyWallpaper2(ctx);
1973
2103
  syncWallpaper();
@@ -1997,6 +2127,11 @@ window.__ModuleLoader__.load({
1997
2127
  setSkin: (id) => {
1998
2128
  ctx.theme.setTheme(id);
1999
2129
  writeSavedSkin(id);
2130
+ // Deterministically push the new preference into the slot store AND
2131
+ // re-shade the wallpaper so the selected card follows immediately,
2132
+ // independent of theme/change emission timing.
2133
+ skinBound?.sync(id, (ctx.theme.getTheme().revision));
2134
+ if (wallpaperBackgroundCss() !== null) applyWallpaper2(ctx);
2000
2135
  }
2001
2136
  };
2002
2137
  };
@@ -2042,6 +2177,14 @@ window.__ModuleLoader__.load({
2042
2177
  applyWallpaper2(ctx);
2043
2178
  syncWallpaper();
2044
2179
  },
2180
+ applyFromHistory: (kind, value) => {
2181
+ const resolvedKind = kind === "gradient" || kind === "url" ? kind : "image";
2182
+ if (value && value.length > 4) {
2183
+ setWallpaperKind(ctx, resolvedKind, value);
2184
+ } else {
2185
+ syncWallpaper();
2186
+ }
2187
+ },
2045
2188
  clearWallpaper: () => {
2046
2189
  removeWallpaper(ctx);
2047
2190
  }
@@ -2110,6 +2253,7 @@ window.__ModuleLoader__.load({
2110
2253
  // P0: per-user accent override row.
2111
2254
  const accentStore = createAccentStore();
2112
2255
  let accentBound;
2256
+ let accentRevision = 0;
2113
2257
  const accentInjected = (actions) => {
2114
2258
  accentBound = actions;
2115
2259
  const base = resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT;
@@ -2117,12 +2261,19 @@ window.__ModuleLoader__.load({
2117
2261
  return {
2118
2262
  setAccent: (value) => {
2119
2263
  const applied = setAccent(ctx, value === DEFAULT_ACCENT ? null : value);
2120
- accentBound?.sync(applied || DEFAULT_ACCENT, resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT, 0);
2264
+ accentBound?.sync(
2265
+ applied || DEFAULT_ACCENT,
2266
+ resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT,
2267
+ ++accentRevision
2268
+ );
2121
2269
  },
2122
2270
  clearAccent: () => {
2123
2271
  setAccent(ctx, null);
2124
- accentBound?.sync(DEFAULT_ACCENT, resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT, 0);
2125
- syncSkin(ctx.theme.getTheme());
2272
+ accentBound?.sync(
2273
+ DEFAULT_ACCENT,
2274
+ resolveAccent(ctx.theme.getTheme()) || DEFAULT_ACCENT,
2275
+ ++accentRevision
2276
+ );
2126
2277
  }
2127
2278
  };
2128
2279
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dream-skin",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "DeepSeek Harness 换肤插件 (Dream Skin for DeepSeek Harness): curated --dsw-alias-* theme presets, a custom translucent wallpaper with opacity/blur controls, theme-pack import/export + share links, per-user accent, favorites & surprise-me, and durable per-browser persistence — in the spirit of the Codex Dream Skin project.",
5
5
  "license": "MIT",
6
6
  "type": "module",