@taosee258/dsh-client-ui-skin-qingxiao 0.1.4 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +25 -25
- package/README.md +100 -99
- package/lib/client.js +170 -57
- package/lib/index.js +190 -178
- package/package.json +6 -5
- package/preview/screen-dark.png +0 -0
- package/preview/screen-light.png +0 -0
- package/skin.json +30 -30
package/LICENSE
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 the qingxiao skin authors
|
|
4
|
-
|
|
5
|
-
You are free to:
|
|
6
|
-
|
|
7
|
-
Share — copy and redistribute the material in any medium or format
|
|
8
|
-
Adapt — remix, transform, and build upon the material
|
|
9
|
-
|
|
10
|
-
Under the following terms:
|
|
11
|
-
|
|
12
|
-
Attribution — You must give appropriate credit, provide a link to the
|
|
13
|
-
license, and indicate if changes were made.
|
|
14
|
-
|
|
15
|
-
NonCommercial — You may not use the material for commercial purposes.
|
|
16
|
-
|
|
17
|
-
ShareAlike — If you remix, transform, or build upon the material, you
|
|
18
|
-
must distribute your contributions under the same license as the original.
|
|
19
|
-
|
|
20
|
-
Full license text: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
|
|
21
|
-
|
|
22
|
-
Note: the bundled artwork (assets/qx.jpg) depicts the character 清宵 (Qingxiao)
|
|
23
|
-
from Wuthering Waves (Kuro Games). It is included for personal, non-commercial
|
|
24
|
-
decoration only and is not covered by the code license above; all rights
|
|
25
|
-
belong to their respective owners.
|
|
1
|
+
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 the qingxiao skin authors
|
|
4
|
+
|
|
5
|
+
You are free to:
|
|
6
|
+
|
|
7
|
+
Share — copy and redistribute the material in any medium or format
|
|
8
|
+
Adapt — remix, transform, and build upon the material
|
|
9
|
+
|
|
10
|
+
Under the following terms:
|
|
11
|
+
|
|
12
|
+
Attribution — You must give appropriate credit, provide a link to the
|
|
13
|
+
license, and indicate if changes were made.
|
|
14
|
+
|
|
15
|
+
NonCommercial — You may not use the material for commercial purposes.
|
|
16
|
+
|
|
17
|
+
ShareAlike — If you remix, transform, or build upon the material, you
|
|
18
|
+
must distribute your contributions under the same license as the original.
|
|
19
|
+
|
|
20
|
+
Full license text: https://creativecommons.org/licenses/by-nc-sa/4.0/legalcode
|
|
21
|
+
|
|
22
|
+
Note: the bundled artwork (assets/qx.jpg) depicts the character 清宵 (Qingxiao)
|
|
23
|
+
from Wuthering Waves (Kuro Games). It is included for personal, non-commercial
|
|
24
|
+
decoration only and is not covered by the code license above; all rights
|
|
25
|
+
belong to their respective owners.
|
package/README.md
CHANGED
|
@@ -1,99 +1,100 @@
|
|
|
1
|
-
# 清宵 · 弦凝清霄 — DSH 美化包
|
|
2
|
-
|
|
3
|
-
以《鸣潮》角色**清宵**(3.6 版本登场的五星气动·迅刀共鸣者,瑝珑「镇玄司骑」,琴剑双修的隐世剑仙)为主题的 DeepSeek Harness (DSH) Web 界面皮肤。
|
|
4
|
-
|
|
5
|
-
> 「弦凝千古寂,剑起满天清」
|
|
6
|
-
|
|
7
|
-
配色调色板取自清宵的形象:**冰蓝**(发色)、**青碧**(发饰流苏)、**月白**(衣装)、**玄夜蓝**(暗色形态)、**鎏金**(金饰点缀)。
|
|
8
|
-
|
|
9
|
-

|
|
10
|
-
|
|
11
|
-

|
|
12
|
-
|
|
13
|
-
## 这个皮肤有什么
|
|
14
|
-
|
|
15
|
-
- **背景画卷**:默认铺一张清宵插画当背景,亮色、暗色模式都能透出它。可以在设置面板里分别为两种模式换成你自己的图(PNG / JPG / WebP / GIF,7MB 以内),也能一键换回默认。
|
|
16
|
-
- **全套配色重制**:侧边栏、按钮、输入框、对话区、代码块、滚动条……界面每一处都按清宵的配色重新调过;暗色模式是专门的「玄夜剑鸣」氛围。
|
|
17
|
-
-
|
|
18
|
-
- **字永远看得清**:文字颜色专门为「压在插画背景上」调校过——正文浓黑/亮白,次要文字也比 DSH 原生的灰色深两档;背景还有可调浓度的柔光遮罩兜底。
|
|
19
|
-
- **剑气流光**:可选的粒子装饰,青碧或鎏金两种色调;系统开了「减少动态效果」会自动静止。
|
|
20
|
-
- **亮暗切换动画**:切换主题时有一抹剑光扫过屏幕的小动画,浏览器标签栏颜色和图标也会跟着换。
|
|
21
|
-
- **新会话迎宾页**:打开空会话时,屏幕中央浮现「清 宵 · 镇玄司骑 · 徒儿,你来了……」的题字,开始对话后自动退场。
|
|
22
|
-
- **设置跟着账号走**:所有偏好保存在 DSH 的数据目录里,换个浏览器、重启电脑都还在。
|
|
23
|
-
|
|
24
|
-
## 设置面板
|
|
25
|
-
|
|
26
|
-
点界面右上角的**清宵剑钰圆形按钮**打开调色盘。按钮可以拖到任意位置,位置会记住;面板底部有「回到右上角」一键复位。
|
|
27
|
-
|
|
28
|
-
| 分区 | 能调什么 |
|
|
29
|
-
| --- | --- |
|
|
30
|
-
| 背景画卷 | 亮/暗两种模式的背景图更换与复原 |
|
|
31
|
-
| 阅读清晰度 | 文字柔光开关 · 背景遮罩浓淡 · 面板实透 · 正文字号大小 |
|
|
32
|
-
| 界面琉璃 | 对话区宽度 · 面板磨砂底 |
|
|
33
|
-
| 毛玻璃虚化 | 总开关 · 插件窗/侧栏面板分开控制 · 虚化强度 0–30(0=关) |
|
|
34
|
-
| 剑气流光 | 开关 · 粒子数量 · 流动速度 |
|
|
35
|
-
| 复原 | 全部恢复默认 |
|
|
36
|
-
|
|
37
|
-
## 版本
|
|
38
|
-
|
|
39
|
-
各版本改动见 [CHANGELOG.md](CHANGELOG.md)。
|
|
40
|
-
|
|
41
|
-
## 安装
|
|
42
|
-
|
|
43
|
-
### 懒人版
|
|
44
|
-
|
|
45
|
-
直接对你的 DSH
|
|
46
|
-
```
|
|
47
|
-
安装一下这个皮肤包:@taosee258/dsh-client-ui-skin-qingxiao
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### 手动安装
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```sh
|
|
55
|
-
# 方式 A(推荐):从 npm 安装
|
|
56
|
-
dsh plugin --profile
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
```sh
|
|
60
|
-
# 方式 B:用 git URL 安装(始终对应仓库最新版)
|
|
61
|
-
dsh plugin --profile
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
```sh
|
|
65
|
-
# 方式 C:先克隆到本地任意位置,再把实际路径交给 dsh
|
|
66
|
-
git clone https://github.com/taoser258/dsh-client-ui-skin-qingxiao.git
|
|
67
|
-
dsh plugin --profile
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
**手动放置安装**:把本包整个文件夹复制到 DSH 的 `profiles
|
|
71
|
-
|
|
72
|
-
```yaml
|
|
73
|
-
- insert:
|
|
74
|
-
- id: ui-skin-qingxiao
|
|
75
|
-
name: '@taosee258/dsh-client-ui-skin-qingxiao'
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
重启 DSH 即可。
|
|
79
|
-
|
|
80
|
-
## 兼容性
|
|
81
|
-
|
|
82
|
-
- DSH Web
|
|
83
|
-
-
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
1
|
+
# 清宵 · 弦凝清霄 — DSH 美化包
|
|
2
|
+
|
|
3
|
+
以《鸣潮》角色**清宵**(3.6 版本登场的五星气动·迅刀共鸣者,瑝珑「镇玄司骑」,琴剑双修的隐世剑仙)为主题的 DeepSeek Harness (DSH) Web 界面皮肤。
|
|
4
|
+
|
|
5
|
+
> 「弦凝千古寂,剑起满天清」
|
|
6
|
+
|
|
7
|
+
配色调色板取自清宵的形象:**冰蓝**(发色)、**青碧**(发饰流苏)、**月白**(衣装)、**玄夜蓝**(暗色形态)、**鎏金**(金饰点缀)。
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+

|
|
12
|
+
|
|
13
|
+
## 这个皮肤有什么
|
|
14
|
+
|
|
15
|
+
- **背景画卷**:默认铺一张清宵插画当背景,亮色、暗色模式都能透出它。可以在设置面板里分别为两种模式换成你自己的图(PNG / JPG / WebP / GIF,7MB 以内),也能一键换回默认。
|
|
16
|
+
- **全套配色重制**:侧边栏、按钮、输入框、对话区、代码块、滚动条……界面每一处都按清宵的配色重新调过;暗色模式是专门的「玄夜剑鸣」氛围。
|
|
17
|
+
- **毛玻璃效果**:打开插件的小窗口(比如用量统计)、左右两侧面板、插件页/自动化任务页等整页视图、设置弹窗乃至窗口顶栏,背后的画面都会被柔和地虚化掉——壁纸的轮廓透得出来,但绝不跟文字打架。想多糊可以多糊(0–30 档随意调),不想要可以整体关掉,也可以只关插件窗或只关侧栏。
|
|
18
|
+
- **字永远看得清**:文字颜色专门为「压在插画背景上」调校过——正文浓黑/亮白,次要文字也比 DSH 原生的灰色深两档;背景还有可调浓度的柔光遮罩兜底。
|
|
19
|
+
- **剑气流光**:可选的粒子装饰,青碧或鎏金两种色调;系统开了「减少动态效果」会自动静止。
|
|
20
|
+
- **亮暗切换动画**:切换主题时有一抹剑光扫过屏幕的小动画,浏览器标签栏颜色和图标也会跟着换。
|
|
21
|
+
- **新会话迎宾页**:打开空会话时,屏幕中央浮现「清 宵 · 镇玄司骑 · 徒儿,你来了……」的题字,开始对话后自动退场。
|
|
22
|
+
- **设置跟着账号走**:所有偏好保存在 DSH 的数据目录里,换个浏览器、重启电脑都还在。
|
|
23
|
+
|
|
24
|
+
## 设置面板
|
|
25
|
+
|
|
26
|
+
点界面右上角的**清宵剑钰圆形按钮**打开调色盘。按钮可以拖到任意位置,位置会记住;面板底部有「回到右上角」一键复位。
|
|
27
|
+
|
|
28
|
+
| 分区 | 能调什么 |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| 背景画卷 | 亮/暗两种模式的背景图更换与复原 |
|
|
31
|
+
| 阅读清晰度 | 文字柔光开关 · 背景遮罩浓淡 · 面板实透 · 正文字号大小 |
|
|
32
|
+
| 界面琉璃 | 对话区宽度 · 面板磨砂底 |
|
|
33
|
+
| 毛玻璃虚化 | 总开关 · 插件窗/侧栏面板分开控制 · 虚化强度 0–30(0=关) |
|
|
34
|
+
| 剑气流光 | 开关 · 粒子数量 · 流动速度 |
|
|
35
|
+
| 复原 | 全部恢复默认 |
|
|
36
|
+
|
|
37
|
+
## 版本
|
|
38
|
+
|
|
39
|
+
各版本改动见 [CHANGELOG.md](CHANGELOG.md)。
|
|
40
|
+
|
|
41
|
+
## 安装
|
|
42
|
+
|
|
43
|
+
### 懒人版
|
|
44
|
+
|
|
45
|
+
直接对你的 DSH 说(桌面端、网页端都适用,会装进当前档案):
|
|
46
|
+
```
|
|
47
|
+
安装一下这个皮肤包:@taosee258/dsh-client-ui-skin-qingxiao
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 手动安装
|
|
51
|
+
|
|
52
|
+
**命令行安装**(任选其一;`--profile` 按目标填:桌面端 `desktop`、网页端 `web`):
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
# 方式 A(推荐):从 npm 安装
|
|
56
|
+
dsh plugin --profile desktop add @taosee258/dsh-client-ui-skin-qingxiao
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
# 方式 B:用 git URL 安装(始终对应仓库最新版)
|
|
61
|
+
dsh plugin --profile desktop add https://github.com/taoser258/dsh-client-ui-skin-qingxiao
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```sh
|
|
65
|
+
# 方式 C:先克隆到本地任意位置,再把实际路径交给 dsh
|
|
66
|
+
git clone https://github.com/taoser258/dsh-client-ui-skin-qingxiao.git
|
|
67
|
+
dsh plugin --profile desktop add /path/to/dsh-client-ui-skin-qingxiao
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**手动放置安装**:把本包整个文件夹复制到 DSH 的 `profiles/<档案名>/node_modules/@taosee258/dsh-client-ui-skin-qingxiao/` 下(桌面端档案为 `desktop`),然后在 profile 的 `cordis.patch.yml` 里追加一条(与本包自带的 `cordis.patch.yml` 保持一致):
|
|
71
|
+
|
|
72
|
+
```yaml
|
|
73
|
+
- insert:
|
|
74
|
+
- id: ui-skin-qingxiao
|
|
75
|
+
name: '@taosee258/dsh-client-ui-skin-qingxiao'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
重启 DSH 即可。
|
|
79
|
+
|
|
80
|
+
## 兼容性
|
|
81
|
+
|
|
82
|
+
- DSH Web / 桌面端:0.1.0-rc.6 至 0.2.0-rc.2
|
|
83
|
+
- 自 0.2.0 起针对官方桌面端 0.2.0-rc.2 深度适配:字号令牌新基准、顶栏毛玻璃横带与原生窗口按钮融合、插件/任务等整页视图毛玻璃背板、开关与徽章配色对齐
|
|
84
|
+
- 平台:Web / Windows 桌面端(设置保存在各自档案的 `data/` 目录下)
|
|
85
|
+
- 最近验证:2026-10-01(0.2.0-rc.2 桌面端亮/暗两态真机实测)
|
|
86
|
+
|
|
87
|
+
## 版权所有人
|
|
88
|
+
|
|
89
|
+
| 版权所有人 | 版权所有内容 |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Kuro Games(库洛游戏) | 「鸣潮」游戏作品及清宵(Qingxiao)角色形象原作 |
|
|
92
|
+
| Fumi(pixiv) | 默认背景插画(`assets/qx.jpg`)原作 |
|
|
93
|
+
| taoser | 皮肤实现(配色、毛玻璃、粒子装饰与界面逻辑) |
|
|
94
|
+
|
|
95
|
+
\*本皮肤为同人创作,与 Kuro Games 无关联。
|
|
96
|
+
|
|
97
|
+
## 署名与许可
|
|
98
|
+
|
|
99
|
+
- 默认背景插画来自 **pixiv 画师 Fumi** 的《鸣潮》清宵同人插画(`assets/qx.jpg`),角色设定与游戏内容版权归库洛游戏所有。本皮肤仅供个人美化学习使用,与官方无关,请勿商用。
|
|
100
|
+
- 插件代码与结构在 CC BY-NC-SA 4.0 下发布,请勿用于商业用途。
|
package/lib/client.js
CHANGED
|
@@ -13,7 +13,7 @@ window.__ModuleLoader__.load({
|
|
|
13
13
|
|
|
14
14
|
var SKIN_OWNER = "qingxiao";
|
|
15
15
|
// 与 package.json 的 version 保持一致(面板页脚会展示)。
|
|
16
|
-
var SKIN_VERSION = "0.
|
|
16
|
+
var SKIN_VERSION = "0.2.3";
|
|
17
17
|
var SKIN_TITLE = "清宵 · DeepSeek Harness";
|
|
18
18
|
var SKIN_SYSTEM_CHROME_COLOR_LIGHT = "#EEF7FB";
|
|
19
19
|
var SKIN_SYSTEM_CHROME_COLOR_DARK = "#0B1E2E";
|
|
@@ -30,67 +30,82 @@ window.__ModuleLoader__.load({
|
|
|
30
30
|
];
|
|
31
31
|
|
|
32
32
|
// ── 正文字号缩放:DSH markdown 字体令牌表 ──
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
33
|
+
// 基准取自 @deepseek-ai/dsh-client-ui-theme 0.2.0-rc.2 的令牌定义:
|
|
34
|
+
// base 系 : var(--dsh-content-font-size, 14px) / calc(24px + delta)
|
|
35
|
+
// h1/h2/h3 : (21/19/18px + delta) / (30/28/26px + delta)
|
|
36
|
+
// small 系 : 12px / 20px
|
|
37
|
+
// table 系 : var(--dsh-content-font-size-secondary, 13px) / calc(22px + delta2)
|
|
38
|
+
// code 系 : 12/19 · 11/19 · 11/16
|
|
39
|
+
// delta 是官方设置里的正文字号偏移(--dsh-content-font-delta,body 上
|
|
40
|
+
// 定义为 calc(内容字号 - 14px))。缩放把整个表达式乘上 S,官方偏移在皮肤
|
|
41
|
+
// 缩放下继续生效;100% 时与官方令牌逐字节一致。
|
|
42
|
+
// 每项:[名, 字重("" = 不写), 是否斜体, 字族, 字号表达式, 行高表达式],
|
|
43
|
+
// 表达式里的 $S 生成时替换为缩放字面量(如 1.05),再整体包进 calc()。
|
|
44
|
+
// calc 包 var 的写法与官方令牌同构(官方 shorthand 本就带 calc+var);
|
|
45
|
+
// 不要退回纯 px 字面量——那会把官方的字号偏移一并抹掉。
|
|
46
|
+
var QX_DELTA = "var(--dsh-content-font-delta, 0px)";
|
|
47
|
+
var QX_DELTA_2 = "var(--dsh-content-font-delta-secondary, 0px)";
|
|
48
|
+
var QX_CONTENT_SIZE = "var(--dsh-content-font-size, 14px)";
|
|
49
|
+
var QX_CONTENT_SIZE_2 = "var(--dsh-content-font-size-secondary, 13px)";
|
|
37
50
|
var QX_FONT_TOKENS = [
|
|
38
|
-
["base",
|
|
39
|
-
["base-strong",
|
|
40
|
-
["base-italic",
|
|
41
|
-
["base-strong-italic",
|
|
42
|
-
["h1",
|
|
43
|
-
["h2",
|
|
44
|
-
["h3",
|
|
45
|
-
["h4",
|
|
46
|
-
["small",
|
|
47
|
-
["small-strong",
|
|
48
|
-
["small-italic",
|
|
49
|
-
["small-strong-italic",
|
|
50
|
-
["table",
|
|
51
|
-
["table-head",
|
|
52
|
-
["code",
|
|
53
|
-
["code-block",
|
|
54
|
-
["code-block-small",
|
|
51
|
+
["base", "", false, "text", QX_CONTENT_SIZE + " * $S", "(24px + " + QX_DELTA + ") * $S"],
|
|
52
|
+
["base-strong", "600", false, "text", QX_CONTENT_SIZE + " * $S", "(24px + " + QX_DELTA + ") * $S"],
|
|
53
|
+
["base-italic", "", true, "text", QX_CONTENT_SIZE + " * $S", "(24px + " + QX_DELTA + ") * $S"],
|
|
54
|
+
["base-strong-italic", "600", true, "text", QX_CONTENT_SIZE + " * $S", "(24px + " + QX_DELTA + ") * $S"],
|
|
55
|
+
["h1", "700", false, "text", "(21px + " + QX_DELTA + ") * $S", "(30px + " + QX_DELTA + ") * $S"],
|
|
56
|
+
["h2", "700", false, "text", "(19px + " + QX_DELTA + ") * $S", "(28px + " + QX_DELTA + ") * $S"],
|
|
57
|
+
["h3", "700", false, "text", "(18px + " + QX_DELTA + ") * $S", "(26px + " + QX_DELTA + ") * $S"],
|
|
58
|
+
["h4", "600", false, "text", QX_CONTENT_SIZE + " * $S", "(24px + " + QX_DELTA + ") * $S"],
|
|
59
|
+
["small", "", false, "text", "12px * $S", "20px * $S"],
|
|
60
|
+
["small-strong", "600", false, "text", "12px * $S", "20px * $S"],
|
|
61
|
+
["small-italic", "", true, "text", "12px * $S", "20px * $S"],
|
|
62
|
+
["small-strong-italic", "600", true, "text", "12px * $S", "20px * $S"],
|
|
63
|
+
["table", "", false, "text", QX_CONTENT_SIZE_2 + " * $S", "(22px + " + QX_DELTA_2 + ") * $S"],
|
|
64
|
+
["table-head", "500", false, "text", QX_CONTENT_SIZE_2 + " * $S", "(22px + " + QX_DELTA_2 + ") * $S"],
|
|
65
|
+
["code", "", false, "code", "12px * $S", "19px * $S"],
|
|
66
|
+
["code-block", "", false, "code", "11px * $S", "19px * $S"],
|
|
67
|
+
["code-block-small", "", false, "code", "11px * $S", "16px * $S"]
|
|
55
68
|
];
|
|
56
|
-
var QX_FONT_SCOPE = "body[data-dsh-qingxiao] :is([data-slot='conversation'], [data-conversation-scroll])";
|
|
69
|
+
var QX_FONT_SCOPE = "body[data-dsh-qingxiao] :is([data-slot='main.conversation'], [data-slot='conversation'], [data-conversation-scroll])";
|
|
57
70
|
|
|
58
71
|
function qxPx(value) {
|
|
59
72
|
return Math.round(value * 100) / 100;
|
|
60
73
|
}
|
|
61
74
|
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
75
|
+
// 生成字号缩放表:基准表达式乘缩放字面量后包进 calc(),var()/delta 原样
|
|
76
|
+
// 保留,这样 DSH 的 font:var(--dsw-font-markdown-*) 正常解析且官方字号
|
|
77
|
+
// 偏移不被抹掉。同时补一组 font-size/line-height 长属性兜底:万一 DSH
|
|
78
|
+
// 改了令牌名,正文仍然会跟着缩放,且 calc 值在嵌套 markdown 里不会二次放大。
|
|
66
79
|
function buildFontScaleCss(scale) {
|
|
67
80
|
var decls = [];
|
|
68
81
|
var out = {};
|
|
82
|
+
var s = qxPx(scale);
|
|
69
83
|
QX_FONT_TOKENS.forEach(function(spec) {
|
|
70
84
|
var name = spec[0];
|
|
71
|
-
var
|
|
72
|
-
var
|
|
73
|
-
var
|
|
74
|
-
var
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
decls.push("--dsw-font-markdown-" + name + "
|
|
78
|
-
decls.push("--dsw-font-markdown-" + name + "-
|
|
85
|
+
var weight = spec[1];
|
|
86
|
+
var italic = spec[2];
|
|
87
|
+
var family = spec[3] === "code" ? "var(--ds-font-family-code)" : "var(--dsw-font-family)";
|
|
88
|
+
var size = "calc(" + spec[4].replace("$S", String(s)) + ")";
|
|
89
|
+
var line = "calc(" + spec[5].replace("$S", String(s)) + ")";
|
|
90
|
+
out[name] = { size: size, line: line };
|
|
91
|
+
decls.push("--dsw-font-markdown-" + name + ": " + (italic ? "italic " : "") + (weight ? weight + " " : "") + size + "/" + line + " " + family + ";");
|
|
92
|
+
decls.push("--dsw-font-markdown-" + name + "-font-size: " + size + ";");
|
|
93
|
+
decls.push("--dsw-font-markdown-" + name + "-line-height: " + line + ";");
|
|
79
94
|
});
|
|
80
|
-
var css = QX_FONT_SCOPE + "{--qx-font-scale:" +
|
|
81
|
-
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown']{font-size:" + out.base
|
|
95
|
+
var css = QX_FONT_SCOPE + "{--qx-font-scale:" + s + ";\n" + decls.join("\n") + "\n}";
|
|
96
|
+
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown']{font-size:" + out.base.size + ";line-height:" + out.base.line + ";}";
|
|
82
97
|
["h1", "h2", "h3"].forEach(function(h) {
|
|
83
|
-
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] " + h + "{font-size:" + out[h]
|
|
98
|
+
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] " + h + "{font-size:" + out[h].size + ";line-height:" + out[h].line + ";}";
|
|
84
99
|
});
|
|
85
|
-
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] :is(h4,h5,h6){font-size:" + out
|
|
86
|
-
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] :is(th,td){font-size:" + out.table
|
|
100
|
+
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] :is(h4,h5,h6){font-size:" + out.base.size + ";line-height:" + out.base.line + ";}";
|
|
101
|
+
css += "\n" + QX_FONT_SCOPE + " [class*='_markdown'] :is(th,td){font-size:" + out.table.size + ";line-height:" + out.table.line + ";}";
|
|
87
102
|
return css;
|
|
88
103
|
}
|
|
89
104
|
|
|
90
105
|
// 实测对话正文当前的像素字号:给面板做自校验用。
|
|
91
106
|
function measureConversationFont() {
|
|
92
107
|
var el = document.querySelector("[data-conversation-scroll] [class*='_markdown']")
|
|
93
|
-
|| document.querySelector("[data-slot='conversation'] [class*='_markdown']");
|
|
108
|
+
|| document.querySelector(":is([data-slot='main.conversation'], [data-slot='conversation']) [class*='_markdown']");
|
|
94
109
|
if (!el || typeof getComputedStyle !== "function") return null;
|
|
95
110
|
var size = parseFloat(getComputedStyle(el).fontSize);
|
|
96
111
|
return isFinite(size) ? Math.round(size * 100) / 100 : null;
|
|
@@ -112,7 +127,7 @@ window.__ModuleLoader__.load({
|
|
|
112
127
|
scrimOpacity: 55,
|
|
113
128
|
panelOpacity: 45,
|
|
114
129
|
contentWidth: 880,
|
|
115
|
-
particleCount:
|
|
130
|
+
particleCount: 25,
|
|
116
131
|
particleSpeed: 100,
|
|
117
132
|
fontScale: 100,
|
|
118
133
|
frostMaster: true,
|
|
@@ -199,6 +214,14 @@ body[data-dsh-qingxiao][data-ds-dark-theme] {
|
|
|
199
214
|
与皮肤配色统一,也避免黑底突兀。文本仍走皮肤深色,够清晰。 */
|
|
200
215
|
--dsw-alias-button-primary-fill: #2E9E98;
|
|
201
216
|
--dsw-alias-button-primary-hover: #26837E;
|
|
217
|
+
/* 主按钮文字:0.2.0 的按钮类用 --dsw-alias-label-primary-foreground 取字色,
|
|
218
|
+
皮肤的全局按钮墨色规则把它压掉了(青碧底配深墨字,发闷)。这里统一
|
|
219
|
+
回月白:青碧底 + 月白字,亮暗两态都干净。 */
|
|
220
|
+
--dsw-alias-label-primary-foreground: #F4F9FC;
|
|
221
|
+
/* 品牌主色:DSH 把它定义成反色墨/白(亮色模式近黑、暗色模式近白),
|
|
222
|
+
开关 ON 轨道和复选框 accent 都读它——暗色下开关全是白轨,与皮肤不搭。
|
|
223
|
+
改为清宵青碧后一并对齐;ON 旋钮走上面的月白,正好是青碧底月白钮。 */
|
|
224
|
+
--dsw-alias-brand-primary: #2E9E98;
|
|
202
225
|
}
|
|
203
226
|
/* 对话区淡灰字(用户反馈):DSH 的次级/三级标签令牌在画卷底上太淡
|
|
204
227
|
(浅色 #61666b/#81858c 的工具行标题、时间戳、卡片描述灰成一片)。
|
|
@@ -207,10 +230,14 @@ body[data-dsh-qingxiao][data-ds-dark-theme] {
|
|
|
207
230
|
body[data-dsh-qingxiao]:not([data-ds-dark-theme]) {
|
|
208
231
|
--dsw-alias-label-secondary: #232d36;
|
|
209
232
|
--dsw-alias-label-tertiary: #3a4550;
|
|
233
|
+
/* 业务信息色:DSH 用 DeepSeek 蓝,信息标签(「实验性」徽章)、
|
|
234
|
+
输入聚焦边框等都读它,改成清宵青碧深色调。 */
|
|
235
|
+
--dsw-alias-state-business-primary: #1F7E86;
|
|
210
236
|
}
|
|
211
237
|
body[data-dsh-qingxiao][data-ds-dark-theme] {
|
|
212
238
|
--dsw-alias-label-secondary: #dde1e5;
|
|
213
239
|
--dsw-alias-label-tertiary: #c4cad1;
|
|
240
|
+
--dsw-alias-state-business-primary: #7FE0D6;
|
|
214
241
|
}
|
|
215
242
|
body[data-dsh-qingxiao] [id=root] {
|
|
216
243
|
background: transparent;
|
|
@@ -286,10 +313,13 @@ body[data-dsh-qingxiao] [class*='sidebarCol'] {
|
|
|
286
313
|
的 ::after 伪元素上,且用 z-index:-1 垫在半透明面板之下、正文之上;
|
|
287
314
|
::after 不包含任何 portal,所以不困浮层,正文也保持清晰,只有底下的
|
|
288
315
|
画卷被磨砂。 */
|
|
289
|
-
|
|
316
|
+
/* 0.2.0-rc.2 起布局把旧 detailsCol 更名为 rightbarCol(CSS Modules 前缀
|
|
317
|
+
BynINW_,类名本体仍含列名后缀,子串匹配不受影响);detailsCol 选择器保留
|
|
318
|
+
兼容旧版布局。 */
|
|
319
|
+
body[data-dsh-qingxiao][data-qx-blur='on']:not([data-qx-frost='off']) :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='_centerCol'], [class*='detailsCol'], [class*='rightbarCol']) {
|
|
290
320
|
position: relative;
|
|
291
321
|
}
|
|
292
|
-
body[data-dsh-qingxiao][data-qx-blur='on']:not([data-qx-frost='off']) :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='_centerCol'], [class*='detailsCol'])::after {
|
|
322
|
+
body[data-dsh-qingxiao][data-qx-blur='on']:not([data-qx-frost='off']) :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='_centerCol'], [class*='detailsCol'], [class*='rightbarCol'])::after {
|
|
293
323
|
content: "";
|
|
294
324
|
position: absolute;
|
|
295
325
|
inset: 0;
|
|
@@ -299,7 +329,8 @@ body[data-dsh-qingxiao][data-qx-blur='on']:not([data-qx-frost='off']) :is([data-
|
|
|
299
329
|
-webkit-backdrop-filter: blur(5px) saturate(1.1);
|
|
300
330
|
}
|
|
301
331
|
body[data-dsh-qingxiao] [class*='_centerCol'],
|
|
302
|
-
body[data-dsh-qingxiao] [class*='detailsCol']
|
|
332
|
+
body[data-dsh-qingxiao] [class*='detailsCol'],
|
|
333
|
+
body[data-dsh-qingxiao] [class*='rightbarCol'] {
|
|
303
334
|
background: rgba(var(--qx-panel-rgb), calc(var(--qx-panel-alpha) * 0.72));
|
|
304
335
|
}
|
|
305
336
|
body[data-dsh-qingxiao] [class*='_centerCol'] > * {
|
|
@@ -310,9 +341,10 @@ body[data-dsh-qingxiao] [class*='_centerCol'] > * {
|
|
|
310
341
|
}
|
|
311
342
|
/* ── 对话区宽度 + 正文字号缩放:接到真正的对话内容上 ──
|
|
312
343
|
旧选择器只作用于 centerCol 的直接子元素,没命中更深的对话内容,所以
|
|
313
|
-
拖这两个滑块没反应。对话内容在 [data-slot='conversation'] >
|
|
314
|
-
|
|
315
|
-
|
|
344
|
+
拖这两个滑块没反应。对话内容在 [data-slot='main.conversation'] > *
|
|
345
|
+
(0.1.x 为 [data-slot='conversation'],滚动容器 [data-conversation-scroll]
|
|
346
|
+
两代同名),正文用 [data-conversation-scroll] 定位。 */
|
|
347
|
+
body[data-dsh-qingxiao] :is([data-slot='main.conversation'], [data-slot='conversation']) > * {
|
|
316
348
|
/* DSH 的对话列宽走 --dsh-chat-content-width(正文列、输入卡、表格溢出都读它),
|
|
317
349
|
只在容器上写 max-width 到 748px 就被 DSH 自己的令牌卡住,所以这里一并覆盖。 */
|
|
318
350
|
--dsh-chat-content-width: var(--qx-content-width);
|
|
@@ -374,10 +406,13 @@ body[data-dsh-qingxiao][data-qx-charms='on'] :is([data-pane='sidebar'], [class*=
|
|
|
374
406
|
radial-gradient(120% 90% at 50% 128%, rgba(var(--qx-cyan-rgb), 0.18), transparent 62%),
|
|
375
407
|
radial-gradient(60% 40% at 18% 118%, rgba(var(--qx-gold-rgb), 0.16), transparent 70%);
|
|
376
408
|
}
|
|
377
|
-
|
|
409
|
+
/* 0.1.x 侧栏根带 data-dsh-sidebar-root;0.2.0-rc.2 起该属性取消,侧栏根只剩
|
|
410
|
+
CSS Modules 哈希类(*_root),只能用 [class*='sidebarCol'] [class*='_root']
|
|
411
|
+
在栏内定位——conversation 的 *_root 不在 sidebarCol 内,不会误伤。 */
|
|
412
|
+
body[data-dsh-qingxiao][data-qx-charms='on'] :is([data-dsh-sidebar-root], [class*='sidebarCol'] [class*='_root']) {
|
|
378
413
|
position: relative;
|
|
379
414
|
}
|
|
380
|
-
body[data-dsh-qingxiao][data-qx-charms='on'] [data-dsh-sidebar-root]::after {
|
|
415
|
+
body[data-dsh-qingxiao][data-qx-charms='on'] :is([data-dsh-sidebar-root], [class*='sidebarCol'] [class*='_root'])::after {
|
|
381
416
|
content: "";
|
|
382
417
|
position: absolute;
|
|
383
418
|
inset: auto 0 0 0;
|
|
@@ -886,7 +921,8 @@ body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-plugin='on'] .qx-frost
|
|
|
886
921
|
/* 3) 原生面板虚化:左侧会话栏 + 右侧详情栏 + 图二文件面板(better-sidebar)。
|
|
887
922
|
CSS Modules 前缀是构建哈希,只能用 [class*='后缀'] 子串匹配;
|
|
888
923
|
_centerCol(对话正文列)与 _frame 绝不要碰。
|
|
889
|
-
detailsCol
|
|
924
|
+
detailsCol 是旧版布局的右详情列,0.2.0-rc.2 更名 rightbarCol,两条并列;
|
|
925
|
+
它们自身是 static,补 position:relative 让伪元素锚定在本列——
|
|
890
926
|
relative 不产生 fixed 包含块,弹窗照样铺得开(v0.1.2 塌缩教训)。
|
|
891
927
|
文件面板并不在 detailsCol 内(t7 纠正 t1 §1 的错误前提):它是
|
|
892
928
|
div[data-dsh-panel](position:absolute、z=40,底色 --dsw-alias-bg-layer-1
|
|
@@ -906,10 +942,10 @@ body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-plugin='on'] .qx-frost
|
|
|
906
942
|
与旧「面板磨砂玻璃」共用 ::after:两列那条与旧规则同特异度 (0,4,2),
|
|
907
943
|
靠本块在 THEME_CSS 里排在后面取胜;面板这条独立成 (0,5,2)。
|
|
908
944
|
同开时由虚化强度接管,不会叠成两层模糊。 */
|
|
909
|
-
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='detailsCol']) {
|
|
945
|
+
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='detailsCol'], [class*='rightbarCol']) {
|
|
910
946
|
position: relative;
|
|
911
947
|
}
|
|
912
|
-
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='detailsCol'])::after,
|
|
948
|
+
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] :is([data-pane='sidebar'], [class*='sidebarCol'], [class*='detailsCol'], [class*='rightbarCol'])::after,
|
|
913
949
|
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] [data-dsh-panel-host] > [data-dsh-panel]::after,
|
|
914
950
|
body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] [data-dsh-panel-host] > [data-dsh-bottom-panel]::after {
|
|
915
951
|
content: "";
|
|
@@ -925,10 +961,10 @@ body[data-dsh-qingxiao][data-qx-frost='on'][data-qx-frost-native='on'] [data-dsh
|
|
|
925
961
|
增强只挑 p/li/td,而面板与列表文字几乎全是 span/div,等于没管到。
|
|
926
962
|
浅色白晕托深色字,暗色墨晕衬亮字;底色一丝未动,纯字体处理。
|
|
927
963
|
挂在既有的「文字对比度增强」开关下(默认 on),调色盘可关。 */
|
|
928
|
-
body[data-dsh-qingxiao][data-qx-contrast='on']:not([data-ds-dark-theme]) :is(.qx-frost, [class*='sidebarCol'], [class*='detailsCol'], [data-dsh-panel], [data-dsh-bottom-panel]) {
|
|
964
|
+
body[data-dsh-qingxiao][data-qx-contrast='on']:not([data-ds-dark-theme]) :is(.qx-frost, [class*='sidebarCol'], [class*='detailsCol'], [class*='rightbarCol'], [data-dsh-panel], [data-dsh-bottom-panel]) {
|
|
929
965
|
text-shadow: 0 0 1px rgba(255, 255, 255, 0.95), 0 0 3px rgba(255, 255, 255, 0.7), 0 0 6px rgba(255, 255, 255, 0.4);
|
|
930
966
|
}
|
|
931
|
-
body[data-dsh-qingxiao][data-qx-contrast='on'][data-ds-dark-theme] :is(.qx-frost, [class*='sidebarCol'], [class*='detailsCol'], [data-dsh-panel], [data-dsh-bottom-panel]) {
|
|
967
|
+
body[data-dsh-qingxiao][data-qx-contrast='on'][data-ds-dark-theme] :is(.qx-frost, [class*='sidebarCol'], [class*='detailsCol'], [class*='rightbarCol'], [data-dsh-panel], [data-dsh-bottom-panel]) {
|
|
932
968
|
text-shadow: 0 0 1px rgba(2, 8, 14, 0.9), 0 0 3px rgba(2, 8, 14, 0.6), 0 0 6px rgba(2, 8, 14, 0.35);
|
|
933
969
|
}
|
|
934
970
|
/* 5) 对话/设置弹窗背板(用户:设置页字看不清):弹窗结构是 fixed 满视口
|
|
@@ -946,6 +982,80 @@ body[data-dsh-qingxiao]:not([data-ds-dark-theme]) [role='dialog'] {
|
|
|
946
982
|
body[data-dsh-qingxiao][data-ds-dark-theme] [role='dialog'] {
|
|
947
983
|
background: rgba(var(--qx-panel-rgb), 0.74);
|
|
948
984
|
}
|
|
985
|
+
|
|
986
|
+
/* ── 0.2.0 桌面端标题栏:毛玻璃横带 + 消除原生按钮色块 ──
|
|
987
|
+
html[data-windows-titlebar] 下,框架::before 是整条拖拽横带(应用/编辑
|
|
988
|
+
菜单与窗口控件都浮在上面),中列另被卡片化(16px 圆角)——画卷在顶栏处
|
|
989
|
+
被切成一条与下方内容分层异色的横带。这里:
|
|
990
|
+
1) 横带改为面板色玻璃底 + 毛玻璃虚化(虚化受「毛玻璃虚化」总开关控制),
|
|
991
|
+
与侧栏玻璃同源,顶部与下方内容连贯;
|
|
992
|
+
2) 中列卡片圆角取消;
|
|
993
|
+
3) 窗口控制按钮的原生实心底色来自 Electron titleBarOverlay(OS 级绘制,
|
|
994
|
+
CSS 画不到,且不接受透明度——皮肤原先的半透明 sidebar-fill 被拆成
|
|
995
|
+
不透明色块,就是按钮后面那块补丁)。preload 会测量一个读
|
|
996
|
+
var(--dsw-specific-sidebar-fill) 的隐藏探针元素并经 IPC 发给
|
|
997
|
+
setTitleBarOverlay;皮肤用 !important 把探针背景压成全透明(探针是
|
|
998
|
+
body 下唯一内联引用该令牌的 span,!important 可压过内联样式),preload
|
|
999
|
+
读到 rgba(0,0,0,0) 后 overlay 即变透明,三个窗口按钮成为浮在玻璃
|
|
1000
|
+
横带上的纯符号。 */
|
|
1001
|
+
html[data-windows-titlebar] body[data-dsh-qingxiao] [class*='_frame']::before {
|
|
1002
|
+
background: rgba(var(--qx-panel-rgb), calc(var(--qx-panel-alpha) * 0.9));
|
|
1003
|
+
}
|
|
1004
|
+
html[data-windows-titlebar] body[data-dsh-qingxiao][data-qx-frost='on'] [class*='_frame']::before {
|
|
1005
|
+
backdrop-filter: blur(var(--qx-frost-blur)) saturate(1.12);
|
|
1006
|
+
-webkit-backdrop-filter: blur(var(--qx-frost-blur)) saturate(1.12);
|
|
1007
|
+
}
|
|
1008
|
+
html[data-windows-titlebar] body[data-dsh-qingxiao] [class*='_centerCol'] {
|
|
1009
|
+
border-radius: 0;
|
|
1010
|
+
}
|
|
1011
|
+
body[data-dsh-qingxiao] > span[style*='--dsw-specific-sidebar-fill'] {
|
|
1012
|
+
background-color: transparent !important;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
/* ── 整页视图毛玻璃背板(插件 / 自动化任务等 _page 页面)──
|
|
1016
|
+
0.2.0 的插件页、自动化任务页等整页视图是 [data-slot='main'] 下的
|
|
1017
|
+
SECTION[class*='_page'],直接铺在画卷上,文字没有任何垫底(浅色模式下
|
|
1018
|
+
尤其糊)。两层处理:
|
|
1019
|
+
1) 半透明面板底写在 _page 自身——它是滚动容器,元素背景不随内容滚动,
|
|
1020
|
+
常驻生效,不依赖任何开关;
|
|
1021
|
+
2) 毛玻璃虚化挂在其非滚动父层 [data-slot='main'] 的 ::before 上(页面
|
|
1022
|
+
容器自身滚动,伪元素挂它身上会被卷走)。:has 限定只有 _page 视图才
|
|
1023
|
+
挂,不碰会话区;position+z-index:0 让 main 自成层叠上下文,-1 伪元素
|
|
1024
|
+
落在 main 内容之下、画卷之上;backdrop-filter 只在伪元素上,无后代、
|
|
1025
|
+
不困浮层。虚化受「毛玻璃虚化」总开关控制(默认开),底色不受。
|
|
1026
|
+
背板必须用 > 直接子选择器:裸 [class*='_page'] 会连 pageTitle/pageHead
|
|
1027
|
+
这类类名一起命中,背板叠背板会浮出一块块白芯片。 */
|
|
1028
|
+
body[data-dsh-qingxiao] [data-slot='main'] > [class*='_page'] {
|
|
1029
|
+
background: rgba(var(--qx-panel-rgb), calc(var(--qx-panel-alpha) * 0.88));
|
|
1030
|
+
}
|
|
1031
|
+
body[data-dsh-qingxiao][data-qx-frost='on'] [data-slot='main']:has(> [class*='_page']) {
|
|
1032
|
+
position: relative;
|
|
1033
|
+
z-index: 0;
|
|
1034
|
+
}
|
|
1035
|
+
body[data-dsh-qingxiao][data-qx-frost='on'] [data-slot='main']:has(> [class*='_page'])::before {
|
|
1036
|
+
content: "";
|
|
1037
|
+
position: absolute;
|
|
1038
|
+
inset: 0;
|
|
1039
|
+
z-index: -1;
|
|
1040
|
+
pointer-events: none;
|
|
1041
|
+
backdrop-filter: blur(var(--qx-frost-blur)) saturate(1.12);
|
|
1042
|
+
-webkit-backdrop-filter: blur(var(--qx-frost-blur)) saturate(1.12);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
/* ── 主按钮文字颜色还原 ──
|
|
1046
|
+
全局按钮墨色规则 (0,2,2) 会盖掉按钮类的
|
|
1047
|
+
var(--dsw-alias-label-primary-foreground)(0,2,0),青碧主按钮的字被涂成
|
|
1048
|
+
深墨、发闷。用 (0,3,2) 还回令牌;令牌值已在上面统一为月白。 */
|
|
1049
|
+
body[data-dsh-qingxiao] [id=root] button[class*='_primary'] {
|
|
1050
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
/* ── markdown 任务复选框 ──
|
|
1054
|
+
DSH 把对话里任务列表的勾选框 accent 设成了次级灰,勾上后灰扑扑的;
|
|
1055
|
+
对齐到品牌主色(上面已改为清宵青碧),与整页勾选控件一致。 */
|
|
1056
|
+
body[data-dsh-qingxiao] [id=root] [class*='_markdown'] input[type='checkbox'] {
|
|
1057
|
+
accent-color: var(--dsw-alias-brand-primary);
|
|
1058
|
+
}
|
|
949
1059
|
`;
|
|
950
1060
|
|
|
951
1061
|
// ═══════════════════════════════════════════════════════════════
|
|
@@ -1606,7 +1716,8 @@ body[data-dsh-qingxiao][data-ds-dark-theme] [role='dialog'] {
|
|
|
1606
1716
|
'<div class="qx-hero-quote">「徒儿,你来了……」</div>';
|
|
1607
1717
|
body.append(heroWelcome);
|
|
1608
1718
|
function syncHeroWelcome() {
|
|
1609
|
-
|
|
1719
|
+
// 0.2.0-rc.2 起会话槽位改名为 main.conversation(0.1.x 为 conversation)。
|
|
1720
|
+
var root = document.querySelector(":is([data-slot='main.conversation'], [data-slot='conversation']) > *");
|
|
1610
1721
|
var on = !!(root && root.getAttribute("data-phase") === "hero");
|
|
1611
1722
|
heroWelcome.dataset.on = on ? "true" : "false";
|
|
1612
1723
|
}
|
|
@@ -1684,7 +1795,9 @@ body[data-dsh-qingxiao][data-ds-dark-theme] [role='dialog'] {
|
|
|
1684
1795
|
// 侧栏/对话区就摘标(慢挂载的 frame 也能兜住)。
|
|
1685
1796
|
var unfrostIfApp = function() {
|
|
1686
1797
|
if (disposed) return; // t4/t5 nit:HMR 重挂后旧实例的迟到复查不得摘新实例刚打的标(摘标是 class 变化,childList-only 观察器看不见)
|
|
1687
|
-
|
|
1798
|
+
// 0.2.0-rc.2 起侧栏根不再带 data-dsh-sidebar-root:改认布局列
|
|
1799
|
+
// [class*='sidebarCol'](应用主框必含布局列,插件窗不含)。
|
|
1800
|
+
if (el.isConnected && el.querySelector("[data-conversation-scroll], [class*='sidebarCol']")) {
|
|
1688
1801
|
el.classList.remove(QX_FROST_CLASS, QX_FROST_SOLID);
|
|
1689
1802
|
}
|
|
1690
1803
|
};
|
package/lib/index.js
CHANGED
|
@@ -1,178 +1,190 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
|
|
6
|
-
const name = "@taosee258/dsh-client-ui-skin-qingxiao";
|
|
7
|
-
const inject = ["webServer"];
|
|
8
|
-
const SETTINGS_ROUTE = "/api/dsh-qingxiao/settings";
|
|
9
|
-
const DEFAULT_BG_ROUTE = "/api/dsh-qingxiao/default-background";
|
|
10
|
-
const SETTINGS_DIR = "dsh-client-ui-skin-qingxiao";
|
|
11
|
-
const SETTINGS_FILE = "settings.json";
|
|
12
|
-
const DEFAULT_BG_FILE = fileURLToPath(new URL("../assets/qx.jpg", import.meta.url));
|
|
13
|
-
const MAX_BODY_BYTES = 15 * 1024 * 1024;
|
|
14
|
-
const MAX_BACKGROUND_BYTES = 7 * 1024 * 1024;
|
|
15
|
-
|
|
16
|
-
const BOOLEAN_KEYS = [
|
|
17
|
-
"textContrastBoost", "panelBlur", "goldTrim",
|
|
18
|
-
"particles", "lightCharms", "darkCharms",
|
|
19
|
-
// v0.1.4 毛玻璃虚化:总开关 + 插件窗/原生面板两个分项
|
|
20
|
-
"frostMaster", "frostPlugin", "frostNative"
|
|
21
|
-
];
|
|
22
|
-
const NUMBER_RANGES = {
|
|
23
|
-
scrimOpacity: [20, 95],
|
|
24
|
-
panelOpacity: [30, 100],
|
|
25
|
-
contentWidth: [500, 1000],
|
|
26
|
-
particleCount: [0, 60],
|
|
27
|
-
particleSpeed: [20, 200],
|
|
28
|
-
fontScale: [85, 125],
|
|
29
|
-
// 虚化强度 0–30px(0 = 关闭等效,前端把 0 视作总开关 off)
|
|
30
|
-
frostBlur: [0, 30]
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
function profileName() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const path = settingsPath();
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { isAbsolute, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const name = "@taosee258/dsh-client-ui-skin-qingxiao";
|
|
7
|
+
const inject = ["webServer"];
|
|
8
|
+
const SETTINGS_ROUTE = "/api/dsh-qingxiao/settings";
|
|
9
|
+
const DEFAULT_BG_ROUTE = "/api/dsh-qingxiao/default-background";
|
|
10
|
+
const SETTINGS_DIR = "dsh-client-ui-skin-qingxiao";
|
|
11
|
+
const SETTINGS_FILE = "settings.json";
|
|
12
|
+
const DEFAULT_BG_FILE = fileURLToPath(new URL("../assets/qx.jpg", import.meta.url));
|
|
13
|
+
const MAX_BODY_BYTES = 15 * 1024 * 1024;
|
|
14
|
+
const MAX_BACKGROUND_BYTES = 7 * 1024 * 1024;
|
|
15
|
+
|
|
16
|
+
const BOOLEAN_KEYS = [
|
|
17
|
+
"textContrastBoost", "panelBlur", "goldTrim",
|
|
18
|
+
"particles", "lightCharms", "darkCharms",
|
|
19
|
+
// v0.1.4 毛玻璃虚化:总开关 + 插件窗/原生面板两个分项
|
|
20
|
+
"frostMaster", "frostPlugin", "frostNative"
|
|
21
|
+
];
|
|
22
|
+
const NUMBER_RANGES = {
|
|
23
|
+
scrimOpacity: [20, 95],
|
|
24
|
+
panelOpacity: [30, 100],
|
|
25
|
+
contentWidth: [500, 1000],
|
|
26
|
+
particleCount: [0, 60],
|
|
27
|
+
particleSpeed: [20, 200],
|
|
28
|
+
fontScale: [85, 125],
|
|
29
|
+
// 虚化强度 0–30px(0 = 关闭等效,前端把 0 视作总开关 off)
|
|
30
|
+
frostBlur: [0, 30]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function profileName() {
|
|
34
|
+
// 0.1.x 桌面端主进程注入 DSH_DESKTOP_PROFILE;0.2.0 起改用 dsh 统一的
|
|
35
|
+
// DSH_PROFILE / DSH_PROFILE_DIR(SKILL.md 所载),主进程自身不再注入名字,
|
|
36
|
+
// 而是把档案固定为 profiles/desktop(app.asar 里 resolveDesktopPaths 的
|
|
37
|
+
// join(dshHome, "profiles", "desktop"))。按新→旧顺序解析。
|
|
38
|
+
const profile = process.env.DSH_PROFILE || process.env.DSH_DESKTOP_PROFILE;
|
|
39
|
+
return profile && /^[A-Za-z0-9_-]+$/.test(profile) ? profile : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function profileDir() {
|
|
43
|
+
const home = process.env.DSH_HOME || join(homedir(), ".dsh");
|
|
44
|
+
const direct = process.env.DSH_PROFILE_DIR;
|
|
45
|
+
if (direct && isAbsolute(direct)) return direct;
|
|
46
|
+
const name = profileName();
|
|
47
|
+
if (name) return join(home, "profiles", name);
|
|
48
|
+
// 0.2.0 桌面端不给插件进程留 profile 环境变量:desktop 目录存在即视为桌面端。
|
|
49
|
+
const desktop = join(home, "profiles", "desktop");
|
|
50
|
+
if (existsSync(desktop)) return desktop;
|
|
51
|
+
return join(home, "profiles", "web");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function settingsPath() {
|
|
55
|
+
return join(profileDir(), "data", SETTINGS_DIR, SETTINGS_FILE);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function isLoopback(req) {
|
|
59
|
+
const address = req.socket && req.socket.remoteAddress;
|
|
60
|
+
return address === "127.0.0.1" || address === "::1" || address === "::ffff:127.0.0.1";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function sendJson(res, status, value) {
|
|
64
|
+
const data = Buffer.from(JSON.stringify(value), "utf8");
|
|
65
|
+
res.writeHead(status, {
|
|
66
|
+
"content-type": "application/json; charset=utf-8",
|
|
67
|
+
"cache-control": "no-store",
|
|
68
|
+
"content-length": String(data.length)
|
|
69
|
+
});
|
|
70
|
+
res.end(data);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function isBackground(value) {
|
|
74
|
+
if (value === null) return true;
|
|
75
|
+
return typeof value === "string" && /^data:image\/(?:png|jpe?g|webp|gif);base64,/i.test(value) && Buffer.byteLength(value, "utf8") <= MAX_BACKGROUND_BYTES;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function sanitizeSettings(value) {
|
|
79
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
80
|
+
const clean = {};
|
|
81
|
+
for (const key of BOOLEAN_KEYS) {
|
|
82
|
+
if (typeof value[key] === "boolean") clean[key] = value[key];
|
|
83
|
+
}
|
|
84
|
+
for (const [key, range] of Object.entries(NUMBER_RANGES)) {
|
|
85
|
+
if (typeof value[key] !== "number" || !Number.isFinite(value[key]) || value[key] < range[0] || value[key] > range[1]) continue;
|
|
86
|
+
clean[key] = value[key];
|
|
87
|
+
}
|
|
88
|
+
for (const key of ["lightBackground", "darkBackground"]) {
|
|
89
|
+
if (isBackground(value[key])) clean[key] = value[key];
|
|
90
|
+
}
|
|
91
|
+
return clean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function readSettings() {
|
|
95
|
+
const path = settingsPath();
|
|
96
|
+
if (!existsSync(path)) return {};
|
|
97
|
+
try {
|
|
98
|
+
return sanitizeSettings(JSON.parse(readFileSync(path, "utf8"))) || {};
|
|
99
|
+
} catch {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function writeSettings(settings) {
|
|
105
|
+
const clean = sanitizeSettings(settings);
|
|
106
|
+
if (clean === null) throw new Error("invalid settings");
|
|
107
|
+
const path = settingsPath();
|
|
108
|
+
const dir = join(profileDir(), "data", SETTINGS_DIR);
|
|
109
|
+
mkdirSync(dir, { recursive: true });
|
|
110
|
+
const temporary = path + ".tmp";
|
|
111
|
+
writeFileSync(temporary, JSON.stringify(clean), "utf8");
|
|
112
|
+
try { renameSync(temporary, path); } catch {
|
|
113
|
+
rmSync(path, { force: true });
|
|
114
|
+
renameSync(temporary, path);
|
|
115
|
+
}
|
|
116
|
+
return clean;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function readBody(req) {
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
let size = 0;
|
|
122
|
+
const chunks = [];
|
|
123
|
+
req.on("data", (chunk) => {
|
|
124
|
+
size += chunk.length;
|
|
125
|
+
if (size > MAX_BODY_BYTES) {
|
|
126
|
+
req.destroy();
|
|
127
|
+
reject(new Error("payload too large"));
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
chunks.push(chunk);
|
|
131
|
+
});
|
|
132
|
+
req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
133
|
+
req.on("error", reject);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function handleSettingsRoute(req, res) {
|
|
138
|
+
if (!isLoopback(req)) {
|
|
139
|
+
res.writeHead(403);
|
|
140
|
+
res.end("forbidden");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (req.method === "GET") {
|
|
144
|
+
sendJson(res, 200, { ok: true, settings: readSettings() });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (req.method !== "PUT") {
|
|
148
|
+
res.writeHead(405, { allow: "GET, PUT" });
|
|
149
|
+
res.end();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const parsed = JSON.parse(await readBody(req));
|
|
154
|
+
const settings = writeSettings(parsed && parsed.settings);
|
|
155
|
+
sendJson(res, 200, { ok: true, settings });
|
|
156
|
+
} catch (error) {
|
|
157
|
+
sendJson(res, 400, { ok: false, message: String((error && error.message) || error) });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let defaultBgCache = null;
|
|
162
|
+
function handleDefaultBackgroundRoute(req, res) {
|
|
163
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
164
|
+
res.writeHead(405, { allow: "GET, HEAD" });
|
|
165
|
+
res.end();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
if (defaultBgCache === null || !defaultBgCache.length) {
|
|
170
|
+
defaultBgCache = readFileSync(DEFAULT_BG_FILE);
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
res.writeHead(404);
|
|
174
|
+
res.end("default background missing");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
res.writeHead(200, {
|
|
178
|
+
"content-type": "image/jpeg",
|
|
179
|
+
"cache-control": "no-store",
|
|
180
|
+
"content-length": String(defaultBgCache.length)
|
|
181
|
+
});
|
|
182
|
+
res.end(req.method === "HEAD" ? undefined : defaultBgCache);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function apply(ctx) {
|
|
186
|
+
ctx.webServer.register({ kind: "exact", path: SETTINGS_ROUTE, handler: handleSettingsRoute });
|
|
187
|
+
return ctx.webServer.register({ kind: "exact", path: DEFAULT_BG_ROUTE, handler: handleDefaultBackgroundRoute });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export { apply, inject, name };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taosee258/dsh-client-ui-skin-qingxiao",
|
|
3
3
|
"description": "Qingxiao (Wuthering Waves) themed skin with ice-blue/jade/moon-white palette, sword-light motes and user-swappable background for the dsh web GUI",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"exports": {
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
"@deepseek-ai/dsh-client-ui-slots"
|
|
21
21
|
],
|
|
22
22
|
"platform": "web",
|
|
23
|
-
"
|
|
23
|
+
"immediately": true,
|
|
24
|
+
"version": "0.1.0-rc.6 - 0.2.0-rc.2"
|
|
24
25
|
}
|
|
25
26
|
},
|
|
26
27
|
"license": "CC-BY-NC-SA-4.0",
|
|
@@ -33,9 +34,9 @@
|
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
35
36
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
36
|
-
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0",
|
|
37
|
-
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0",
|
|
38
|
-
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0",
|
|
37
|
+
"@deepseek-ai/dsh-client-runtime": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-rc.0 <0.2.1-0",
|
|
38
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-rc.0 <0.2.1-0",
|
|
39
|
+
"@deepseek-ai/dsh-host-webserver": ">=0.1.0-rc.6 <0.1.1-0 || >=0.1.1-rc.1 <0.2.0-0 || >=0.2.0-rc.0 <0.2.1-0",
|
|
39
40
|
"react": "^18.2.0"
|
|
40
41
|
},
|
|
41
42
|
"files": [
|
package/preview/screen-dark.png
CHANGED
|
Binary file
|
package/preview/screen-light.png
CHANGED
|
Binary file
|
package/skin.json
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "qingxiao",
|
|
3
|
-
"name": "清宵 · 弦凝清霄",
|
|
4
|
-
"nameEn": "Qingxiao · Strings of the Clear Sky",
|
|
5
|
-
"author": "taoser",
|
|
6
|
-
"tagline": "冰蓝青碧配色 · 月白玻璃面板 · 剑气流光装饰 · 弦剑剑仙氛围",
|
|
7
|
-
"description": "《鸣潮》清宵主题皮肤:以冰蓝、青碧、月白、玄夜蓝构成清冷剑仙调色板,以鎏金与剑气流光作为装饰母题。qx 默认背景可随时在设置面板中更换,遮罩浓度与文字对比增强保证任何背景下文字清晰可读。亮色模式映射月白庭院的清昼氛围,暗色模式映射玄夜剑鸣的深夜氛围。",
|
|
8
|
-
"tags": [
|
|
9
|
-
"anime",
|
|
10
|
-
"wuthering-waves",
|
|
11
|
-
"qingxiao",
|
|
12
|
-
"aero",
|
|
13
|
-
"cyan",
|
|
14
|
-
"ice-blue",
|
|
15
|
-
"gold",
|
|
16
|
-
"sword-immortal"
|
|
17
|
-
],
|
|
18
|
-
"accent": "#56C8C0",
|
|
19
|
-
"bodyAttr": "data-dsh-qingxiao",
|
|
20
|
-
"package": "@taosee258/dsh-client-ui-skin-qingxiao",
|
|
21
|
-
"wiring": {
|
|
22
|
-
"id": "ui-skin-qingxiao",
|
|
23
|
-
"bundleWired": false
|
|
24
|
-
},
|
|
25
|
-
"preview": {
|
|
26
|
-
"light": "preview/screen-light.png",
|
|
27
|
-
"dark": "preview/screen-dark.png"
|
|
28
|
-
},
|
|
29
|
-
"order": 9
|
|
30
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"id": "qingxiao",
|
|
3
|
+
"name": "清宵 · 弦凝清霄",
|
|
4
|
+
"nameEn": "Qingxiao · Strings of the Clear Sky",
|
|
5
|
+
"author": "taoser",
|
|
6
|
+
"tagline": "冰蓝青碧配色 · 月白玻璃面板 · 剑气流光装饰 · 弦剑剑仙氛围",
|
|
7
|
+
"description": "《鸣潮》清宵主题皮肤:以冰蓝、青碧、月白、玄夜蓝构成清冷剑仙调色板,以鎏金与剑气流光作为装饰母题。qx 默认背景可随时在设置面板中更换,遮罩浓度与文字对比增强保证任何背景下文字清晰可读。亮色模式映射月白庭院的清昼氛围,暗色模式映射玄夜剑鸣的深夜氛围。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"anime",
|
|
10
|
+
"wuthering-waves",
|
|
11
|
+
"qingxiao",
|
|
12
|
+
"aero",
|
|
13
|
+
"cyan",
|
|
14
|
+
"ice-blue",
|
|
15
|
+
"gold",
|
|
16
|
+
"sword-immortal"
|
|
17
|
+
],
|
|
18
|
+
"accent": "#56C8C0",
|
|
19
|
+
"bodyAttr": "data-dsh-qingxiao",
|
|
20
|
+
"package": "@taosee258/dsh-client-ui-skin-qingxiao",
|
|
21
|
+
"wiring": {
|
|
22
|
+
"id": "ui-skin-qingxiao",
|
|
23
|
+
"bundleWired": false
|
|
24
|
+
},
|
|
25
|
+
"preview": {
|
|
26
|
+
"light": "preview/screen-light.png",
|
|
27
|
+
"dark": "preview/screen-dark.png"
|
|
28
|
+
},
|
|
29
|
+
"order": 9
|
|
30
|
+
}
|