dsh-long-plugins 2.0.0 → 2.2.0
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 +21 -0
- package/client/client.js +189 -45
- package/dsh.plugin.json +1 -1
- package/lib/index.js +20 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -124,6 +124,27 @@ MIT
|
|
|
124
124
|
|
|
125
125
|
## Changelog / 更新记录
|
|
126
126
|
|
|
127
|
+
### v2.2.0
|
|
128
|
+
|
|
129
|
+
界面优化与重构
|
|
130
|
+
|
|
131
|
+
- 背景图独立层:背景图改为独立图层,新增「背景图模糊 / 背景图透明度」滑杆(单独一组,不影响磨砂卡),并新增「背景罩层颜色」色盘,背景图可模糊、可调透明度、罩色可选。
|
|
132
|
+
- 会话区:去掉会话区独立磨砂卡片,直接透出共享背景(背景图 + 罩层颜色 + 模糊),版面更通透。
|
|
133
|
+
- 输入区:整个输入区外围(composer 根/位置座)透明透出背景。
|
|
134
|
+
- 可读性:浅色主题下弱化标签/元信息文字加深,对比度更高。
|
|
135
|
+
|
|
136
|
+
### v2.1.0
|
|
137
|
+
- 增强:毛玻璃界面(玻璃拟态)进一步打磨。
|
|
138
|
+
- 主题感知磨砂:磨砂卡片颜色跟随系统深色/浅色主题自动反转(浅色=白磨砂深字 / 深色=深磨砂浅字)。
|
|
139
|
+
- 会话区内容反底色全透明化:去掉代码块/提示/气泡等反底色小块,统一融入磨砂卡片。
|
|
140
|
+
- 会话区「启用玻璃」开关:可单独禁用会话区磨砂(还原原生)。
|
|
141
|
+
- 会话区/输入区各自独立「罩色 + 罩强度 + 透明度」调节。
|
|
142
|
+
- 新增「背景图罩」:背景图上叠一层半透明罩色,深度可调。
|
|
143
|
+
- 手机端/窄屏(≤768px)自动禁用毛玻璃,还原 DSH 原生。
|
|
144
|
+
- 输入卡片/底部白色层透明化,更透背景。
|
|
145
|
+
- 修复:输入框下拉/悬浮菜单(`/` 命令、`@` 提及)背景透明,改为不透明随主题色。
|
|
146
|
+
- 修复:玻璃界面自定义背景图上传超大文件报 `Unexpected token '<'` 错误——上传上限提升到 4MiB。
|
|
147
|
+
|
|
127
148
|
### v2.0.0
|
|
128
149
|
- 新增:毛玻璃界面(玻璃拟态)。为 DSH 网页叠加自定义毛玻璃效果,将界面打磨成"玻璃"质感。
|
|
129
150
|
- **自定义背景图**:上传一张背景图铺满整个页面(含左边栏、顶部、会话区),实现桌面壁纸式的背景;左边栏 / 顶部半透明透出背景图,界面更通透。
|
package/client/client.js
CHANGED
|
@@ -974,6 +974,8 @@ window.__ModuleLoader__.load({
|
|
|
974
974
|
const CSS = `
|
|
975
975
|
@font-face{font-family:DshChipCellInput;src:url(data:font/ttf;base64,AAEAAAAKAIAAAwAgT1MvMkT8SmIAAAEoAAAAYGNtYXAADQBPAAABkAAAADRnbHlmAAAAAAAAAcwAAAABaGVhZCwtPGoAAACsAAAANmhoZWEDIg7bAAAA5AAAACRobXR4EZQAAAAAAYgAAAAIbG9jYQAAAAAAAAHEAAAABm1heHAAAwACAAABCAAAACBuYW1lvljk2gAAAdAAAABscG9zdNNweNQAAAI8AAAALQABAAAAAQAAdia1tV8PPPUAAwPoAAAAAOaLfcUAAAAA5ot9xQAAAAAAAAAAAAAAAwACAAAAAAAAAAEAAAMg/zgAAA+gAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAACAAEAAAACAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAwjKAZAABQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAPz8/PwAA//z//AMg/zgAAAMgAMgAAAAAAAAAAAAAAAAAAAAgAAAB9AAAAAAAAAAAAAIAAAADAAAAFAADAAEAAAAUAAQAIAAAAAQABAABAAD//P//AAD//P//AAUAAQAAAAAAAAAAAAAAAAAAAAAAAAAEADYAAQAAAAAAAQALAAAAAQAAAAAAAgAHAAsAAwABBAkAAQAWABIAAwABBAkAAgAOAChEc2hDaGlwQ2VsbFJlZ3VsYXIARABzAGgAQwBoAGkAcABDAGUAbABsAFIAZQBnAHUAbABhAHIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAABAgZvYmpyZXAAAAA=)format("truetype")}
|
|
976
976
|
.uV2eYG_input,.uV2eYG_mirror{font-family:"DshChipCellInput",var(--dsw-font-family)!important}
|
|
977
|
+
/* 输入区随系统深/浅自动切换(原生系统色,文字/背景同源始终匹配),避免深色下白字配浅底 */
|
|
978
|
+
.uV2eYG_input{color-scheme:light dark;background-color:Canvas!important;color:CanvasText!important}
|
|
977
979
|
[data-decoration="chip"][title^="${HIDDEN_LABEL}"]{display:inline-block!important;width:0!important;height:0!important;overflow:hidden!important;background:transparent!important;border:none!important;box-shadow:none!important;margin:0!important;padding:0!important;font-size:0!important;line-height:0!important}
|
|
978
980
|
[data-decoration="chip"][title^="${HIDDEN_LABEL}"]:before,[data-decoration="chip"][title^="${HIDDEN_LABEL}"]>*{display:none!important}
|
|
979
981
|
.dsh-upload-control{display:flex;align-items:center;min-width:0}
|
|
@@ -3058,28 +3060,63 @@ window.__ModuleLoader__.load({
|
|
|
3058
3060
|
html[data-dsh-glass="on"] #root [class*="FJxK0a_root"] {
|
|
3059
3061
|
background-color: transparent !important;
|
|
3060
3062
|
}
|
|
3061
|
-
/*
|
|
3063
|
+
/* 会话滚动区:去掉独立磨砂卡片,直接透出共享背景(背景图+罩层颜色+模糊) */
|
|
3062
3064
|
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] {
|
|
3063
|
-
background-color:
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3065
|
+
background-color: transparent !important;
|
|
3066
|
+
background-image: none !important;
|
|
3067
|
+
backdrop-filter: none !important;
|
|
3068
|
+
-webkit-backdrop-filter: none !important;
|
|
3069
|
+
border-radius: 0 !important;
|
|
3070
|
+
box-shadow: none !important;
|
|
3067
3071
|
overflow: auto;
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3072
|
+
width: 100% !important;
|
|
3073
|
+
max-width: none !important;
|
|
3074
|
+
margin: 0 !important;
|
|
3071
3075
|
}
|
|
3076
|
+
/* 背景图独立层:铺满整页、位于内容之下,可单独设背景图模糊与透明度,不影响内容清晰度 */
|
|
3077
|
+
.dsh-glass-bgimg{position:fixed;inset:0;z-index:-1;pointer-events:none;background-size:cover;background-position:center;background-repeat:no-repeat;display:none;transform:translateZ(0);}
|
|
3072
3078
|
/* 滚动条:细、半透明、圆角,且左移贴在内容区(不占卡片最右边缘),让右边缘过渡柔和 */
|
|
3073
3079
|
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"]::-webkit-scrollbar { width: 8px; }
|
|
3074
3080
|
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"]::-webkit-scrollbar-track { background: transparent; }
|
|
3075
3081
|
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"]::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.35); border-radius: 8px; }
|
|
3076
3082
|
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"]::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.5); }
|
|
3077
|
-
/*
|
|
3078
|
-
html[data-dsh-glass="on"] #root [class*="
|
|
3079
|
-
background-color:
|
|
3080
|
-
|
|
3081
|
-
|
|
3083
|
+
/* 会话区禁用玻璃:scrollBody 还原为透明、无磨砂、无圆角/阴影(保持 DSH 原生会话区外观) */
|
|
3084
|
+
html[data-dsh-glass="on"][data-dsh-session-glass="off"] #root [class*="wSkVaW_scrollBody"] {
|
|
3085
|
+
background-color: transparent !important;
|
|
3086
|
+
background-image: none !important;
|
|
3087
|
+
backdrop-filter: none !important;
|
|
3088
|
+
-webkit-backdrop-filter: none !important;
|
|
3089
|
+
border-radius: 0 !important;
|
|
3090
|
+
box-shadow: none !important;
|
|
3091
|
+
}
|
|
3092
|
+
/* 输入区外围(composer根/位置座)透明透出背景;输入框盒子保留原生白/黑 */
|
|
3093
|
+
html[data-dsh-glass="on"] [class*="wSkVaW_composerSeat"],
|
|
3094
|
+
html[data-dsh-glass="on"] [class*="uV2eYG_root"] {
|
|
3095
|
+
background-color: transparent !important;
|
|
3096
|
+
background-image: none !important;
|
|
3097
|
+
box-shadow: none !important;
|
|
3098
|
+
backdrop-filter: none !important;
|
|
3099
|
+
-webkit-backdrop-filter: none !important;
|
|
3100
|
+
}
|
|
3101
|
+
/* 输入框盒子(uV2eYG_card):只在外层铺淡色底(可调);里层输入区透明避免拼缝白条;文字随主题色 */
|
|
3102
|
+
html[data-dsh-glass="on"] [class*="uV2eYG_card"] {
|
|
3103
|
+
background: linear-gradient(var(--dsh-glass-input-white, rgba(255,255,255,0.3)), var(--dsh-glass-input-white, rgba(255,255,255,0.3))) var(--dsh-glass-input-bg, rgba(26,35,50,0.6)) !important;
|
|
3104
|
+
color: var(--dsw-alias-label-primary, #111827) !important;
|
|
3105
|
+
box-shadow: none !important;
|
|
3106
|
+
backdrop-filter: none !important;
|
|
3107
|
+
-webkit-backdrop-filter: none !important;
|
|
3082
3108
|
}
|
|
3109
|
+
html[data-dsh-glass="on"] [class*="uV2eYG_input"] {
|
|
3110
|
+
background-color: transparent !important;
|
|
3111
|
+
color: var(--dsw-alias-label-primary, #111827) !important;
|
|
3112
|
+
}
|
|
3113
|
+
@media (prefers-color-scheme: dark) {
|
|
3114
|
+
html[data-dsh-glass="on"] [class*="uV2eYG_card"],
|
|
3115
|
+
html[data-dsh-glass="on"] [class*="uV2eYG_input"] { color: var(--dsw-alias-label-primary, #e5e7eb) !important; }
|
|
3116
|
+
}
|
|
3117
|
+
/* 轮次/历史提问预览:默认隐藏(点开才显示),并去掉头部底色,避免底部露出白条 */
|
|
3118
|
+
.dsh-turn-preview:not(.open){display:none !important;}
|
|
3119
|
+
.dsh-turn-preview-head{background:transparent !important;}
|
|
3083
3120
|
|
|
3084
3121
|
html[data-dsh-glass="off"] #root [class*="sidebarCol"],
|
|
3085
3122
|
html[data-dsh-glass="off"] #root [class*="header"],
|
|
@@ -3087,6 +3124,55 @@ window.__ModuleLoader__.load({
|
|
|
3087
3124
|
html[data-dsh-glass="off"] #root [class*="wSkVaW_root"],
|
|
3088
3125
|
html[data-dsh-glass="off"] #root [class*="wSkVaW_scrollBody"],
|
|
3089
3126
|
html[data-dsh-glass="off"] #root [class*="uV2eYG_card"] { background-color: transparent !important; backdrop-filter: none; }
|
|
3127
|
+
/* 用户消息气泡:浅色半透明底(随主题),与 AI 消息(透明/磨砂)区分 */
|
|
3128
|
+
html[data-dsh-glass="on"] #root [class*="ngdEzaw_bubble"]:not([class*="button"]) {
|
|
3129
|
+
background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 62%, transparent) !important;
|
|
3130
|
+
}
|
|
3131
|
+
/* 会话区所有内容元素背景透明化:去掉"反底色"小块衬底,统一融入磨砂卡片 */
|
|
3132
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] *:not([class*="button"]):not([class*="bubble"]):not([class*="_menu"]) {
|
|
3133
|
+
background-color: transparent !important;
|
|
3134
|
+
}
|
|
3135
|
+
/* 会话区内容衬底(代码块/提示/气泡/引用等)玻璃开启时透明化,融入磨砂卡片,去掉浅色小块衬底 */
|
|
3136
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] [class*="n_block"],
|
|
3137
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] [class*="n_bannerWrap"],
|
|
3138
|
+
|
|
3139
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] [class*="n_plain"],
|
|
3140
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] [class*="n_copyButton"],
|
|
3141
|
+
html[data-dsh-glass="on"] #root [class*="wSkVaW_scrollBody"] [class*="md-code-block"] {
|
|
3142
|
+
background-color: transparent !important;
|
|
3143
|
+
}
|
|
3144
|
+
/* uV2eYG_add: composer 里随内容变化的白色衬底,玻璃开启时透明化 */
|
|
3145
|
+
html[data-dsh-glass="on"] #root [class*="uV2eYG_add"] {
|
|
3146
|
+
background-color: transparent !important;
|
|
3147
|
+
}
|
|
3148
|
+
/* 输入框下拉/悬浮菜单(如 / 命令、@ 提及):背景给不透明随主题色,避免叠在会话磨砂卡上重叠看不清 */
|
|
3149
|
+
html[data-dsh-glass="on"] #root [class*="_menu"][class*="_menu"][class*="_menu"][class*="_menu"] {
|
|
3150
|
+
background-color: var(--dsw-specific-input-major, #e8edf3) !important;
|
|
3151
|
+
background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
|
|
3152
|
+
backdrop-filter: none !important;
|
|
3153
|
+
-webkit-backdrop-filter: none !important;
|
|
3154
|
+
}
|
|
3155
|
+
/* 输入框旁权限/功能选择下拉(盾牌 Full access 等 Radix 风格菜单):与 / 命令菜单同样处理 */
|
|
3156
|
+
html[data-dsh-glass="on"] #root [class*="uV2eYG_card"] [class*="_root_"]:has([class*="_list_"]) {
|
|
3157
|
+
background-color: var(--dsw-specific-input-major, #e8edf3) !important;
|
|
3158
|
+
background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
|
|
3159
|
+
backdrop-filter: none !important;
|
|
3160
|
+
-webkit-backdrop-filter: none !important;
|
|
3161
|
+
}
|
|
3162
|
+
html[data-dsh-glass="on"] #root [class*="uV2eYG_card"] [class*="_list_"] {
|
|
3163
|
+
background-color: var(--dsw-specific-input-major, #e8edf3) !important;
|
|
3164
|
+
background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
|
|
3165
|
+
backdrop-filter: none !important;
|
|
3166
|
+
-webkit-backdrop-filter: none !important;
|
|
3167
|
+
}
|
|
3168
|
+
/* 玻璃开启 + 浅色系统主题:加深弱化标签/元信息文字,避免浅灰字叠在浅磨砂卡上看不清 */
|
|
3169
|
+
@media (prefers-color-scheme: light) {
|
|
3170
|
+
html[data-dsh-glass="on"],
|
|
3171
|
+
html[data-dsh-glass="on"] * {
|
|
3172
|
+
--dsw-alias-label-secondary: #383d44 !important;
|
|
3173
|
+
--dsw-alias-label-tertiary: #50545b !important;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3090
3176
|
.dsh-glass-section{display:flex;flex-direction:column;gap:16px;min-width:0;padding:4px 2px 24px;color:var(--dsw-alias-label-primary)}
|
|
3091
3177
|
.dsh-glass-head{display:flex;align-items:center;justify-content:space-between;gap:16px}
|
|
3092
3178
|
.dsh-glass-head h2{margin:0;font-size:20px;line-height:28px}
|
|
@@ -3115,7 +3201,7 @@ window.__ModuleLoader__.load({
|
|
|
3115
3201
|
.dsh-glass-error{padding:10px 12px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary);font-size:12px}
|
|
3116
3202
|
.dsh-glass-note{margin:0;font-size:12px;color:var(--dsw-alias-label-tertiary)}
|
|
3117
3203
|
`
|
|
3118
|
-
const GLASS_SWATCHES = ['#
|
|
3204
|
+
const GLASS_SWATCHES = ['#1a2332', '#0f1420', '#1e3a5f', '#1e5e46', '#5e2e5e', '#6e2323']
|
|
3119
3205
|
const glassText = (e) => (e && e.message) ? e.message : String(e)
|
|
3120
3206
|
function glassImageInput(value, onChange) {
|
|
3121
3207
|
return React.createElement('label', { className: 'dsh-glass-file' },
|
|
@@ -3131,11 +3217,14 @@ window.__ModuleLoader__.load({
|
|
|
3131
3217
|
)
|
|
3132
3218
|
}
|
|
3133
3219
|
// 会话区/输入区共用设置卡:罩色 + 罩强度
|
|
3134
|
-
const GlassZoneCard = ({ title, zone, onChange }) => {
|
|
3135
|
-
const z = zone || { color: '#1a2332', mask: 0.45 }
|
|
3220
|
+
const GlassZoneCard = ({ title, zone, onChange, showGlassToggle }) => {
|
|
3221
|
+
const z = zone || { color: '#1a2332', mask: 0.45, enabled: true }
|
|
3136
3222
|
const setPatch = (p) => onChange({ ...z, ...p })
|
|
3137
3223
|
return React.createElement('div', { className: 'dsh-glass-card' },
|
|
3138
3224
|
React.createElement('div', { className: 'dsh-glass-zone-title' }, title),
|
|
3225
|
+
showGlassToggle ? React.createElement('div', { className: 'dsh-glass-row' },
|
|
3226
|
+
React.createElement('label', { className: 'dsh-glass-switch' }, React.createElement('input', { type: 'checkbox', checked: z.enabled !== false, onChange: (e) => setPatch({ enabled: e.target.checked }) }), title + ' 启用玻璃'),
|
|
3227
|
+
) : null,
|
|
3139
3228
|
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3140
3229
|
React.createElement('label', null, title + ' 罩色'),
|
|
3141
3230
|
React.createElement('div', { className: 'dsh-glass-swatches' },
|
|
@@ -3148,6 +3237,11 @@ window.__ModuleLoader__.load({
|
|
|
3148
3237
|
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 0.95, step: 0.01, value: z.mask ?? 0.45, onChange: (e) => setPatch({ mask: Number(e.target.value) }) }),
|
|
3149
3238
|
React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((Number(z.mask ?? 0.45)) * 100)}%`),
|
|
3150
3239
|
),
|
|
3240
|
+
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3241
|
+
React.createElement('label', null, title + ' 透明度'),
|
|
3242
|
+
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 1, step: 0.01, value: z.opacity ?? 0.5, onChange: (e) => setPatch({ opacity: Number(e.target.value) }) }),
|
|
3243
|
+
React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((Number(z.opacity ?? 0.5)) * 100)}%`),
|
|
3244
|
+
),
|
|
3151
3245
|
)
|
|
3152
3246
|
}
|
|
3153
3247
|
const GlassSettingsSection = () => {
|
|
@@ -3168,12 +3262,13 @@ window.__ModuleLoader__.load({
|
|
|
3168
3262
|
setState((s) => ({ ...s, saving: true, error: '' }))
|
|
3169
3263
|
try {
|
|
3170
3264
|
const cfg = state.cfg || {}
|
|
3265
|
+
const num = (v, fb) => ((typeof v === 'number' && Number.isFinite(v) && v >= 0) ? v : fb)
|
|
3171
3266
|
const payload = {
|
|
3172
|
-
enabled: !!cfg.enabled, blur:
|
|
3173
|
-
bgImage: state.bgImage || cfg.bgImage || '',
|
|
3267
|
+
enabled: !!cfg.enabled, blur: num(cfg.blur, 0),
|
|
3268
|
+
bgImage: state.bgImage || cfg.bgImage || '', bgMask: num(cfg.bgMask, 0.28), bgColor: cfg.bgColor || '#1a2332', bgBlur: num(cfg.bgBlur, 0), bgOpacity: num(cfg.bgOpacity, 1),
|
|
3174
3269
|
zone: {
|
|
3175
|
-
session: { color: (cfg.session && cfg.session.color) || '#1a2332', mask:
|
|
3176
|
-
input: { color: (cfg.input && cfg.input.color) || '#1a2332', mask:
|
|
3270
|
+
session: { enabled: cfg.session && cfg.session.enabled !== false, color: (cfg.session && cfg.session.color) || '#1a2332', mask: num(cfg.session && cfg.session.mask, 0.45), opacity: num(cfg.session && cfg.session.opacity, 0.5) },
|
|
3271
|
+
input: { color: (cfg.input && cfg.input.color) || '#1a2332', mask: num(cfg.input && cfg.input.mask, 0.6), opacity: num(cfg.input && cfg.input.opacity, 0.55) },
|
|
3177
3272
|
},
|
|
3178
3273
|
}
|
|
3179
3274
|
const r = await fetch('/api/dsh-uploads/glass-config', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) })
|
|
@@ -3197,13 +3292,30 @@ window.__ModuleLoader__.load({
|
|
|
3197
3292
|
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 80, value: cfg.blur ?? 20, onChange: (e) => patch({ blur: Number(e.target.value) }) }),
|
|
3198
3293
|
React.createElement('span', { className: 'dsh-glass-val' }, `${Number(cfg.blur ?? 20)} px`),
|
|
3199
3294
|
),
|
|
3200
|
-
React.createElement(GlassZoneCard, { title: '会话区', zone: cfg.session, onChange: (p) => patchZone('session', p) }),
|
|
3201
|
-
React.createElement(GlassZoneCard, { title: '输入区', zone: cfg.input, onChange: (p) => patchZone('input', p) }),
|
|
3202
3295
|
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3203
3296
|
React.createElement('label', null, '共用背景图'),
|
|
3204
3297
|
React.createElement('div', { className: 'dsh-glass-bg' }, glassImageInput(state.bgImage, (v) => setState((s) => ({ ...s, bgImage: v })))),
|
|
3205
3298
|
),
|
|
3206
|
-
React.createElement('
|
|
3299
|
+
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3300
|
+
React.createElement('label', null, '背景图罩'),
|
|
3301
|
+
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 0.95, step: 0.01, value: cfg.bgMask ?? 0.28, onChange: (e) => patch({ bgMask: Number(e.target.value) }) }),
|
|
3302
|
+
React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((Number(cfg.bgMask ?? 0.28)) * 100)}%`),
|
|
3303
|
+
),
|
|
3304
|
+
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3305
|
+
React.createElement('label', null, '背景罩层颜色'),
|
|
3306
|
+
React.createElement('label', { className: 'dsh-glass-colorpicker' }, '色盘', React.createElement('input', { type: 'color', value: cfg.bgColor || '#1a2332', onChange: (e) => patch({ bgColor: e.target.value }) })),
|
|
3307
|
+
),
|
|
3308
|
+
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3309
|
+
React.createElement('label', null, '背景图模糊'),
|
|
3310
|
+
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 60, value: cfg.bgBlur ?? 0, onChange: (e) => patch({ bgBlur: Number(e.target.value) }) }),
|
|
3311
|
+
React.createElement('span', { className: 'dsh-glass-val' }, `${Number(cfg.bgBlur ?? 0)} px`),
|
|
3312
|
+
),
|
|
3313
|
+
React.createElement('div', { className: 'dsh-glass-row' },
|
|
3314
|
+
React.createElement('label', null, '背景图透明度'),
|
|
3315
|
+
React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 1, step: 0.01, value: cfg.bgOpacity ?? 1, onChange: (e) => patch({ bgOpacity: Number(e.target.value) }) }),
|
|
3316
|
+
React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((Number(cfg.bgOpacity ?? 1)) * 100)}%`),
|
|
3317
|
+
),
|
|
3318
|
+
React.createElement('p', { className: 'dsh-glass-note' }, '提示:背景图铺满整页(可加背景图罩);背景图模糊/透明度单独可调;会话区使用自己的罩色、罩强度与透明度;左栏/顶部透出背景图;输入框保持系统原生样式。'),
|
|
3207
3319
|
React.createElement('div', { className: 'dsh-glass-actions' },
|
|
3208
3320
|
React.createElement('button', { type: 'button', onClick: load }, '重置'),
|
|
3209
3321
|
React.createElement('button', { type: 'button', className: 'primary', disabled: state.saving, onClick: save }, state.saving ? '保存中…' : '保存生效'),
|
|
@@ -3243,33 +3355,65 @@ window.__ModuleLoader__.load({
|
|
|
3243
3355
|
|
|
3244
3356
|
window.__dshGlassApply = (cfg) => {
|
|
3245
3357
|
const c = cfg || {}
|
|
3358
|
+
// 手机端/窄屏(<=768px):不开启毛玻璃,还原 DSH 原生样式(清背景图/罩变量/磨砂)。
|
|
3359
|
+
if (window.innerWidth <= 768) {
|
|
3360
|
+
root.setAttribute('data-dsh-glass', 'off')
|
|
3361
|
+
root.setAttribute('data-dsh-session-glass', 'off')
|
|
3362
|
+
root.style.setProperty('--dsh-glass-blur', '')
|
|
3363
|
+
root.style.setProperty('--dsh-glass-session-bg', '')
|
|
3364
|
+
root.style.setProperty('--dsh-glass-input-bg', '')
|
|
3365
|
+
root.style.setProperty('--dsh-glass-bg-zone', '')
|
|
3366
|
+
const b = document.body
|
|
3367
|
+
b.style.backgroundImage = 'none'; b.style.backgroundSize = ''; b.style.backgroundPosition = ''; b.style.backgroundRepeat = ''
|
|
3368
|
+
const fr = document.querySelector('#root > div > div') || document.querySelector('#root > div')
|
|
3369
|
+
if (fr) { fr.style.backgroundColor = ''; fr.style.backgroundImage = 'none'; fr.style.backgroundSize = ''; fr.style.backgroundPosition = ''; fr.style.backgroundRepeat = '' }
|
|
3370
|
+
const bgEl = document.querySelector('.dsh-glass-bgimg'); if (bgEl) { bgEl.style.display = 'none' }
|
|
3371
|
+
return
|
|
3372
|
+
}
|
|
3246
3373
|
root.setAttribute('data-dsh-glass', c.enabled ? 'on' : 'off')
|
|
3247
|
-
|
|
3248
|
-
|
|
3374
|
+
const sessOn = !(c.zone && c.zone.session && c.zone.session.enabled === false)
|
|
3375
|
+
root.setAttribute('data-dsh-session-glass', sessOn ? 'on' : 'off')
|
|
3376
|
+
const blurn = Number(c.blur); const blur = Math.max(0, Math.min(80, Number.isFinite(blurn) ? blurn : 16))
|
|
3249
3377
|
root.style.setProperty('--dsh-glass-blur', blur + 'px')
|
|
3250
|
-
const zs = (c.zone && c.zone.session) || { color: '#1a2332', mask: 0.45 }
|
|
3251
|
-
const zi = (c.zone && c.zone.input) || { color: '#1a2332', mask: 0.6 }
|
|
3252
|
-
|
|
3253
|
-
root.style.setProperty('--dsh-glass-
|
|
3378
|
+
const zs = (c.zone && c.zone.session) || { color: '#1a2332', mask: 0.45, opacity: 0.5 }
|
|
3379
|
+
const zi = (c.zone && c.zone.input) || { color: '#1a2332', mask: 0.6, opacity: 0.55 }
|
|
3380
|
+
const smn = Number(zs.mask); const sm = Math.min(0.95, Math.max(0, Number.isFinite(smn) ? smn : 0.45))
|
|
3381
|
+
root.style.setProperty('--dsh-glass-session-bg', `rgba(${hexToRgb(zs.color)},${sm})`)
|
|
3382
|
+
const imn = Number(zi.mask); const im = Math.min(0.95, Math.max(0, Number.isFinite(imn) ? imn : 0.6))
|
|
3383
|
+
root.style.setProperty('--dsh-glass-input-bg', `rgba(${hexToRgb(zi.color)},${im})`)
|
|
3384
|
+
// 透明度=透明程度:越大越透明(100%=>雾面无填充,完全透出背景)
|
|
3385
|
+
const sop = Math.min(1, Math.max(0, Number.isFinite(Number(zs.opacity)) ? Number(zs.opacity) : 0.5))
|
|
3386
|
+
root.style.setProperty('--dsh-glass-session-white', `color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) ${Math.round((1 - sop) * 100)}%, transparent)`)
|
|
3387
|
+
const iop = Math.min(1, Math.max(0, Number.isFinite(Number(zi.opacity)) ? Number(zi.opacity) : 0.55))
|
|
3388
|
+
root.style.setProperty('--dsh-glass-input-white', `color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) ${Math.round((1 - iop) * 100)}%, transparent)`)
|
|
3389
|
+
// 背景图罩:整页背景图上叠一层半透明罩色
|
|
3390
|
+
const bgc = c.bgColor || '#1a2332'
|
|
3391
|
+
const bgmn = Number(c.bgMask); const bgm = Math.min(0.95, Math.max(0, Number.isFinite(bgmn) ? bgmn : 0.28))
|
|
3392
|
+
root.style.setProperty('--dsh-glass-bg-zone', `rgba(${hexToRgb(bgc)},${bgm})`)
|
|
3254
3393
|
|
|
3255
3394
|
const body = document.body
|
|
3256
3395
|
const frame = document.querySelector('#root > div > div') || document.querySelector('#root > div')
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3396
|
+
// 背景图独立层:铺满整页、位于内容之下;背景图模糊/透明度单独可调(不影响内容清晰度)
|
|
3397
|
+
let bgimg = document.querySelector('.dsh-glass-bgimg')
|
|
3398
|
+
if (!bgimg) { bgimg = document.createElement('div'); bgimg.className = 'dsh-glass-bgimg'; document.body.appendChild(bgimg) }
|
|
3399
|
+
const gz = root.style.getPropertyValue('--dsh-glass-bg-zone') || `rgba(${hexToRgb(c.bgColor || '#1a2332')},0.28)`
|
|
3400
|
+
if (c.enabled && c.bgImage) {
|
|
3401
|
+
bgimg.style.display = 'block'
|
|
3402
|
+
bgimg.style.backgroundImage = `linear-gradient(${gz},${gz}), url('${c.bgImage}')`
|
|
3403
|
+
bgimg.style.backgroundSize = 'cover'
|
|
3404
|
+
bgimg.style.backgroundPosition = 'center'
|
|
3405
|
+
bgimg.style.backgroundRepeat = 'no-repeat'
|
|
3406
|
+
const bblur = Math.max(0, Math.min(80, Number.isFinite(Number(c.bgBlur)) ? Number(c.bgBlur) : 0))
|
|
3407
|
+
bgimg.style.filter = bblur > 0 ? `blur(${bblur}px)` : 'none'
|
|
3408
|
+
const bop = Math.max(0, Math.min(1, Number.isFinite(Number(c.bgOpacity)) ? Number(c.bgOpacity) : 1))
|
|
3409
|
+
bgimg.style.opacity = String(bop)
|
|
3410
|
+
} else {
|
|
3411
|
+
bgimg.style.display = 'none'
|
|
3270
3412
|
}
|
|
3271
|
-
|
|
3272
|
-
|
|
3413
|
+
// 移除 body/frame 上的锐利背景图(改由独立背景层显示),避免重复/遮盖
|
|
3414
|
+
body.style.backgroundImage = 'none'
|
|
3415
|
+
if (c.enabled && c.bgImage) { body.style.backgroundColor = 'transparent' } else { body.style.backgroundColor = '' }
|
|
3416
|
+
if (frame) { frame.style.backgroundImage = 'none'; frame.style.backgroundColor = 'transparent' }
|
|
3273
3417
|
centerScroll()
|
|
3274
3418
|
}
|
|
3275
3419
|
return () => {
|
|
@@ -3281,7 +3425,7 @@ window.__ModuleLoader__.load({
|
|
|
3281
3425
|
ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'glass-ui', order: 40, label: '毛玻璃界面' }, GlassSettingsSection))
|
|
3282
3426
|
ctx.effect(() => {
|
|
3283
3427
|
fetch('/api/dsh-uploads/glass-config', { cache: 'no-store' }).then((r) => r.json()).then((b) => {
|
|
3284
|
-
if (b && b.cfg) { window.__dshGlassApply && window.__dshGlassApply({
|
|
3428
|
+
if (b && b.cfg) { window.__dshGlassApply && window.__dshGlassApply({ ...b.cfg, bgImage: b.bgImage }) }
|
|
3285
3429
|
}).catch(() => {})
|
|
3286
3430
|
}, 'dsh-long-plugins: glass boot')
|
|
3287
3431
|
},
|
package/dsh.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-long-plugins",
|
|
3
3
|
"description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), and polished file preview (Word & PowerPoint real preview with zoom/pan, rendered Markdown), plus an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). | 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx)、Word/PowerPoint 真实预览(可缩放、翻页);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.2.0",
|
|
5
5
|
"entry": {
|
|
6
6
|
"name": "dsh-long-plugins",
|
|
7
7
|
"inject": [
|
package/lib/index.js
CHANGED
|
@@ -190,20 +190,24 @@ export function isTrustedUploadRequest(req, trustedHosts = []) {
|
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
/** Read a JSON request body (bounded; 1 MiB to fit large edited documents). */
|
|
193
|
-
function readJsonBody(request) {
|
|
193
|
+
function readJsonBody(request, maxBytes = 1024 * 1024) {
|
|
194
194
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
195
195
|
let size = 0;
|
|
196
|
+
let tooBig = false;
|
|
196
197
|
const chunks = [];
|
|
197
198
|
request.on("data", (chunk) => {
|
|
199
|
+
if (tooBig) return;
|
|
198
200
|
size += chunk.length;
|
|
199
|
-
if (size >
|
|
200
|
-
|
|
201
|
-
|
|
201
|
+
if (size > maxBytes) {
|
|
202
|
+
tooBig = true;
|
|
203
|
+
chunks.length = 0;
|
|
204
|
+
rejectPromise(new HttpError(413, "body too large"));
|
|
202
205
|
return;
|
|
203
206
|
}
|
|
204
207
|
chunks.push(chunk);
|
|
205
208
|
});
|
|
206
209
|
request.on("end", () => {
|
|
210
|
+
if (tooBig) return;
|
|
207
211
|
try {
|
|
208
212
|
resolvePromise(JSON.parse(Buffer.concat(chunks).toString("utf8")));
|
|
209
213
|
} catch (error) {
|
|
@@ -675,6 +679,10 @@ function sanitizeGlass(input) {
|
|
|
675
679
|
if ("color" in input) out.color = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(String(input.color)) ? String(input.color) : undefined;
|
|
676
680
|
const sanitizeUri = (v) => { const s = String(v ?? ""); return (/^data:image\/(png|jpe?g|webp|gif);base64,/.test(s) && s.length <= 2 * 1024 * 1024 + 256) ? s : undefined; };
|
|
677
681
|
if ("bgImage" in input) out.bgImage = sanitizeUri(input.bgImage);
|
|
682
|
+
if ("bgColor" in input) out.bgColor = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(String(input.bgColor)) ? String(input.bgColor) : undefined;
|
|
683
|
+
if ("bgMask" in input) { const n = Number(input.bgMask); out.bgMask = Number.isFinite(n) ? Math.max(0, Math.min(0.95, n)) : undefined; }
|
|
684
|
+
if ("bgBlur" in input) { const n = Number(input.bgBlur); out.bgBlur = Number.isFinite(n) ? Math.max(0, Math.min(80, n)) : undefined; }
|
|
685
|
+
if ("bgOpacity" in input) { const n = Number(input.bgOpacity); out.bgOpacity = Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : undefined; }
|
|
678
686
|
// 会话区/输入区各自独立罩色+罩强度
|
|
679
687
|
if (input.zone && typeof input.zone === "object") {
|
|
680
688
|
const zo = {};
|
|
@@ -682,8 +690,10 @@ function sanitizeGlass(input) {
|
|
|
682
690
|
const z = input.zone[key];
|
|
683
691
|
if (z && typeof z === "object") {
|
|
684
692
|
const o = {};
|
|
693
|
+
if ("enabled" in z) o.enabled = z.enabled === true;
|
|
685
694
|
if ("color" in z) o.color = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(String(z.color)) ? String(z.color) : undefined;
|
|
686
695
|
if ("mask" in z) { const n = Number(z.mask); o.mask = Number.isFinite(n) ? Math.max(0, Math.min(0.95, n)) : undefined; }
|
|
696
|
+
if ("opacity" in z) { const n = Number(z.opacity); o.opacity = Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : undefined; }
|
|
687
697
|
zo[key] = Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));
|
|
688
698
|
}
|
|
689
699
|
}
|
|
@@ -1584,8 +1594,8 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
|
|
|
1584
1594
|
// 背景图以 data-URI 存进配置,随配置持久化。enabled=总开关;blur=磨砂模糊;mask=整页罩强度;
|
|
1585
1595
|
// color=叠加/罩色;bgImage=共用背景图。顶栏/左栏的"罩"与整页共用 mask+color(不再单独存,简化)。
|
|
1586
1596
|
const GLASS_DEFAULTS = {
|
|
1587
|
-
enabled: false, blur: 20, bgImage: "",
|
|
1588
|
-
zone: { session: { color: "#1a2332", mask: 0.45 }, input: { color: "#1a2332", mask: 0.6 } },
|
|
1597
|
+
enabled: false, blur: 20, bgImage: "", bgColor: "#1a2332", bgMask: 0.28,
|
|
1598
|
+
zone: { session: { color: "#1a2332", mask: 0.45, opacity: 0.5 }, input: { color: "#1a2332", mask: 0.6, opacity: 0.55 } },
|
|
1589
1599
|
};
|
|
1590
1600
|
const glassDir = resolve(homedir(), ".dsh-long-plugins");
|
|
1591
1601
|
const glassFile = join(glassDir, "glass.json");
|
|
@@ -1602,8 +1612,9 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
|
|
|
1602
1612
|
found: true,
|
|
1603
1613
|
cfg: {
|
|
1604
1614
|
enabled: cfg.enabled, blur: cfg.blur,
|
|
1605
|
-
session: cfg.zone?.session || { color: "#1a2332", mask: 0.45 },
|
|
1606
|
-
input: cfg.zone?.input || { color: "#1a2332", mask: 0.6 },
|
|
1615
|
+
session: cfg.zone?.session || { enabled: true, color: "#1a2332", mask: 0.45, opacity: 0.5 },
|
|
1616
|
+
input: cfg.zone?.input || { color: "#1a2332", mask: 0.6, opacity: 0.55 },
|
|
1617
|
+
bgColor: cfg.bgColor || "#1a2332", bgMask: cfg.bgMask ?? 0.28,
|
|
1607
1618
|
bgImage: cfg.bgImage ? { present: true, bytes: Math.round((cfg.bgImage.length * 3) / 4) } : { present: false },
|
|
1608
1619
|
},
|
|
1609
1620
|
bgImage: cfg.bgImage,
|
|
@@ -1611,7 +1622,7 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
|
|
|
1611
1622
|
return;
|
|
1612
1623
|
}
|
|
1613
1624
|
if (req.method === "POST") {
|
|
1614
|
-
const body = await readJsonBody(req);
|
|
1625
|
+
const body = await readJsonBody(req, 4 * 1024 * 1024);
|
|
1615
1626
|
const current = await readGlassJSON();
|
|
1616
1627
|
const next = { ...current, ...sanitizeGlass(typeof body === "object" && body !== null ? body : {}) };
|
|
1617
1628
|
await mkdir(glassDir, { recursive: true, mode: 0o700 });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-long-plugins",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Merged DSH web plugins: upload manager (drag-and-drop attach any file to the message), workspace output files, skill docs, account balance, Markdown-to-Word (md2docx), and polished file preview (Word & PowerPoint real preview with zoom/pan, rendered Markdown), plus an auto-repair install for DSH core patches (reverse-proxy WebSocket heartbeat, upgrade relink). | 一个插件整合 DSH Web 的常用增强:上传管理(拖放上传:拖任意文件到会话框直接附加)、工作区「输出文件」面板、技能文档浏览、账户余额显示、Markdown 转 Word(md2docx)、Word/PowerPoint 真实预览(可缩放、翻页);并自带修复安装,自动重连 DSH 核心补丁(反代 WebSocket 心跳、升级重连)。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|