dsh-dream-skin 0.2.2 → 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 +148 -6
  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. */
@@ -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": "恢复主题色",
@@ -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")
@@ -1692,17 +1767,43 @@ window.__ModuleLoader__.load({
1692
1767
  syncWallpaper();
1693
1768
  }
1694
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
+
1695
1796
  /** Set a wallpaper by kind and value. */
1696
1797
  function setWallpaperKind(ctx, kind, value) {
1697
1798
  writeStorage(WALLPAPER_KIND_KEY, kind);
1698
1799
  if (kind === "gradient") {
1699
1800
  writeStorage(WALLPAPER_GRADIENT_KEY, value);
1700
- if (value === null) writeStorage(WALLPAPER_GRADIENT_KEY, null);
1701
1801
  } else if (kind === "url") {
1702
1802
  writeStorage(WALLPAPER_URL_KEY, value);
1703
1803
  } else {
1704
1804
  writeStorage(WALLPAPER_KEY, value);
1705
1805
  }
1806
+ pushWallpaperHistory(kind, value);
1706
1807
  applyWallpaper2(ctx);
1707
1808
  syncWallpaper();
1708
1809
  }
@@ -1735,6 +1836,13 @@ window.__ModuleLoader__.load({
1735
1836
  //#endregion
1736
1837
 
1737
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
+
1738
1846
  /**
1739
1847
  * Accent row: pick an arbitrary brand-accent color (or clear to follow
1740
1848
  * the active theme). Uses an `<input type="color">` + the current accent
@@ -1778,6 +1886,21 @@ window.__ModuleLoader__.load({
1778
1886
  }) : null
1779
1887
  ]
1780
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
+ }),
1781
1904
  (0, react_jsx_runtime.jsx)("div", {
1782
1905
  style: styles.hint,
1783
1906
  children: t("accent.hint")
@@ -1968,7 +2091,13 @@ window.__ModuleLoader__.load({
1968
2091
  wallpaperRevision += 1;
1969
2092
  // Store the raw data URL (not the CSS url(...) wrapper) so the
1970
2093
  // Wallpaper row can render an <img> preview and test `url !== null`.
1971
- wallpaperBound?.sync(readWallpaper(), readWallpaperOpacity(), readWallpaperBlur(), wallpaperRevision);
2094
+ wallpaperBound?.sync(
2095
+ readWallpaper(),
2096
+ readWallpaperOpacity(),
2097
+ readWallpaperBlur(),
2098
+ readWallpaperHistory(),
2099
+ wallpaperRevision
2100
+ );
1972
2101
  };
1973
2102
  applyWallpaper2(ctx);
1974
2103
  syncWallpaper();
@@ -1998,6 +2127,11 @@ window.__ModuleLoader__.load({
1998
2127
  setSkin: (id) => {
1999
2128
  ctx.theme.setTheme(id);
2000
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);
2001
2135
  }
2002
2136
  };
2003
2137
  };
@@ -2043,6 +2177,14 @@ window.__ModuleLoader__.load({
2043
2177
  applyWallpaper2(ctx);
2044
2178
  syncWallpaper();
2045
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
+ },
2046
2188
  clearWallpaper: () => {
2047
2189
  removeWallpaper(ctx);
2048
2190
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dream-skin",
3
- "version": "0.2.2",
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",