dsh-background-by-model 0.7.6 → 0.7.7
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 +13 -1
- package/CHANGELOG.zh.md +13 -1
- package/README.md +13 -11
- package/README.zh.md +13 -11
- package/lib/client.js +47 -30
- package/lib/index.js +34 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
> The full release history lives here; the two most recent releases (v0.7.
|
|
3
|
+
> The full release history lives here; the two most recent releases (v0.7.7 / v0.7.6) are also listed in [README.md](./README.md#recent-optimizations).
|
|
4
|
+
|
|
5
|
+
## v0.7.7
|
|
6
|
+
|
|
7
|
+
- **A fresh install starts on the author's own profile, and it needs no network** — the shipped defaults on the Interface tab now ARE the numbers the recommended profile carries (`preset/theme-config.json` in the [assets repository](https://github.com/HarmlessFunny/assets)): main background `0%`, left panel `10%`, right panel `45%`, cards `100%`, code `81%`, inputs `88%` with `60 px` of blur, settings `100%`, conversation text `35%`, trajectory `73%`, every other blur `0`. So the panel is worth looking at before a single byte is fetched, and the profile's one click adds rules and pictures instead of changing the numbers underneath them. Every one of those values used to be chosen per key for **safety** rather than for looks — `bg` at 0.85 so the host surface stayed visible under the wallpaper, `code` fully opaque because "a code block is read, not looked through", `input` blur at 0 because a blur costs a compositor layer — which is why a new install opened on a pale approximation of the host rather than on a configuration anyone would actually run. Two consequences are named rather than discovered later: the main background starts at `0%`, so with no wallpaper yet the window is the host's own canvas (the palette and its ink are unaffected — they come from the theme colour, not from this alpha), and `check:code-plate` now pins the profile's `81%` instead of "defaults to opaque". The constants live in `src/schema.ts` under a note saying they are copied from a live data directory, so changing the profile's numbers means moving them together; the README's Interface section says the same.
|
|
8
|
+
|
|
9
|
+
- **`rightbarOpacity` keeps its "never owned" state while a fresh install starts owned** — the preview panel's `null` means "follow `opacities.bg`", and that is not a theoretical state: **every** release so far has written it, because a panel the user never dragged is persisted as an explicit `null`. The new sanitizer (`normalizeRightbarOpacity`) therefore reads `null` back as itself and hands the shipped `45%` only to a key that is not there at all. Treating `null` as "missing" would have silently repainted the preview panel of every existing configuration whose panel was following the main background — exactly the kind of silent migration the config shape's versioning exists to prevent. A fresh install starts owned at `45%`; `null` is now reachable only by hand, since the UI has never had a control that goes back to it.
|
|
10
|
+
|
|
11
|
+
- **The festival switch ships OFF** — a first install paints what the model rules say and nothing else, and the single switch on the Config page is how the feature is asked for. It shipped ON before, on the argument that the point of the feature is that the background changes by itself on the day; that is the right answer for a configuration somebody has already chosen — which is why the recommended profile still turns it **ON** — but not for a plugin that has just been installed and has no wallpaper of its own yet, where the first thing a new user would see on 中秋节 is a festival picture nobody asked for. The sanitizer is now "a real boolean is honoured, anything else takes the shipped default" rather than "only an explicit `false` turns it off": the absent field of a config written before the feature existed, and junk from a hand-edit, both mean OFF. The per-holiday switches inside the block are untouched — they are details of a feature that is already switched on, not the switch itself.
|
|
12
|
+
|
|
13
|
+
- **The percentage pill in each Interface card is gone** — the number was already on the slider row directly below it, so the card head is the icon and the name again and `.dab-part-badge` goes with it, stylesheet rule included.
|
|
14
|
+
|
|
15
|
+
- **Gates** — `pnpm test` is still nine checks; the defaults above moved `check:code-plate` (the code plate ships on the profile's `81%`) and `check:node`, whose new assertions are written **by value** so that a constant changed without the profile — or the profile changed without the constants — fails a check instead of drifting out of step: the appearance numbers a config with no file at all comes up with, an explicit `null` preview panel reading back as itself, a number of its own surviving, a hand-edit that is not a number landing on the shipped `45%`, and the festival switch through both booleans and a non-boolean.
|
|
4
16
|
|
|
5
17
|
## v0.7.6
|
|
6
18
|
|
package/CHANGELOG.zh.md
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
-
> 这里保留完整的历史记录;最近两个版本(v0.7.
|
|
3
|
+
> 这里保留完整的历史记录;最近两个版本(v0.7.7 / v0.7.6)同时列在 [README.zh.md](./README.zh.md#近期优化) 里。
|
|
4
|
+
|
|
5
|
+
## v0.7.7
|
|
6
|
+
|
|
7
|
+
- **新装出来就是作者本人那套外观,而且不用联网** —— 「界面」页的出厂默认值现在**就是**推荐配置里那套数字([assets 仓库](https://github.com/HarmlessFunny/assets)里的 `preset/theme-config.json`):主背景 `0%`、左侧栏 `10%`、右侧栏 `45%`、卡片 `100%`、代码块 `81%`、输入框与控件 `88%` 外加 `60 px` 模糊、设置面板 `100%`、对话文本框 `35%`、轨迹页 `73%`、其余模糊全 `0`。于是第一次装上、一个字节都还没下,界面就已经值得看;而推荐配置那一下点击加进来的是规则和图片,不是把底下的数字换掉。这些数字此前**每一个都是按「安全」而不是按「好看」逐项挑的** —— `bg` 取 0.85 是为了让宿主表面在壁纸之下仍然可见,`code` 全不透明是因为「代码块是拿来读的、不是拿来看穿的」,`input` 模糊取 0 是因为一层模糊要付一个合成层的代价 —— 这就是为什么以前新装打开的是一个「宿主的苍白近似」,而不是任何人真会用的配置。两个后果是写明的、不是等着以后被发现的:主背景从 `0%` 起步,所以还没有壁纸时窗口就是宿主自己的画布(配色与墨色不受影响,它们来自主题色而不是这个 alpha);而 `check:code-plate` 现在钉住的是配置里的 `81%`,不再是「默认不透明」。这些常量住在 `src/schema.ts`,旁边就写着它们是从真实数据目录抄出来的那一份,所以改推荐配置的数字就得把两边一起搬;README 的「界面」一节说的是同一件事。
|
|
8
|
+
|
|
9
|
+
- **`rightbarOpacity` 保留了它「从未被拥有」的状态,而新装出来是已被拥有的** —— 预览栏的 `null` 意思是「跟随 `opacities.bg`」,而它不是一个理论状态:此前**每一个**版本都写过它 —— 用户从没拖过的那一栏,落盘就是显式的 `null`。所以新的净化器(`normalizeRightbarOpacity`)把 `null` 读回成它自己,只有「这个键根本不在」才拿到出厂的 `45%`。把 `null` 当成「缺失」,会把每一份「预览栏正跟着主背景」的既有配置悄悄重画 —— 而这正是这套配置形状做版本号要防的那种静默迁移。新装从 `45%` 起步、是已被拥有的;`null` 现在只剩下手写可达,因为界面从来就没有一个能回到它的控件。
|
|
10
|
+
|
|
11
|
+
- **节日开关出厂是关的** —— 第一次装上只画模型规则说的东西,别的什么都不画;「配置」页那一个开关才是「要这个功能」的表达方式。它此前是开的,理由是「这个功能的意义就在于到日子背景自己换」;那个理由对于一份**已经被人选定的**配置是对的 —— 所以推荐配置仍然把它**打开** —— 但对于一个刚装上、自己还没有任何壁纸的插件不对:中秋当天,新用户看到的第一样东西会是一张没人要的节日图。净化规则也从「只有显式的 `false` 才关掉」改成「真正的布尔值算数,其它一律取出厂默认」:功能出现之前写下的配置里那个缺失的字段、以及手改出来的垃圾值,现在都意味着关。块内每个节日各自那个开关没动 —— 那是一个已经打开的功能内部的细节,不是这个开关本身。
|
|
12
|
+
|
|
13
|
+
- **「界面」页每张卡片上那个百分比胶囊删掉了** —— 那个数字本来就在它正下方的滑块行上,于是卡头又只剩图标和名字,`.dab-part-badge` 连同它的样式规则一起走。
|
|
14
|
+
|
|
15
|
+
- **门禁** —— `pnpm test` 仍是九道;上面这些默认值动到的是 `check:code-plate`(代码块出厂走配置的 `81%`)与 `check:node`,后者的新断言是**按值**写死的,所以「改了常量没改配置、或改了配置没改常量」会直接让一道校验失败,而不是慢慢漂开:完全没有配置文件时读出来的那套外观数字、显式 `null` 的预览栏读回成它自己、它自己的数字被保留、非数字的手改值落回出厂的 `45%`,以及节日开关两个布尔方向加一个非布尔值。
|
|
4
16
|
|
|
5
17
|
## v0.7.6
|
|
6
18
|
|
package/README.md
CHANGED
|
@@ -113,7 +113,7 @@ What a wallpaper **change** looks like. It lives on the **Config** page, it is t
|
|
|
113
113
|
|
|
114
114
|
### Holiday backgrounds
|
|
115
115
|
|
|
116
|
-
A small one, not a settings block: **one switch on the Config page and nothing else**. It
|
|
116
|
+
A small one, not a settings block: **one switch on the Config page and nothing else**. It ships **off** — turn it on and on the day the background changes by itself and changes back the next morning. (The [recommended profile](#recommended-profile) below turns it on for you.)
|
|
117
117
|
|
|
118
118
|
- **How it behaves** — On 中秋节 and 国庆节 the wallpaper switches to that holiday's own image, with that holiday's own fixed theme color (中秋 `#384A77`, 国庆 `#FFF6EB`). The next day, the model rules take over again.
|
|
119
119
|
- **Mid-Autumn Festival** — 农历八月十五, the day itself. It moves every year (2024-09-17, 2025-10-06, 2026-09-25, 2027-09-15 …), so it is resolved from the Chinese calendar at runtime, in **Asia/Shanghai** — the lunar day turns over at Beijing midnight, not yours.
|
|
@@ -122,7 +122,7 @@ A small one, not a settings block: **one switch on the Config page and nothing e
|
|
|
122
122
|
- **A holiday with no image falls through** to the model rules rather than blanking the wallpaper.
|
|
123
123
|
- **The art is downloaded, not shipped** — a compressed wallpaper per holiday (228 KB and 500 KB at native resolution, against 8.37 MB of source art), hosted in the project's [assets repository](https://github.com/HarmlessFunny/assets) rather than in the package: they were two thirds of the tarball for a picture that is looked at one day a year. The download is gated on the **calendar**, so a profile that is not on a holiday fetches nothing at all, and the first read on the day caches the file under `holiday-cache/` — every boot after that, and every year after that, is answered from disk and needs no network. The reference is pinned to a **commit**, never a branch, so reshuffling the repository's screenshots cannot break a shipped festival; a `jsDelivr` mirror is tried first and `raw.githubusercontent.com` second, and if both are unreachable the holiday simply does not take over — the model rules keep painting.
|
|
124
124
|
- **Neither the art nor the palette is swappable, by design** — an easter egg that asks to be configured is not an easter egg. A holiday slot is read-only: a file dropped into `modelbg-h-midautumn` / `modelbg-h-nationalday` is ignored by every read, and the plugin refuses to write, fetch into or delete those slots. The download lands in `holiday-cache/`, keyed by asset name and never by slot, so the store still never holds a `modelbg-h-*` file. The theme colors are constants in the holiday definition and are forced on every read — on the holiday **and on its image**, since a theme color lives on the image now — so a hand-edited `color` in `theme-config.json` cannot repaint a festival either. Its layout mode is the definition's **Fill** for the same reason (the art is full-bleed, and a stale `fit` would letterbox it), while the **framing** next to it stays yours. Theme exports therefore carry your rules only.
|
|
125
|
-
- **Turning it
|
|
125
|
+
- **Turning it on** — the switch on the Config page, or `"holidays": { "enabled": true }` in the same file. Only a real `true` counts: the feature is on because a configuration says so, not because nothing has been said. The per-holiday switches inside it (中秋 / 国庆) are a different thing and still default to on — they are details of a feature that is already switched on.
|
|
126
126
|
|
|
127
127
|
### Per-rule and per-image settings
|
|
128
128
|
|
|
@@ -135,15 +135,18 @@ A small one, not a settings block: **one switch on the Config page and nothing e
|
|
|
135
135
|
|
|
136
136
|
### Global settings (Interface tab)
|
|
137
137
|
|
|
138
|
+
- **What a fresh install starts on** — the shipped numbers **are the author's own profile**, i.e. the Interface numbers the [recommended profile](#recommended-profile) carries, so a first run already looks like that without downloading anything: main background `0%`, left panel `10%`, right panel `45%`, cards & panels `100%`, code blocks `81%`, input & controls `88%` with `60 px` of blur, settings panel `100%`, conversation text `35%`, trajectory `73%`, and every other blur `0`. The two are kept in step by hand — the profile is published straight out of a live data directory, so changing its numbers means moving these constants with them. (The two settings this tab does not own are deliberately *not* copied from the profile: the [festival switch](#holiday-backgrounds) ships off, and the [switch duration](#switch-effect-global) keeps the 320 ms cross-fade — the profile uses its 3000 ms maximum.)
|
|
138
139
|
- **Per-part Interface Opacity** — Independent sliders for the main background, left panel, right panel, cards & panels (including the dropdowns and menus around the dialog), the input & controls (composer box, Cordis panel), plus the settings panel and the conversation text box. Independent of the theme color: a rule with no color keeps every one of these sliders live.
|
|
139
140
|
- **Per-part Interface Blur** — Frosted-glass `backdrop-filter` blur (`0–60 px`) for each interface part, including a real backdrop on the composer and Cordis panel via stable host selectors.
|
|
140
141
|
- **Conversation & Trajectory** — The message list is wrapped in a translucent card automatically, and the trajectory page gets whole-page opacity & blur controls, letting the wallpaper shine through the content.
|
|
141
|
-
- **Right Panel** — The column that slides in from the right when you open a file now has a card of its own: its opacity follows **Main background**
|
|
142
|
+
- **Right Panel** — The column that slides in from the right when you open a file now has a card of its own: this card owns its opacity from the first drag, and until then it follows **Main background** — the state a config written while that was the shipped default is in, since a fresh install already owns the panel at the profile's `45%` — and its blur stacks on top of the main-background blur. While closed it takes no space and costs nothing.
|
|
142
143
|
|
|
143
144
|
### Recommended profile
|
|
144
145
|
|
|
145
146
|
The Config tab's first card downloads the author's own configuration — rules, wallpapers and interface settings — from the project's [assets repository](https://github.com/HarmlessFunny/assets) and installs it in one click.
|
|
146
147
|
|
|
148
|
+
**Every Interface number in it is what the plugin already ships with** — each opacity, blur and tint alpha in `theme-config.json` is the number a fresh install starts on (see [Global settings](#global-settings-interface-tab)) — so on a new install this button adds the rules and the pictures. Two settings it brings that a fresh install does not have are outside that tab: the [festival switch](#holiday-backgrounds), which ships off and this profile turns on, and the [switch duration](#switch-effect-global), which the profile sets to its 3000 ms maximum where the shipped default is the 320 ms cross-fade every earlier release used. On a store whose sliders you have already moved, adopting it resets those too: it is a whole configuration, not a patch.
|
|
149
|
+
|
|
147
150
|
**It is hosted in the store's own shape**, not as one bundled document:
|
|
148
151
|
|
|
149
152
|
```
|
|
@@ -297,7 +300,13 @@ Two things can hold it, and both are on the card: the effect is **Instant**, or
|
|
|
297
300
|
|
|
298
301
|
## Recent Optimizations
|
|
299
302
|
|
|
300
|
-
> Only the two most recent releases are listed here; older ones (v0.7.
|
|
303
|
+
> Only the two most recent releases are listed here; older ones (v0.7.5 and earlier) live in [CHANGELOG.md](./CHANGELOG.md).
|
|
304
|
+
|
|
305
|
+
### v0.7.7
|
|
306
|
+
|
|
307
|
+
- **A fresh install starts on the author's own profile, with nothing to download** — the shipped Interface numbers are now the ones the [recommended profile](#recommended-profile) carries: main background `0%`, left panel `10%`, right panel `45%`, code plate `81%`, inputs `88%` with `60 px` of blur, conversation text `35%`, trajectory `73%`. The plugin therefore looks right before a byte is fetched, and the profile's one click adds pictures rather than changing the look underneath them. Every one of those numbers used to be picked per key for **safety** rather than for looks — `bg` 0.85 so the host surface stayed visible under it, `code` fully opaque because a code block is read rather than looked through, `input` blur 0 because blur costs a compositor layer — which is why a new install opened on a pale approximation of the host instead of on a configuration anyone would run. The preview panel is the one field that needed care: `null` ("never dragged, so follow the main background") is preserved as itself rather than read as a missing key, because every release so far has **written** it — a panel the user never dragged sits on disk as an explicit `null`, and taking that for "missing" would have repainted the panel in every existing configuration.
|
|
308
|
+
- **The festival switch ships off** — a first run paints what the model rules say and nothing else; the switch on the Config page is how the feature is asked for, and the recommended profile turns it on, which is the difference between a chosen configuration and a fresh one. Only a real boolean counts now: an absent field, or a hand-edit that is not `true`/`false`, takes the shipped default instead of the old "anything but `false` means on".
|
|
309
|
+
- **The percentage pill in each Interface card is gone** — the number was already on the slider row below it, so the card head is the icon and the name again.
|
|
301
310
|
|
|
302
311
|
### v0.7.6
|
|
303
312
|
|
|
@@ -307,13 +316,6 @@ Two things can hold it, and both are on the card: the effect is **Instant**, or
|
|
|
307
316
|
- **A recommended profile you can install in one click** — the Config tab gained a third card that downloads the author's own configuration from the same assets repository and writes it in place of yours (see [Recommended profile](#recommended-profile)). **It is hosted in the store's own shape** — a `preset.json` shape gate, a readable `theme-config.json`, and one raw file per slot — which is what makes it editable where it lives: the config is 6.5 KB of JSON you can edit on GitHub, replacing a wallpaper is replacing a file, and publishing it is a `cp` out of the data directory. It was first written as a single theme file with every wallpaper inlined as base64, at 2.9 MB where 99.8% of the bytes were a picture; that is not a thing anyone can hand-edit, and the format was changed for exactly that reason. The plugin fetches the manifest and the config, derives the file list from `rules[].images[].slot` (no second place to keep in sync), and fetches the wallpapers one request each, four at a time — showing `3/7` on the button while it runs — so each file gets its own mirror fallback and its own validation. Applied through the same `applyThemeFile` a hand-picked file goes through, assembled on the client into the shape `exportTheme` writes; it is the only action in the panel that destroys anything, so it is the only one that asks, and the download happens **before** the question so the confirmation can state what is actually in hand (7 rules · 7 wallpapers · 2.9 MB). **The store is emptied first, deliberately:** `nextSlot` hands slots out as `m1`, `m2`, … — a counter, not a random token — so a downloaded profile and the store it lands in collide on those names as a matter of course, and "replace everything with this" is only true if the everything is actually gone; that is also why there is no undo. The wipe runs **after** the download and never before it, because an unreachable CDN must not cost the user their configuration on the way to a profile that never arrived, and a host too old to write this build's config shape is refused before anything is deleted. **One missing wallpaper fails the whole attempt and names the file** — a profile that quietly arrived short a picture is precisely the silent failure that pinning the festival art to a commit exists to prevent, so the loud failure is what makes a branch reference acceptable here; the two holiday slots a config legally names are dropped from the request set rather than asked for, since the store can never hold a `modelbg-h-*` file. `holiday-cache/` is left alone, and nothing about the profile is written to the store or cached to disk — the whole point of the button is to fetch what is there *now*.
|
|
308
317
|
- **The published package drops from 1.1 MB to about 220 kB** — the documentation screenshots (`example_img/`, three webp files, 220 KB) moved into the same assets repository and both READMEs reference them by absolute jsDelivr URL (an absolute URL keeps the images on the npm page unbroken just as well, without putting binaries in the tarball or their history in `.git`); `screenshots.json`, which nothing consumes, is deleted; and `lib/client.js.map` (a 624 KB source map, useless to anyone installing the package) is no longer published, though it stays in the repository. Thirteen files became ten.
|
|
309
318
|
|
|
310
|
-
### v0.7.5
|
|
311
|
-
|
|
312
|
-
- **The layout mode belongs to the picture, not the rule** — 适应 / 填充 / 拉伸 / 平铺 / 居中 was one value per rule, so a rotation through a landscape photo and a tall phone screenshot could not letterbox one and fill the other. It now lives on `images[].bgMode`, read back from the image being painted, and the chip row under the filmstrip edits the image selected there (disabled, not hidden, while a rule has no picture yet). `SCHEMA_VERSION` moves to **6** because both directions of this move are silent: a schema-5 host would drop a per-image mode on its first write (拉伸 coming back 适应), and a schema-6 read of a schema-5 config lifts the rule-level value onto every one of its images, so no existing wallpaper lands on the default. A holiday's image is 填充 from its definition, like the slot and the colours beside it; the framing stays yours.
|
|
313
|
-
- **The fade only animates what the palette in force writes (a fix)** — "有时候切换背景时(图上为浅色切换为浅色),白色色块会渐变为黑色色块…白色渐变完黑色后立马切到白色", with the white value measured as `237, 243, 254`. That number is the answer: `#edf3fe` = `--dsw-static-deepseek-50`, which is what the host's light scheme paints `--dsw-specific-bubble` with — the user message bubble — and its dark-scheme value is `#2c2c2e`. The fade had registered that name because it asks for the **dark** branch's token list (the superset) and hands the whole thing to the `:root` and `body` scopes, while the light branch writes only 35 of those 80 names: the other 45 (the bubble, the settings dropdown fills, the tip/tooltip/toast surfaces, the code-block header segments, the status colours) still belong to the **host**, and the plugin is what makes the host switch schemes for a moment — it disposes and re-registers its theme on every colour change, and the host's disposer resets the preference to `system`, which on a dark desktop paints the host's dark palette until that call finishes. With the reported 3000 ms switch, one frame of it became a three-second ramp. A scope's token is now emitted only when the palette in force writes it (the registrations still cover all 80 names, so the dark palette is unchanged), and a skin whose colour scheme already holds is not rebuilt at all. Measured on the reported palette: `body`'s transition list goes 80 → 35 names, the bubble and the dropdown fill are out of it, and `--dsw-alias-bg-base`, `--dsw-alias-bg-layer-2` and the code plate stay in.
|
|
314
|
-
- **The code block follows the palette, and its plate has an opacity of its own (a fix)** — "代码块背景有点问题": dark green ink on a near-black plate inside a **light** interface. The host's shiki sheet declares `--shiki-background: var(--dsw-alias-markdown-code-block)` on `:root`, while the token was declared on `body` only, so the root element had nothing to read but the fade registration's `initial-value` — the host's own colour, sampled once. The palette rule is emitted for `:root` too, `:root` joins the fade scopes, the plate and its banner are palette tints again, and a new **`code`** part drives both surfaces, each through its own variable, defaulting to opaque.
|
|
315
|
-
- **Four small ones** — the rotation switch no longer stays "on" when deleting images leaves fewer than two (the panel disables the switch there, so it could not be turned off either; `normalizeRule` enforces the same invariant for imports), "切换时长" is printed once instead of twice, and the profile footer's package name and the brand tile link to the repository, with `check:ui` comparing that one address against `package.json`.
|
|
316
|
-
- **Gates** — `pnpm test` is now **eight** checks: `check:code-plate` and `check:image-mode` join the suite, `check:rotation` gained the switch-and-count invariant, `check:ui` the repository-link agreement, `check:transition` the fade-ownership rule and `check:repaint` the two lines that arm the fade.
|
|
317
319
|
|
|
318
320
|
## Star History
|
|
319
321
|
|
package/README.zh.md
CHANGED
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
|
|
114
114
|
### 节日特殊背景
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
小小一个,不是一整块设置:**「配置」页上一个开关,别的什么都没有**。它出厂是**关**的 —— 打开它,到了日子背景自己换,第二天早上自己换回。(下面的[推荐配置](#推荐配置)会替你把它打开。)
|
|
117
117
|
|
|
118
118
|
- **行为** — 中秋与国庆当天,壁纸换成那个节日自己的图片,并配上该节日固定的主题色(中秋 `#384A77`、国庆 `#FFF6EB`);第二天交还给模型规则。这份配色同时写在节日条目和它的图片上——主题色现在住在图片里——所以以后节日也能多图轮换、每张带自己的配色。
|
|
119
119
|
- **中秋节** — 农历八月十五当天。它在公历上逐年移动(2024-09-17、2025-10-06、2026-09-25、2027-09-15……),所以是运行时按农历换算的,时区钉在 **Asia/Shanghai** —— 农历日期在北京时间午夜翻页,不是你那边的午夜。
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
- **没有图的节日会回落到模型规则**,而不是把背景刷空。
|
|
123
123
|
- **画是下载来的,不是随包发的** — 每个节日一张压缩过的壁纸(原生分辨率下 228 KB 与 500 KB,原图共 8.37 MB),放在项目自己的 [assets 仓库](https://github.com/HarmlessFunny/assets)里,而不是打进包里 —— 它们占了整个 tarball 的三分之二,而这张画一年只被看一天。下载由**日历**把关:不在节日的配置一点流量都不会有;当天第一次读取会把它缓存到 `holiday-cache/`,此后每一次启动、往后每一年,都直接读磁盘、不再联网。引用钉死在一个 **commit** 上而不是分支,所以你以后整理仓库里的截图不可能弄坏一个已经发出去的节日;先走 `jsDelivr`、失败再走 `raw.githubusercontent.com`,两个都不通时这个节日就是不接管 —— 模型规则继续画,不会白屏。
|
|
124
124
|
- **图片和配色都不可替换,这是刻意的** — 一个要求用户去配置的彩蛋就不是彩蛋了。节日槽位是只读的:往 `modelbg-h-midautumn` / `modelbg-h-nationalday` 里放文件不会被任何一次读取采用,插件也拒绝写入、抓取和删除这两个槽位。下载落进 `holiday-cache/`,按**素材名**而不是槽位命名,所以数据目录里依然永远不会出现 `modelbg-h-*` 文件。主题色是节日定义里的常量、每次读取都强制覆盖——**节日条目和它的图片两处都覆盖**,所以手改 `theme-config.json` 里的 `color` 也换不掉节日配色。布局模式同理固定为定义里的**填充**(这些画本来就是满幅的,一个残留的 `fit` 会给它加黑边),而旁边的**取景**仍然是你自己的。导出的主题文件只包含你自己的规则。
|
|
125
|
-
-
|
|
125
|
+
- **想要它** — 打开「配置」页那个开关,或者在同一个文件里写 `"holidays": { "enabled": true }`。只有真正的 `true` 算数:这个功能是「配置说了要」才开的,不是「没人说话」就默认开。它内部每个节日(中秋 / 国庆)各自那个开关是另一回事,仍然默认开着 —— 那是一个已经打开的功能内部的细节。
|
|
126
126
|
|
|
127
127
|
### 规则与图片各自的设置
|
|
128
128
|
|
|
@@ -135,15 +135,18 @@
|
|
|
135
135
|
|
|
136
136
|
### 全局设置(「界面」页)
|
|
137
137
|
|
|
138
|
+
- **新装出来是什么样** — 出厂那套数字**就是作者本人的配置**,也就是[推荐配置](#推荐配置)「界面」页那套数字,所以第一次装上、什么都没下载,界面就已经是这套样子:主背景 `0%`、左侧栏 `10%`、右侧栏 `45%`、卡片面板 `100%`、代码块 `81%`、输入框与控件 `88%`(外加 `60 px` 模糊)、设置面板 `100%`、对话文本框 `35%`、轨迹页 `73%`,其余模糊都是 `0`。两边靠手工保持一致:配置文件是从真实数据目录直接发出去的,改它的数字就得同步改这些常量。(这一页不管的两项刻意**不**照抄那份配置:[节日开关](#节日特殊背景)出厂关着,[切换时长](#切换效果全局)仍保留 320 ms 的交叉淡入 —— 那份配置用的是它 3000 ms 的上限。)
|
|
138
139
|
- **分部位界面透明度** — 主背景、左侧栏、右侧栏、卡片面板(含对话框周围的选项框/菜单)、输入框与控件(发送框、Cordis 插件面板)、设置面板与对话文本框各自独立滑块。与主题色无关:某条规则没有主题色时这些滑块同样生效。
|
|
139
140
|
- **分部位界面模糊度** — 每个界面部位可独立调整毛玻璃 `backdrop-filter` 模糊(`0–60 px`),并通过宿主的稳定选择器为发送框与 Cordis 面板提供真实背景模糊。
|
|
140
141
|
- **对话与轨迹页** — 消息列表自动包裹为半透明卡片,轨迹页可整页调节透明度与模糊,让壁纸从内容后方透出来。
|
|
141
|
-
- **右侧栏** —
|
|
142
|
+
- **右侧栏** — 点开文件后从右侧滑出的那一栏有了自己的卡片:拖过一次之后这张卡就自己拥有透明度,在那之前它跟随「主背景」—— 那是「出厂值还是 `null` 的年代」写下的配置所处的状态,而新装出来就是自己拥有这一栏的,取配置里的 `45%`;模糊则在主背景模糊之上再叠加,关闭时不占位置、无副作用。
|
|
142
143
|
|
|
143
144
|
### 推荐配置
|
|
144
145
|
|
|
145
146
|
「配置」页的第一张卡会从项目自己的 [assets 仓库](https://github.com/HarmlessFunny/assets)下载作者本人正在用的那套配置 —— 规则、壁纸与接口设置 —— 一键装好。
|
|
146
147
|
|
|
148
|
+
**它里面「界面」页的每一个数字,就是插件出厂自带的** —— `theme-config.json` 里的每一个透明度、模糊和染色 alpha,都是新装出来时的数字(见上面的「全局设置」)—— 所以在全新的机器上,这个按钮加进去的是规则和图片。它另外带来的两样东西不在这一页上:[节日开关](#节日特殊背景),出厂关着、这份配置把它打开;以及[切换时长](#切换效果全局),这份配置取它 3000 ms 的上限,而出厂默认是此前每一个版本都在用的 320 ms 交叉淡入。如果这个数据目录里的滑块已经被你动过,采用配置会把它们一并复位:它是一整份配置,不是一个补丁。
|
|
149
|
+
|
|
147
150
|
**它托管在数据目录自己的形状里**,而不是打包成一个文档:
|
|
148
151
|
|
|
149
152
|
```
|
|
@@ -297,7 +300,13 @@ pnpm run typecheck
|
|
|
297
300
|
|
|
298
301
|
## 近期优化
|
|
299
302
|
|
|
300
|
-
> 这里只列最近两个版本;更早的版本(v0.7.
|
|
303
|
+
> 这里只列最近两个版本;更早的版本(v0.7.5 及以前)见 [CHANGELOG.zh.md](./CHANGELOG.zh.md)。
|
|
304
|
+
|
|
305
|
+
### v0.7.7
|
|
306
|
+
|
|
307
|
+
- **新装出来就是作者本人那套外观,而且不用联网** —— 「界面」页出厂那套数字现在就是[推荐配置](#推荐配置)里那套:主背景 `0%`、左侧栏 `10%`、右侧栏 `45%`、代码块 `81%`、输入框与控件 `88%` 外加 `60 px` 模糊、对话文本框 `35%`、轨迹页 `73%`。所以一个字节都还没取,界面就已经是对的,而推荐配置那一下点击加进来的是图片,不是把底下的观感换掉。这些数字此前**每一个都是按「安全」而不是按「好看」逐项挑的** —— `bg` 取 0.85 是为了让宿主表面在壁纸下仍然可见,`code` 全不透明是因为「代码块是拿来读的、不是拿来看穿的」,`input` 模糊取 0 是因为一层模糊要付一个合成层的代价 —— 这就是为什么以前新装打开的是一个「宿主的苍白近似」,而不是任何人真会用的配置。预览栏是唯一需要小心处理的字段:`null`(「从没拖过,跟随主背景」)被读回成它自己、而不是当成缺失的键,因为此前每一个版本都**写过**它 —— 用户没拖过的那一栏在磁盘上就是显式的 `null`,把它当成「缺失」会把每一份既有配置里的那一栏都重画一遍。
|
|
308
|
+
- **节日开关出厂是关的** —— 第一次装上只画模型规则说的东西;「配置」页那个开关才是「要这个功能」的表达,而推荐配置会把它打开 —— 这就是「选定的配置」和「全新的配置」之间的区别。现在只有真正的布尔值算数:缺失的字段、以及手改出来的非 `true`/`false` 值,都落回出厂默认,而不是旧的「只要不是 `false` 就算开」。
|
|
309
|
+
- **「界面」页每张卡片上那个百分比胶囊删掉了** —— 那个数字本来就在它正下方的滑块行上,于是卡头又只剩图标和名字。
|
|
301
310
|
|
|
302
311
|
### v0.7.6
|
|
303
312
|
|
|
@@ -307,13 +316,6 @@ pnpm run typecheck
|
|
|
307
316
|
- **一键装上「推荐配置」** —— 「配置」页多了第三张卡,从同一个 assets 仓库下载作者本人正在用的那套配置并就地覆盖你的(见[推荐配置](#推荐配置))。**它托管在数据目录自己的形状里** —— 一个 `preset.json` 形状闸门、一份可读的 `theme-config.json`、加上每个槽位一个原始文件 —— 这正是它「在所在的地方就可编辑」的原因:配置是 6.5 KB 的 JSON,可以直接在 GitHub 上改;换一张壁纸就是替换一个文件;发布它就是从数据目录里 `cp` 一下。它一开始被写成单个主题文件、所有壁纸内联成 base64,2.9 MB 里 99.8% 是图片 —— 那不是任何人能手改的东西,格式就是为这个改的。插件先取 manifest 与 config,从 `rules[].images[].slot` 推出文件清单(没有第二处要同步),再一个文件一个请求地取壁纸(四路并发) —— 过程中按钮上显示 `3/7` —— 于是每个文件都有自己的镜像回退和校验。落地时走的还是本地文件那条 `applyThemeFile`,在客户端组装成 `exportTheme` 写出的形状;它是这个面板里唯一会销毁东西的操作,所以也是唯一会先问一句的,而下载发生在**提问之前**,确认框因此能如实说出手里到底有什么(7 条规则 · 7 张壁纸 · 2.9 MB)。**先清空再写入是刻意的**:`nextSlot` 分配槽位用的是 `m1`、`m2`…… 一个计数器而不是随机串,所以下载来的配置和它落进去的那个数据目录必然在这些名字上撞车,「用它替换一切」只有在那个「一切」真的没了的时候才成立 —— 这也是它没有撤销的原因。清空跑在下载**之后**、绝不在之前,因为 CDN 不通不该让你在等一个永远没来的推荐配置的路上先弄丢自己的配置;而一个旧到写不了这套配置形状的宿主,会在删除任何东西之前就被拒绝。**少一张壁纸就整体失败并报出是哪个文件** —— 一份悄悄少了图的配置,恰恰是「节日素材钉死 commit」那条契约要防的静默失效,所以这个响亮的失败正是分支引用在这里可以被接受的原因;config 合法列出的那两个节日槽位会被从请求清单里剔掉而不是去请求,因为数据目录里永远不可能有 `modelbg-h-*` 文件。`holiday-cache/` 不碰,配置也从不写进数据目录、从不落盘缓存 —— 那个按钮的全部意义就是拿到**此刻**的那一份。
|
|
308
317
|
- **发布包从 1.1 MB 瘦到约 220 kB** —— 文档截图(`example_img/`,三个 webp 共 220 KB)搬去同一个 assets 仓库、两份 README 改用 jsDelivr 绝对地址(绝对地址同样能让 npm 页面上的图不裂,还不用把二进制塞进包和 `.git` 历史);没有消费方的 `screenshots.json` 删掉;`lib/client.js.map`(624 KB 的源码映射,对装包的人没用)不再发布,仓库里仍然保留。13 个文件 → 10 个。
|
|
309
318
|
|
|
310
|
-
### v0.7.5
|
|
311
|
-
|
|
312
|
-
- **布局模式属于图片,不属于规则** —— 适应 / 填充 / 拉伸 / 平铺 / 居中 此前是每条规则一个值,于是一轮里既有横构图照片又有竖屏截图时,没法让一张留黑边、另一张铺满。现在它存在 `images[].bgMode` 上、从**正在画的那张图**读回,胶片条下面那排胶囊编辑的也是那里选中的图(规则还没有图片时是**禁用**而不是隐藏)。`SCHEMA_VERSION` 因此升到 **6**,因为两个方向都是无声的:schema 5 的宿主会在第一次写入时丢掉逐图模式(设成 拉伸 的图变回 适应),而 schema 6 读老配置时会把规则级的值抬到每一张图上,现成壁纸不会掉到默认值。节日的图按**定义**就是 填充(和它旁边的槽位、颜色同一条规矩),旁边的取景仍然是你自己的。
|
|
313
|
-
- **渐变只作用于当前调色板真正写入的东西(修复)** —— 「有时候切换背景时,白色色块会渐变为黑色色块…白色渐变完黑色后立马切到白色」,白色值量到 `237, 243, 254`。那就是 `#edf3fe` = `--dsw-static-deepseek-50`,也就是宿主浅色方案的 `--dsw-specific-bubble`(你自己的消息气泡;深色方案是 `#2c2c2e`)。渐变之所以注册了这个名字,是因为它要的是**深色**分支的 token 表、又把整张表交给了 `:root`/`body` —— 浅色分支只写这 80 个名字里的 35 个,剩下 45 个(气泡、设置里的下拉框底色、提示与气泡框、代码块右上角小按钮、状态色)仍然归**宿主**;而让宿主短暂换方案的正是插件自己:每次换配色都销毁并重新注册主题,宿主的销毁器把偏好重置为 `system`,在深色桌面上那一瞬间画的就是宿主的深色调色板。配上报告里 3000ms 的切换时长,一帧的错色就成了三秒的渐变。现在只有当前调色板真正写入的 token 才会拿到过渡(注册表仍是全部 80 个,深色调色板完全没变),配色方案没变也不再重建皮肤。实测:`body` 的过渡列表 80 → 35 个名字,气泡与下拉框出局,`--dsw-alias-bg-base` / `-layer-2` / 代码块底板仍在。
|
|
314
|
-
- **代码块跟着调色板走,底板有了自己的透明度(修复)** —— 「代码块背景有点问题」:浅色界面里深绿文字压在近黑底板上。宿主的 shiki 表在 `:root` 上声明 `--shiki-background: var(--dsw-alias-markdown-code-block)`,而该 token 只声明在 `body` 上,于是根元素只能读到过渡注册的 `initial-value` —— 采样一次的宿主颜色。现在调色板规则对 `:root` 一并发出(`:root` 也加入渐变作用域),底板与 banner 重新是调色板的染色,并新增 **`code`** 档位驱动这两块表面、各读自己的变量,默认不透明。
|
|
315
|
-
- **四个小修** —— 删图删到不足两张时轮换开关不再卡在「开」(面板在那里本来就把它禁用了,于是也关不掉;`normalizeRule` 对导入的配置强制同一条不变量);「切换时长」只印一次;资料页页脚的包名与品牌磁贴现在是指向仓库的链接,`check:ui` 拿那一个地址和 `package.json` 对比。
|
|
316
|
-
- **门禁** —— `pnpm test` 现在是**八道**:`check:code-plate` 与 `check:image-mode` 加入,`check:rotation` 增加开关不变量,`check:ui` 增加链接一致性,`check:transition` 增加渐变归属规则,`check:repaint` 钉住武装渐变的那两行。
|
|
317
319
|
|
|
318
320
|
## Star History
|
|
319
321
|
|
package/lib/client.js
CHANGED
|
@@ -648,11 +648,11 @@ window.__ModuleLoader__.load({
|
|
|
648
648
|
"input"
|
|
649
649
|
];
|
|
650
650
|
const DEFAULT_PART_OPACITIES = {
|
|
651
|
-
bg:
|
|
652
|
-
sidebar: .
|
|
651
|
+
bg: 0,
|
|
652
|
+
sidebar: .1,
|
|
653
653
|
card: 1,
|
|
654
|
-
code:
|
|
655
|
-
input:
|
|
654
|
+
code: .81,
|
|
655
|
+
input: .88
|
|
656
656
|
};
|
|
657
657
|
/**
|
|
658
658
|
* Interface blur (px, 0..60), global (Interface page):
|
|
@@ -683,7 +683,7 @@ window.__ModuleLoader__.load({
|
|
|
683
683
|
chat: 0,
|
|
684
684
|
trajectory: 0,
|
|
685
685
|
rightbar: 0,
|
|
686
|
-
input:
|
|
686
|
+
input: 60
|
|
687
687
|
};
|
|
688
688
|
/** Longest allowed switch duration; 0 is a hard cut. */
|
|
689
689
|
const TRANSITION_MAX_MS = 3e3;
|
|
@@ -742,6 +742,9 @@ window.__ModuleLoader__.load({
|
|
|
742
742
|
function ruleCanPaint(rule) {
|
|
743
743
|
return rule.enabled && (ruleSlots(rule).length > 0 || rule.color !== null);
|
|
744
744
|
}
|
|
745
|
+
const DEFAULT_CHAT_TEXT_OPACITY = .35;
|
|
746
|
+
const DEFAULT_TRAJECTORY_OPACITY = .73;
|
|
747
|
+
const DEFAULT_RIGHTBAR_OPACITY = .45;
|
|
745
748
|
/**
|
|
746
749
|
* `#RRGGBB` → the `[h, s, l]` triple every rule stores (`s` and `l` in 0..1), or
|
|
747
750
|
* null when the string is not a hex color.
|
|
@@ -818,12 +821,12 @@ window.__ModuleLoader__.load({
|
|
|
818
821
|
blurs: { ...DEFAULT_PART_BLURS },
|
|
819
822
|
transition: defaultTransition(),
|
|
820
823
|
settingsOpacity: 1,
|
|
821
|
-
chatTextOpacity:
|
|
822
|
-
trajectoryOpacity:
|
|
823
|
-
rightbarOpacity:
|
|
824
|
+
chatTextOpacity: DEFAULT_CHAT_TEXT_OPACITY,
|
|
825
|
+
trajectoryOpacity: DEFAULT_TRAJECTORY_OPACITY,
|
|
826
|
+
rightbarOpacity: DEFAULT_RIGHTBAR_OPACITY,
|
|
824
827
|
autoExtract: true,
|
|
825
828
|
holidays: {
|
|
826
|
-
enabled:
|
|
829
|
+
enabled: false,
|
|
827
830
|
items: defaultHolidayRules()
|
|
828
831
|
}
|
|
829
832
|
};
|
|
@@ -1058,10 +1061,32 @@ window.__ModuleLoader__.load({
|
|
|
1058
1061
|
if (typeof id === "string") stored.set(id, item);
|
|
1059
1062
|
}
|
|
1060
1063
|
return {
|
|
1061
|
-
enabled: r.enabled
|
|
1064
|
+
enabled: typeof r.enabled === "boolean" ? r.enabled : false,
|
|
1062
1065
|
items: HOLIDAYS.map((def) => normalizeHolidayRule(def, stored.get(def.id)))
|
|
1063
1066
|
};
|
|
1064
1067
|
}
|
|
1068
|
+
/**
|
|
1069
|
+
* The file-preview panel's own opacity.
|
|
1070
|
+
*
|
|
1071
|
+
* Three states, and the middle one is why this is a function rather than the
|
|
1072
|
+
* one-line fallback every other field gets: a real number is the card's own
|
|
1073
|
+
* value, `null` is "never owned, so follow `opacities.bg`", and a KEY that is not
|
|
1074
|
+
* there at all — a hand-written config, or one written before the option existed
|
|
1075
|
+
* — is the shipped profile's 45% (see DEFAULT_RIGHTBAR_OPACITY).
|
|
1076
|
+
*
|
|
1077
|
+
* `null` has to survive as ITSELF instead of falling through to the default:
|
|
1078
|
+
* every release so far has written it — a panel the user never dragged is
|
|
1079
|
+
* persisted as an explicit `null` — so treating it as "missing" would hand the
|
|
1080
|
+
* shipped 45% to every configuration whose preview panel was following the main
|
|
1081
|
+
* background, a silent change to a setup nobody asked to change. It is also
|
|
1082
|
+
* unreachable from the UI (no control returns to it); it exists for configs that
|
|
1083
|
+
* were written while the shipped default was `null`.
|
|
1084
|
+
*/
|
|
1085
|
+
function normalizeRightbarOpacity(v) {
|
|
1086
|
+
if (v === null) return null;
|
|
1087
|
+
if (typeof v === "number" && isFinite(v)) return clamp01(v, 1);
|
|
1088
|
+
return DEFAULT_RIGHTBAR_OPACITY;
|
|
1089
|
+
}
|
|
1065
1090
|
/** Coerce an unknown persisted value into a valid ThemeConfig, falling back per-field. */
|
|
1066
1091
|
function normalizeConfig(raw) {
|
|
1067
1092
|
const r = raw ?? {};
|
|
@@ -1078,9 +1103,9 @@ window.__ModuleLoader__.load({
|
|
|
1078
1103
|
blurs,
|
|
1079
1104
|
transition: normalizeTransition(r.transition, legacyFadeMs(r.rules)),
|
|
1080
1105
|
settingsOpacity: clamp01(r.settingsOpacity, 1),
|
|
1081
|
-
chatTextOpacity: clamp01(r.chatTextOpacity,
|
|
1082
|
-
trajectoryOpacity: clamp01(r.trajectoryOpacity,
|
|
1083
|
-
rightbarOpacity:
|
|
1106
|
+
chatTextOpacity: clamp01(r.chatTextOpacity, DEFAULT_CHAT_TEXT_OPACITY),
|
|
1107
|
+
trajectoryOpacity: clamp01(r.trajectoryOpacity, DEFAULT_TRAJECTORY_OPACITY),
|
|
1108
|
+
rightbarOpacity: normalizeRightbarOpacity(r.rightbarOpacity),
|
|
1084
1109
|
autoExtract: r.autoExtract !== false,
|
|
1085
1110
|
holidays: normalizeHolidays(r.holidays)
|
|
1086
1111
|
};
|
|
@@ -1364,10 +1389,10 @@ window.__ModuleLoader__.load({
|
|
|
1364
1389
|
return clamp01(cfg.settingsOpacity, 1);
|
|
1365
1390
|
}
|
|
1366
1391
|
function rChatTextOpacity() {
|
|
1367
|
-
return clamp01(cfg.chatTextOpacity,
|
|
1392
|
+
return clamp01(cfg.chatTextOpacity, DEFAULT_CHAT_TEXT_OPACITY);
|
|
1368
1393
|
}
|
|
1369
1394
|
function rTrajectoryOpacity() {
|
|
1370
|
-
return clamp01(cfg.trajectoryOpacity,
|
|
1395
|
+
return clamp01(cfg.trajectoryOpacity, DEFAULT_TRAJECTORY_OPACITY);
|
|
1371
1396
|
}
|
|
1372
1397
|
/** Own opacity of the file-preview panel; while unowned it IS the main background's. */
|
|
1373
1398
|
function rRightbarOpacity() {
|
|
@@ -2254,7 +2279,6 @@ window.__ModuleLoader__.load({
|
|
|
2254
2279
|
.dab-part-head{display:flex;align-items:center;gap:11px;margin-bottom:14px}
|
|
2255
2280
|
.dab-part-ico{width:32px;height:32px;flex:none;border-radius:10px;display:grid;place-items:center;color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-bg-layer-2);background:color-mix(in srgb,var(--dsw-alias-brand-primary) 12%,transparent)}
|
|
2256
2281
|
.dab-part-name{font-size:13.5px;font-weight:600}
|
|
2257
|
-
.dab-part-badge{margin-left:auto;font-family:var(--dab-mono);font-size:11px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2);border-radius:99px;padding:3px 9px}
|
|
2258
2282
|
|
|
2259
2283
|
/* ── segmented control ───────────────────────────────────────────────────── */
|
|
2260
2284
|
.dab-seg{position:relative;display:inline-flex;padding:3px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:11px}
|
|
@@ -4573,20 +4597,13 @@ window.__ModuleLoader__.load({
|
|
|
4573
4597
|
children: [
|
|
4574
4598
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4575
4599
|
className: "dab-part-head",
|
|
4576
|
-
children: [
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
children: t(labelKey)
|
|
4584
|
-
}),
|
|
4585
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4586
|
-
className: "dab-part-badge",
|
|
4587
|
-
children: [Math.round(opacity * 100), "%"]
|
|
4588
|
-
})
|
|
4589
|
-
]
|
|
4600
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4601
|
+
className: "dab-part-ico",
|
|
4602
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { size: 16 })
|
|
4603
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4604
|
+
className: "dab-part-name",
|
|
4605
|
+
children: t(labelKey)
|
|
4606
|
+
})]
|
|
4590
4607
|
}),
|
|
4591
4608
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LiveSlider, {
|
|
4592
4609
|
label: t("uiOpacity"),
|
package/lib/index.js
CHANGED
|
@@ -87,11 +87,11 @@ const PART_OPACITY_KEYS = [
|
|
|
87
87
|
"input"
|
|
88
88
|
];
|
|
89
89
|
const DEFAULT_PART_OPACITIES = {
|
|
90
|
-
bg:
|
|
91
|
-
sidebar: .
|
|
90
|
+
bg: 0,
|
|
91
|
+
sidebar: .1,
|
|
92
92
|
card: 1,
|
|
93
|
-
code:
|
|
94
|
-
input:
|
|
93
|
+
code: .81,
|
|
94
|
+
input: .88
|
|
95
95
|
};
|
|
96
96
|
/**
|
|
97
97
|
* Interface blur (px, 0..60), global (Interface page):
|
|
@@ -122,7 +122,7 @@ const DEFAULT_PART_BLURS = {
|
|
|
122
122
|
chat: 0,
|
|
123
123
|
trajectory: 0,
|
|
124
124
|
rightbar: 0,
|
|
125
|
-
input:
|
|
125
|
+
input: 60
|
|
126
126
|
};
|
|
127
127
|
/** Longest allowed switch duration; 0 is a hard cut. */
|
|
128
128
|
const TRANSITION_MAX_MS = 3e3;
|
|
@@ -146,6 +146,9 @@ const DEFAULT_TRANSITION = {
|
|
|
146
146
|
easing: "ease",
|
|
147
147
|
durationMs: 320
|
|
148
148
|
};
|
|
149
|
+
const DEFAULT_CHAT_TEXT_OPACITY = .35;
|
|
150
|
+
const DEFAULT_TRAJECTORY_OPACITY = .73;
|
|
151
|
+
const DEFAULT_RIGHTBAR_OPACITY = .45;
|
|
149
152
|
/**
|
|
150
153
|
* `#RRGGBB` → the `[h, s, l]` triple every rule stores (`s` and `l` in 0..1), or
|
|
151
154
|
* null when the string is not a hex color.
|
|
@@ -440,10 +443,32 @@ function normalizeHolidays(raw) {
|
|
|
440
443
|
if (typeof id === "string") stored.set(id, item);
|
|
441
444
|
}
|
|
442
445
|
return {
|
|
443
|
-
enabled: r.enabled
|
|
446
|
+
enabled: typeof r.enabled === "boolean" ? r.enabled : false,
|
|
444
447
|
items: HOLIDAYS.map((def) => normalizeHolidayRule(def, stored.get(def.id)))
|
|
445
448
|
};
|
|
446
449
|
}
|
|
450
|
+
/**
|
|
451
|
+
* The file-preview panel's own opacity.
|
|
452
|
+
*
|
|
453
|
+
* Three states, and the middle one is why this is a function rather than the
|
|
454
|
+
* one-line fallback every other field gets: a real number is the card's own
|
|
455
|
+
* value, `null` is "never owned, so follow `opacities.bg`", and a KEY that is not
|
|
456
|
+
* there at all — a hand-written config, or one written before the option existed
|
|
457
|
+
* — is the shipped profile's 45% (see DEFAULT_RIGHTBAR_OPACITY).
|
|
458
|
+
*
|
|
459
|
+
* `null` has to survive as ITSELF instead of falling through to the default:
|
|
460
|
+
* every release so far has written it — a panel the user never dragged is
|
|
461
|
+
* persisted as an explicit `null` — so treating it as "missing" would hand the
|
|
462
|
+
* shipped 45% to every configuration whose preview panel was following the main
|
|
463
|
+
* background, a silent change to a setup nobody asked to change. It is also
|
|
464
|
+
* unreachable from the UI (no control returns to it); it exists for configs that
|
|
465
|
+
* were written while the shipped default was `null`.
|
|
466
|
+
*/
|
|
467
|
+
function normalizeRightbarOpacity(v) {
|
|
468
|
+
if (v === null) return null;
|
|
469
|
+
if (typeof v === "number" && isFinite(v)) return clamp01(v, 1);
|
|
470
|
+
return DEFAULT_RIGHTBAR_OPACITY;
|
|
471
|
+
}
|
|
447
472
|
/** Coerce an unknown persisted value into a valid ThemeConfig, falling back per-field. */
|
|
448
473
|
function normalizeConfig(raw) {
|
|
449
474
|
const r = raw ?? {};
|
|
@@ -460,9 +485,9 @@ function normalizeConfig(raw) {
|
|
|
460
485
|
blurs,
|
|
461
486
|
transition: normalizeTransition(r.transition, legacyFadeMs(r.rules)),
|
|
462
487
|
settingsOpacity: clamp01(r.settingsOpacity, 1),
|
|
463
|
-
chatTextOpacity: clamp01(r.chatTextOpacity,
|
|
464
|
-
trajectoryOpacity: clamp01(r.trajectoryOpacity,
|
|
465
|
-
rightbarOpacity:
|
|
488
|
+
chatTextOpacity: clamp01(r.chatTextOpacity, DEFAULT_CHAT_TEXT_OPACITY),
|
|
489
|
+
trajectoryOpacity: clamp01(r.trajectoryOpacity, DEFAULT_TRAJECTORY_OPACITY),
|
|
490
|
+
rightbarOpacity: normalizeRightbarOpacity(r.rightbarOpacity),
|
|
466
491
|
autoExtract: r.autoExtract !== false,
|
|
467
492
|
holidays: normalizeHolidays(r.holidays)
|
|
468
493
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-background-by-model",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.7",
|
|
4
4
|
"description": "Appearance plugin for DeepSeek Harness: an ordered list of model rules, each carrying its own wallpapers — every image with its own framing and theme color — plus layout mode, opacity and blur; the background follows the model you switch to, and a rule can rotate through several images on its own rhythm.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|