dsh-dream-skin 0.2.2 โ†’ 0.2.4

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.en.md CHANGED
@@ -6,11 +6,16 @@
6
6
 
7
7
  # dsh-dream-skin ๐Ÿ”ฎ
8
8
 
9
- **Make DeepSeek Harness breathe, feel, and belong to you.**
9
+ **Give DeepSeek Harness a face that breathes, feels, and belongs to you.**
10
10
 
11
- Native skinning + wallpaper + theme packs โ€” a romance-engineered project built entirely on DSH's official `--dsw-*` token system.
11
+ Native skinning ยท wallpaper ยท shareable theme packs โ€” a romance-engineered project built entirely on DSH's official `--dsw-*` token system.
12
12
 
13
- > 3-line install ยท 8 original themes ยท 2 visual layers ยท 1-click share
13
+ > **TL;DR: code with atmosphere.** โœจ
14
+
15
+ | ๐ŸŽจ 8 original themes | ๐Ÿ–ผ๏ธ wallpaper + opacity/blur | ๐ŸŒˆ one-click accent | ๐Ÿ“ฆ shareable theme packs |
16
+ |---|---|---|---|
17
+
18
+ > 3-line install ยท purely native (no injection, no installer patches) ยท survives DSH updates
14
19
 
15
20
  [ไธญๆ–‡](./README.md) ยท [Changelog](./CHANGELOG.md) ยท [Project Notes](./docs/PROJECT.md) ยท [Publishing Guide](./docs/publishing-to-npm.md)
16
21
 
@@ -38,6 +43,18 @@ Native skinning + wallpaper + theme packs โ€” a romance-engineered project built
38
43
 
39
44
  ---
40
45
 
46
+ ## ๐Ÿ“ธ Screenshots
47
+
48
+ > Real screenshots, not mockups. Left: DSH after applying a skin; right: the dedicated **Theme / Appearance** section in Settings.
49
+
50
+ <p align="center">
51
+ <img src="docs/screenshots/preview.png" alt="DSH skin preview" width="46%"/>
52
+ &nbsp;&nbsp;
53
+ <img src="docs/screenshots/settings.png" alt="Theme section in settings" width="46%"/>
54
+ </p>
55
+
56
+ ---
57
+
41
58
  ## ๐Ÿ† Why it earns a star (vs alternatives)
42
59
 
43
60
  | Capability | Ours | Other DSH skinning | Codex-Dream-Skin (desktop) |
@@ -55,7 +72,7 @@ Native skinning + wallpaper + theme packs โ€” a romance-engineered project built
55
72
 
56
73
  | Capability | Description |
57
74
  |------------|-------------|
58
- | ๐ŸŽจ **8 bundled presets (Mirage)** | Switch instantly under **Settings โ†’ General โ†’ Skins**, light & dark |
75
+ | ๐ŸŽจ **8 bundled presets (Mirage)** | Switch instantly under **Settings โ†’ Theme / Appearance**, light & dark |
59
76
  | ๐Ÿ–ผ๏ธ **Custom wallpaper** | Pick a local image (auto-compressed โ‰ค2MB), tune **opacity / blur** |
60
77
  | ๐Ÿ”ค **Opaque inner surfaces** | Cards, inputs, message bubbles stay readable โ€” never washed out |
61
78
  | โ†ฉ๏ธ **Default restore** | Back to DSH's built-in appearance (follow system) in one click |
@@ -68,9 +85,10 @@ Differentiation inspired by existing DSH skin projects plus Codex's skin UX:
68
85
  | Capability | Description |
69
86
  |------------|-------------|
70
87
  | ๐Ÿ“ฆ **Theme-pack format + import/export** | A `*.dsh-theme.json` pack = format marker + version + manifest (id/name/author/scheme/accent/tokens). Import a file, one-click apply, and copy a **share link** (encoded in the URL hash) |
71
- | ๐ŸŒˆ **Per-user Accent** | Stack a custom brand-accent color over the active skin (`overrideTokens` layer, the skin itself untouched), or **randomize** / clear |
72
- | ๐Ÿ–ผ๏ธ **Wallpaper 2.0** | Besides local images: **image URL** and **gradient presets**, with a **per-skin suggested gradient** and an **auto-dim** mode (gently fades while focusing tasks) |
88
+ | ๐ŸŒˆ **Per-user Accent** | Stack a custom brand-accent over the active skin (`overrideTokens` layer, the skin untouched): **12 one-click preset swatches**, a color picker, **randomize**, and clear |
89
+ | ๐Ÿ–ผ๏ธ **Wallpaper 2.0** | Local image / **image URL** / **gradient presets**, with a **per-skin suggested gradient** and **auto-dim**; **Recent** (up to 5) to switch back in one click |
73
90
  | ๐Ÿงฉ **Local pack library** | All built-in skins + imported packs in one place; **apply / favorite** in a click |
91
+ | โœ… **Clear selection feedback** | Switching skins updates the checked/bordered highlight **instantly** โ€” no stale white highlight box |
74
92
  | ๐ŸŽฒ **Surprise me** | Randomly switch to a theme different from the current one |
75
93
  | โญ **Favorites** | Star your favorite skins and switch between them fast |
76
94
  | โœ… **Validation + rollback** | Pack import validates format / required tokens / color legality; failures or removals fall back safely |
@@ -82,7 +100,7 @@ Differentiation inspired by existing DSH skin projects plus Codex's skin UX:
82
100
  dsh plugin --profile web add dsh-dream-skin
83
101
  # 2. restart
84
102
  dsh web
85
- # 3. open Settings โ†’ General โ†’ Skins and pick one โ†’ done.
103
+ # 3. open Settings โ†’ Theme / Appearance โ†’ pick a skin โ†’ done.
86
104
  ```
87
105
 
88
106
  > Installs the published npm package โ€” no cloning. If `dsh plugin add` reports a workspace error, append `-w`.
@@ -104,7 +122,7 @@ packages**:
104
122
 
105
123
  - **Install command = the official one**: `dsh plugin --profile web add dsh-dream-skin`
106
124
  - **Uses official extension points**: `ctx.theme` (register themes), `ctx.theme.overrideTokens` (override layers),
107
- `ctx.slots` (mount UI into **Settings โ†’ General**).
125
+ `ctx.slots` (mount UI into a dedicated **Settings โ†’ Theme / Appearance** section).
108
126
  - **Manifest contract matches official packages**: `dsh.bundle` + `dsh.client` + `exports["./client"]`.
109
127
 
110
128
  In other words: you are not installing a fringe script โ€” this is a standard skin plugin inside DSH's official plugin
@@ -157,7 +175,7 @@ Then **restart** the web server:
157
175
  dsh web
158
176
  ```
159
177
 
160
- Open **Settings โ†’ General** to see the **Skins**, **Accent**, **Wallpaper** / **Advanced Wallpaper**, and **Theme Packs** rows.
178
+ Open **Settings โ†’ Theme / Appearance** to see the **Skins**, **Accent**, **Wallpaper** / **Advanced Wallpaper**, and **Theme Packs** rows.
161
179
 
162
180
  > The `-w` (workspace) flag is needed on a bare `add` because every profile ships a `pnpm-workspace.yaml`; pnpm treats
163
181
  > the profile directory as a workspace root, so a bare add fails with `ERR_PNPM_ADDING_TO_ROOT`. If your profile already
@@ -169,6 +187,26 @@ Open **Settings โ†’ General** to see the **Skins**, **Accent**, **Wallpaper** /
169
187
  dsh plugin --profile web add -w /path/to/dsh-dream-skin
170
188
  ```
171
189
 
190
+ ## ๐Ÿ”„ Update / Uninstall
191
+
192
+ **Update to the latest** (when installed from the npm release):
193
+
194
+ ```sh
195
+ dsh plugin --profile web update dsh-dream-skin
196
+ dsh web # restart to pick it up
197
+ ```
198
+
199
+ > Stuck on an old version after an update? pnpm's minimum-release-age (supply-chain) policy can hold back a
200
+ > freshly published release. In the profile dir run:
201
+ > `pnpm add dsh-dream-skin@latest --config.minimumReleaseAge=0` to force it.
202
+
203
+ **Uninstall:**
204
+
205
+ ```sh
206
+ dsh plugin --profile web remove dsh-dream-skin
207
+ dsh web # restores the official appearance
208
+ ```
209
+
172
210
  ## ๐Ÿงฉ Compatibility
173
211
 
174
212
  | Item | Value |
@@ -231,6 +269,8 @@ seeds (`react`, `react/jsx-runtime`, โ€ฆ) and registered client bundles (`@deeps
231
269
  it then appears in Settings automatically. Add a `skin.<id>` key to both the `zh` and `en` dictionaries.
232
270
  - **Ship a theme pack (recommended)**: follow [`docs/examples/sample-theme-pack.json`](./docs/examples/sample-theme-pack.json) โ€”
233
271
  one `*.dsh-theme.json` is importable in Settings and shareable via a link, no code changes needed.
272
+ - **Add your own wallpapers**: drop images into [`wallpapers/`](./wallpapers/) (distribute only what you have rights
273
+ to), then import them via DSH's "Wallpaper" row.
234
274
  - **Validate**: `npm test` (VM smoke tests covering factory eval, `apply()`, and pack import/persistence).
235
275
  - **Repaint**: reference the `--dsw-alias-*` tokens (full contract in [`docs/themes-spec.md`](./docs/themes-spec.md)).
236
276
 
@@ -251,6 +291,11 @@ seeds (`react`, `react/jsx-runtime`, โ€ฆ) and registered client bundles (`@deeps
251
291
  Issues and PRs welcome! Please read the [Contributing Guide](./CONTRIBUTING.md) and follow the
252
292
  [Code of Conduct](./CODE_OF_CONDUCT.md).
253
293
 
294
+ ## โญ Support the project
295
+
296
+ If you like it: star **โญ** the repo, thumbs-up **๐Ÿ‘** on npm, or share it with DSH friends โ€” it helps the project
297
+ get discovered and keeps it maintained. Want to contribute themes / an online Studio / more skins? Join in.
298
+
254
299
  ## ๐Ÿ”’ Security
255
300
 
256
301
  Found a security issue? Don't open a public issue โ€” see the [Security Policy](./SECURITY.md).
package/README.md CHANGED
@@ -6,11 +6,16 @@
6
6
 
7
7
  # dsh-dream-skin ๐Ÿ”ฎ
8
8
 
9
- **่ฎฉ DeepSeek Harness ไนŸไผšๅ‘ผๅธใ€ๆœ‰ๆƒ…็ปชใ€ๅฑžไบŽไฝ ใ€‚**
9
+ **่ฎฉ DeepSeek Harness ๆขไธ€ๅผ ไผšๅ‘ผๅธใ€ๆœ‰ๆƒ…็ปชใ€ๅฑžไบŽไฝ ็š„่„ธใ€‚**
10
10
 
11
- ๅŽŸ็”Ÿๆข่‚ค + ๅฃ็บธ + ไธป้ข˜ๅŒ…๏ผŒไธ€ๅฅ—ๅฎŒๅ…จ็”จๅฎ˜ๆ–น `--dsw-*` token ็ณป็ปŸๅฎž็Žฐ็š„ๆตชๆผซๅทฅ็จ‹ใ€‚
11
+ ๅŽŸ็”Ÿๆข่‚ค ยท ่ƒŒๆ™ฏๅฃ็บธ ยท ไธป้ข˜ๅŒ…ๅˆ†ไบซ โ€”โ€” ๅฎŒๅ…จ็”จๅฎ˜ๆ–น `--dsw-*` token ็ณป็ปŸๅฎž็Žฐ็š„ๆตชๆผซๅทฅ็จ‹ใ€‚่ฃ…ไธ€ๆฌก๏ผŒ็ปˆ่บซๅฏๆขใ€‚
12
12
 
13
- > 3 ่กŒๅฎ‰่ฃ… ยท 8 ๅฅ—ๅŽŸๅˆ›ไธป้ข˜ ยท 2 ๅฑ‚่ง†่ง‰ๅ ๅŠ  ยท 1 ้”ฎๅˆ†ไบซ
13
+ > **ไธ€ๅฅ่ฏ๏ผšๅ†™ไปฃ็ ๏ผŒไนŸ่ฆๆœ‰ๆฐ›ๅ›ดๆ„Ÿใ€‚** โœจ
14
+
15
+ | ๐ŸŽจ 8 ๅฅ—ๅŽŸๅˆ›ไธป้ข˜ | ๐Ÿ–ผ๏ธ ๅฃ็บธ + ้€ๆ˜Žๅบฆ/ๆจก็ณŠ | ๐ŸŒˆ ๅผบ่ฐƒ่‰ฒ็‚นไธ€ไธ‹ | ๐Ÿ“ฆ ไธป้ข˜ๅŒ…ๅฏๅˆ†ไบซ |
16
+ |---|---|---|---|
17
+
18
+ > 3 ่กŒๅฎ‰่ฃ… ยท ็บฏๅŽŸ็”Ÿ๏ผˆๆ— ๆณจๅ…ฅ/ไธๆ”นๅฎ‰่ฃ…ๅŒ…๏ผ‰ยท ไธๅ›  DSH ๆ›ดๆ–ฐๅคฑๆ•ˆ
14
19
 
15
20
  [English](./README.en.md) ยท [ๅ˜ๆ›ดๆ—ฅๅฟ—](./CHANGELOG.md) ยท [้กน็›ฎ่ฏดๆ˜Ž](./docs/PROJECT.md) ยท [ๅ‘ๅธƒๆŒ‡ๅผ•](./docs/publishing-to-npm.md)
16
21
 
@@ -37,6 +42,18 @@
37
42
 
38
43
  ---
39
44
 
45
+ ## ๐Ÿ“ธ ๅฎžๆœบๆˆชๅ›พ
46
+
47
+ > ็œŸๆœบๆ•ˆๆžœ๏ผŒ้žๆฆ‚ๅฟตๅ›พใ€‚ๅทฆ๏ผšๅบ”็”จๆŸๅฅ—็šฎ่‚คๅŽ็š„ DSH ็•Œ้ข๏ผ›ๅณ๏ผš่ฎพ็ฝฎ้‡Œ็š„ใ€Œๅค–่ง‚ / Themeใ€ๅˆ†่Š‚ใ€‚
48
+
49
+ <p align="center">
50
+ <img src="docs/screenshots/preview.png" alt="DSH ็šฎ่‚คๅฎžๆœบ้ข„่งˆ" width="46%"/>
51
+ &nbsp;&nbsp;
52
+ <img src="docs/screenshots/settings.png" alt="่ฎพ็ฝฎไธญ็š„ๅค–่ง‚ๅˆ†่Š‚" width="46%"/>
53
+ </p>
54
+
55
+ ---
56
+
40
57
  ## ๐Ÿ† ไธบไป€ไนˆๅ€ผๅพ—็”จ๏ผˆvs ๅŒ็ฑป๏ผ‰
41
58
 
42
59
  | ่ƒฝๅŠ› | ๆœฌๆ’ไปถ | ๅ…ถๅฎƒ DSH ๆข่‚คๆ–นๆกˆ | Codex-Dream-Skin (ๆกŒ้ข) |
@@ -54,7 +71,7 @@
54
71
 
55
72
  | ่ƒฝๅŠ› | ่ฏดๆ˜Ž |
56
73
  |------|------|
57
- | ๐ŸŽจ **8 ๅฅ—ไธป้ข˜้ข„่ฎพ๏ผˆMirage ๅนปๆขฆ๏ผ‰** | ๅœจ **่ฎพ็ฝฎ โ†’ ๅธธ่ง„ โ†’ ็šฎ่‚ค** ไธ€้”ฎๅˆ‡ๆข๏ผŒๆต…่‰ฒ / ๆทฑ่‰ฒๅ…ผ้กพ |
74
+ | ๐ŸŽจ **8 ๅฅ—ไธป้ข˜้ข„่ฎพ๏ผˆMirage ๅนปๆขฆ๏ผ‰** | ๅœจ **่ฎพ็ฝฎ โ†’ ๅค–่ง‚๏ผˆTheme๏ผ‰** ไธ€้”ฎๅˆ‡ๆข๏ผŒๆต…่‰ฒ / ๆทฑ่‰ฒๅ…ผ้กพ |
58
75
  | ๐Ÿ–ผ๏ธ **่‡ชๅฎšไน‰ๅฃ็บธ** | ไธŠไผ ๆœฌๅœฐๅ›พ๏ผˆ่‡ชๅŠจๅŽ‹็ผฉ โ‰ค2MB๏ผ‰๏ผŒ่ฐƒ่Š‚**้€ๆ˜Žๅบฆ / ๆจก็ณŠ** |
59
76
  | ๐Ÿ”ค **ๅ†…ๅฑ‚ไธ้€ๆ˜Ž** | ๅก็‰‡ใ€่พ“ๅ…ฅๆก†ใ€ๆถˆๆฏๆฐ”ๆณกไธ่ขซๅฃ็บธ็›–ไฝ๏ผŒๅฏ่ฏปๆ€งไผ˜ๅ…ˆ |
60
77
  | โ†ฉ๏ธ **้ป˜่ฎค่ฟ˜ๅŽŸ** | ไธ€้”ฎๅ›žๅˆฐ DSH ๅ†…็ฝฎๅค–่ง‚๏ผˆ่ทŸ้š็ณป็ปŸ๏ผ‰ |
@@ -67,9 +84,10 @@
67
84
  | ่ƒฝๅŠ› | ่ฏดๆ˜Ž |
68
85
  |------|------|
69
86
  | ๐Ÿ“ฆ **ไธป้ข˜ๅŒ…ๆ ผๅผ + ๅฏผๅ…ฅ/ๅฏผๅ‡บ** | ไธ€ไธช `*.dsh-theme.json` ไธป้ข˜ๅŒ… = ๆ ผๅผๆ ‡่ฎฐ + ็‰ˆๆœฌ + manifest๏ผˆid/name/ไฝœ่€…/่‰ฒ็ณป/accent/tokens๏ผ‰ใ€‚ๅฏ**ๅฏผๅ…ฅๆ–‡ไปถ**ใ€**ไธ€้”ฎๅบ”็”จ**ใ€**ๅคๅˆถๅˆ†ไบซ้“พๆŽฅ**๏ผˆ็ผ–็ ่ฟ› URL hash๏ผ‰ |
70
- | ๐ŸŒˆ **ๆฏ็”จๆˆทๅผบ่ฐƒ่‰ฒ Accent** | ไธบๅฝ“ๅ‰็šฎ่‚คๅ ๅŠ ไธ€ไธช่‡ชๅฎšไน‰ๅ“็‰Œๅผบ่ฐƒ่‰ฒ๏ผˆ`overrideTokens` ๅฑ‚๏ผŒไธๅŠจ็šฎ่‚คๆœฌ่บซ๏ผ‰๏ผŒๆˆ–**้šๆœบไธ€ไธช** / **ๆขๅคไธป้ข˜่‰ฒ** |
71
- | ๐Ÿ–ผ๏ธ **ๅฃ็บธ 2.0** | ้™คๆœฌๅœฐๅ›พๅค–๏ผŒๆ”ฏๆŒ**ๅ›พ็‰‡ URL** ไธŽ**ๆธๅ˜้ข„่ฎพ**๏ผŒๆฏๅฅ—็šฎ่‚ค**่‡ชๅŠจๅปบ่ฎฎ**ไธ€ๅผ ๆธๅ˜๏ผŒๅฏ**่‡ชๅŠจๅผฑๅŒ–**๏ผˆ่š็„ฆไปปๅŠกๆ—ถ้™ไฝŽๅนฒๆ‰ฐ๏ผ‰ |
87
+ | ๐ŸŒˆ **ๆฏ็”จๆˆทๅผบ่ฐƒ่‰ฒ Accent** | ไธบๅฝ“ๅ‰็šฎ่‚คๅ ๅŠ ไธ€ไธช่‡ชๅฎšไน‰ๅ“็‰Œๅผบ่ฐƒ่‰ฒ๏ผˆ`overrideTokens` ๅฑ‚๏ผŒไธๅŠจ็šฎ่‚คๆœฌ่บซ๏ผ‰๏ผŒ**12 ไธชๅ…ธๅž‹่‰ฒๅ—ไธ€้”ฎ้€‰่‰ฒ** + ้€‰่‰ฒ็›˜ + ้šๆœบ + ๆขๅคไธป้ข˜่‰ฒ |
88
+ | ๐Ÿ–ผ๏ธ **ๅฃ็บธ 2.0** | ๆœฌๅœฐๅ›พ / **ๅ›พ็‰‡ URL** / **ๆธๅ˜้ข„่ฎพ**๏ผŒๆฏๅฅ—็šฎ่‚ค**่‡ชๅŠจๅปบ่ฎฎ**ไธ€ๅผ ๆธๅ˜๏ผŒๅฏ**่‡ชๅŠจๅผฑๅŒ–**๏ผˆ่š็„ฆไปปๅŠกๆ—ถ้™ไฝŽๅนฒๆ‰ฐ๏ผ‰๏ผ›**ๆœ€่ฟ‘ไฝฟ็”จ**๏ผˆๆœ€ๅคš 5 ๅผ ๏ผ‰ไธ€้”ฎๆขๅ›ž |
72
89
  | ๐Ÿงฉ **ๆœฌๅœฐไธป้ข˜ๅŒ…ๅบ“** | ๆ‰€ๆœ‰ๅ†…็ฝฎ็šฎ่‚ค + ๅฏผๅ…ฅ็š„่‡ชๅฎšไน‰ๅŒ…้›†ไธญๅฑ•็คบ๏ผŒ**ๅบ”็”จ / ๆ”ถ่—** ไธ€้”ฎๅฎŒๆˆ |
90
+ | โœ… **ๆธ…ๆ™ฐ้€‰ไธญๅ้ฆˆ** | ๅˆ‡ๆข็šฎ่‚คๆ—ถ้€‰ไธญๆ€๏ผˆโœ“ + ่พนๆก†๏ผ‰**ๅณๆ—ถ่ทŸ้š**๏ผŒไธๅ†ๆฎ‹็•™ๆจก็ณŠ็š„็™ฝ่‰ฒ้ซ˜ไบฎๆก† |
73
91
  | ๐ŸŽฒ **ๆขไธ€ไธช่ฏ•่ฏ•๏ผˆsurprise me๏ผ‰** | ้šๆœบๆŒ‘ไธ€ไธชๅ’Œไฝ ๅฝ“ๅ‰ไธๅŒ็š„ไธป้ข˜ |
74
92
  | โญ **ๆ”ถ่—** | ๆ”ถ่—ๅ–œๆฌข็š„็šฎ่‚ค๏ผŒๅฟซ้€Ÿๅˆ‡ๆข |
75
93
  | โœ… **ๆ ก้ชŒ + ๅ›žๆปš** | ๅฏผๅ…ฅๆ—ถไผšๆ ก้ชŒๆ ผๅผ/ๅฟ…ๅกซ token/้ขœ่‰ฒๅˆๆณ•ๆ€ง๏ผ›ๅคฑ่ดฅๆˆ–็งป้™คๆ—ถๅฎ‰ๅ…จๅ›ž้€€๏ผŒไธๅš็ ดๅๆ€งๆ›ดๆ”น |
@@ -90,7 +108,7 @@ DeepSeek Harness ็š„ๅฃๅทๆ˜ฏใ€Œไธ€ๅˆ‡็š†ๆ’ไปถใ€๏ผšๆจกๅž‹ใ€ๅทฅๅ…ทใ€ๆฒ™็ฎฑใ€
90
108
 
91
109
  - **ๅฎ‰่ฃ…ๅ‘ฝไปค = ๅฎ˜ๆ–นๅ”ฏไธ€ๅฎ‰่ฃ…ๅ‘ฝไปค**๏ผš`dsh plugin --profile web add dsh-dream-skin`
92
110
  - **่ฐƒ็”จ็š„ๆ˜ฏๅฎ˜ๆ–นๆ‰ฉๅฑ•็‚น**๏ผš`ctx.theme`๏ผˆๆณจๅ†Œไธป้ข˜๏ผ‰ใ€`ctx.theme.overrideTokens`๏ผˆๅ ๅŠ ๅฑ‚๏ผ‰ใ€
93
- `ctx.slots`๏ผˆๆŠŠ UI ๆŒ‚่ฟ› **่ฎพ็ฝฎ โ†’ ๅธธ่ง„**๏ผ‰ใ€‚
111
+ `ctx.slots`๏ผˆๆŠŠ UI ๆŒ‚่ฟ›็‹ฌ็ซ‹็š„ **่ฎพ็ฝฎ โ†’ ๅค–่ง‚ / Theme** ๅˆ†่Š‚๏ผ‰ใ€‚
94
112
  - **manifest ๅฅ‘็บฆไธŽๅฎ˜ๆ–นไธ€่‡ด**๏ผš`dsh.bundle` + `dsh.client` + `exports["./client"]`ใ€‚
95
113
 
96
114
  ไนŸๅฐฑๆ˜ฏ่ฏด๏ผš**ไฝ ่ฃ…็š„ไธๆ˜ฏไธ€ไธชๆ—้—จๅทฆ้“็š„่„šๆœฌ๏ผŒ่€Œๆ˜ฏ DSH ๅฎ˜ๆ–นๆ’ไปถไฝ“็ณป้‡Œ็š„ๆ ‡ๅ‡†็šฎ่‚คๆ’ไปถใ€‚**
@@ -134,7 +152,7 @@ DeepSeek Harness ็š„ๅฃๅทๆ˜ฏใ€Œไธ€ๅˆ‡็š†ๆ’ไปถใ€๏ผšๆจกๅž‹ใ€ๅทฅๅ…ทใ€ๆฒ™็ฎฑใ€
134
152
  dsh plugin --profile web add dsh-dream-skin
135
153
  # 2. ้‡ๅฏ
136
154
  dsh web
137
- # 3. ๆ‰“ๅผ€ ่ฎพ็ฝฎ โ†’ ๅธธ่ง„ โ†’ ็šฎ่‚ค๏ผŒๆŒ‘ไธ€ๅฅ— โ†’ ๅฎŒใ€‚
155
+ # 3. ๆ‰“ๅผ€ ่ฎพ็ฝฎ โ†’ ๅค–่ง‚๏ผˆTheme๏ผ‰โ†’ ็šฎ่‚ค๏ผŒๆŒ‘ไธ€ๅฅ— โ†’ ๅฎŒใ€‚
138
156
  ```
139
157
 
140
158
  > ่ฃ…็š„ๆ˜ฏ npm ๅทฒๅฎŒๆˆๅ‘ๅธƒ็š„ๆญฃๅผๅŒ…๏ผŒๆ— ้œ€ cloneใ€‚่‹ฅ `dsh plugin add` ๆŠฅ workspace ็›ธๅ…ณ้”™่ฏฏ๏ผŒ่กฅไธ€ไธช `-w` ๅณๅฏใ€‚
@@ -154,7 +172,7 @@ dsh plugin --profile web add dsh-dream-skin
154
172
  dsh web
155
173
  ```
156
174
 
157
- ๆ‰“ๅผ€ **่ฎพ็ฝฎ โ†’ ๅธธ่ง„**๏ผŒๅณๅฏ็œ‹ๅˆฐใ€Œ็šฎ่‚คใ€ใ€Œๅผบ่ฐƒ่‰ฒใ€ใ€Œ่ƒŒๆ™ฏๅ›พ็‰‡ / ้ซ˜็บงๅฃ็บธใ€ไธŽใ€Œไธป้ข˜ๅŒ…ใ€็ญ‰่กŒใ€‚
175
+ ๆ‰“ๅผ€ **่ฎพ็ฝฎ โ†’ ๅค–่ง‚๏ผˆTheme๏ผ‰**๏ผŒๅณๅฏ็œ‹ๅˆฐใ€Œ็šฎ่‚คใ€ใ€Œๅผบ่ฐƒ่‰ฒใ€ใ€Œ่ƒŒๆ™ฏๅ›พ็‰‡ / ้ซ˜็บงๅฃ็บธใ€ไธŽใ€Œไธป้ข˜ๅŒ…ใ€็ญ‰่กŒใ€‚
158
176
 
159
177
  > `-w` ๆ ‡ๅฟ—ๅœจ่ฃธ `add` ๆ—ถๅฟ…้œ€๏ผšๆฏไธช profile ่‡ชๅธฆ `pnpm-workspace.yaml`๏ผŒpnpm ไผšๆŠŠๅฎƒๅฝ“ไฝœ workspace ๆ น๏ผŒ่ฃธๅŠ ๆŠฅ้”™
160
178
  > `ERR_PNPM_ADDING_TO_ROOT`ใ€‚่‹ฅๅทฒๅŠ ่ฟ‡ `-w`๏ผŒๅŽ็ปญ็”จ็Žฐๆœ‰ workspace ๅณๆ— ้œ€้‡ๅคใ€‚
@@ -165,6 +183,25 @@ dsh web
165
183
  dsh plugin --profile web add -w /path/to/dsh-dream-skin
166
184
  ```
167
185
 
186
+ ## ๐Ÿ”„ ๆ›ดๆ–ฐ / ๅธ่ฝฝ
187
+
188
+ **ๆ›ดๆ–ฐๅˆฐๆœ€ๆ–ฐ็‰ˆ**๏ผˆ่ฃ…็š„ๆ˜ฏ npm ๆญฃๅผๅŒ…ๆ—ถ๏ผ‰๏ผš
189
+
190
+ ```sh
191
+ dsh plugin --profile web update dsh-dream-skin
192
+ dsh web # ้‡ๅฏ็”Ÿๆ•ˆ
193
+ ```
194
+
195
+ > ่‹ฅๆ›ดๆ–ฐๅŽไปๆ˜พ็คบๆ—ง็‰ˆๆœฌ๏ผŒๅฏ่ƒฝๆ˜ฏ pnpm ็š„ๆœ€ๅฐๅ‘ๅธƒๅนด้พ„๏ผˆsupply-chain๏ผ‰็ญ–็•ฅๆŒกไฝไบ†ๅˆšๅ‘ๅธƒ็š„ๆ–ฐ็‰ˆๆœฌ๏ผš
196
+ > ๅœจ profile ็›ฎๅฝ•ๆ‰ง่กŒ `pnpm add dsh-dream-skin@latest --config.minimumReleaseAge=0` ๅณๅฏ็ป•่ฟ‡ใ€‚
197
+
198
+ **ๅธ่ฝฝ**๏ผš
199
+
200
+ ```sh
201
+ dsh plugin --profile web remove dsh-dream-skin
202
+ dsh web # ้‡ๅฏๅŽๆขๅคๅฎ˜ๆ–นๅค–่ง‚
203
+ ```
204
+
168
205
  ## ๐Ÿงฉ ๅ…ผๅฎนๆ€ง
169
206
 
170
207
  | ้กน | ๅ€ผ |
@@ -226,6 +263,8 @@ bundle๏ผˆ`@deepseek-ai/dsh-client-runtime/client`ใ€โ€ฆ๏ผ‰ใ€‚
226
263
  ๅฎƒๅณ่‡ชๅŠจๅ‡บ็Žฐๅœจ่ฎพ็ฝฎ้‡Œ๏ผ›่ฎฐๅพ—ๅœจ `zh` / `en` ่ฏๅ…ธ่กฅ `skin.<id>` ๆ–‡ๆกˆใ€‚
227
264
  - **ๅšไธ€ไธชไธป้ข˜ๅŒ…๏ผˆๆŽจ่ๅˆ†ๅ‘ๆ–นๅผ๏ผ‰**๏ผšๅ‚่€ƒ [`docs/examples/sample-theme-pack.json`](./docs/examples/sample-theme-pack.json)๏ผŒ
228
265
  ไธ€ไธช `*.dsh-theme.json` ๅณๅฏๅœจ่ฎพ็ฝฎ้‡Œๅฏผๅ…ฅๆˆ–้€š่ฟ‡ๅˆ†ไบซ้“พๆŽฅๅˆ†ๅ‘็ป™ๅˆซไบบ๏ผŒๆ— ้œ€ๆ”นไปฃ็ ใ€‚
266
+ - **ๆ”พไฝ ่‡ชๅทฑ็š„ๅฃ็บธ**๏ผšๆŠŠๅ›พ็‰‡ไธข่ฟ› [`wallpapers/`](./wallpapers/)๏ผˆๆณจๆ„ๅชๅœจไฝ ๆœ‰ๆƒ้™็š„ๅ‰ๆไธ‹ๅˆ†ๅ‘๏ผ‰๏ผŒๅ†ๅœจ
267
+ DSH ็š„ใ€Œ่ƒŒๆ™ฏๅ›พ็‰‡ใ€้‡Œๅฏผๅ…ฅๅณๅฏใ€‚
229
268
  - **่ท‘ๆ ก้ชŒ**๏ผš`npm test`๏ผˆVM ๅ†’็ƒŸๆต‹่ฏ•๏ผŒ่ฆ†็›– factory ๆฑ‚ๅ€ผใ€`apply` ๆŒ‚่ฝฝใ€ไธป้ข˜ๅŒ…ๅฏผๅ…ฅ/ๆŒไน…ๅŒ–๏ผ‰ใ€‚
230
269
  - **ๆข้…่‰ฒ**๏ผšๅ‚่€ƒ `--dsw-alias-*` ไปค็‰Œ๏ผˆๅฎŒๆ•ดๅฅ‘็บฆ่ง [`docs/themes-spec.md`](./docs/themes-spec.md)๏ผ‰ใ€‚
231
270
 
@@ -245,6 +284,11 @@ bundle๏ผˆ`@deepseek-ai/dsh-client-runtime/client`ใ€โ€ฆ๏ผ‰ใ€‚
245
284
 
246
285
  ๆฌข่ฟŽๆไบค Issue ไธŽ PR๏ผ่ฏทๅ…ˆ้˜…่ฏป [่ดก็ŒฎๆŒ‡ๅ—](./CONTRIBUTING.md)๏ผŒๅนถ้ตๅพช [Code of Conduct](./CODE_OF_CONDUCT.md)ใ€‚
247
286
 
287
+ ## โญ ๆ”ฏๆŒ่ฟ™ไธช้กน็›ฎ
288
+
289
+ ๅ–œๆฌข็š„่ฏ๏ผŒ็ป™ไป“ๅบ“็‚นไธช **Star โญ**ใ€ๅœจ npm ไธŠ็‚นไธช **๐Ÿ‘**๏ผŒๆˆ–ๆŠŠๅฎƒ่ฝฌๅ‘็ป™ไฝ ็š„ DSH ๆœ‹ๅ‹โ€”โ€”่ฟ™ไผš่ฎฉๆ›ดๅคšไบบๅ‘็Žฐๅฎƒ๏ผŒ
290
+ ไนŸ่ƒฝๆฟ€ๅŠฑๆŒ็ปญ็ปดๆŠคใ€‚ๆƒณไธ€่ตทๅšไธป้ข˜ๅบ“ / ๅœจ็บฟ Studio / ๆ›ดๅคšไธป้ข˜๏ผŸๆฌข่ฟŽๆฅ่ดก็Œฎใ€‚
291
+
248
292
  ## ๐Ÿ”’ ๅฎ‰ๅ…จ
249
293
 
250
294
  ๅ‘็Žฐๅฎ‰ๅ…จ้—ฎ้ข˜๏ผŸ่ฏทๅ‹ฟ็›ดๆŽฅๅผ€ๅ…ฌๅผ€ Issueโ€”โ€”ๅ‚่ง [ๅฎ‰ๅ…จ็ญ–็•ฅ](./SECURITY.md)ใ€‚
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,7 +348,10 @@ 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๏ผ‰",
354
+ "accent.pick": "้€‰่‰ฒโ€ฆ",
348
355
  "accent.random": "้šๆœบ",
349
356
  "accent.clear": "ๆขๅคไธป้ข˜่‰ฒ",
350
357
  "accent.hint": "ไธบๅฝ“ๅ‰็šฎ่‚ค่ฎพ็ฝฎไธ€ไธช่‡ชๅฎšไน‰ๅผบ่ฐƒ่‰ฒ๏ผˆๅ ๅŠ ๅฑ‚๏ผŒไธๅฝฑๅ“็šฎ่‚คๆœฌ่บซ๏ผ‰๏ผ›็‚นใ€Œๆขๅคไธป้ข˜่‰ฒใ€ๅ›žๅˆฐ็šฎ่‚ค้ป˜่ฎคๅผบ่ฐƒ่‰ฒ",
@@ -381,7 +388,10 @@ window.__ModuleLoader__.load({
381
388
  "background.opacity": "Opacity",
382
389
  "background.blur": "Blur",
383
390
  "background.hint": "The image shows through the translucent main canvas and sidebar; inner surfaces stay opaque for readability",
391
+ "background.history": "Recent",
392
+ "background.historyApply": "Click to switch back",
384
393
  "accent.title": "Accent",
394
+ "accent.pick": "Pickโ€ฆ",
385
395
  "accent.random": "Random",
386
396
  "accent.clear": "Reset to theme",
387
397
  "accent.hint": "Set a custom accent color for the active skin (an override layer โ€” the skin itself is untouched). Reset to return to the skin's default accent.",
@@ -612,14 +622,16 @@ window.__ModuleLoader__.load({
612
622
  url: null,
613
623
  opacity: DEFAULT_WALLPAPER_OPACITY,
614
624
  blur: DEFAULT_WALLPAPER_BLUR,
625
+ history: [],
615
626
  revision: -1
616
627
  }),
617
628
  actions: {
618
- sync: (d, url, opacity, blur, revision) => {
629
+ sync: (d, url, opacity, blur, history, revision) => {
619
630
  if (revision <= d.revision) return;
620
631
  d.url = url;
621
632
  d.opacity = opacity;
622
633
  d.blur = blur;
634
+ d.history = history;
623
635
  d.revision = revision;
624
636
  }
625
637
  }
@@ -637,6 +649,11 @@ window.__ModuleLoader__.load({
637
649
  gap: "10px",
638
650
  padding: "16px 0"
639
651
  },
652
+ section: {
653
+ display: "flex",
654
+ flexDirection: "column",
655
+ width: "100%"
656
+ },
640
657
  title: {
641
658
  color: "var(--dsw-alias-label-primary)",
642
659
  fontSize: "14px",
@@ -661,15 +678,31 @@ window.__ModuleLoader__.load({
661
678
  width: "96px",
662
679
  padding: "3px",
663
680
  borderRadius: "10px",
664
- border: "2px solid transparent",
665
681
  background: "transparent",
682
+ border: "none",
666
683
  cursor: "pointer",
667
684
  font: "inherit",
668
- boxSizing: "border-box"
685
+ boxSizing: "border-box",
686
+ position: "relative",
687
+ outline: "none"
669
688
  },
670
689
  cardSelected: {
671
- borderColor: "var(--dsw-alias-brand-primary)",
672
- background: "var(--dsw-alias-interactive-bg-hover)"
690
+ boxShadow: "0 0 0 2px var(--dsw-alias-brand-primary)",
691
+ background: "rgba(127, 127, 127, 0.10)"
692
+ },
693
+ cardCheck: {
694
+ position: "absolute",
695
+ top: "-4px",
696
+ right: "-4px",
697
+ width: "18px",
698
+ height: "18px",
699
+ borderRadius: "50%",
700
+ background: "var(--dsw-alias-brand-primary)",
701
+ color: "#ffffff",
702
+ fontSize: "12px",
703
+ lineHeight: "18px",
704
+ textAlign: "center",
705
+ fontWeight: 700
673
706
  },
674
707
  cardLabel: {
675
708
  color: "var(--dsw-alias-label-secondary)",
@@ -756,6 +789,40 @@ window.__ModuleLoader__.load({
756
789
  cursor: "pointer",
757
790
  padding: 0
758
791
  },
792
+ historyThumb: {
793
+ width: "56px",
794
+ height: "36px",
795
+ borderRadius: "8px",
796
+ border: "1px solid var(--dsw-alias-border-l2)",
797
+ cursor: "pointer",
798
+ padding: 0,
799
+ boxSizing: "border-box",
800
+ backgroundSize: "cover",
801
+ backgroundPosition: "center"
802
+ },
803
+ accentPreset: {
804
+ width: "24px",
805
+ height: "24px",
806
+ borderRadius: "50%",
807
+ border: "1px solid rgba(128,128,128,0.4)",
808
+ cursor: "pointer",
809
+ padding: 0,
810
+ boxSizing: "border-box"
811
+ },
812
+ accentDot: {
813
+ width: "22px",
814
+ height: "22px",
815
+ borderRadius: "50%",
816
+ border: "1px solid var(--dsw-alias-border-l2)",
817
+ boxSizing: "border-box",
818
+ flex: "none"
819
+ },
820
+ accentHex: {
821
+ color: "var(--dsw-alias-label-secondary)",
822
+ fontSize: "13px",
823
+ lineHeight: "20px",
824
+ fontFamily: "ui-monospace, monospace"
825
+ },
759
826
  checkbox: {
760
827
  accentColor: "var(--dsw-alias-brand-primary)",
761
828
  width: "16px",
@@ -857,6 +924,10 @@ window.__ModuleLoader__.load({
857
924
  ...(selected ? styles.cardSelected : {})
858
925
  },
859
926
  children: [
927
+ selected ? (0, react_jsx_runtime.jsx)("span", {
928
+ style: styles.cardCheck,
929
+ children: "โœ“"
930
+ }) : null,
860
931
  (0, react_jsx_runtime.jsx)(Swatch, { tokens: skin.tokens }),
861
932
  (0, react_jsx_runtime.jsx)("span", {
862
933
  style: {
@@ -948,10 +1019,11 @@ window.__ModuleLoader__.load({
948
1019
  * Wallpaper row: choose (compressed to a data URL), preview, tune the
949
1020
  * wash opacity and blur, and remove the wallpaper.
950
1021
  */
951
- function WallpaperRow({ t, setWallpaper, setOpacity, setBlur, useStore }) {
1022
+ function WallpaperRow({ t, setWallpaper, setOpacity, setBlur, applyFromHistory, useStore }) {
952
1023
  const url = useStore((s) => s.url);
953
1024
  const opacity = useStore((s) => s.opacity);
954
1025
  const blur = useStore((s) => s.blur);
1026
+ const history = useStore((s) => s.history);
955
1027
  const inputRef = (0, _react.useRef)(null);
956
1028
  const onPick = () => inputRef.current?.click();
957
1029
  const onFile = (event) => {
@@ -1019,6 +1091,31 @@ window.__ModuleLoader__.load({
1019
1091
  format: (v) => `${v}px`,
1020
1092
  onChange: setBlur
1021
1093
  }),
1094
+ history && history.length > 0 ? (0, react_jsx_runtime.jsxs)("div", {
1095
+ style: { ...styles.group, padding: "8px 0", borderBottom: "none" },
1096
+ children: [
1097
+ (0, react_jsx_runtime.jsx)("div", {
1098
+ style: styles.title,
1099
+ children: t("background.history")
1100
+ }),
1101
+ (0, react_jsx_runtime.jsxs)("div", {
1102
+ style: styles.actionRow,
1103
+ children: history.map((entry, i) => {
1104
+ const isImage = entry.kind !== "gradient" && entry.kind !== "url";
1105
+ return (0, react_jsx_runtime.jsx)("button", {
1106
+ type: "button",
1107
+ title: t("background.historyApply"),
1108
+ style: {
1109
+ ...styles.historyThumb,
1110
+ background: isImage ? `url("${entry.value}") center/cover no-repeat` : entry.value
1111
+ },
1112
+ onClick: () => applyFromHistory(entry.kind, entry.value),
1113
+ children: null
1114
+ }, i);
1115
+ })
1116
+ })
1117
+ ]
1118
+ }) : null,
1022
1119
  (0, react_jsx_runtime.jsx)("div", {
1023
1120
  style: styles.hint,
1024
1121
  children: t("background.hint")
@@ -1692,17 +1789,43 @@ window.__ModuleLoader__.load({
1692
1789
  syncWallpaper();
1693
1790
  }
1694
1791
 
1792
+ /** Read recent wallpaper history entries [{kind,value}]. */
1793
+ function readWallpaperHistory() {
1794
+ const raw = readStorage(WALLPAPER_HISTORY_KEY);
1795
+ if (raw === null) return [];
1796
+ try {
1797
+ const parsed = JSON.parse(raw);
1798
+ return Array.isArray(parsed) ? parsed.filter((e) => e && typeof e.value === "string") : [];
1799
+ } catch {
1800
+ return [];
1801
+ }
1802
+ }
1803
+
1804
+ /** Persist the wallpaper history list. */
1805
+ function writeWallpaperHistory(list) {
1806
+ writeStorage(WALLPAPER_HISTORY_KEY, JSON.stringify(list.slice(0, WALLPAPER_HISTORY_MAX)));
1807
+ }
1808
+
1809
+ /** Record a wallpaper setting into history (dedupe by kind+value, newest first). */
1810
+ function pushWallpaperHistory(kind, value) {
1811
+ if (value === null || value === undefined || value === "") return;
1812
+ const list = readWallpaperHistory();
1813
+ const deduped = list.filter((e) => !(e.kind === kind && e.value === value));
1814
+ deduped.unshift({ kind, value });
1815
+ writeWallpaperHistory(deduped);
1816
+ }
1817
+
1695
1818
  /** Set a wallpaper by kind and value. */
1696
1819
  function setWallpaperKind(ctx, kind, value) {
1697
1820
  writeStorage(WALLPAPER_KIND_KEY, kind);
1698
1821
  if (kind === "gradient") {
1699
1822
  writeStorage(WALLPAPER_GRADIENT_KEY, value);
1700
- if (value === null) writeStorage(WALLPAPER_GRADIENT_KEY, null);
1701
1823
  } else if (kind === "url") {
1702
1824
  writeStorage(WALLPAPER_URL_KEY, value);
1703
1825
  } else {
1704
1826
  writeStorage(WALLPAPER_KEY, value);
1705
1827
  }
1828
+ pushWallpaperHistory(kind, value);
1706
1829
  applyWallpaper2(ctx);
1707
1830
  syncWallpaper();
1708
1831
  }
@@ -1735,6 +1858,13 @@ window.__ModuleLoader__.load({
1735
1858
  //#endregion
1736
1859
 
1737
1860
  //#region dsh-dream-skin: P0 UI rows (accent + packs)
1861
+ /** Curated accent presets users can pick with one click. */
1862
+ const ACCENT_PRESETS = [
1863
+ "#4f83f2", "#2563eb", "#34d399", "#22d3ee", "#a78bfa",
1864
+ "#fb923c", "#f87171", "#fbbf24", "#e879f9", "#f472b6",
1865
+ "#2dd4bf", "#a3e635"
1866
+ ];
1867
+
1738
1868
  /**
1739
1869
  * Accent row: pick an arbitrary brand-accent color (or clear to follow
1740
1870
  * the active theme). Uses an `<input type="color">` + the current accent
@@ -1745,6 +1875,7 @@ window.__ModuleLoader__.load({
1745
1875
  const base = useStore((s) => s.base);
1746
1876
  const activeValue = accent !== DEFAULT_ACCENT ? accent : base;
1747
1877
  const inputValue = normalizeHex(activeValue) || "#4f83f2";
1878
+ const accentPickerRef = (0, _react.useRef)(null);
1748
1879
  return (0, react_jsx_runtime.jsxs)("div", {
1749
1880
  style: styles.group,
1750
1881
  children: [
@@ -1755,10 +1886,27 @@ window.__ModuleLoader__.load({
1755
1886
  (0, react_jsx_runtime.jsxs)("div", {
1756
1887
  style: styles.actionRow,
1757
1888
  children: [
1889
+ (0, react_jsx_runtime.jsx)("span", {
1890
+ style: { ...styles.accentDot, background: inputValue },
1891
+ children: null
1892
+ }),
1893
+ (0, react_jsx_runtime.jsx)("span", {
1894
+ style: styles.accentHex,
1895
+ children: inputValue
1896
+ }),
1897
+ (0, react_jsx_runtime.jsx)("button", {
1898
+ type: "button",
1899
+ style: styles.button,
1900
+ onClick: () => {
1901
+ if (accentPickerRef.current) accentPickerRef.current.click();
1902
+ },
1903
+ children: t("accent.pick")
1904
+ }),
1758
1905
  (0, react_jsx_runtime.jsx)("input", {
1906
+ ref: accentPickerRef,
1759
1907
  type: "color",
1760
1908
  value: inputValue,
1761
- style: { ...styles.swatch, width: "40px", height: "32px", padding: 0, border: "none", borderRadius: "8px", cursor: "pointer" },
1909
+ style: { display: "none" },
1762
1910
  onChange: (event) => setAccent(event.target.value)
1763
1911
  }),
1764
1912
  (0, react_jsx_runtime.jsx)("button", {
@@ -1778,6 +1926,21 @@ window.__ModuleLoader__.load({
1778
1926
  }) : null
1779
1927
  ]
1780
1928
  }),
1929
+ (0, react_jsx_runtime.jsxs)("div", {
1930
+ style: styles.actionRow,
1931
+ children: ACCENT_PRESETS.map((hex) => (0, react_jsx_runtime.jsx)("button", {
1932
+ type: "button",
1933
+ title: hex,
1934
+ "aria-pressed": activeValue === hex,
1935
+ style: {
1936
+ ...styles.accentPreset,
1937
+ background: hex,
1938
+ ...(activeValue === hex ? { outline: "2px solid var(--dsw-alias-label-primary)", outlineOffset: "1px" } : {})
1939
+ },
1940
+ onClick: () => setAccent(hex),
1941
+ children: null
1942
+ }, hex))
1943
+ }),
1781
1944
  (0, react_jsx_runtime.jsx)("div", {
1782
1945
  style: styles.hint,
1783
1946
  children: t("accent.hint")
@@ -1922,6 +2085,21 @@ window.__ModuleLoader__.load({
1922
2085
  });
1923
2086
  }
1924
2087
  //#endregion
2088
+
2089
+ //#region dsh-dream-skin: Appearance settings section
2090
+ /**
2091
+ * A dedicated "Theme / ๅค–่ง‚" settings section. Hosts the skin, wallpaper,
2092
+ * advanced wallpaper, accent and theme-pack rows โ€” instead of flat rows in
2093
+ * the General section, they live under their own category in the settings
2094
+ * left nav.
2095
+ */
2096
+ function DreamSkinSection({ renderSlot }) {
2097
+ return (0, react_jsx_runtime.jsx)("div", {
2098
+ style: styles.section,
2099
+ children: renderSlot("settings.dreamSkin.item", {})
2100
+ });
2101
+ }
2102
+ //#endregion
1925
2103
  //#region dsh-dream-skin: client plugin body
1926
2104
  /**
1927
2105
  * Required services: theme runtime (skins, switching, token override
@@ -1968,7 +2146,13 @@ window.__ModuleLoader__.load({
1968
2146
  wallpaperRevision += 1;
1969
2147
  // Store the raw data URL (not the CSS url(...) wrapper) so the
1970
2148
  // Wallpaper row can render an <img> preview and test `url !== null`.
1971
- wallpaperBound?.sync(readWallpaper(), readWallpaperOpacity(), readWallpaperBlur(), wallpaperRevision);
2149
+ wallpaperBound?.sync(
2150
+ readWallpaper(),
2151
+ readWallpaperOpacity(),
2152
+ readWallpaperBlur(),
2153
+ readWallpaperHistory(),
2154
+ wallpaperRevision
2155
+ );
1972
2156
  };
1973
2157
  applyWallpaper2(ctx);
1974
2158
  syncWallpaper();
@@ -1979,8 +2163,18 @@ window.__ModuleLoader__.load({
1979
2163
 
1980
2164
  const skinStore = createSkinStore();
1981
2165
  let skinBound;
2166
+ // Monotonic revision for the skin slot store. Using a locally incrementing
2167
+ // counter (instead of the host theme revision) guarantees the store ALWAYS
2168
+ // updates on every click โ€” even if theme/change timing races or the host
2169
+ // revision doesn't bump as expected โ€” so the selected card follows instantly.
2170
+ let skinRevision = 0;
2171
+ const syncSkinWith = (id) => {
2172
+ skinBound?.sync(id, ++skinRevision);
2173
+ // A skin/scheme switch changes the base color; re-shade the wash.
2174
+ if (wallpaperBackgroundCss() !== null) applyWallpaper2(ctx);
2175
+ };
1982
2176
  const syncSkin = (snapshot) => {
1983
- skinBound?.sync(snapshot.preference, snapshot.revision);
2177
+ skinBound?.sync(snapshot.preference, ++skinRevision);
1984
2178
  // A skin/scheme switch changes the base color; re-shade the wash.
1985
2179
  if (wallpaperBackgroundCss() !== null) applyWallpaper2(ctx);
1986
2180
  };
@@ -1998,11 +2192,30 @@ window.__ModuleLoader__.load({
1998
2192
  setSkin: (id) => {
1999
2193
  ctx.theme.setTheme(id);
2000
2194
  writeSavedSkin(id);
2195
+ // Deterministically push the new preference into the slot store AND
2196
+ // re-shade the wallpaper so the selected card follows immediately,
2197
+ // independent of theme/change emission timing.
2198
+ syncSkinWith(id);
2001
2199
  }
2002
2200
  };
2003
2201
  };
2004
- ctx.slots.inject("settings.general.item", () => ctx.slots.register({
2005
- name: "settings.general.item",
2202
+ // Register our own "Theme / ๅค–่ง‚" settings section. It appears in the
2203
+ // settings left-nav and hosts all skin features (skin, wallpaper,
2204
+ // advanced wallpaper, accent, theme packs) under a single category.
2205
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
2206
+ name: "settings.section",
2207
+ id: "dream-skin",
2208
+ order: 10,
2209
+ label: "Theme / ๅค–่ง‚",
2210
+ locale: SETTINGS_NS,
2211
+ children: { "settings.dreamSkin.item": {
2212
+ kind: "list",
2213
+ scope: "root"
2214
+ } }
2215
+ }, DreamSkinSection));
2216
+
2217
+ ctx.slots.inject("settings.dreamSkin.item", () => ctx.slots.register({
2218
+ name: "settings.dreamSkin.item",
2006
2219
  id: "dream-skin",
2007
2220
  order: 20,
2008
2221
  store: skinStore,
@@ -2043,13 +2256,21 @@ window.__ModuleLoader__.load({
2043
2256
  applyWallpaper2(ctx);
2044
2257
  syncWallpaper();
2045
2258
  },
2259
+ applyFromHistory: (kind, value) => {
2260
+ const resolvedKind = kind === "gradient" || kind === "url" ? kind : "image";
2261
+ if (value && value.length > 4) {
2262
+ setWallpaperKind(ctx, resolvedKind, value);
2263
+ } else {
2264
+ syncWallpaper();
2265
+ }
2266
+ },
2046
2267
  clearWallpaper: () => {
2047
2268
  removeWallpaper(ctx);
2048
2269
  }
2049
2270
  };
2050
2271
  };
2051
- ctx.slots.inject("settings.general.item", () => ctx.slots.register({
2052
- name: "settings.general.item",
2272
+ ctx.slots.inject("settings.dreamSkin.item", () => ctx.slots.register({
2273
+ name: "settings.dreamSkin.item",
2053
2274
  id: "dream-skin-wallpaper",
2054
2275
  order: 30,
2055
2276
  store: wallpaperStore,
@@ -2099,8 +2320,8 @@ window.__ModuleLoader__.load({
2099
2320
  }
2100
2321
  };
2101
2322
  };
2102
- ctx.slots.inject("settings.general.item", () => ctx.slots.register({
2103
- name: "settings.general.item",
2323
+ ctx.slots.inject("settings.dreamSkin.item", () => ctx.slots.register({
2324
+ name: "settings.dreamSkin.item",
2104
2325
  id: "dream-skin-wallpaper-advanced",
2105
2326
  order: 31,
2106
2327
  store: advWallpaperStore,
@@ -2135,8 +2356,8 @@ window.__ModuleLoader__.load({
2135
2356
  }
2136
2357
  };
2137
2358
  };
2138
- ctx.slots.inject("settings.general.item", () => ctx.slots.register({
2139
- name: "settings.general.item",
2359
+ ctx.slots.inject("settings.dreamSkin.item", () => ctx.slots.register({
2360
+ name: "settings.dreamSkin.item",
2140
2361
  id: "dream-skin-accent",
2141
2362
  order: 25,
2142
2363
  store: accentStore,
@@ -2177,8 +2398,8 @@ window.__ModuleLoader__.load({
2177
2398
  surprise: refreshSurprise
2178
2399
  };
2179
2400
  };
2180
- ctx.slots.inject("settings.general.item", () => ctx.slots.register({
2181
- name: "settings.general.item",
2401
+ ctx.slots.inject("settings.dreamSkin.item", () => ctx.slots.register({
2402
+ name: "settings.dreamSkin.item",
2182
2403
  id: "dream-skin-packs",
2183
2404
  order: 40,
2184
2405
  store: packStore,
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.4",
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",