dsh-theme-customizer 1.0.3 → 1.0.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/PATCH-CORDIS-BUTTON.md +1 -1
- package/README.en.md +5 -4
- package/README.md +5 -4
- package/apply-patch.cjs +1 -1
- package/lib/client.js +235 -64
- package/package.json +1 -1
package/PATCH-CORDIS-BUTTON.md
CHANGED
package/README.en.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## 🎨 Theme Gallery
|
|
14
14
|
|
|
15
|
-
Four AI-generated wallpaper themes
|
|
15
|
+
Four AI-generated wallpaper themes, each with two main-UI "display area" modes: **include sidebar** and **exclude sidebar**, plus matching `.tczp` presets for one-click import (see "Asset Pack" below).
|
|
16
16
|
|
|
17
17
|
| 🌌 Aurora Nights (dark) | 🌇 Sunset Clouds (bright) |
|
|
18
18
|
|:---:|:---:|
|
|
@@ -22,7 +22,7 @@ Four AI-generated wallpaper themes (alternating dark/bright), each with two main
|
|
|
22
22
|
|
|
23
23
|
## 📸 Screenshots
|
|
24
24
|
|
|
25
|
-
Each theme has two modes (presets `-0` / `-1`): **display area includes sidebar**
|
|
25
|
+
Each theme has two modes (presets `-0` / `-1`): **display area includes sidebar** and **display area excludes sidebar** . Each mode has 3 shots: front-1 / front-2 / settings.
|
|
26
26
|
|
|
27
27
|
<details>
|
|
28
28
|
<summary>🌌 Aurora Nights (dark)</summary>
|
|
@@ -98,6 +98,7 @@ Each theme has two modes (presets `-0` / `-1`): **display area includes sidebar*
|
|
|
98
98
|
- Each area: None / Solid color / Image (with crop & selection) + opacity (**larger value = more transparent**) + base color (independent layer)
|
|
99
99
|
- Main background supports "include sidebar / exclude sidebar" display area toggle
|
|
100
100
|
- Sidebar image fades out directly via mask — never covers the top UI or the settings panel
|
|
101
|
+
- **Independent "when collapsed" settings** for both Main and Sidebar (applied when the sidebar is folded; cross-fade transition on toggle)
|
|
101
102
|
- **Borders module**: color + opacity for all default UI borders/dividers, independently for 5 areas (Main incl. sidebar / Cordis / Composer / Settings / Floating panel)
|
|
102
103
|
- **Text colors module**: 5 categories (Body / Process / Auxiliary / Faded / Accent), shared across light & dark themes, restorable to official defaults
|
|
103
104
|
- **Brand color**: color + opacity for the top-left DeepSeek Harness logo; the "Harness" wordmark can be tinted separately
|
|
@@ -130,7 +131,7 @@ Then **restart dsh web** for it to take effect. Verify: Settings → Theme shoul
|
|
|
130
131
|
|
|
131
132
|
## Persistent Cordis button (optional)
|
|
132
133
|
|
|
133
|
-
The "Cordis button always visible" toggle in Theme settings **requires
|
|
134
|
+
The "Cordis button always visible" toggle in Theme settings **requires patching the dsh-client-ui-cordis package** (provided by this plugin's `apply-patch.cjs`); without the patch the toggle has no effect. Install:
|
|
134
135
|
|
|
135
136
|
```bash
|
|
136
137
|
node apply-patch.cjs # apply patch (auto backup)
|
|
@@ -162,7 +163,7 @@ Presets panel → "Import preset" and pick a `.tczp` file to restore a whole con
|
|
|
162
163
|
|
|
163
164
|
## 📦 Asset Pack
|
|
164
165
|
|
|
165
|
-
The **full assets** for all four themes (original wallpapers + 8 `.tczp` presets + all showcase screenshots) are packed in
|
|
166
|
+
The **full assets** for all four themes (original wallpapers + 8 `.tczp` presets + all showcase screenshots) are packed in `assets.7z` attached to [GitHub Releases](https://github.com/lxxz1918/dsh-theme-customizer/releases). Download and extract with 7-Zip:
|
|
166
167
|
|
|
167
168
|
```
|
|
168
169
|
展示/
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
## 🎨 主题展示
|
|
14
14
|
|
|
15
|
-
四套 AI
|
|
15
|
+
四套 AI 生成的壁纸作为主题的示例,每套含两种主界面「显示区域」模式:**包含侧边栏**与**不包含侧边栏**,配套 `.tczp` 预设一键导入。(详见下方“资源包”)
|
|
16
16
|
|
|
17
17
|
| 🌌 星空极光(暗) | 🌇 黄昏云海(亮) |
|
|
18
18
|
|:---:|:---:|
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
## 📸 界面截图
|
|
24
24
|
|
|
25
|
-
每套主题两种模式(对应预设 `-0` / `-1
|
|
25
|
+
每套主题两种模式(对应预设 `-0` / `-1`):**显示区域包含侧边栏**与**显示区域不包含侧边栏**。每种模式 3 张:正面-1 / 正面-2 / 设置面。
|
|
26
26
|
|
|
27
27
|
<details>
|
|
28
28
|
<summary>🌌 星空极光(暗)</summary>
|
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
- 每区域:无 / 纯色 / 图片(选区裁剪)+ 透明度(**数值越大越透明**)+ 底色(独立层)
|
|
99
99
|
- 主界面支持「包含侧边栏 / 不包含侧边栏」显示区域切换
|
|
100
100
|
- 侧边栏图片用 mask 直接淡出,不盖顶部 UI、不挡设置面板
|
|
101
|
+
- **侧边栏收起后独立配置**:主界面 / 侧边栏各有一份「收起后」设置(折叠侧边栏时生效,切换淡入淡出)
|
|
101
102
|
- **框线板块**:所有界面默认边框/分隔线颜色 + 透明度,主界面(含侧边栏)/ Cordis / 输入区 / 设置界面 / 浮窗 5 区域独立
|
|
102
103
|
- **字体颜色板块**:正文 / 过程 / 辅助 / 弱化 / 强调 5 类文字颜色(亮暗主题共用,可恢复官方默认)
|
|
103
104
|
- **标志调色**:左上角 DeepSeek Harness 标志颜色 + 透明度;「Harness」文字部分可单独调色
|
|
@@ -130,7 +131,7 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
130
131
|
|
|
131
132
|
## Cordis 按钮常驻(可选)
|
|
132
133
|
|
|
133
|
-
主题设置里「Cordis
|
|
134
|
+
主题设置里「Cordis 按钮常驻」开关**依赖 dsh-client-ui-cordis 补丁**(本插件随包提供 `apply-patch.cjs` 一键打补丁),未打补丁时开关不生效。安装:
|
|
134
135
|
|
|
135
136
|
```bash
|
|
136
137
|
node apply-patch.cjs # 打补丁(自动备份)
|
|
@@ -162,7 +163,7 @@ dsh plugin --profile web add <本仓库路径>
|
|
|
162
163
|
|
|
163
164
|
## 📦 素材包
|
|
164
165
|
|
|
165
|
-
四套主题的**完整素材**(壁纸原图 + 8 个 `.tczp` 预设 + 全部展示截图)打包在 [GitHub Releases 附件](https://github.com/lxxz1918/dsh-theme-customizer/releases) 的
|
|
166
|
+
四套主题的**完整素材**(壁纸原图 + 8 个 `.tczp` 预设 + 全部展示截图)打包在 [GitHub Releases 附件](https://github.com/lxxz1918/dsh-theme-customizer/releases) 的 `assets.7z` 中,下载后 7-Zip 解压即可:
|
|
166
167
|
|
|
167
168
|
```
|
|
168
169
|
展示/
|
package/apply-patch.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// apply-patch.cjs ——
|
|
1
|
+
// apply-patch.cjs —— Cordis 按钮常驻补丁一键安装/撤销(dsh-theme-customizer 随包脚本)
|
|
2
2
|
// 背景:官方 dsh-client-ui-cordis 在"没有任何动态插件活动"时 return null(按钮隐藏)。
|
|
3
3
|
// 本补丁让按钮显隐受 window.__TCZ_HIDE_OFFICIAL_CORDIS 控制(主题插件「Cordis 按钮常驻」开关使用)。
|
|
4
4
|
// ⚠️ DSH 升级会覆盖官方包 → 升级后需重跑本脚本。
|
package/lib/client.js
CHANGED
|
@@ -80,8 +80,10 @@ window.__ModuleLoader__.load({
|
|
|
80
80
|
// 透明度语义统一:数值大 = 透明(主界面与侧边栏一致);默认 0 = 不透明(实/清晰)
|
|
81
81
|
// 主界面底色:默认开启白色(bottomEnabled/bottomColor/bottomOpacity,复用 emptyArea 字段,逻辑同侧边栏)
|
|
82
82
|
// 作用是主界面最底层垫色:模式"无"时显示白底;纯色/图片盖在底色之上
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
// v1.0.4 侧边栏收起态:app.collapsedSidebar = 主界面「侧边栏收起后」独立配置(默认 mode:'none' 官方原样)
|
|
84
|
+
app: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0, collapsedSidebar: emptyArea() },
|
|
85
|
+
// v1.0.4 侧边栏收起态:sidebar.collapsed = 侧边栏「收起后」独立配置(默认 mode:'none' 官方原样)
|
|
86
|
+
sidebar: { ...emptyArea(), opacity: 0, collapsed: emptyArea() },
|
|
85
87
|
// 输入区(composer):像主界面——默认白底常驻(bottomEnabled:true/color:#fff),背景作用在 [data-composer-seat]
|
|
86
88
|
composer: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 },
|
|
87
89
|
// 设置界面(details,v0.9.12):像主界面——默认白底常驻,背景作用在官方设置面板 [class*="VOzbGW_panel"]
|
|
@@ -307,7 +309,11 @@ window.__ModuleLoader__.load({
|
|
|
307
309
|
function detectSidebar() {
|
|
308
310
|
try {
|
|
309
311
|
if (typeof document === 'undefined') return null
|
|
310
|
-
|
|
312
|
+
// v1.0.4 折叠态检测(先行):官方收起时根容器带 hHd-Xa_collapsed class(F12 实测稳定后缀)。
|
|
313
|
+
// ⚠️ 选择器必须稳定:展开/折叠返回同一个容器(优先外层列容器),否则 buildSidebarCss 的
|
|
314
|
+
// 展开/收起规则用不同选择器 → 折叠后展开规则残留(图片未被隐藏)。列容器折叠后宽度通常仍 >50。
|
|
315
|
+
const collapsed = !!document.querySelector('[class*="_collapsed"]')
|
|
316
|
+
const candidates = ['[class*="sidebar"]', '[class*="Sidebar"]', '[class*="sideBar"]', 'nav', '[class*="hHd-Xa_root"]']
|
|
311
317
|
for (const sel of candidates) {
|
|
312
318
|
const els = document.querySelectorAll(sel)
|
|
313
319
|
for (const el of els) {
|
|
@@ -315,10 +321,21 @@ window.__ModuleLoader__.load({
|
|
|
315
321
|
if (r.width > 50 && r.height > 100 && r.left === 0 && r.top === 0) {
|
|
316
322
|
const cls = typeof el.className === 'string' ? el.className.split(/\s+/).filter(Boolean)[0] : ''
|
|
317
323
|
const selector = cls ? '.' + cls.replace(/[^a-zA-Z0-9_-]/g, '\\$&') : el.tagName.toLowerCase()
|
|
318
|
-
return { selector, ratio: r.width / r.height, width: r.width, height: r.height }
|
|
324
|
+
return { selector, ratio: r.width / r.height, width: r.width, height: r.height, collapsed }
|
|
319
325
|
}
|
|
320
326
|
}
|
|
321
327
|
}
|
|
328
|
+
// 折叠态兜底(窄栏 <50px 列容器不匹配):量 hHd-Xa_root。⚠️ 此时 selector 可能与展开态不同,
|
|
329
|
+
// buildSidebarCss 用 :has() 双选择器兜底(自身含 collapsed 或后代含),见 07
|
|
330
|
+
if (collapsed) {
|
|
331
|
+
const root = document.querySelector('[class*="hHd-Xa_root"]')
|
|
332
|
+
if (root) {
|
|
333
|
+
const r = root.getBoundingClientRect()
|
|
334
|
+
const cls = typeof root.className === 'string' ? root.className.split(/\s+/).filter(Boolean)[0] : ''
|
|
335
|
+
const selector = cls ? '.' + cls.replace(/[^a-zA-Z0-9_-]/g, '\\$&') : 'nav'
|
|
336
|
+
return { selector, ratio: r.width / Math.max(1, r.height), width: r.width, height: r.height, collapsed }
|
|
337
|
+
}
|
|
338
|
+
}
|
|
322
339
|
return null
|
|
323
340
|
} catch (e) { /* 忽略 */ }
|
|
324
341
|
return null
|
|
@@ -391,8 +408,9 @@ window.__ModuleLoader__.load({
|
|
|
391
408
|
function setDetailsDragEnabled(v) { detailsDragEnabled = v; notify(); saveNow() }
|
|
392
409
|
// ⚠️ 值未变跳过(2026-08-22 梳理修复):resize/observer 每触发都调用,值没变也 notify 会全量重渲染
|
|
393
410
|
// (Cordis 面板 MutationObserver 监听整个 body 节点增删 → 对话流每挂载一条消息都触发一次)
|
|
411
|
+
// v1.0.4:collapsed 折叠态也参与比较(折叠切换触发 CSS 重建)
|
|
394
412
|
function setSidebarInfo(next) {
|
|
395
|
-
if (sidebarInfo && next && sidebarInfo.selector === next.selector && sidebarInfo.ratio === next.ratio && sidebarInfo.width === next.width && sidebarInfo.height === next.height) return
|
|
413
|
+
if (sidebarInfo && next && sidebarInfo.selector === next.selector && sidebarInfo.ratio === next.ratio && sidebarInfo.width === next.width && sidebarInfo.height === next.height && sidebarInfo.collapsed === next.collapsed) return
|
|
396
414
|
sidebarInfo = next
|
|
397
415
|
notify()
|
|
398
416
|
}
|
|
@@ -447,8 +465,8 @@ window.__ModuleLoader__.load({
|
|
|
447
465
|
cordisEntry = true
|
|
448
466
|
applyCordisEntryFlag()
|
|
449
467
|
areas = {
|
|
450
|
-
app: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 },
|
|
451
|
-
sidebar: { ...emptyArea(), opacity: 0 },
|
|
468
|
+
app: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0, collapsedSidebar: emptyArea() },
|
|
469
|
+
sidebar: { ...emptyArea(), opacity: 0, collapsed: emptyArea() },
|
|
452
470
|
composer: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 },
|
|
453
471
|
details: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 },
|
|
454
472
|
float: { ...emptyArea(), opacity: 0, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 },
|
|
@@ -576,6 +594,14 @@ window.__ModuleLoader__.load({
|
|
|
576
594
|
} else if (areas.cordis.bottomColor == null) {
|
|
577
595
|
areas.cordis = { ...areas.cordis, bottomEnabled: true, bottomColor: '#ffffff', bottomOpacity: 0 }
|
|
578
596
|
}
|
|
597
|
+
// v1.0.4 侧边栏收起态:app.collapsedSidebar / sidebar.collapsed 嵌套配置(默认 mode:'none' 官方原样)。
|
|
598
|
+
// 旧配置无此键 → 无条件补 emptyArea(防 buildSidebarCss/buildAppCss 读 undefined.mode 崩溃)
|
|
599
|
+
if (areas.app && typeof areas.app === 'object' && (areas.app.collapsedSidebar === undefined || areas.app.collapsedSidebar.mode === undefined)) {
|
|
600
|
+
areas.app = { ...areas.app, collapsedSidebar: emptyArea() }
|
|
601
|
+
}
|
|
602
|
+
if (areas.sidebar && typeof areas.sidebar === 'object' && (areas.sidebar.collapsed === undefined || areas.sidebar.collapsed.mode === undefined)) {
|
|
603
|
+
areas.sidebar = { ...areas.sidebar, collapsed: emptyArea() }
|
|
604
|
+
}
|
|
579
605
|
if (c.colors && typeof c.colors === 'object') colors = { main: null, process: null, aux: null, faded: null, accent: null, ...c.colors }
|
|
580
606
|
if (c.newSession && typeof c.newSession === 'object') {
|
|
581
607
|
// 兼容旧数据:无 bottomEnabled 字段时,旧 bottomColor 有值 = 底色已开启;
|
|
@@ -786,6 +812,9 @@ window.__ModuleLoader__.load({
|
|
|
786
812
|
}
|
|
787
813
|
nextAreas[a.id] = area
|
|
788
814
|
}
|
|
815
|
+
// v1.0.4 侧边栏收起态:预设缺 collapsedSidebar/collapsed 字段(或字段异常缺 mode)→ 补默认(防读 undefined.mode 崩溃)
|
|
816
|
+
if (nextAreas.app && (!nextAreas.app.collapsedSidebar || nextAreas.app.collapsedSidebar.mode === undefined)) nextAreas.app = { ...nextAreas.app, collapsedSidebar: emptyArea() }
|
|
817
|
+
if (nextAreas.sidebar && (!nextAreas.sidebar.collapsed || nextAreas.sidebar.collapsed.mode === undefined)) nextAreas.sidebar = { ...nextAreas.sidebar, collapsed: emptyArea() }
|
|
789
818
|
areas = nextAreas
|
|
790
819
|
// ── 文字颜色:完整覆盖(null=恢复官方)──
|
|
791
820
|
colors = { main: null, process: null, aux: null, faded: null, accent: null }
|
|
@@ -876,6 +905,13 @@ window.__ModuleLoader__.load({
|
|
|
876
905
|
if (areas.sidebar.mode === 'image' && areas.sidebar.image && sidebarInfo && sidebarInfo.selector) {
|
|
877
906
|
parts.push(sidebarInfo.selector + ' { --tcz-sidebar-img: url("' + areas.sidebar.image.dataURI + '"); }')
|
|
878
907
|
}
|
|
908
|
+
// v1.0.4 收起态侧边栏图片变量:用收起态选择器(自身含 collapsed class 或后代含)
|
|
909
|
+
const sc = areas.sidebar.collapsed
|
|
910
|
+
if (sc && sc.mode === 'image' && sc.image && sidebarInfo && sidebarInfo.selector) {
|
|
911
|
+
const sel = sidebarInfo.selector
|
|
912
|
+
parts.push(sel + '[class*="_collapsed"] { --tcz-sidebar-img: url("' + sc.image.dataURI + '"); }')
|
|
913
|
+
parts.push(sel + ':has([class*="_collapsed"]) { --tcz-sidebar-img: url("' + sc.image.dataURI + '"); }')
|
|
914
|
+
}
|
|
879
915
|
if (areas.composer.mode === 'image' && areas.composer.image) {
|
|
880
916
|
parts.push('[data-composer-card] { --tcz-composer-img: url("' + areas.composer.image.dataURI + '"); }')
|
|
881
917
|
}
|
|
@@ -900,33 +936,41 @@ window.__ModuleLoader__.load({
|
|
|
900
936
|
function buildAppCss() {
|
|
901
937
|
// 主界面(html,body 背景)。底色 = 最底层垫色(常驻仅颜色);模式内容(纯色渐变/图片)叠在其上。
|
|
902
938
|
// 图片直接拼 dataURI(不用 var():多层 background-image 里 var() 替换失效 → 图片不显示);图片已在选图时 downscale 体积小
|
|
939
|
+
// v1.0.4 收起态:侧边栏折叠(hHd-Xa_collapsed)时用 areas.app.collapsedSidebar 独立配置(默认 none 官方原样);
|
|
940
|
+
// 折叠 class 在侧边栏内层 → 主界面用 :has() 从根选择。展开态用 areas.app + includeSidebar 偏移逻辑(不变)
|
|
903
941
|
const cssParts = []
|
|
942
|
+
// 折叠判定:html 内存在 collapsed 侧边栏(收起时切换)
|
|
943
|
+
const collapsedNow = sidebarInfo && sidebarInfo.collapsed
|
|
944
|
+
const appArea = collapsedNow ? (areas.app.collapsedSidebar || { mode: 'none', opacity: 0 }) : areas.app
|
|
945
|
+
const useInclude = appArea.includeSidebar !== false
|
|
946
|
+
// 收起态宽度 = 侧边栏收起后的实测宽度(默认窄栏 ~50px;未检测到时用 52 近似)
|
|
947
|
+
const sbW = collapsedNow
|
|
948
|
+
? (sidebarInfo.width > 0 && sidebarInfo.width < 120 ? Math.round(sidebarInfo.width) : 52)
|
|
949
|
+
: (sidebarInfo && sidebarInfo.width ? Math.round(sidebarInfo.width) : 0)
|
|
904
950
|
let appBottom = null
|
|
905
|
-
if (
|
|
906
|
-
const abRgb = parseRgb(
|
|
951
|
+
if (appArea.bottomColor) {
|
|
952
|
+
const abRgb = parseRgb(appArea.bottomColor)
|
|
907
953
|
appBottom = 'rgb(' + abRgb[0] + ',' + abRgb[1] + ',' + abRgb[2] + ')'
|
|
908
954
|
}
|
|
909
|
-
const appImg =
|
|
910
|
-
const appInclude =
|
|
911
|
-
if (
|
|
912
|
-
const op =
|
|
913
|
-
const layerRgb = appBottom ? parseRgb(
|
|
955
|
+
const appImg = appArea.image
|
|
956
|
+
const appInclude = useInclude
|
|
957
|
+
if (appArea.mode === 'image' && appImg) {
|
|
958
|
+
const op = appArea.opacity == null ? 0 : appArea.opacity
|
|
959
|
+
const layerRgb = appBottom ? parseRgb(appArea.bottomColor) : parseRgb(baseBg)
|
|
914
960
|
const grad = 'linear-gradient(rgba(' + layerRgb[0] + ',' + layerRgb[1] + ',' + layerRgb[2] + ',' + op + '), rgba(' + layerRgb[0] + ',' + layerRgb[1] + ',' + layerRgb[2] + ',' + op + '))'
|
|
915
961
|
const url = 'url("' + appImg.dataURI + '")'
|
|
916
|
-
if (!appInclude &&
|
|
917
|
-
const sbW = Math.round(sidebarInfo.width)
|
|
962
|
+
if (!appInclude && sbW > 0) {
|
|
918
963
|
const mainW = Math.max(100, Math.round(window.innerWidth - sbW))
|
|
919
964
|
cssParts.push('html, body { background-color: ' + (appBottom || baseBg) + ' !important; background-image: ' + grad + ', ' + url + ' !important; background-size: ' + mainW + 'px 100%, ' + mainW + 'px 100% !important; background-position: ' + sbW + 'px center, ' + sbW + 'px center !important; background-repeat: no-repeat, no-repeat !important; }')
|
|
920
965
|
} else {
|
|
921
966
|
cssParts.push('html, body { background-color: ' + (appBottom || 'transparent') + ' !important; background-image: ' + grad + ', ' + url + ' !important; background-size: cover, cover !important; background-position: center !important; background-repeat: no-repeat !important; background-attachment: fixed !important; }')
|
|
922
967
|
}
|
|
923
|
-
} else if (
|
|
924
|
-
const a = 1 - (
|
|
925
|
-
const rgbC = parseRgb(
|
|
968
|
+
} else if (appArea.mode === 'color') {
|
|
969
|
+
const a = 1 - (appArea.opacity == null ? 0 : appArea.opacity)
|
|
970
|
+
const rgbC = parseRgb(appArea.color)
|
|
926
971
|
const bg = appBottom || baseBg
|
|
927
972
|
const grad = 'linear-gradient(rgba(' + rgbC[0] + ',' + rgbC[1] + ',' + rgbC[2] + ',' + a + '), rgba(' + rgbC[0] + ',' + rgbC[1] + ',' + rgbC[2] + ',' + a + '))'
|
|
928
|
-
if (!appInclude &&
|
|
929
|
-
const sbW = Math.round(sidebarInfo.width)
|
|
973
|
+
if (!appInclude && sbW > 0) {
|
|
930
974
|
const mainW = Math.max(100, Math.round(window.innerWidth - sbW))
|
|
931
975
|
cssParts.push('html, body { background-color: ' + bg + ' !important; background-image: ' + grad + ' !important; background-size: ' + mainW + 'px 100% !important; background-position: ' + sbW + 'px center !important; background-repeat: no-repeat !important; }')
|
|
932
976
|
} else {
|
|
@@ -937,6 +981,7 @@ window.__ModuleLoader__.load({
|
|
|
937
981
|
// 曾做 html,body 垫色(v0.9.2),但官方 _frame/三列等容器自带不透明背景盖住垫色看不到,
|
|
938
982
|
// 且侧边栏「无」模式透出下层会透出垫色 → "侧边栏变红"(连锁问题)。
|
|
939
983
|
// 主界面「无」模式已不显示底色选项(09 AreaEditor);旧配置残留 bottomColor 也不再垫色。
|
|
984
|
+
// v1.0.4 收起态 none:同样零注入(官方原样)——但收起态无垫色会露出官方白底(无主界面图时正常)
|
|
940
985
|
}
|
|
941
986
|
return cssParts.join(' ')
|
|
942
987
|
}
|
|
@@ -1009,28 +1054,46 @@ window.__ModuleLoader__.load({
|
|
|
1009
1054
|
}
|
|
1010
1055
|
function buildSidebarCss() {
|
|
1011
1056
|
// 侧边栏(底色 + 图片/纯色/无);三层独立架构(层1 body / 层2 底色 / 层3 ::before 图片)
|
|
1057
|
+
// v1.0.4 收起态:折叠(官方 hHd-Xa_collapsed class,F12 实测)时用 areas.sidebar.collapsed 独立配置;
|
|
1058
|
+
// 默认 mode:'none' = 官方原样(背景层 opacity:0)。切换用 transition 淡入淡出(容器/伪元素 opacity 过渡)。
|
|
1059
|
+
// 折叠 class 在内层 hHd-Xa_root 上(sidebarInfo.selector 是外层列容器)→ 用 :has() 区分两态
|
|
1012
1060
|
const cssParts = []
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
const
|
|
1061
|
+
const sel = sidebarInfo && sidebarInfo.selector ? sidebarInfo.selector : null
|
|
1062
|
+
// 收起态选择器:collapsed class 可能在容器自身(兜底分支选中 hHd-Xa_root)或后代(列容器选中 _sidebarCol)
|
|
1063
|
+
const colSel = sel ? sel + '[class*="_collapsed"], ' + sel + ':has([class*="_collapsed"])' : null
|
|
1064
|
+
// 展开态选择器:非折叠才生效(:not 双条件)——与收起规则互斥,防折叠后展开规则残留
|
|
1065
|
+
const expSel = sel ? sel + ':not([class*="_collapsed"]):not(:has([class*="_collapsed"]))' : null
|
|
1066
|
+
if (!sel) return cssParts.join(' ')
|
|
1067
|
+
const mk = (area, isCollapsed) => {
|
|
1068
|
+
const out = []
|
|
1069
|
+
const bottomColor = (() => {
|
|
1070
|
+
if (!area.bottomEnabled || !area.bottomColor) return null
|
|
1071
|
+
const ba = 1 - (area.bottomOpacity == null ? 0 : area.bottomOpacity)
|
|
1072
|
+
const [br, bg, bb] = parseRgb(area.bottomColor)
|
|
1073
|
+
return 'rgba(' + br + ',' + bg + ',' + bb + ',' + ba + ')'
|
|
1074
|
+
})()
|
|
1075
|
+
// 容器:底色 + 过渡(背景色淡入淡出;收起态默认官方原样 = 透明底)
|
|
1021
1076
|
const bottom = bottomColor || 'transparent'
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1077
|
+
out.push((isCollapsed ? colSel : expSel) + ' { position: relative !important; background-color: ' + bottom + ' !important; transition: background-color 0.35s ease !important; }')
|
|
1078
|
+
if (area.mode === 'image' && area.image) {
|
|
1079
|
+
const maskAlpha = 1 - (area.opacity == null ? 0 : area.opacity)
|
|
1080
|
+
out.push((isCollapsed ? colSel : expSel) + '::before { content: "" !important; position: absolute !important; inset: 0 !important; pointer-events: none !important; background-image: var(--tcz-sidebar-img) !important; background-size: cover !important; background-position: center !important; background-repeat: no-repeat !important; -webkit-mask-image: linear-gradient(rgba(0,0,0,' + maskAlpha + '), rgba(0,0,0,' + maskAlpha + ')) !important; mask-image: linear-gradient(rgba(0,0,0,' + maskAlpha + '), rgba(0,0,0,' + maskAlpha + ')) !important; opacity: 1 !important; transition: opacity 0.35s ease !important; }')
|
|
1081
|
+
} else if (area.mode === 'color') {
|
|
1082
|
+
// ⚠️ 纯色用**容器 background**(不用 ::before):容器背景天然在内容之下,永不盖 UI(v20 架构)。
|
|
1083
|
+
// v1.0.4 重构曾改 ::before → 盖住所有 UI(回归,用户反馈"纯色模式上边 UI 在颜色层下")→ 改回容器背景。
|
|
1084
|
+
const a = 1 - (area.opacity == null ? 0 : area.opacity)
|
|
1085
|
+
const [r, g, b] = parseRgb(area.color)
|
|
1086
|
+
out.push((isCollapsed ? colSel : expSel) + ' { background-color: ' + bottom + ' !important; background-image: linear-gradient(rgba(' + r + ',' + g + ',' + b + ',' + a + '), rgba(' + r + ',' + g + ',' + b + ',' + a + ')) !important; background-size: cover !important; background-position: center !important; background-repeat: no-repeat !important; }')
|
|
1087
|
+
} else {
|
|
1088
|
+
// 无/透明:背景层淡出(opacity 0),官方原样透出
|
|
1089
|
+
out.push((isCollapsed ? colSel : expSel) + '::before { content: "" !important; position: absolute !important; inset: 0 !important; pointer-events: none !important; opacity: 0 !important; transition: opacity 0.35s ease !important; }')
|
|
1090
|
+
}
|
|
1091
|
+
return out
|
|
1033
1092
|
}
|
|
1093
|
+
// 展开态(默认)规则
|
|
1094
|
+
cssParts.push.apply(cssParts, mk(areas.sidebar, false))
|
|
1095
|
+
// 收起态规则(若配置了收起模式;默认 none → 淡出)
|
|
1096
|
+
cssParts.push.apply(cssParts, mk(areas.sidebar.collapsed || { mode: 'none', opacity: 0 }, true))
|
|
1034
1097
|
return cssParts.join(' ')
|
|
1035
1098
|
}
|
|
1036
1099
|
function buildBrandCss() {
|
|
@@ -1129,11 +1192,26 @@ window.__ModuleLoader__.load({
|
|
|
1129
1192
|
return cssParts.join(' ')
|
|
1130
1193
|
}
|
|
1131
1194
|
function buildLiftCss() {
|
|
1132
|
-
//
|
|
1195
|
+
// 侧边栏图片模式下内容提升(v20 铁律:任何会包住官方设置面板的祖先都不得建层叠上下文)。
|
|
1196
|
+
// v1.0.4 修正(两次迭代):
|
|
1197
|
+
// · 第一版:regionArea/footArea 加 z-index:1(建 mini 上下文)→ **盖住设置面板**(面板 DOM 在侧边栏内,
|
|
1198
|
+
// settingsArea 是兄弟,z-index:1 > auto 把面板压住,用户反馈"上方那一栏覆盖设置界面上层")。
|
|
1199
|
+
// · 正确方案:用 `position: relative`(**不加 z-index**)——relative + z-index:auto **不建层叠上下文**
|
|
1200
|
+
// (面板不受影响),且内容 DOM 顺序在 ::before(伪元素,渲染为第一个子)之后 → 自然绘制在图片层之上。
|
|
1201
|
+
// · logoRow/新会话保持 z-index:1(v20 已验证安全:内部无 fixed 面板)。
|
|
1202
|
+
// · settingsArea 也加 position:relative(让设置按钮可见于图片层之上,且不关面板——relative 不建上下文)。
|
|
1203
|
+
// 收起态图片(areas.sidebar.collapsed mode image)同样需要提升。
|
|
1133
1204
|
const cssParts = []
|
|
1134
|
-
|
|
1205
|
+
const hasExpandImg = areas.sidebar.mode === 'image' && areas.sidebar.image && sidebarInfo && sidebarInfo.selector
|
|
1206
|
+
const sc = areas.sidebar.collapsed
|
|
1207
|
+
const hasCollapsedImg = sc && sc.mode === 'image' && sc.image && sidebarInfo && sidebarInfo.selector
|
|
1208
|
+
if (hasExpandImg || hasCollapsedImg) {
|
|
1135
1209
|
cssParts.push(sidebarInfo.selector + ' [class*="_logoRow"] { position: relative !important; z-index: 1 !important; }')
|
|
1136
1210
|
cssParts.push('[class*="_newSession"]:not([class*="_newSessionLabel"]) { position: relative !important; z-index: 1 !important; }')
|
|
1211
|
+
// 内容区提升(不建上下文):relative 无 z-index → DOM 顺序盖住 ::before,且不影响设置面板
|
|
1212
|
+
cssParts.push(sidebarInfo.selector + ' [class*="_regionArea"] { position: relative !important; }')
|
|
1213
|
+
cssParts.push(sidebarInfo.selector + ' [class*="_footArea"] { position: relative !important; }')
|
|
1214
|
+
cssParts.push(sidebarInfo.selector + ' [class*="_settingsArea"] { position: relative !important; }')
|
|
1137
1215
|
}
|
|
1138
1216
|
return cssParts.join(' ')
|
|
1139
1217
|
}
|
|
@@ -1292,11 +1370,20 @@ window.__ModuleLoader__.load({
|
|
|
1292
1370
|
function buildThemeTokens() {
|
|
1293
1371
|
const tokens = {}
|
|
1294
1372
|
const app = areas.app, sb = areas.sidebar
|
|
1295
|
-
|
|
1373
|
+
// v1.0.4:主界面 bg-base 透明化按当前折叠态判定(收起态 none → 不含该 token = 官方默认;
|
|
1374
|
+
// ⚠️ 勿设 null——官方 validateOverrides 拒绝 null(必须 {light,dark} 字符串对),同名 source
|
|
1375
|
+
// 整层替换,新层不含 bg-base 即恢复官方)
|
|
1376
|
+
const collapsedNow = sidebarInfo && sidebarInfo.collapsed
|
|
1377
|
+
const appArea = collapsedNow ? (areas.app.collapsedSidebar || {}) : app
|
|
1378
|
+
if (appArea.mode === 'color' || appArea.mode === 'image') {
|
|
1296
1379
|
tokens['--dsw-alias-bg-base'] = { light: 'transparent', dark: 'transparent' }
|
|
1297
|
-
if (
|
|
1380
|
+
if (appArea.includeSidebar !== false) tokens['--dsw-specific-sidebar-fill'] = { light: 'transparent', dark: 'transparent' }
|
|
1298
1381
|
}
|
|
1299
|
-
|
|
1382
|
+
// v1.0.4:侧边栏 fill 透明化按当前折叠态判定——收起态用 areas.sidebar.collapsed 配置
|
|
1383
|
+
// (有背景才透明化 fill,否则保留官方白 = 官方原样,符合"收起后默认官方原样"语义)
|
|
1384
|
+
const sbCollapsed = sidebarInfo && sidebarInfo.collapsed
|
|
1385
|
+
const sbArea = sbCollapsed ? (areas.sidebar.collapsed || {}) : sb
|
|
1386
|
+
if (sbArea.mode === 'transparent' || sbArea.mode === 'image' || sbArea.mode === 'color') tokens['--dsw-specific-sidebar-fill'] = { light: 'transparent', dark: 'transparent' }
|
|
1300
1387
|
for (const it of COLOR_ITEMS) {
|
|
1301
1388
|
const v = colors[it.key]
|
|
1302
1389
|
if (!v) continue
|
|
@@ -1399,7 +1486,25 @@ window.__ModuleLoader__.load({
|
|
|
1399
1486
|
if (!sidebarInfo) refresh()
|
|
1400
1487
|
// 网页变化(窗口缩放/布局变动)时重新检测侧边栏比例,保证选区比例始终跟手
|
|
1401
1488
|
window.addEventListener('resize', refresh)
|
|
1402
|
-
|
|
1489
|
+
// v1.0.4 折叠态监听:官方折叠/展开会增删 hHd-Xa_collapsed class(F12 实测稳定后缀)。
|
|
1490
|
+
// MutationObserver 监听 body 子树 class 变化 → 折叠切换时重新检测(collapsed + 宽度),
|
|
1491
|
+
// setSidebarInfo 值比较保证零冗余重渲染。零定时器(事件驱动)
|
|
1492
|
+
let collapseObserver = null
|
|
1493
|
+
try {
|
|
1494
|
+
let lastCollapsed = !!(document.querySelector('[class*="_collapsed"]'))
|
|
1495
|
+
collapseObserver = new MutationObserver(() => {
|
|
1496
|
+
const nowCollapsed = !!(document.querySelector('[class*="_collapsed"]'))
|
|
1497
|
+
if (nowCollapsed !== lastCollapsed) {
|
|
1498
|
+
lastCollapsed = nowCollapsed
|
|
1499
|
+
refresh()
|
|
1500
|
+
}
|
|
1501
|
+
})
|
|
1502
|
+
collapseObserver.observe(document.body, { attributes: true, attributeFilter: ['class'], subtree: true, childList: true })
|
|
1503
|
+
} catch (e) { /* 忽略(observer 不可用时只在 resize 时重检) */ }
|
|
1504
|
+
return () => {
|
|
1505
|
+
window.removeEventListener('resize', refresh)
|
|
1506
|
+
if (collapseObserver) { try { collapseObserver.disconnect() } catch (e) { /* 忽略 */ } }
|
|
1507
|
+
}
|
|
1403
1508
|
}, [])
|
|
1404
1509
|
|
|
1405
1510
|
// 输入区固定高度:卡片实测宽高比缓存。
|
|
@@ -1520,8 +1625,11 @@ window.__ModuleLoader__.load({
|
|
|
1520
1625
|
React.useEffect(() => {
|
|
1521
1626
|
const cleanup = () => document.querySelectorAll('[data-thmcz-details-reset]').forEach((el) => { try { el.remove() } catch (e) { /* 忽略 */ } })
|
|
1522
1627
|
if (!detailsDragEnabled) { cleanup(); return undefined }
|
|
1628
|
+
// v1.0.4:侧边栏折叠态不注入复位按钮(收起后 trigger 变窄,两文字挤在一起——用户要求收起后不显示)
|
|
1629
|
+
const isCollapsed = () => !!document.querySelector('[class*="_collapsed"]')
|
|
1523
1630
|
let btn = null
|
|
1524
1631
|
const ensure = () => {
|
|
1632
|
+
if (isCollapsed()) { if (btn) { try { btn.remove() } catch (e) { /* 忽略 */ } btn = null } return }
|
|
1525
1633
|
if (btn) return
|
|
1526
1634
|
const t = document.querySelector('[class*="VOzbGW_trigger"]')
|
|
1527
1635
|
if (!t) return
|
|
@@ -1537,8 +1645,8 @@ window.__ModuleLoader__.load({
|
|
|
1537
1645
|
ensure()
|
|
1538
1646
|
let obs = null
|
|
1539
1647
|
try {
|
|
1540
|
-
obs = new MutationObserver(ensure)
|
|
1541
|
-
obs.observe(document.body, { childList: true, subtree: true })
|
|
1648
|
+
obs = new MutationObserver(() => { ensure() })
|
|
1649
|
+
obs.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] })
|
|
1542
1650
|
} catch (e) { /* 忽略 */ }
|
|
1543
1651
|
window.addEventListener('resize', ensure)
|
|
1544
1652
|
return () => {
|
|
@@ -1558,18 +1666,21 @@ window.__ModuleLoader__.load({
|
|
|
1558
1666
|
if (!theme || typeof theme.overrideTokens !== 'function') return undefined
|
|
1559
1667
|
const tokens = buildThemeTokens()
|
|
1560
1668
|
let disposer
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
}
|
|
1669
|
+
// v1.0.4:tokens 为空也调用(空对象整层替换 → 清除旧透明覆盖,恢复官方)——
|
|
1670
|
+
// 折叠态 none 需把展开态设置的 bg-base transparent 清掉;旧逻辑空对象直接跳过会残留
|
|
1671
|
+
try { disposer = theme.overrideTokens('theme-customizer', tokens) } catch (e) { /* 忽略 */ }
|
|
1564
1672
|
return () => { if (typeof disposer === 'function') disposer() }
|
|
1565
|
-
}, [areas.app
|
|
1673
|
+
}, [areas.app, areas.sidebar, sidebarInfo, colors, convBgs])
|
|
1566
1674
|
|
|
1567
1675
|
// 各模块 CSS 用缓存(依赖只含本模块状态;拖动中 manualCssRefresh 已直更 style,这里保证 React 状态一致)
|
|
1568
1676
|
// ⚠️ 防御:areas.float/details/cordis 可能 undefined(旧配置整体替换后缺键),依赖数组用兜底访问(v0.9.13 事故修复)
|
|
1569
1677
|
const flDep = areas.float || {}
|
|
1570
1678
|
const detDep = areas.details || {}
|
|
1571
1679
|
const corDep = areas.cordis || {}
|
|
1572
|
-
|
|
1680
|
+
// v1.0.4:imgVars 依赖必须含收起态图片(areas.sidebar.collapsed.image 引用)——只设「收起后」图片时
|
|
1681
|
+
// areas.sidebar.mode/image(展开态)不变,缺依赖 → useMemo 不重算 → --tcz-sidebar-img 变量不生成 → 图片不显示
|
|
1682
|
+
const scImg = areas.sidebar && areas.sidebar.collapsed && areas.sidebar.collapsed.image
|
|
1683
|
+
const imgVars = React.useMemo(() => buildImgVars(), [areas.sidebar.mode, areas.sidebar.image, scImg, areas.composer.mode, areas.composer.image, newSession.mode, newSession.image, detDep.mode, detDep.image, flDep.mode, flDep.image, corDep.mode, corDep.image, sidebarInfo])
|
|
1573
1684
|
const appCss = React.useMemo(() => buildAppCss(), [areas.app, sidebarInfo, baseBg])
|
|
1574
1685
|
const composerCss = React.useMemo(() => buildComposerCss(), [areas.composer, composerFixedHeight, composerRows, baseBg])
|
|
1575
1686
|
const detailsCss = React.useMemo(() => buildDetailsCss(), [areas.details, baseBg, detailsPos])
|
|
@@ -1577,7 +1688,8 @@ window.__ModuleLoader__.load({
|
|
|
1577
1688
|
const brandCss = React.useMemo(() => buildBrandCss(), [brand, brandHarness])
|
|
1578
1689
|
const bordersCss = React.useMemo(() => buildBordersCss(), [borders])
|
|
1579
1690
|
const newSessionCss = React.useMemo(() => buildNewSessionCss(), [newSession])
|
|
1580
|
-
|
|
1691
|
+
// v1.0.4:liftCss 依赖同加收起态图片(收起态图片时 logoRow 提升)
|
|
1692
|
+
const liftCss = React.useMemo(() => buildLiftCss(), [areas.sidebar.mode, areas.sidebar.image, scImg, sidebarInfo])
|
|
1581
1693
|
const cordisCss = React.useMemo(() => buildCordisCss(), [areas.cordis, baseBg])
|
|
1582
1694
|
const floatCss = React.useMemo(() => buildFloatCss(), [floatVisible, areas.float])
|
|
1583
1695
|
const convCss = React.useMemo(() => buildConvCss(), [convBgs.scrollbar, convBgs.chatScroll, convBgs.todoCollapsed, convBgs.todoExpanded, convBgs.addBtn, convBgs.cmdMenu, convBgs.addBtnOpacity, convBgs.cmdMenuOpacity, convBgs.toBottom, convBgs.sliderColor, convBgs.sliderOpacity, convBgs.sliderTrackColor, convBgs.sliderTrackOpacity, convBgs.scrollColor, convBgs.scrollOpacity, convBgs.scrollbarOpacity, convBgs.chatScrollOpacity, convBgs.todoCollapsedOpacity, convBgs.todoExpandedOpacity, convBgs.toBottomOpacity, convBgs.bubbleOpacity, convBgs.inlineOpacity, convBgs.codeOpacity])
|
|
@@ -1987,6 +2099,15 @@ window.__ModuleLoader__.load({
|
|
|
1987
2099
|
}
|
|
1988
2100
|
return 16 / 9
|
|
1989
2101
|
}
|
|
2102
|
+
// v1.0.4 侧边栏收起后子版块裁剪比例:窄栏极窄(宽 ~52-70px / 高 ~视口),与展开侧边栏/视口比例完全不同。
|
|
2103
|
+
// 折叠时用 sidebarInfo 实测窄栏比例;展开时用官方窄栏宽度近似(rail 模式 ~60px)/ 视口高度
|
|
2104
|
+
function getCollapsedRatio() {
|
|
2105
|
+
if (sidebarInfo && sidebarInfo.collapsed && sidebarInfo.width > 0 && sidebarInfo.height > 0) {
|
|
2106
|
+
return sidebarInfo.width / sidebarInfo.height
|
|
2107
|
+
}
|
|
2108
|
+
const vh = typeof window !== 'undefined' ? window.innerHeight : 800
|
|
2109
|
+
return 60 / vh
|
|
2110
|
+
}
|
|
1990
2111
|
|
|
1991
2112
|
// ════════ 09_background.js ════════
|
|
1992
2113
|
// ┌─ 片段 09_background ────────────────────────────
|
|
@@ -2040,7 +2161,9 @@ window.__ModuleLoader__.load({
|
|
|
2040
2161
|
modes.map((m) => React.createElement('option', { key: m.id, value: m.id }, m.label)))
|
|
2041
2162
|
: null,
|
|
2042
2163
|
),
|
|
2043
|
-
|
|
2164
|
+
// v1.0.4:collapsedSubApp(主界面收起后)也显示区域开关——与 app 同布局
|
|
2165
|
+
// (「主界面」标签行 → 显示区域 → 模式内容,用户定位置)
|
|
2166
|
+
(area.id === 'app' || area.id === 'collapsedSubApp')
|
|
2044
2167
|
? React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', marginTop: '4px', marginBottom: '4px', flexWrap: 'wrap' } },
|
|
2045
2168
|
React.createElement('span', { style: { fontSize: '12px', color: 'var(--dsw-alias-label-secondary)', flex: 'none' } }, '显示区域:'),
|
|
2046
2169
|
React.createElement('button', { type: 'button', onClick: () => onChange({ ...value, includeSidebar: true }), style: { padding: '4px 10px', borderRadius: '6px', cursor: 'pointer', border: '1px solid ' + (value.includeSidebar === false ? 'var(--dsw-alias-border-l2)' : 'var(--dsw-alias-brand-primary)'), background: value.includeSidebar === false ? 'transparent' : 'var(--dsw-alias-brand-primary)', color: value.includeSidebar === false ? 'var(--dsw-alias-label-primary)' : '#fff', fontSize: '12px' } }, '包含侧边栏'),
|
|
@@ -2082,8 +2205,10 @@ window.__ModuleLoader__.load({
|
|
|
2082
2205
|
// ⚠️ v1.0.1(2026-08-22 用户定):主界面「无」模式不显示底色——无模式下官方原样、不做垫色
|
|
2083
2206
|
// (此前「无」模式垫色被官方 _frame/三列不透明背景盖住看不到,且透出到侧边栏导致"侧边栏变红"连锁问题);
|
|
2084
2207
|
// 纯色/图片模式的底层垫色保留(appBottom 仍参与 color/image 分支)
|
|
2085
|
-
|
|
2086
|
-
|
|
2208
|
+
// v1.0.4:collapsedSub(侧边栏收起后)支持底色(同 sidebar:可开关 + 透明度);
|
|
2209
|
+
// collapsedSubApp(主界面收起后)= app 式(无开关、无透明度、仅颜色)
|
|
2210
|
+
(area.id !== 'app' || value.mode !== 'none') && (area.id === 'app' || area.id === 'sidebar' || area.id === 'composer' || area.id === 'details' || area.id === 'float' || area.id === 'cordis' || area.id === 'collapsedSub' || area.id === 'collapsedSubApp')
|
|
2211
|
+
? React.createElement(BottomRow, { value: value, onChange: (next) => onChange({ ...value, ...next }), style: { marginTop: '4px', marginBottom: '4px' }, title: '底色', hideOpacity: area.id === 'app' || area.id === 'collapsedSubApp', noSwitch: area.id !== 'sidebar' && area.id !== 'collapsedSub' })
|
|
2087
2212
|
: null,
|
|
2088
2213
|
children,
|
|
2089
2214
|
)
|
|
@@ -2232,7 +2357,7 @@ window.__ModuleLoader__.load({
|
|
|
2232
2357
|
|
|
2233
2358
|
// 「Cordis 按钮常驻」勾选(v0.9.14 起在 Cordis 插件界面区域卡片内,原独立卡片已删):
|
|
2234
2359
|
// 自身订阅 store(main 通道),childModules useMemo 闭包不捕获旧值。
|
|
2235
|
-
// v1.0.0
|
|
2360
|
+
// v1.0.0 开源:开关旁加小字——此开关依赖 dsh-client-ui-cordis 补丁(本插件自带的 apply-patch.cjs 补丁),未打补丁时不生效(用户定"留着,标明要打补丁")
|
|
2236
2361
|
function CordisEntryToggle() {
|
|
2237
2362
|
const { cordisEntry } = useStore(['main'])
|
|
2238
2363
|
// 开关仅勾选框触发(v0.9.20)
|
|
@@ -2242,7 +2367,7 @@ window.__ModuleLoader__.load({
|
|
|
2242
2367
|
React.createElement('span', null, 'Cordis 按钮常驻'),
|
|
2243
2368
|
),
|
|
2244
2369
|
React.createElement('div', { style: { fontSize: '11px', color: 'var(--dsw-alias-label-caption)', marginTop: '4px', marginLeft: '22px' } },
|
|
2245
|
-
'
|
|
2370
|
+
'需安装 Cordis 按钮补丁才生效(见 PATCH-CORDIS-BUTTON.md)'),
|
|
2246
2371
|
)
|
|
2247
2372
|
}
|
|
2248
2373
|
|
|
@@ -2331,9 +2456,25 @@ window.__ModuleLoader__.load({
|
|
|
2331
2456
|
)
|
|
2332
2457
|
}
|
|
2333
2458
|
|
|
2459
|
+
// 「侧边栏收起后 / 主界面侧边栏收起后」子版块(v1.0.4):
|
|
2460
|
+
// 复用 AreaEditor 渲染嵌套配置(areas.sidebar.collapsed / areas.app.collapsedSidebar,默认 mode:'none' 官方原样)。
|
|
2461
|
+
// 简化:收起态无「无/透明」区分(模式列表去 transparent);用独立 AreaEditor 实例 + 独立 area 描述。
|
|
2462
|
+
// v1.0.4 补充:主界面收起后的「显示区域」开关由 AreaEditor 内部渲染(area.id === 'collapsedSubApp',
|
|
2463
|
+
// 与 app 同布局:标签行 → 显示区域 → 模式内容);appLike=true 底色 = 主界面式(无开关、无透明度)
|
|
2464
|
+
function CollapsedAreaEditor({ label, value, onChange, ratio, appLike }) {
|
|
2465
|
+
// 收起态子版块的区域描述:mode 列表 = color/image/none(默认官方原样,无 transparent)
|
|
2466
|
+
// id:侧边栏收起后 = collapsedSub(sidebar 式底色);主界面收起后 = collapsedSubApp(app 式底色,AreaEditor 按 id 区分)
|
|
2467
|
+
const innerId = appLike ? 'collapsedSubApp' : 'collapsedSub'
|
|
2468
|
+
const innerArea = React.useMemo(() => ({ id: innerId, label, supported: true, modes: ['none', 'color', 'image'] }), [innerId, label])
|
|
2469
|
+
return React.createElement('div', { style: { marginTop: '6px', borderTop: '1px dashed var(--dsw-alias-border-l2)', paddingTop: '6px' } },
|
|
2470
|
+
React.createElement('div', { style: { fontSize: '12px', color: 'var(--dsw-alias-label-secondary)', marginBottom: '4px' } }, '侧边栏收起后'),
|
|
2471
|
+
React.createElement(AreaEditor, { area: innerArea, value: value, onChange: onChange, ratio: ratio }),
|
|
2472
|
+
)
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2334
2475
|
// 「界面」模块外壳(原 ModuleContent background 分支):透明度说明 → 全部 AREAS 区域卡片(主界面/侧边栏/对话区/输入区/设置界面/浮窗面板/Cordis 插件界面)
|
|
2335
2476
|
function BackgroundModule() {
|
|
2336
|
-
const { areas, sidebarInfo,
|
|
2477
|
+
const { areas, sidebarInfo, showOpacityHint } = useStore()
|
|
2337
2478
|
// 性能优化 2026-08-21:AreaEditor 已 memo 化 → onChange/children 必须稳定引用,
|
|
2338
2479
|
// 否则父级每次重渲染都新建闭包/元素,memo 浅比较失效(所有区域跟着全量重渲染)
|
|
2339
2480
|
const changeArea = React.useMemo(() => {
|
|
@@ -2341,13 +2482,23 @@ window.__ModuleLoader__.load({
|
|
|
2341
2482
|
for (const a of AREAS) m[a.id] = (v) => setArea(a.id, v)
|
|
2342
2483
|
return m
|
|
2343
2484
|
}, [])
|
|
2485
|
+
// v1.0.4 收起态子版块 onChange(写回嵌套字段,触发 areas 引用变化 → AreaCss 重算):
|
|
2486
|
+
// 稳定引用(useMemo),避免父级重渲染破坏 AreaEditor memo
|
|
2487
|
+
const changeCollapsed = React.useMemo(() => ({
|
|
2488
|
+
sidebar: (v) => setArea('sidebar', { ...areas.sidebar, collapsed: v }),
|
|
2489
|
+
app: (v) => setArea('app', { ...areas.app, collapsedSidebar: v }),
|
|
2490
|
+
}), [areas.sidebar, areas.app])
|
|
2344
2491
|
const childModules = React.useMemo(() => ({
|
|
2345
2492
|
// 「新会话」是侧边栏区块的一部分;「统计条/命令」是输入区区块的一部分(渲染在对应卡片内部末尾);
|
|
2346
2493
|
// 「对话区背景」是对话区区块的一部分(渲染在对话区卡片内部末尾)
|
|
2347
2494
|
// 输入区卡片内部结构(v0.9.11 用户定):底色(AreaEditor 内)→ 输入框高度(ComposerHeightRow,板块直属)→ 统计条/命令(ComposerEditor 子版块)
|
|
2348
2495
|
// 浮窗面板卡片(v0.9.13):背景调整(AreaEditor)+ 显示透明度说明勾选(children)
|
|
2349
2496
|
// 各子版块自身订阅 store → store 变化时自行重渲染,不受父级跳过影响
|
|
2497
|
+
// v1.0.4:主界面/侧边栏卡片加「收起后」子版块(CollapsedAreaEditor 内部用独立 AreaEditor,自有 state);
|
|
2498
|
+
// 侧边栏卡片的「侧边栏收起后」在最上方(用户定:在标志 BrandEditor 上面)
|
|
2350
2499
|
sidebar: React.createElement(React.Fragment, null,
|
|
2500
|
+
// v1.0.4 收起后子版块:ratio 用窄栏实测比例(getCollapsedRatio,折叠时实测 / 展开时 ~60px 近似)
|
|
2501
|
+
React.createElement(CollapsedAreaEditor, { label: '侧边栏', value: (areas.sidebar && areas.sidebar.collapsed) || { mode: 'none', opacity: 0 }, onChange: changeCollapsed.sidebar, ratio: getCollapsedRatio() }),
|
|
2351
2502
|
React.createElement(BrandEditor, null),
|
|
2352
2503
|
React.createElement(NewSessionEditor, null),
|
|
2353
2504
|
),
|
|
@@ -2362,7 +2513,7 @@ window.__ModuleLoader__.load({
|
|
|
2362
2513
|
),
|
|
2363
2514
|
cordis: React.createElement(CordisEntryToggle, null),
|
|
2364
2515
|
details: React.createElement(DetailsResetPos, null),
|
|
2365
|
-
}), [])
|
|
2516
|
+
}), [areas.sidebar, areas.app, changeCollapsed, sidebarInfo])
|
|
2366
2517
|
return React.createElement('div', null,
|
|
2367
2518
|
showOpacityHint
|
|
2368
2519
|
? React.createElement('div', { style: { fontSize: '12px', color: 'var(--dsw-alias-label-secondary)', marginBottom: '8px', whiteSpace: 'pre-line' } },
|
|
@@ -2373,7 +2524,27 @@ window.__ModuleLoader__.load({
|
|
|
2373
2524
|
// ⚠️ 防御:旧配置整体替换后新区域(float/details/cordis)可能缺失 → emptyArea 兜底(v0.9.13 事故修复)
|
|
2374
2525
|
area: a, value: areas[a.id] && typeof areas[a.id] === 'object' ? areas[a.id] : emptyArea(), onChange: changeArea[a.id],
|
|
2375
2526
|
ratio: getCropRatio(a),
|
|
2376
|
-
children:
|
|
2527
|
+
children: a.id === 'app'
|
|
2528
|
+
? React.createElement(React.Fragment, null,
|
|
2529
|
+
React.createElement(CollapsedAreaEditor, {
|
|
2530
|
+
label: '主界面', appLike: true,
|
|
2531
|
+
value: (areas.app && areas.app.collapsedSidebar) || { mode: 'none', opacity: 0 },
|
|
2532
|
+
onChange: changeCollapsed.app,
|
|
2533
|
+
// 收起后主界面选区比例:不包含侧边栏时 = (视口宽-窄栏宽)/高;包含时 = 整屏
|
|
2534
|
+
ratio: (() => {
|
|
2535
|
+
const vw = typeof window !== 'undefined' ? window.innerWidth : 1280
|
|
2536
|
+
const vh = typeof window !== 'undefined' ? window.innerHeight : 800
|
|
2537
|
+
const cs = (areas.app && areas.app.collapsedSidebar) || {}
|
|
2538
|
+
if (cs.includeSidebar === false) {
|
|
2539
|
+
const sbw = sidebarInfo && sidebarInfo.width < 120 ? sidebarInfo.width : 60
|
|
2540
|
+
return Math.max(0.1, (vw - sbw) / vh)
|
|
2541
|
+
}
|
|
2542
|
+
return vw / vh
|
|
2543
|
+
})(),
|
|
2544
|
+
}),
|
|
2545
|
+
childModules[a.id] || null,
|
|
2546
|
+
)
|
|
2547
|
+
: (childModules[a.id] || null),
|
|
2377
2548
|
})),
|
|
2378
2549
|
)
|
|
2379
2550
|
}
|
|
@@ -2924,9 +3095,9 @@ window.__ModuleLoader__.load({
|
|
|
2924
3095
|
// ✅ 最终方案:侧边栏复位按钮改用**原生 DOM 注入**(07 AreaCss useEffect:VOzbGW_trigger 右半注入),
|
|
2925
3096
|
// 不再注册任何 sidebar 槽位。
|
|
2926
3097
|
|
|
2927
|
-
// ── Cordis
|
|
3098
|
+
// ── Cordis 常驻:官方按钮已由 dsh-client-ui-cordis 补丁(apply-patch.cjs)支持常驻(window.__TCZ_HIDE_OFFICIAL_CORDIS 控制开关)──
|
|
2928
3099
|
// 开关状态同步到 window 变量(官方组件渲染时读取);false=常驻,true=恢复官方逻辑
|
|
2929
|
-
//
|
|
3100
|
+
// 补丁已监听 'tcz:cordis-visibility' 事件 → 切换后立即重渲染(无需刷新页面)
|
|
2930
3101
|
function applyCordisEntryFlag() {
|
|
2931
3102
|
try { window.__TCZ_HIDE_OFFICIAL_CORDIS = !cordisEntry } catch (e) { /* 忽略 */ }
|
|
2932
3103
|
try { window.dispatchEvent(new Event('tcz:cordis-visibility')) } catch (e) { /* 忽略 */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-theme-customizer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "DeepSeek Harness (DSH) Web 界面自定义主题插件:七区域背景(主界面/侧边栏/输入区/设置界面/浮窗/Cordis,纯色/图片/选区裁剪/透明度)、文字颜色 5 类、框线颜色、标志调色、对话区细节定制、输入区统计条接管、浮动主题面板、预设导入导出(.tczp 含图)、localStorage 持久化。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|