dsh-client-ui-seaglass 1.6.0 → 1.6.1
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.en.md +2 -1
- package/README.md +2 -1
- package/assets/11.png +0 -0
- package/assets/12.png +0 -0
- package/assets/13.png +0 -0
- package/assets/14.png +0 -0
- package/lib/client.js +73 -8
- package/package.json +4 -2
- package/screenshots.json +6 -0
package/README.en.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.md)
|
|
4
4
|
|
|
5
|
-
> **Compatibility** — DSH `0.1.2-rc.1` · **Updated** 2026-09-06 · Plugin v1.6.
|
|
5
|
+
> **Compatibility** — DSH `0.1.2-rc.1` · **Updated** 2026-09-06 · Plugin v1.6.1
|
|
6
6
|
|
|
7
7
|
Seaglass is a highly customizable glassmorphism theme: it turns many surfaces into frosted-glass panes, and you can use your own images or videos as the backdrop. Switch the theme off and you are back to the stock UI — without changing a single line of DSH source. If you like the theme, feedback and PRs are welcome.
|
|
8
8
|
|
|
@@ -34,5 +34,6 @@ Clone the repo anywhere, then hand the **local folder** straight to `dsh plugin
|
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
36
|
git clone https://github.com/xiyunyunyun/dsh-client-ui-seaglass.git
|
|
37
|
+
npm install
|
|
37
38
|
dsh plugin --profile web add "C:\\path\\to\\dsh-client-ui-seaglass" # your actual clone path (absolute path recommended)
|
|
38
39
|
```
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.en.md) | 中文
|
|
4
4
|
|
|
5
|
-
> **适配版本** — DSH `0.1.2-rc.1` · **更新日期** 2026-09-06 · 插件 v1.6.
|
|
5
|
+
> **适配版本** — DSH `0.1.2-rc.1` · **更新日期** 2026-09-06 · 插件 v1.6.1
|
|
6
6
|
|
|
7
7
|
Seaglass 是一个高自由度的玻璃质感主题。把许多页面做成了磨砂玻璃片,你可以自定义图片和视频作为背景。关掉开关就回到原生界面,不改 DSH 任何一行源码。如果你喜欢该主题,欢迎提出建议或者拉到本地修改并提交PR。
|
|
8
8
|
|
|
@@ -34,6 +34,7 @@ dsh plugin --profile web add dsh-client-ui-seaglass
|
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
36
|
git clone https://github.com/xiyunyunyun/dsh-client-ui-seaglass.git
|
|
37
|
+
npm install
|
|
37
38
|
dsh plugin --profile web add "C:\path\to\dsh-client-ui-seaglass" # 用你的实际克隆路径(建议绝对路径)
|
|
38
39
|
```
|
|
39
40
|
|
package/assets/11.png
ADDED
|
Binary file
|
package/assets/12.png
ADDED
|
Binary file
|
package/assets/13.png
ADDED
|
Binary file
|
package/assets/14.png
ADDED
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -1991,7 +1991,7 @@ function closestSpot(target) {
|
|
|
1991
1991
|
let spotCache = null;
|
|
1992
1992
|
/** Drop the shared spot cache (the seam stamper calls this after touching
|
|
1993
1993
|
* any spot attribute; a full re-query happens on the next spotElements). */
|
|
1994
|
-
function invalidateSpotCache
|
|
1994
|
+
function invalidateSpotCache() {
|
|
1995
1995
|
spotCache = null;
|
|
1996
1996
|
}
|
|
1997
1997
|
/** Every stamped pane in document order. */
|
|
@@ -2550,12 +2550,42 @@ function stampPopoverShell(el, cs) {
|
|
|
2550
2550
|
* passes skip the memo: a root REUSED by React for a different view (same
|
|
2551
2551
|
* div, swapped children) gets re-judged within one catch-all period. */
|
|
2552
2552
|
const chatViewRoots = new WeakSet();
|
|
2553
|
+
/** Grace period before a non-chat verdict is TRUSTED. When a session opens,
|
|
2554
|
+
* the view root mounts FIRST and the chat marker set lands ~1.3s later
|
|
2555
|
+
* (measured: the conversation payload is loaded asynchronously) — a root
|
|
2556
|
+
* judged on its first frames reads as a plugin view, gets stamped
|
|
2557
|
+
* data-dsh-view + a spot on the ROOT ITSELF, and the whole message flow
|
|
2558
|
+
* tilts under the cursor until the next pass strips it (~1.7s of visibly
|
|
2559
|
+
* skewed text). So a fresh root enters a grace window instead: chat
|
|
2560
|
+
* markers appearing within it flip the verdict for free (every mutation
|
|
2561
|
+
* pass re-judges), and only a root that is STILL non-chat after the window
|
|
2562
|
+
* is stamped. The cost is a one-off ~1.5s glass delay for genuine plugin
|
|
2563
|
+
* views. */
|
|
2564
|
+
const PLUGIN_VIEW_GRACE_MS = 1500;
|
|
2565
|
+
const pluginViewFirstSeen = new WeakMap();
|
|
2566
|
+
let graceRecheckTimer = 0;
|
|
2567
|
+
/** Whether the stamper's feeds are live. The grace recheck timer can outlive
|
|
2568
|
+
* startSeamStamper (its closure owns no shared state with this module-level
|
|
2569
|
+
* helper), so the timer checks this flag instead of a closure variable. */
|
|
2570
|
+
let seamStamperActive = false;
|
|
2571
|
+
/** One delayed full re-check pass so a root whose grace window expires
|
|
2572
|
+
* between mutations still gets stamped (mutation passes alone may not fire
|
|
2573
|
+
* once the view settles). Idempotent — a pending timer is never doubled. */
|
|
2574
|
+
function scheduleGraceRecheck() {
|
|
2575
|
+
if (graceRecheckTimer !== 0) return;
|
|
2576
|
+
graceRecheckTimer = window.setTimeout(() => {
|
|
2577
|
+
graceRecheckTimer = 0;
|
|
2578
|
+
if (!seamStamperActive) return;
|
|
2579
|
+
stampAll(null);
|
|
2580
|
+
}, PLUGIN_VIEW_GRACE_MS + 50);
|
|
2581
|
+
}
|
|
2553
2582
|
function stampPluginViews(full) {
|
|
2554
2583
|
let touched = false;
|
|
2555
2584
|
for (const root of document.querySelectorAll("[data-slot=\"conversation.view\"] > *")) {
|
|
2556
2585
|
const isChat = !full && chatViewRoots.has(root) || root.querySelector("[data-slot^='conversation.chat'], [data-slot^='tool.call'], [data-composer-card], [data-dsh-inputbar]") !== null;
|
|
2557
|
-
if (isChat) chatViewRoots.add(root);
|
|
2558
2586
|
if (isChat) {
|
|
2587
|
+
chatViewRoots.add(root);
|
|
2588
|
+
pluginViewFirstSeen.delete(root);
|
|
2559
2589
|
if (root.hasAttribute("data-dsh-view")) {
|
|
2560
2590
|
root.removeAttribute("data-dsh-view");
|
|
2561
2591
|
touched = true;
|
|
@@ -2566,6 +2596,16 @@ function stampPluginViews(full) {
|
|
|
2566
2596
|
}
|
|
2567
2597
|
continue;
|
|
2568
2598
|
}
|
|
2599
|
+
const seen = pluginViewFirstSeen.get(root);
|
|
2600
|
+
if (seen === undefined) {
|
|
2601
|
+
pluginViewFirstSeen.set(root, performance.now());
|
|
2602
|
+
scheduleGraceRecheck();
|
|
2603
|
+
continue;
|
|
2604
|
+
}
|
|
2605
|
+
if (performance.now() - seen < PLUGIN_VIEW_GRACE_MS) {
|
|
2606
|
+
scheduleGraceRecheck();
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2569
2609
|
if (!root.hasAttribute("data-dsh-view")) {
|
|
2570
2610
|
root.setAttribute("data-dsh-view", "");
|
|
2571
2611
|
touched = true;
|
|
@@ -2593,6 +2633,7 @@ function stampPluginViews(full) {
|
|
|
2593
2633
|
* @returns a disposer that disconnects the observer.
|
|
2594
2634
|
*/
|
|
2595
2635
|
function startSeamStamper() {
|
|
2636
|
+
seamStamperActive = true;
|
|
2596
2637
|
stampAll(null);
|
|
2597
2638
|
let scheduled = 0;
|
|
2598
2639
|
let disposed = false;
|
|
@@ -2624,9 +2665,12 @@ function startSeamStamper() {
|
|
|
2624
2665
|
}, 800);
|
|
2625
2666
|
return () => {
|
|
2626
2667
|
disposed = true;
|
|
2668
|
+
seamStamperActive = false;
|
|
2627
2669
|
if (scheduled !== 0) cancelAnimationFrame(scheduled);
|
|
2628
2670
|
scheduled = 0;
|
|
2629
2671
|
window.clearInterval(catchAll);
|
|
2672
|
+
if (graceRecheckTimer !== 0) clearTimeout(graceRecheckTimer);
|
|
2673
|
+
graceRecheckTimer = 0;
|
|
2630
2674
|
observer.disconnect();
|
|
2631
2675
|
};
|
|
2632
2676
|
}
|
|
@@ -3360,6 +3404,7 @@ function startSpotlight() {
|
|
|
3360
3404
|
if (current === spot) {
|
|
3361
3405
|
current = null;
|
|
3362
3406
|
session = null;
|
|
3407
|
+
lastPointer = null;
|
|
3363
3408
|
}
|
|
3364
3409
|
const glow = spot.querySelector(`:scope > [${GLOW_ATTR}]`);
|
|
3365
3410
|
if (glow !== null) glow.style.removeProperty("background-image");
|
|
@@ -3368,6 +3413,23 @@ function startSpotlight() {
|
|
|
3368
3413
|
}
|
|
3369
3414
|
easeBack(spot);
|
|
3370
3415
|
};
|
|
3416
|
+
/** The pointer position whose radial was painted last (viewport space).
|
|
3417
|
+
* Geometry refreshes (the keeper's measure) must repaint the radial
|
|
3418
|
+
* against it — see the keeper callback below. */
|
|
3419
|
+
let lastPointer = null;
|
|
3420
|
+
/** Write (or clear) the glow radial for a pointer position. The gradient's
|
|
3421
|
+
* at coordinates are relative to the glow overlay's box (the visible
|
|
3422
|
+
* glass union), so whenever that box moves the radial must be rewritten
|
|
3423
|
+
* in the same breath — a stale at against a moved box misplaces the glow
|
|
3424
|
+
* by exactly the box shift. */
|
|
3425
|
+
const writeGlow = (s, clientX, clientY) => {
|
|
3426
|
+
if (s.glow === null) return;
|
|
3427
|
+
if (glowGated()) {
|
|
3428
|
+
s.glow.style.backgroundImage = `radial-gradient(${GLOW_RADIUS}px at ${clientX - s.visual.left}px ${clientY - s.visual.top}px, var(--dsh-aqua-spot-color, ${GLOW_FALLBACK}), transparent 70%)`;
|
|
3429
|
+
} else {
|
|
3430
|
+
s.glow.style.removeProperty("background-image");
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3371
3433
|
/** Capture (or refresh) the hover geometry; sets the glow overlay box. */
|
|
3372
3434
|
const measure = (spot) => {
|
|
3373
3435
|
const visual = visualRect(spot);
|
|
@@ -3391,6 +3453,7 @@ function startSpotlight() {
|
|
|
3391
3453
|
if (raf !== 0) return;
|
|
3392
3454
|
raf = requestAnimationFrame(() => {
|
|
3393
3455
|
raf = 0;
|
|
3456
|
+
if (session !== s) return;
|
|
3394
3457
|
const { spot, visual, local } = s;
|
|
3395
3458
|
if (!inside(visual, clientX, clientY)) {
|
|
3396
3459
|
clearSpot(spot);
|
|
@@ -3402,11 +3465,11 @@ function startSpotlight() {
|
|
|
3402
3465
|
glow = s.glow;
|
|
3403
3466
|
}
|
|
3404
3467
|
if (glow !== null) {
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3468
|
+
lastPointer = {
|
|
3469
|
+
x: clientX,
|
|
3470
|
+
y: clientY
|
|
3471
|
+
};
|
|
3472
|
+
writeGlow(s, clientX, clientY);
|
|
3410
3473
|
}
|
|
3411
3474
|
if (tiltGated() && tiltable(spot)) {
|
|
3412
3475
|
const dx = Math.min(.5, Math.max(-.5, (clientX - visual.left) / visual.width - .5));
|
|
@@ -3524,7 +3587,9 @@ function startSpotlight() {
|
|
|
3524
3587
|
if (session === null || refreshRaf !== 0) return;
|
|
3525
3588
|
refreshRaf = requestAnimationFrame(() => {
|
|
3526
3589
|
refreshRaf = 0;
|
|
3527
|
-
if (session
|
|
3590
|
+
if (session === null) return;
|
|
3591
|
+
session = measure(session.spot);
|
|
3592
|
+
if (lastPointer !== null) writeGlow(session, lastPointer.x, lastPointer.y);
|
|
3528
3593
|
});
|
|
3529
3594
|
});
|
|
3530
3595
|
document.addEventListener("pointermove", onMove, { passive: true });
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-client-ui-seaglass",
|
|
3
3
|
"description": "Seaglass: a highly customizable glassmorphism theme for the Web surface — adjustable blur, frost, fluid or wallpaper backdrop, unified corners, and motion",
|
|
4
|
-
"version": "1.6.
|
|
4
|
+
"version": "1.6.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -88,7 +88,9 @@
|
|
|
88
88
|
"lib/invariant.js",
|
|
89
89
|
"lib/client.js",
|
|
90
90
|
"lib/types/**/*.d.ts",
|
|
91
|
-
"cordis.patch.yml"
|
|
91
|
+
"cordis.patch.yml",
|
|
92
|
+
"screenshots.json",
|
|
93
|
+
"assets/*.png"
|
|
92
94
|
],
|
|
93
95
|
"dependencies": {
|
|
94
96
|
"@deepseek-ai/schemastery": "3.18.2"
|