dsh-long-plugins 2.2.2 → 2.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/client/client.js CHANGED
@@ -3139,18 +3139,31 @@ window.__ModuleLoader__.load({
3139
3139
  html[data-dsh-glass="on"] [class*="ModalContent"],
3140
3140
  html[data-dsh-glass="on"] [class*="overlay"] [class*="content"],
3141
3141
  html[data-dsh-glass="on"] [class*="_content"][class*="dialog"] {
3142
- background-color: var(--dsw-specific-input-major, #e8edf3) !important;
3142
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3143
3143
  color: var(--dsw-alias-label-primary) !important;
3144
- backdrop-filter: blur(8px) !important;
3145
- -webkit-backdrop-filter: blur(8px) !important;
3144
+ backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3145
+ -webkit-backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3146
3146
  }
3147
- /* DSH 提问/弹窗卡(M8wy4a_card):不透明底+原生文字, 避免透明重叠、白字 */
3148
- html[data-dsh-glass="on"] [class*="M8wy4a_card"],
3149
- html[data-dsh-glass="on"] [data-chain-overlay-fallback] [class*="card"] {
3150
- background-color: var(--dsw-specific-input-major, #e8edf3) !important;
3147
+ /* DSH 提问/弹窗卡(M8wy4a_card):不透明底+原生文字, 避免透明重叠、白字。
3148
+ 注意: 不能再用 [data-chain-overlay-fallback] [class*=card](会误匹配输入框 uV2eYG_card 加 blur 造成重影) */
3149
+ html[data-dsh-glass="on"] [class*="M8wy4a_card"] {
3150
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3151
+ color: var(--dsw-alias-label-primary) !important;
3152
+ backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3153
+ -webkit-backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3154
+ }
3155
+ /* 任务/todo 面板(lXshSW_root, 在 conversation.input.dock 内):不透明底+可读文字, 不透明与会话重叠 */
3156
+ html[data-dsh-glass="on"] [class*="lXshSW_root"],
3157
+ html[data-dsh-glass="on"] [class*="lXshSW_body"] {
3158
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3159
+ color: var(--dsw-alias-label-primary) !important;
3160
+ backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3161
+ -webkit-backdrop-filter: blur(var(--dsh-glass-blur, 16px)) !important;
3162
+ }
3163
+ html[data-dsh-glass="on"] [class*="lXshSW_header"] [class*="lXshSW_title"],
3164
+ html[data-dsh-glass="on"] [class*="lXshSW_header"] [class*="lXshSW_progress"],
3165
+ html[data-dsh-glass="on"] [class*="lXshSW_item"] {
3151
3166
  color: var(--dsw-alias-label-primary) !important;
3152
- backdrop-filter: blur(8px) !important;
3153
- -webkit-backdrop-filter: blur(8px) !important;
3154
3167
  }
3155
3168
  /* 轮次/历史提问预览:默认隐藏(点开才显示),并去掉头部底色,避免底部露出白条 */
3156
3169
  .dsh-turn-preview:not(.open){display:none !important;}
@@ -3206,20 +3219,20 @@ window.__ModuleLoader__.load({
3206
3219
  }
3207
3220
  /* 输入框下拉/悬浮菜单(如 / 命令、@ 提及):背景给不透明随主题色,避免叠在会话磨砂卡上重叠看不清 */
3208
3221
  html[data-dsh-glass="on"] #root [class*="_menu"][class*="_menu"][class*="_menu"][class*="_menu"] {
3209
- background-color: var(--dsw-specific-input-major, #e8edf3) !important;
3222
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3210
3223
  background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
3211
3224
  backdrop-filter: none !important;
3212
3225
  -webkit-backdrop-filter: none !important;
3213
3226
  }
3214
3227
  /* 输入框旁权限/功能选择下拉(盾牌 Full access 等 Radix 风格菜单):与 / 命令菜单同样处理 */
3215
3228
  html[data-dsh-glass="on"] #root [class*="uV2eYG_card"] [class*="_root_"]:has([class*="_list_"]) {
3216
- background-color: var(--dsw-specific-input-major, #e8edf3) !important;
3229
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3217
3230
  background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
3218
3231
  backdrop-filter: none !important;
3219
3232
  -webkit-backdrop-filter: none !important;
3220
3233
  }
3221
3234
  html[data-dsh-glass="on"] #root [class*="uV2eYG_card"] [class*="_list_"] {
3222
- background-color: var(--dsw-specific-input-major, #e8edf3) !important;
3235
+ background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 76%, transparent) !important;
3223
3236
  background-color: color-mix(in srgb, var(--dsw-specific-input-major, #e8edf3) 97%, transparent) !important;
3224
3237
  backdrop-filter: none !important;
3225
3238
  -webkit-backdrop-filter: none !important;
@@ -3307,14 +3320,16 @@ window.__ModuleLoader__.load({
3307
3320
  )
3308
3321
  }
3309
3322
  const GlassSettingsSection = () => {
3310
- const [state, setState] = React.useState({ loading: true, saving: false, error: '', cfg: null, bgImage: '' })
3323
+ const [state, setState] = React.useState({ loading: true, saving: false, error: '', cfg: null, bgImage: '', bgList: [] })
3311
3324
  const load = React.useCallback(async () => {
3312
3325
  setState((s) => ({ ...s, loading: true, error: '' }))
3313
3326
  try {
3314
3327
  const r = await fetch('/api/dsh-uploads/glass-config', { cache: 'no-store' })
3315
3328
  const b = await r.json()
3316
3329
  if (!r.ok) throw new Error(b.error || ('HTTP ' + r.status))
3317
- setState((s) => ({ ...s, loading: false, cfg: b.cfg, bgImage: b.bgImage || '' }))
3330
+ let list = []
3331
+ try { const rb = await fetch('/api/dsh-uploads/glass-backgrounds', { cache: 'no-store' }); const jb = await rb.json(); list = jb.list || [] } catch (_) {}
3332
+ setState((s) => ({ ...s, loading: false, cfg: b.cfg, bgImage: b.bgImage || '', bgList: list }))
3318
3333
  } catch (e) { setState((s) => ({ ...s, loading: false, error: glassText(e) })) }
3319
3334
  }, [])
3320
3335
  React.useEffect(() => { load(); }, [load])
@@ -3370,13 +3385,12 @@ window.__ModuleLoader__.load({
3370
3385
  state.error ? React.createElement('div', { className: 'dsh-glass-error' }, state.error) : null,
3371
3386
  React.createElement('div', { className: 'dsh-glass-card' },
3372
3387
  React.createElement('div', { className: 'dsh-glass-row' },
3373
- React.createElement('label', null, '磨砂模糊强度'),
3374
- 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) }) }),
3375
- React.createElement('span', { className: 'dsh-glass-val' }, `${Number(cfg.blur ?? 20)} px`),
3376
- ),
3377
- React.createElement('div', { className: 'dsh-glass-row' },
3378
- React.createElement('label', null, '共用背景图'),
3388
+ React.createElement('label', null, '背景图'),
3379
3389
  React.createElement('div', { className: 'dsh-glass-bg' }, glassImageInput(state.bgImage, (v) => setState((s) => ({ ...s, bgImage: v })))),
3390
+ state.bgList && state.bgList.length ? React.createElement('select', { className: 'dsh-glass-file', value: '', style: { marginLeft: 8 }, onChange: async (e) => {
3391
+ const name = e.target.value; if (!name) return
3392
+ try { const rb = await fetch('/api/dsh-uploads/glass-backgrounds?name=' + encodeURIComponent(name), { cache: 'no-store' }); const uri = await rb.text(); if (uri && uri.startsWith('data:image/')) setState((s) => ({ ...s, bgImage: uri })) } catch (_) {}
3393
+ } }, React.createElement('option', { value: '' }, '选择旧图…'), state.bgList.map((n, i) => React.createElement('option', { key: n, value: n }, '背景图 ' + (i + 1))) ) : null,
3380
3394
  ),
3381
3395
  React.createElement('div', { className: 'dsh-glass-card' },
3382
3396
  React.createElement('div', { className: 'dsh-glass-zone-title' }, '背景罩'),
@@ -3403,9 +3417,18 @@ window.__ModuleLoader__.load({
3403
3417
  React.createElement('span', { className: 'dsh-glass-val' }, `${Number(cfg.bgBlur ?? 0)} px`),
3404
3418
  ),
3405
3419
  React.createElement('div', { className: 'dsh-glass-row' },
3406
- React.createElement('label', null, '背景图透明度'),
3407
- 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) }) }),
3408
- React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((Number(cfg.bgOpacity ?? 1)) * 100)}%`),
3420
+ React.createElement('label', null, '背景透明度'),
3421
+ React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 100, value: Math.round((1 - (Number(cfg.bgOpacity ?? 1))) * 100), onChange: (e) => patch({ bgOpacity: 1 - Number(e.target.value) / 100 }) }),
3422
+ React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((1 - (Number(cfg.bgOpacity ?? 1))) * 100)}%`),
3423
+ ),
3424
+ React.createElement('div', { className: 'dsh-glass-card' },
3425
+ React.createElement('div', { className: 'dsh-glass-zone-title' }, '面板'),
3426
+ React.createElement('div', { className: 'dsh-glass-row' },
3427
+ React.createElement('label', null, '面板磨砂'),
3428
+ 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) }) }),
3429
+ React.createElement('span', { className: 'dsh-glass-val' }, `${Number(cfg.blur ?? 20)} px`),
3430
+ ),
3431
+ React.createElement('p', { className: 'dsh-glass-note' }, '作用于弹窗/任务卡等面板的磨砂玻璃强度(0 = 关闭磨砂)。'),
3409
3432
  ),
3410
3433
  React.createElement('div', { className: 'dsh-glass-card' },
3411
3434
  React.createElement('div', { className: 'dsh-glass-zone-title' }, '输入框'),
@@ -3419,13 +3442,13 @@ window.__ModuleLoader__.load({
3419
3442
  React.createElement('button', { type: 'button', style: { marginLeft: 8, fontSize: 12 }, onClick: () => patchInput(t, { color: '', opacity: 1 }) }, '原生'),
3420
3443
  ),
3421
3444
  React.createElement('div', { className: 'dsh-glass-row' },
3422
- React.createElement('label', null, '不透明度'),
3423
- React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 1, step: 0.01, value: (typeof tb.opacity === 'number') ? tb.opacity : 1, onChange: (e) => patchInput(t, { opacity: Number(e.target.value) }) }),
3424
- React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((typeof tb.opacity === 'number' ? tb.opacity : 1) * 100)}%`),
3445
+ React.createElement('label', null, '透明度'),
3446
+ React.createElement('input', { type: 'range', className: 'dsh-glass-range', min: 0, max: 100, value: Math.round((1 - (typeof tb.opacity === 'number' ? tb.opacity : 1)) * 100), onChange: (e) => patchInput(t, { opacity: 1 - Number(e.target.value) / 100 }) }),
3447
+ React.createElement('span', { className: 'dsh-glass-val' }, `${Math.round((1 - (typeof tb.opacity === 'number' ? tb.opacity : 1)) * 100)}%`),
3425
3448
  ),
3426
3449
  )
3427
3450
  }),
3428
- React.createElement('p', { className: 'dsh-glass-note' }, '浅色主题与深色主题可分别设置。100% = 实底不透明,越低越透出背景图;"原生" = 跟随该主题的 DSH 原生色。文字颜色按背景亮度自动配深/浅,保证可读。'),
3451
+ React.createElement('p', { className: 'dsh-glass-note' }, '浅色主题与深色主题可分别设置。0% = 全不透明,100% = 全透明;"原生" = 跟随该主题的 DSH 原生色。文字颜色按背景亮度自动配深/浅,保证可读。'),
3429
3452
  ),
3430
3453
  React.createElement('p', { className: 'dsh-glass-note' }, '提示:背景图铺满整页(可加背景图罩);背景图模糊/透明度单独可调;会话区使用自己的罩色、罩强度与透明度;左栏/顶部透出背景图;输入框颜色/不透明度可单独设置。'),
3431
3454
  React.createElement('div', { className: 'dsh-glass-actions' },
@@ -3695,9 +3718,10 @@ window.__ModuleLoader__.load({
3695
3718
  const fg = dark ? '#f2f6fa' : '#1a2332'
3696
3719
  // 只匹配提问/弹窗卡(M8wy4a_card),避免误匹配输入框 uV2eYG_card(含"card")导致 blur 重影
3697
3720
  document.querySelectorAll('[class*="M8wy4a_card"]').forEach((el) => {
3698
- el.style.setProperty('background-color', bg, 'important')
3721
+ const rgb = bg
3722
+ el.style.setProperty('background-color', `color-mix(in srgb, ${rgb} 76%, transparent)`, 'important')
3699
3723
  el.style.setProperty('color', fg, 'important')
3700
- el.style.setProperty('backdrop-filter', 'blur(8px)')
3724
+ el.style.setProperty('backdrop-filter', 'blur(var(--dsh-glass-blur, 20px))')
3701
3725
  })
3702
3726
  }
3703
3727
  // 主题相关的东西统一重算:背景罩 + 输入框。切主题时由 observer/mq 触发。
@@ -3733,6 +3757,8 @@ window.__ModuleLoader__.load({
3733
3757
  bgimg.style.backgroundSize = 'cover'
3734
3758
  bgimg.style.backgroundPosition = 'center'
3735
3759
  bgimg.style.backgroundRepeat = 'no-repeat'
3760
+ // 背景图模糊 = 背景图模糊(bgBlur) + 磨砂模糊强度(blur),两者叠加让背景图一起磨砂
3761
+ // 背景图模糊 = 仅背景图模糊(bgBlur);面板磨砂(blur)作用于弹窗/任务面板的 backdrop-filter
3736
3762
  const bblur = Math.max(0, Math.min(80, Number.isFinite(Number(c.bgBlur)) ? Number(c.bgBlur) : 0))
3737
3763
  bgimg.style.filter = bblur > 0 ? `blur(${bblur}px)` : 'none'
3738
3764
  const bop = Math.max(0, Math.min(1, Number.isFinite(Number(c.bgOpacity)) ? Number(c.bgOpacity) : 1))
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": "2.2.2",
4
+ "version": "2.2.3",
5
5
  "entry": {
6
6
  "name": "dsh-long-plugins",
7
7
  "inject": [
package/lib/index.js CHANGED
@@ -1631,6 +1631,7 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
1631
1631
  };
1632
1632
  const glassDir = resolve(homedir(), ".dsh-long-plugins");
1633
1633
  const glassFile = join(glassDir, "glass.json");
1634
+ const bgDir = join(glassDir, "backgrounds");
1634
1635
  async function readGlassJSON() {
1635
1636
  try { const raw = JSON.parse(await readFile(glassFile, "utf8")); return { ...GLASS_DEFAULTS, ...(raw && typeof raw === "object" ? raw : {}) }; }
1636
1637
  catch { return { ...GLASS_DEFAULTS }; }
@@ -1649,6 +1650,7 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
1649
1650
  inputBox: cfg.inputBox || { light: { color: "", opacity: 1 }, dark: { color: "", opacity: 1 } },
1650
1651
  bgTint: cfg.bgTint || { light: { color: "#1a2332", mask: 0.28 }, dark: { color: "#1a2332", mask: 0.28 } },
1651
1652
  bgColor: cfg.bgColor || "#1a2332", bgMask: cfg.bgMask ?? 0.28,
1653
+ bgBlur: cfg.bgBlur ?? 0, bgOpacity: cfg.bgOpacity ?? 1,
1652
1654
  bgImage: cfg.bgImage ? { present: true, bytes: Math.round((cfg.bgImage.length * 3) / 4) } : { present: false },
1653
1655
  },
1654
1656
  bgImage: cfg.bgImage,
@@ -1661,6 +1663,14 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
1661
1663
  const next = { ...current, ...sanitizeGlass(typeof body === "object" && body !== null ? body : {}) };
1662
1664
  await mkdir(glassDir, { recursive: true, mode: 0o700 });
1663
1665
  await writeFile(glassFile, JSON.stringify(next, null, 2), "utf8");
1666
+ // 背景图若有变更且是 data-URI, 存入 backgrounds/ 供"选择旧图"使用
1667
+ if (next.bgImage && current.bgImage !== next.bgImage && /^data:image\//.test(next.bgImage)) {
1668
+ try {
1669
+ await mkdir(bgDir, { recursive: true, mode: 0o700 });
1670
+ const name = Date.now() + ":" + Math.random().toString(36).slice(2, 8) + ".uri";
1671
+ await writeFile(join(bgDir, name), next.bgImage, "utf8");
1672
+ } catch (_) {}
1673
+ }
1664
1674
  sendJson(res, 200, { ok: true, saved: true });
1665
1675
  return;
1666
1676
  }
@@ -1669,8 +1679,26 @@ window.addEventListener('resize',function(){ try{ if(fitMode) zoomFit(); else ap
1669
1679
  sendError(res, error, onError);
1670
1680
  }
1671
1681
  };
1682
+ // 背景图历史(供设置面板"选择旧图"):GET 列出,GET ?name= 返回对应 data-URI
1683
+ const glassBackgrounds = async (req, res) => {
1684
+ try {
1685
+ requireTrusted(req);
1686
+ const url = new URL(req.url, "http://x");
1687
+ const name = url.searchParams.get("name");
1688
+ if (name) {
1689
+ if (!/^[\w.:-]+\.uri$/.test(name)) { sendError(res, new Error("bad name"), onError); return; }
1690
+ try { const buf = await readFile(join(bgDir, name)); res.writeHead(200, { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" }); res.end(buf); return; }
1691
+ catch { sendJson(res, 404, { error: "not found" }); return; }
1692
+ }
1693
+ let list = [];
1694
+ try { list = (await readdir(bgDir)).filter((n) => n.endsWith(".uri")).sort().reverse().slice(0, 30); } catch (_) {}
1695
+ sendJson(res, 200, { list });
1696
+ } catch (error) {
1697
+ sendError(res, error, onError);
1698
+ }
1699
+ };
1672
1700
 
1673
- return { root, maxFileBytes, totalMaxBytes, api, download, preview, workspaceList, workspaceFile, workspacePreview, workspaceBrowse, workspaceDelete, workspaceRename, workspaceSave, docxPreviewPage, docxPreviewAsset, pptxPreviewPage, xlsxPreviewPage, xlsxPreviewAsset, glassConfig };
1701
+ return { root, maxFileBytes, totalMaxBytes, api, download, preview, workspaceList, workspaceFile, workspacePreview, workspaceBrowse, workspaceDelete, workspaceRename, workspaceSave, docxPreviewPage, docxPreviewAsset, pptxPreviewPage, xlsxPreviewPage, xlsxPreviewAsset, glassConfig, glassBackgrounds };
1674
1702
  }
1675
1703
 
1676
1704
  /** 人类可读文件大小。 */
@@ -2575,6 +2603,12 @@ export async function apply(ctx, config = {}) {
2575
2603
  handler: handlers.glassConfig,
2576
2604
  }), "dsh-long-plugins: glass-ui config route");
2577
2605
 
2606
+ ctx.effect(() => ctx.webServer.register({
2607
+ kind: "exact",
2608
+ path: "/api/dsh-uploads/glass-backgrounds",
2609
+ handler: handlers.glassBackgrounds,
2610
+ }), "dsh-long-plugins: glass-ui backgrounds route");
2611
+
2578
2612
  ctx.effect(() => ctx.webServer.register({
2579
2613
  kind: "exact",
2580
2614
  path: "/api/dsh-uploads/workspace-browse",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-long-plugins",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
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",