dsh-deepseek-style-theme 1.43.3 → 1.43.6
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.md +11 -0
- package/cordis.patch.yml +6 -6
- package/lib/client.js +212 -49
- package/lib/index.js +19 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
为 DeepSeek Harness Web GUI 复刻 DeepSeek 官网视觉的主题皮肤插件。
|
|
4
4
|
|
|
5
|
+
## 鸣谢
|
|
6
|
+
|
|
7
|
+
本插件的两块核心视觉——**流体背景**与**玻璃质感**——都不是从零写出来的,它们分别来自下面两个上游项目。没有它们,这个主题不会有现在这个样子:
|
|
8
|
+
|
|
9
|
+
| 上游 | 作者 | 本插件用到了什么 |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| [dsh-theme-mineradio](https://github.com/dhicoc/dsh-theme-mineradio) | [@dhicoc](https://github.com/dhicoc) | 流体背景的**三段 GLSL 着色器**(顶点 / 流场 / 显示)是上游的逐字节副本;四分之一分辨率流场 + 双 framebuffer 乒乓的求解器结构、玻璃色散折射滤镜、光标视差、对话框悬停倾斜同样移植自上游 |
|
|
12
|
+
| [deepseek-harness-background](https://github.com/HaoyueQin/deepseek-harness-background) | [@HaoyueQin](https://github.com/HaoyueQin) | 液态玻璃配方的**技法来源**(半透明填充 + 竖向光泽 + 背板滤镜链的设计思路),本插件按自己的选择器与 `--dshome-glass-*` 变量重新表达,未复制源码 |
|
|
13
|
+
|
|
14
|
+
两个项目均为 MIT 许可;完整许可原文见 [`THIRD-PARTY-NOTICES.md`](./THIRD-PARTY-NOTICES.md),随包发布,再分发时必须保留。详细的移植范围与改写点见下文「[第三方代码与署名](#第三方代码与署名)」。
|
|
15
|
+
|
|
5
16
|
## 特性
|
|
6
17
|
|
|
7
18
|
- **流体流动背景(1.42.0+)**:全屏 WebGL2 双通道流体模拟——四分之一分辨率的流场(衰减 + 带速度的指针笔刷,两个 framebuffer 乒乓)被全分辨率的域扭曲噪声渲染器采样,带旋流迭代与三色柔性混合;按钮悬停会轻推流场、点击则荡开涟漪。配色跟随 DSTT 三色令牌(峰谷红 / 谷时蓝 / 常态绿)实时重新着色,无需重挂。**无 WebGL2 时自动回落到原来的粒子背景**(粒子实现完整保留)
|
package/cordis.patch.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# DeepSeek-Style-Theme bundle patch: inserts its public dsh.client entry into
|
|
2
|
-
# the web plugin roster. The bundle is the official dsh plugin shape — install
|
|
3
|
-
# it with `dsh plugin --profile <name> add <path-or-git-url>`.
|
|
4
|
-
- insert:
|
|
5
|
-
- id: ui-skin-deepseek-style
|
|
6
|
-
name: 'dsh-deepseek-style-theme'
|
|
1
|
+
# DeepSeek-Style-Theme bundle patch: inserts its public dsh.client entry into
|
|
2
|
+
# the web plugin roster. The bundle is the official dsh plugin shape — install
|
|
3
|
+
# it with `dsh plugin --profile <name> add <path-or-git-url>`.
|
|
4
|
+
- insert:
|
|
5
|
+
- id: ui-skin-deepseek-style
|
|
6
|
+
name: 'dsh-deepseek-style-theme'
|
package/lib/client.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
// The loader requires this bundle to register itself under the id the host asked
|
|
2
|
+
// for, and that id is the package NAME of whichever copy is installed -- which is
|
|
3
|
+
// not one value during a rename. The package moved from
|
|
4
|
+
// @dsh-external/dsh-deepseek-style-theme to the unscoped dsh-deepseek-style-theme
|
|
5
|
+
// in 1.43.1, so a profile installed before the rename asks for the old id and one
|
|
6
|
+
// installed after asks for the new one. A single hard-coded literal therefore
|
|
7
|
+
// breaks whichever half it does not match, and BOTH directions were hit for real,
|
|
8
|
+
// one machine each:
|
|
9
|
+
//
|
|
10
|
+
// literal old, install new -> "loaded without registering \"dsh-deepseek-style-theme\""
|
|
11
|
+
// literal new, install old -> "loaded without registering \"@dsh-external/...\""
|
|
12
|
+
//
|
|
13
|
+
// So register under BOTH ids with the same factory: the loader finds the one it
|
|
14
|
+
// wants and the other entry is simply never asked for. The registrations are
|
|
15
|
+
// guarded individually because a loader might reject an id it did not request,
|
|
16
|
+
// and that must not take the working one down with it.
|
|
17
|
+
const dshDeepseekStyleThemeFactory = (require) => {
|
|
18
|
+
var module = { exports: {} };
|
|
19
|
+
var exports = module.exports;
|
|
16
20
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
17
21
|
const React = require("react");
|
|
18
22
|
|
|
@@ -991,18 +995,20 @@ void main() {
|
|
|
991
995
|
const CORE_CSS = `
|
|
992
996
|
:root{--ds-brand:#059669;--ds-brand-deep:#047857;--ds-brand-mid:#10B981;--ds-brand-light:#34D399;--ds-glass-blur:24px}
|
|
993
997
|
html,body{background-color:transparent!important}
|
|
994
|
-
/*
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
998
|
+
/* THE LABEL TOKENS ARE NOT PINNED HERE, AND MUST NOT BE AGAIN.
|
|
999
|
+
A previous attempt at the invisible-text bug declared
|
|
1000
|
+
body{--dsw-alias-label-primary:...!important} under our own scheme marker,
|
|
1001
|
+
so that background and text could never end up on opposite sides. It did fix
|
|
1002
|
+
that, and it broke something worse: those !important declarations outrank the
|
|
1003
|
+
PRODUCT's tokens, so when the user switched appearance the product changed its
|
|
1004
|
+
own tokens and this stylesheet kept painting the old ones. The UI looked like
|
|
1005
|
+
the switch was dead.
|
|
1006
|
+
Measured on the real page: with the theme's style tags removed the switch
|
|
1007
|
+
works, with them present it does not, and reverting the header z-index changes
|
|
1008
|
+
nothing -- i.e. it is this sheet, and it is these declarations.
|
|
1009
|
+
The invisible-text hazard stays open on purpose. A stuck appearance switch is
|
|
1010
|
+
a broken control; near-white text on a near-white page at least still reads
|
|
1011
|
+
once the marker agrees. Do not re-add these two rules. */
|
|
1006
1012
|
body{background:radial-gradient(1200px 700px at 12% -10%,color-mix(in srgb,var(--ds-brand) 14%,transparent),transparent 60%),radial-gradient(1000px 600px at 105% 12%,color-mix(in srgb,var(--ds-brand-light) 16%,transparent),transparent 55%),radial-gradient(900px 700px at 50% 115%,color-mix(in srgb,var(--ds-brand) 10%,transparent),transparent 60%),linear-gradient(180deg,#fbfbfd 0%,#f5f6fa 100%);background-attachment:fixed}
|
|
1007
1013
|
body[data-dshome-color=red]{--ds-brand:#F5222D;--ds-brand-deep:#CF1322;--ds-brand-mid:#FF4D4F;--ds-brand-light:#FF7875}
|
|
1008
1014
|
body[data-dshome-color=blue]{--ds-brand:#4D6BFE;--ds-brand-deep:#3A65C2;--ds-brand-mid:#4176E6;--ds-brand-light:#73A3D2}
|
|
@@ -1639,6 +1645,18 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1639
1645
|
-webkit-backdrop-filter:url(#dshome-glass-dispersion) blur(var(--dshome-liquid-blur-sidebar)) saturate(var(--dshome-liquid-saturate))!important;
|
|
1640
1646
|
backdrop-filter:url(#dshome-glass-dispersion) blur(var(--dshome-liquid-blur-sidebar)) saturate(var(--dshome-liquid-saturate))!important;
|
|
1641
1647
|
}
|
|
1648
|
+
/* Backdrop blur, switched off by the durable backdropBlur setting. Each glass
|
|
1649
|
+
recipe reads its radius from a variable, so turning the frosting off is one
|
|
1650
|
+
0px per variable -- the translucency, the sheen and the edge refraction all
|
|
1651
|
+
stay exactly as they were. Written with a body step so it also out-ranks the
|
|
1652
|
+
html[data-dshome-glass] block the liquid radii are declared in. */
|
|
1653
|
+
html[data-dshome-blur="off"],
|
|
1654
|
+
html[data-dshome-blur="off"] body{
|
|
1655
|
+
--dshome-glass-blur:0px;
|
|
1656
|
+
--dshome-liquid-blur:0px;
|
|
1657
|
+
--dshome-liquid-blur-sidebar:0px;
|
|
1658
|
+
--dshome-liquid-blur-composer:0px;
|
|
1659
|
+
}
|
|
1642
1660
|
@media (prefers-reduced-motion:reduce){
|
|
1643
1661
|
html[data-dshome-glass="liquid"] .hHd-Xa_root::after{
|
|
1644
1662
|
animation:none;
|
|
@@ -1710,6 +1728,20 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1710
1728
|
* subscription is unavailable.
|
|
1711
1729
|
*/
|
|
1712
1730
|
function createDarkSync(ctx, theme) {
|
|
1731
|
+
/** Last value we wrote to the body; null until the first apply(). */
|
|
1732
|
+
let lastDark = null;
|
|
1733
|
+
/**
|
|
1734
|
+
* Scheme-change listeners. The dark marker is a marker only if someone
|
|
1735
|
+
* reads it: the stylesheet matches on it, and the ambient background reads
|
|
1736
|
+
* it for its palette (see startAmbient). A listener that throws must not
|
|
1737
|
+
* cost the others their update, so each call is boxed.
|
|
1738
|
+
*/
|
|
1739
|
+
const darkListeners = new Set();
|
|
1740
|
+
const notifyDark = (dark) => {
|
|
1741
|
+
for (const fn of darkListeners) {
|
|
1742
|
+
try { fn(dark); } catch (error) {}
|
|
1743
|
+
}
|
|
1744
|
+
};
|
|
1713
1745
|
const apply = () => {
|
|
1714
1746
|
let dark = false;
|
|
1715
1747
|
// Two signals, and BOTH of them lie in some state -- measured, not
|
|
@@ -1733,10 +1765,19 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1733
1765
|
}
|
|
1734
1766
|
}
|
|
1735
1767
|
if (!dark) dark = document.body.hasAttribute('data-ds-dark-theme');
|
|
1768
|
+
// Remember what we actually put on the body, so a later apply() that
|
|
1769
|
+
// lands on the same answer does not wake the background up for
|
|
1770
|
+
// nothing. `lastDark` is null until the first write.
|
|
1771
|
+
const changed = lastDark !== dark;
|
|
1772
|
+
lastDark = dark;
|
|
1736
1773
|
if (dark) document.body.setAttribute('data-dshome-dark', '');
|
|
1737
1774
|
else document.body.removeAttribute('data-dshome-dark');
|
|
1775
|
+
// Publish the write. The marker is what EVERY dark rule and the fluid
|
|
1776
|
+
// palette read, so a light/dark switch that only set the attribute left
|
|
1777
|
+
// the background on the scheme it was mounted with -- reported as
|
|
1778
|
+
// "切到深色背景还是蓝白".
|
|
1779
|
+
if (changed) notifyDark(dark);
|
|
1738
1780
|
};
|
|
1739
|
-
apply();
|
|
1740
1781
|
let unsubscribe = null;
|
|
1741
1782
|
try {
|
|
1742
1783
|
unsubscribe = ctx.on('theme/change', apply);
|
|
@@ -1753,9 +1794,21 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1753
1794
|
} catch (error) {
|
|
1754
1795
|
mirror = null;
|
|
1755
1796
|
}
|
|
1756
|
-
return
|
|
1757
|
-
|
|
1758
|
-
|
|
1797
|
+
return {
|
|
1798
|
+
/**
|
|
1799
|
+
* Subscribe to light/dark *writes*. Nothing is replayed on subscribe:
|
|
1800
|
+
* a reader that needs the current value reads the attribute (or calls
|
|
1801
|
+
* dshomeDark()), which keeps one source of truth.
|
|
1802
|
+
*/
|
|
1803
|
+
subscribe: (fn) => {
|
|
1804
|
+
darkListeners.add(fn);
|
|
1805
|
+
return () => darkListeners.delete(fn);
|
|
1806
|
+
},
|
|
1807
|
+
dispose: () => {
|
|
1808
|
+
darkListeners.clear();
|
|
1809
|
+
if (unsubscribe !== null) unsubscribe();
|
|
1810
|
+
if (mirror !== null) mirror.disconnect();
|
|
1811
|
+
}
|
|
1759
1812
|
};
|
|
1760
1813
|
}
|
|
1761
1814
|
|
|
@@ -1771,6 +1824,7 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1771
1824
|
const apply = () => {
|
|
1772
1825
|
root.setAttribute('data-dshome-glass', dsttGetGlass());
|
|
1773
1826
|
root.setAttribute('data-dshome-composer', dsttGetComposer());
|
|
1827
|
+
root.setAttribute('data-dshome-blur', dsttGetBlur() ? 'on' : 'off');
|
|
1774
1828
|
};
|
|
1775
1829
|
apply();
|
|
1776
1830
|
const unsubscribe = dsttSubscribe(apply);
|
|
@@ -1778,6 +1832,7 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
1778
1832
|
unsubscribe();
|
|
1779
1833
|
root.removeAttribute('data-dshome-glass');
|
|
1780
1834
|
root.removeAttribute('data-dshome-composer');
|
|
1835
|
+
root.removeAttribute('data-dshome-blur');
|
|
1781
1836
|
};
|
|
1782
1837
|
}
|
|
1783
1838
|
|
|
@@ -2019,25 +2074,48 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
2019
2074
|
};
|
|
2020
2075
|
applyGlass();
|
|
2021
2076
|
const unsubscribeGlass = dsttSubscribe(applyGlass);
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2077
|
+
// ── palette reconciliation ────────────────────────────────────────────
|
|
2078
|
+
// One reader for BOTH inputs the palette depends on: the colour token on
|
|
2079
|
+
// <body> and the dark marker. Reported symptom: "切主题模式背景不变 /
|
|
2080
|
+
// 深色模式背景还是蓝白". The colour half of that was a real dead end --
|
|
2081
|
+
// `subscribeColor` only fires when the notified colour string CHANGES, so
|
|
2082
|
+
// the boot race (this canvas mounts, then the durable mode arrives over
|
|
2083
|
+
// the async bridge and re-resolves the colour) left the flow painted from
|
|
2084
|
+
// whatever the driver had guessed first, and a mode switch that resolved
|
|
2085
|
+
// to the same colour never notified at all. The scheme half had no
|
|
2086
|
+
// listener: a MutationObserver was watching the marker, but `darkSync`
|
|
2087
|
+
// pointedly does not set a *changed* value twice, and the marker itself
|
|
2088
|
+
// was the only thing written.
|
|
2089
|
+
// So: derive from the DOM on every signal instead of trusting the event to
|
|
2090
|
+
// carry it, and box every listener so one throw cannot cost the rest.
|
|
2091
|
+
let fluidParams = JSON.stringify(dshomeFluidParams());
|
|
2092
|
+
const syncFluid = () => {
|
|
2093
|
+
const next = dshomeFluidParams();
|
|
2094
|
+
const key = JSON.stringify(next);
|
|
2095
|
+
if (key === fluidParams) return;
|
|
2096
|
+
fluidParams = key;
|
|
2097
|
+
try { fluid.setParams(next); } catch (error) {}
|
|
2098
|
+
};
|
|
2099
|
+
const unsubscribeColor = subscribeColor((color) => {
|
|
2100
|
+
syncFluid();
|
|
2101
|
+
try { dispersion.setTint(FLUID_HUES[color] ?? FLUID_HUES.green); } catch (error) {}
|
|
2025
2102
|
});
|
|
2026
|
-
|
|
2027
|
-
//
|
|
2028
|
-
//
|
|
2029
|
-
//
|
|
2030
|
-
let
|
|
2103
|
+
const unsubscribeDark = darkSync === null ? null : darkSync.subscribe(syncFluid);
|
|
2104
|
+
// The colour driver writes the token as an attribute; watching it as well
|
|
2105
|
+
// keeps this correct no matter who wrote it (the peak-hour chain, a manual
|
|
2106
|
+
// mode pick, or a future caller that forgets to notify).
|
|
2107
|
+
let tokenMirror = null;
|
|
2031
2108
|
try {
|
|
2032
|
-
|
|
2033
|
-
|
|
2109
|
+
tokenMirror = new MutationObserver(syncFluid);
|
|
2110
|
+
tokenMirror.observe(document.body, { attributes: true, attributeFilter: ['data-dshome-color'] });
|
|
2034
2111
|
} catch (error) {
|
|
2035
|
-
|
|
2112
|
+
tokenMirror = null;
|
|
2036
2113
|
}
|
|
2037
2114
|
return () => {
|
|
2038
|
-
|
|
2115
|
+
unsubscribeColor();
|
|
2116
|
+
if (unsubscribeDark !== null) unsubscribeDark();
|
|
2039
2117
|
unsubscribeGlass();
|
|
2040
|
-
if (
|
|
2118
|
+
if (tokenMirror !== null) tokenMirror.disconnect();
|
|
2041
2119
|
dispersion.dispose();
|
|
2042
2120
|
stopParallax();
|
|
2043
2121
|
stopSpotter();
|
|
@@ -2159,7 +2237,20 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
2159
2237
|
const colors = palette();
|
|
2160
2238
|
for (const p of parts) p.c = colors[(Math.random() * colors.length) | 0];
|
|
2161
2239
|
};
|
|
2240
|
+
// Two inputs again: the colour token (notified) and the dark marker
|
|
2241
|
+
// (written by darkSync). The particle palette is per scheme, so a
|
|
2242
|
+
// light/dark switch has to re-roll the colours too -- otherwise the
|
|
2243
|
+
// fallback background keeps the scheme it was mounted with, exactly the
|
|
2244
|
+
// bug the fluid path had.
|
|
2162
2245
|
const unsubscribeColor = subscribeColor(refreshColors);
|
|
2246
|
+
const unsubscribeDark = darkSync === null ? null : darkSync.subscribe(refreshColors);
|
|
2247
|
+
let tokenMirror = null;
|
|
2248
|
+
try {
|
|
2249
|
+
tokenMirror = new MutationObserver(refreshColors);
|
|
2250
|
+
tokenMirror.observe(document.body, { attributes: true, attributeFilter: ['data-dshome-color'] });
|
|
2251
|
+
} catch (error) {
|
|
2252
|
+
tokenMirror = null;
|
|
2253
|
+
}
|
|
2163
2254
|
|
|
2164
2255
|
window.addEventListener('resize', resize);
|
|
2165
2256
|
resize();
|
|
@@ -2171,6 +2262,8 @@ html[data-dshome-dispersion][data-dshome-glass="liquid"] body .hHd-Xa_root::befo
|
|
|
2171
2262
|
cancelAnimationFrame(rafId);
|
|
2172
2263
|
window.removeEventListener('resize', resize);
|
|
2173
2264
|
unsubscribeColor();
|
|
2265
|
+
if (unsubscribeDark !== null) unsubscribeDark();
|
|
2266
|
+
if (tokenMirror !== null) tokenMirror.disconnect();
|
|
2174
2267
|
canvas.remove();
|
|
2175
2268
|
};
|
|
2176
2269
|
}
|
|
@@ -3420,7 +3513,7 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3420
3513
|
* plugin's own loopback channel instead; every reader (the color driver,
|
|
3421
3514
|
* the settings tab) subscribes to this mirror.
|
|
3422
3515
|
*/
|
|
3423
|
-
const dsttState = { mode: "peakvalley-redblue", fluidBrush: false, glassStyle: DSTT_GLASS_DEFAULT, composer: DSTT_COMPOSER_DEFAULT, listeners: new Set() };
|
|
3516
|
+
const dsttState = { mode: "peakvalley-redblue", fluidBrush: false, glassStyle: DSTT_GLASS_DEFAULT, composer: DSTT_COMPOSER_DEFAULT, blur: true, listeners: new Set() };
|
|
3424
3517
|
// Fields the user has chosen in this session. A host half that predates a
|
|
3425
3518
|
// field ignores it and answers without it -- or with its own default -- so
|
|
3426
3519
|
// without this a fresh choice gets overwritten by the next sync and the
|
|
@@ -3432,6 +3525,26 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3432
3525
|
if (dsttState.composer === "origin") return "wide";
|
|
3433
3526
|
return DSTT_COMPOSER.includes(dsttState.composer) ? dsttState.composer : DSTT_COMPOSER_DEFAULT;
|
|
3434
3527
|
};
|
|
3528
|
+
const dsttGetBlur = () => dsttState.blur !== false;
|
|
3529
|
+
/**
|
|
3530
|
+
* Turn the glass frosting on or off. Same shape as the other CSS-only
|
|
3531
|
+
* preferences: apply locally first, then let the host persist it, and treat
|
|
3532
|
+
* its answer as confirmation only.
|
|
3533
|
+
*/
|
|
3534
|
+
async function dsttSetBlur(ctx, next) {
|
|
3535
|
+
dsttState.blur = next === true;
|
|
3536
|
+
dsttTouched.add("blur");
|
|
3537
|
+
dsttNotify();
|
|
3538
|
+
try {
|
|
3539
|
+
const result = await bridgeCall(DSTT_SET, { mode: dsttState.mode, backdropBlur: dsttState.blur });
|
|
3540
|
+
if (result !== undefined && result !== null && result.ok === true) {
|
|
3541
|
+
return result.value.backdropBlur === dsttState.blur;
|
|
3542
|
+
}
|
|
3543
|
+
} catch (error) {
|
|
3544
|
+
// Fall through: the local choice stands, it just was not stored.
|
|
3545
|
+
}
|
|
3546
|
+
return false;
|
|
3547
|
+
}
|
|
3435
3548
|
/**
|
|
3436
3549
|
* Persist the composer's refraction width through the bridge.
|
|
3437
3550
|
*
|
|
@@ -3527,6 +3640,9 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3527
3640
|
return await response.json();
|
|
3528
3641
|
}
|
|
3529
3642
|
|
|
3643
|
+
/** Fallback used when the host half is unavailable. */
|
|
3644
|
+
const dsttGetBlurFallback = () => dsttState.blur !== false;
|
|
3645
|
+
|
|
3530
3646
|
/** Pull the durable mode from the host half once. */
|
|
3531
3647
|
async function dsttSync(ctx) {
|
|
3532
3648
|
try {
|
|
@@ -3541,6 +3657,7 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3541
3657
|
// which is what made a fresh choice look like it snapped back.
|
|
3542
3658
|
if (!dsttTouched.has("glassStyle") && DSTT_GLASS_STYLES.includes(result.value.glassStyle)) dsttState.glassStyle = result.value.glassStyle;
|
|
3543
3659
|
if (!dsttTouched.has("composer") && DSTT_COMPOSER.includes(result.value.composerRefraction)) dsttState.composer = result.value.composerRefraction;
|
|
3660
|
+
if (!dsttTouched.has("blur") && typeof result.value.backdropBlur === "boolean") dsttState.blur = result.value.backdropBlur;
|
|
3544
3661
|
dsttNotify();
|
|
3545
3662
|
}
|
|
3546
3663
|
} catch (error) {}
|
|
@@ -3705,10 +3822,18 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3705
3822
|
|
|
3706
3823
|
anchor();
|
|
3707
3824
|
|
|
3825
|
+
// The durable mode crosses an async bridge (dsttSync), so the anchor above
|
|
3826
|
+
// may have resolved the colour from the DEFAULT mode -- its 常态绿/常态蓝
|
|
3827
|
+
// token then never appears, and the background keeps the first guess. One
|
|
3828
|
+
// extra read after the sync has had its turn fixes the boot race, and it
|
|
3829
|
+
// is idempotent, so it cannot fight a later answer.
|
|
3830
|
+
const bootTimer = setTimeout(anchor, 0);
|
|
3831
|
+
|
|
3708
3832
|
try { unsubscribe = dsttSubscribe(anchor); } catch (error) { unsubscribe = null; }
|
|
3709
3833
|
|
|
3710
3834
|
return () => {
|
|
3711
3835
|
stopped = true;
|
|
3836
|
+
clearTimeout(bootTimer);
|
|
3712
3837
|
if (chainTimer !== 0) clearTimeout(chainTimer);
|
|
3713
3838
|
if (unsubscribe !== null) unsubscribe();
|
|
3714
3839
|
document.removeEventListener('visibilitychange', onVisibility);
|
|
@@ -3801,6 +3926,11 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3801
3926
|
if (dstt === undefined || typeof dstt.setComposer !== 'function' || next === composerNow) return;
|
|
3802
3927
|
dstt.setComposer(next);
|
|
3803
3928
|
};
|
|
3929
|
+
const blurOn = dstt !== undefined && typeof dstt.blur === 'function' ? dstt.blur() !== false : true;
|
|
3930
|
+
const toggleBlur = () => {
|
|
3931
|
+
if (dstt === undefined || typeof dstt.setBlur !== 'function') return;
|
|
3932
|
+
dstt.setBlur(!blurOn);
|
|
3933
|
+
};
|
|
3804
3934
|
|
|
3805
3935
|
return React.createElement('div', { className: 'dshome-dstt' },
|
|
3806
3936
|
React.createElement('h3', null,
|
|
@@ -3867,6 +3997,19 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3867
3997
|
className: 'dshome-dstt-seg-btn' + (composerNow === choice ? ' dshome-on' : ''),
|
|
3868
3998
|
onClick: () => pickComposer(choice)
|
|
3869
3999
|
}, isZh ? DSTT_COMPOSER_LABELS[choice].zh : DSTT_COMPOSER_LABELS[choice].en)))),
|
|
4000
|
+
React.createElement('div', { className: 'dshome-dstt-row' },
|
|
4001
|
+
React.createElement('div', { className: 'dshome-dstt-row-body' },
|
|
4002
|
+
React.createElement('div', { className: 'dshome-dstt-row-title' }, isZh ? '背景模糊(磨砂)' : 'Backdrop blur'),
|
|
4003
|
+
React.createElement('div', { className: 'dshome-dstt-row-hint' }, isZh
|
|
4004
|
+
? '玻璃面板后面那层虚化。关闭后玻璃变成纯半透明:通透度、顶部光泽、边缘折射都保留,只是不再把背后的东西磨掉。'
|
|
4005
|
+
: 'The frosting behind every glass pane. Off leaves the translucency, the sheen and the edge refraction intact and only stops blurring what is behind the glass.')),
|
|
4006
|
+
React.createElement('button', {
|
|
4007
|
+
type: 'button',
|
|
4008
|
+
role: 'switch',
|
|
4009
|
+
'aria-checked': blurOn,
|
|
4010
|
+
className: 'dshome-dstt-seg-btn' + (blurOn ? ' dshome-on' : ''),
|
|
4011
|
+
onClick: toggleBlur
|
|
4012
|
+
}, blurOn ? (isZh ? '已开启' : 'On') : (isZh ? '已关闭' : 'Off'))),
|
|
3870
4013
|
React.createElement('div', { className: 'dshome-dstt-status', 'data-peak': timeSliced && peakNow },
|
|
3871
4014
|
'当前:' + colorName + ' · ' + status));
|
|
3872
4015
|
}
|
|
@@ -3894,8 +4037,18 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3894
4037
|
|
|
3895
4038
|
// Dark marker: owned attribute driven by the theme service, never by
|
|
3896
4039
|
// the product's attribute name. Must precede the patch blocks so the
|
|
3897
|
-
// dark selectors match from the first paint.
|
|
3898
|
-
|
|
4040
|
+
// dark selectors match from the first paint. The handle is kept in scope
|
|
4041
|
+
// because the ambient background subscribes to its writes: the marker
|
|
4042
|
+
// alone was not enough, since nothing re-read it when the scheme changed.
|
|
4043
|
+
let darkSync = null;
|
|
4044
|
+
ctx.effect(() => {
|
|
4045
|
+
const handle = createDarkSync(ctx, theme);
|
|
4046
|
+
darkSync = handle;
|
|
4047
|
+
return () => {
|
|
4048
|
+
if (darkSync === handle) darkSync = null;
|
|
4049
|
+
handle.dispose();
|
|
4050
|
+
};
|
|
4051
|
+
}, 'deepseek-style-theme: dark sync');
|
|
3899
4052
|
|
|
3900
4053
|
// Glass-recipe marker: same idea, and it has to be on <html> before the
|
|
3901
4054
|
// first paint of the glass surfaces or the pane flashes the other recipe.
|
|
@@ -3986,6 +4139,8 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3986
4139
|
setGlass: (next) => dsttSetGlass(ctx, next),
|
|
3987
4140
|
composer: dsttGetComposer,
|
|
3988
4141
|
setComposer: (next) => dsttSetComposer(ctx, next),
|
|
4142
|
+
blur: dsttGetBlur,
|
|
4143
|
+
setBlur: (next) => dsttSetBlur(ctx, next),
|
|
3989
4144
|
subscribe: dsttSubscribe
|
|
3990
4145
|
},
|
|
3991
4146
|
locale: ctx.get('locale')
|
|
@@ -3997,5 +4152,13 @@ body[data-dshome-dark] .${CLS}{background:rgba(14,30,60,.94);box-shadow:0 18px 4
|
|
|
3997
4152
|
exports.apply = apply;
|
|
3998
4153
|
exports.inject = ['theme', 'slots', 'locale', 'workspaces', 'connection'];
|
|
3999
4154
|
return module.exports;
|
|
4000
|
-
|
|
4001
|
-
|
|
4155
|
+
};
|
|
4156
|
+
|
|
4157
|
+
// Both ids, same factory. See the note at the top of this file for why one
|
|
4158
|
+
// literal cannot work during the rename.
|
|
4159
|
+
try {
|
|
4160
|
+
window.__ModuleLoader__.load({ id: "dsh-deepseek-style-theme", factory: dshDeepseekStyleThemeFactory });
|
|
4161
|
+
} catch (error) {}
|
|
4162
|
+
try {
|
|
4163
|
+
window.__ModuleLoader__.load({ id: "@dsh-external/dsh-deepseek-style-theme", factory: dshDeepseekStyleThemeFactory });
|
|
4164
|
+
} catch (error) {}
|
package/lib/index.js
CHANGED
|
@@ -134,7 +134,12 @@ const DsttSettingsSchema = z === null ? null : z.object({
|
|
|
134
134
|
z.const("wide"),
|
|
135
135
|
z.const("origin"),
|
|
136
136
|
z.const("off")
|
|
137
|
-
]).default(COMPOSER_REFRACTION_DEFAULT)
|
|
137
|
+
]).default(COMPOSER_REFRACTION_DEFAULT),
|
|
138
|
+
// The `blur()` term in every glass surface's backdrop chain. Turning it off
|
|
139
|
+
// keeps the translucency, the sheen and the edge refraction and drops only
|
|
140
|
+
// the frosting -- implemented as four variables driven to 0px, so nothing
|
|
141
|
+
// else about the recipes moves.
|
|
142
|
+
backdropBlur: z.boolean().default(true)
|
|
138
143
|
});
|
|
139
144
|
|
|
140
145
|
/** Map a legacy 1.37.x mode id onto a four-mode id, or null when nothing to do. */
|
|
@@ -585,7 +590,8 @@ function dsttRead(ctx) {
|
|
|
585
590
|
mode: DSTT_MODES.includes(stored) ? stored : DSTT_MODE_DEFAULT,
|
|
586
591
|
fluidBrush: descriptor.value.fluidBrush === true,
|
|
587
592
|
glassStyle: dsttGlassValue(ctx),
|
|
588
|
-
composerRefraction: dsttComposerValue(ctx)
|
|
593
|
+
composerRefraction: dsttComposerValue(ctx),
|
|
594
|
+
backdropBlur: descriptor.value.backdropBlur !== false
|
|
589
595
|
}
|
|
590
596
|
};
|
|
591
597
|
}
|
|
@@ -597,7 +603,7 @@ function dsttRead(ctx) {
|
|
|
597
603
|
* persist a choice without a second round trip. None of them is mandatory the
|
|
598
604
|
* way `mode` is — an older client that only knows about the mode keeps working.
|
|
599
605
|
*/
|
|
600
|
-
async function dsttWrite(ctx, mode, fluidBrush, glassStyle, composerRefraction) {
|
|
606
|
+
async function dsttWrite(ctx, mode, fluidBrush, glassStyle, composerRefraction, backdropBlur) {
|
|
601
607
|
if (!DSTT_MODES.includes(mode)) {
|
|
602
608
|
return failure("bad-request", `mode must be one of ${DSTT_MODES.join("/")}`, { issues: [] });
|
|
603
609
|
}
|
|
@@ -607,6 +613,7 @@ async function dsttWrite(ctx, mode, fluidBrush, glassStyle, composerRefraction)
|
|
|
607
613
|
if (typeof fluidBrush === "boolean") ops.push({ op: "set", path: ["fluidBrush"], value: fluidBrush });
|
|
608
614
|
if (wantsGlass) ops.push({ op: "set", path: ["glassStyle"], value: glassStyle });
|
|
609
615
|
if (wantsComposer) ops.push({ op: "set", path: ["composerRefraction"], value: composerRefraction });
|
|
616
|
+
if (typeof backdropBlur === "boolean") ops.push({ op: "set", path: ["backdropBlur"], value: backdropBlur });
|
|
610
617
|
const settings = ctx.get("settings");
|
|
611
618
|
if (settings === undefined || settings === null || typeof settings.mutate !== "function") {
|
|
612
619
|
return failure("internal", "settings service unavailable", {});
|
|
@@ -622,11 +629,18 @@ async function dsttWrite(ctx, mode, fluidBrush, glassStyle, composerRefraction)
|
|
|
622
629
|
mode,
|
|
623
630
|
fluidBrush: typeof fluidBrush === "boolean" ? fluidBrush === true : dsttBrushValue(ctx),
|
|
624
631
|
glassStyle: wantsGlass ? glassStyle : dsttGlassValue(ctx),
|
|
625
|
-
composerRefraction: wantsComposer ? composerRefraction : dsttComposerValue(ctx)
|
|
632
|
+
composerRefraction: wantsComposer ? composerRefraction : dsttComposerValue(ctx),
|
|
633
|
+
backdropBlur: typeof backdropBlur === "boolean" ? backdropBlur : dsttBlurValue(ctx)
|
|
626
634
|
}
|
|
627
635
|
};
|
|
628
636
|
}
|
|
629
637
|
|
|
638
|
+
/** The stored backdrop-blur preference, defaulting to on. */
|
|
639
|
+
function dsttBlurValue(ctx) {
|
|
640
|
+
const descriptor = settingsDescriptor(ctx, DSTT_SETTINGS_NS);
|
|
641
|
+
return descriptor === null ? true : descriptor.value.backdropBlur !== false;
|
|
642
|
+
}
|
|
643
|
+
|
|
630
644
|
/**
|
|
631
645
|
* The stored composer-refraction width, defaulting to the 8px band. `origin` was
|
|
632
646
|
* this option's first id: it is still accepted by the schema so a settings file
|
|
@@ -704,7 +718,7 @@ function apply(ctx) {
|
|
|
704
718
|
if (endpoint === DSTT_GET) return dsttRead(ctx);
|
|
705
719
|
if (endpoint === DSTT_SET) {
|
|
706
720
|
const payloadObject = payload === null || payload === undefined || typeof payload !== "object" ? {} : payload;
|
|
707
|
-
return await dsttWrite(ctx, payloadObject.mode, payloadObject.fluidBrush, payloadObject.glassStyle, payloadObject.composerRefraction);
|
|
721
|
+
return await dsttWrite(ctx, payloadObject.mode, payloadObject.fluidBrush, payloadObject.glassStyle, payloadObject.composerRefraction, payloadObject.backdropBlur);
|
|
708
722
|
}
|
|
709
723
|
if (endpoint === FILE_OPEN || endpoint === FILE_REVEAL) {
|
|
710
724
|
const target = localPathOf(payload);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-deepseek-style-theme",
|
|
3
3
|
"description": "DeepSeek official-home style theme: WebGL fluid-flow background, liquid glass with SVG edge refraction, glass sidebar and composer, frosted header, running-subagent progress panel, and DeepSeek brand link for the dsh web GUI",
|
|
4
|
-
"version": "1.43.
|
|
4
|
+
"version": "1.43.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"deepseek",
|