dsh-skin-galactic-opera 0.1.8 → 0.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/CHANGELOG.md +18 -0
- package/README.md +197 -29
- package/lib/client.js +137 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## 0.2.0 - 2026-09-04
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Pauses skin animation work while the page is hidden to reduce background CPU/GPU usage.
|
|
10
|
+
- Suspends telemetry scans while the page is hidden, then forces an immediate refresh plus a short follow-up when the page becomes visible again.
|
|
11
|
+
|
|
12
|
+
## 0.1.9 - 2026-09-03
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- Replaces the README with separate English and Simplified Chinese sections linked from a language switcher at the top.
|
|
17
|
+
- Refreshes the bottom-right telemetry HUD promptly when switching conversations or navigating between sessions.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Keeps navigation-triggered telemetry refreshes active even when the instruction input still has focus.
|
|
22
|
+
|
|
5
23
|
## 0.1.8 - 2026-09-03
|
|
6
24
|
|
|
7
25
|
### Added
|
package/README.md
CHANGED
|
@@ -1,37 +1,51 @@
|
|
|
1
1
|
# dsh-skin-galactic-opera
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">DSH Web GUI 非官方 太空歌剧风 暗色 动态 皮肤插件</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="#english">English</a> · <a href="#简体中文">简体中文</a>
|
|
7
|
+
</p>
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
---
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
## English
|
|
12
|
+
|
|
13
|
+
Unofficial cinematic space-opera dark skin bundle for the DSH Web GUI.
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
It uses generic sci-fi visual language: deep-space backgrounds, neon HUD chrome, a central black-hole accretion disk, a planet with orbital elements, scanner UI, comet trails, energy beams, subtle starfighter silhouettes, telemetry chrome, and a hyperspace-style send effect.
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
> This package is not affiliated with, endorsed by, or derived from any specific franchise. It does **not** include or recreate official logos, characters, ship designs, quotes, proprietary names, or protected visual designs.
|
|
18
|
+
|
|
19
|
+
### Features
|
|
12
20
|
|
|
13
21
|
- Registers and enables the `galactic-opera` dark theme.
|
|
14
22
|
- Overrides DSH Web GUI theme tokens for backgrounds, borders, text, brand colors, state colors, scrollbars, and sidebar surfaces.
|
|
15
|
-
- Adds global
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
+
- Adds global space-opera styling:
|
|
24
|
+
- deep-space background layers;
|
|
25
|
+
- diagonal hyperspace lanes;
|
|
26
|
+
- hover glow for buttons, inputs, messages, and code blocks;
|
|
27
|
+
- sci-fi text selection and code block glow.
|
|
28
|
+
- Adds decorative visual elements:
|
|
29
|
+
- central black-hole accretion disk with subtle infall particles;
|
|
30
|
+
- top-right planet, moon, and elliptical satellite orbit;
|
|
31
|
+
- bottom-left rotating scanner HUD and holographic route map;
|
|
32
|
+
- red, cyan, and gold energy beams;
|
|
33
|
+
- sparse twinkling stars, comets, and generic V-shaped starfighter silhouettes;
|
|
34
|
+
- gold mission-briefing crawl panel.
|
|
23
35
|
- Adds interactions:
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
|
|
36
|
+
- subtle pointer parallax;
|
|
37
|
+
- click energy pulse;
|
|
38
|
+
- scanner target ping projected from the clicked position;
|
|
39
|
+
- automatic hyperspace burst after submitting a new instruction or message;
|
|
40
|
+
- fixed bottom-right telemetry/status HUD panel.
|
|
41
|
+
- Uses Shadow DOM for the decorative layer to reduce interference from host application styles.
|
|
30
42
|
- Respects `prefers-reduced-motion: reduce` by disabling major animations.
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
### Telemetry panel
|
|
45
|
+
|
|
46
|
+
When DSH Web exposes bottom status/usage data, the skin keeps the original UI layout in place and mirrors the detected global telemetry into a non-interactive bottom-right HUD panel.
|
|
33
47
|
|
|
34
|
-
|
|
48
|
+
The panel is intended to show a consistent five-line status block:
|
|
35
49
|
|
|
36
50
|
```text
|
|
37
51
|
312 轮 · 8732 步
|
|
@@ -43,9 +57,9 @@ LLM 2253m42s · 工具调用 972m8s
|
|
|
43
57
|
|
|
44
58
|
The skin treats each original pipe-separated bottom-bar segment as a complete information block, so combined items such as `首 token 平均 ... · ... tok/s` and `输入 ... · 输出 ...` remain intact. It also filters nearby message-level timing text and settings/menu text so the panel stays focused on global session telemetry.
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
### Installation
|
|
47
61
|
|
|
48
|
-
|
|
62
|
+
#### From npm
|
|
49
63
|
|
|
50
64
|
Recommended for most users:
|
|
51
65
|
|
|
@@ -59,13 +73,13 @@ npm package page:
|
|
|
59
73
|
https://www.npmjs.com/package/dsh-skin-galactic-opera
|
|
60
74
|
```
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
#### From GitHub
|
|
63
77
|
|
|
64
78
|
```powershell
|
|
65
79
|
dsh plugin --profile web add https://github.com/xmnathan/dsh-skin-galactic-opera.git
|
|
66
80
|
```
|
|
67
81
|
|
|
68
|
-
|
|
82
|
+
#### From a local checkout
|
|
69
83
|
|
|
70
84
|
From the parent directory of this package:
|
|
71
85
|
|
|
@@ -91,7 +105,7 @@ If the browser keeps an older client bundle, use a hard refresh:
|
|
|
91
105
|
Ctrl + F5
|
|
92
106
|
```
|
|
93
107
|
|
|
94
|
-
|
|
108
|
+
### Uninstall
|
|
95
109
|
|
|
96
110
|
```powershell
|
|
97
111
|
dsh plugin --profile web remove dsh-skin-galactic-opera
|
|
@@ -99,7 +113,7 @@ dsh plugin --profile web remove dsh-skin-galactic-opera
|
|
|
99
113
|
|
|
100
114
|
Refresh the Web GUI after uninstalling.
|
|
101
115
|
|
|
102
|
-
|
|
116
|
+
### Development
|
|
103
117
|
|
|
104
118
|
Check browser-side JavaScript syntax:
|
|
105
119
|
|
|
@@ -119,7 +133,7 @@ Publish to npm:
|
|
|
119
133
|
npm publish
|
|
120
134
|
```
|
|
121
135
|
|
|
122
|
-
|
|
136
|
+
### Package structure
|
|
123
137
|
|
|
124
138
|
```text
|
|
125
139
|
dsh-skin-galactic-opera/
|
|
@@ -138,6 +152,160 @@ dsh-skin-galactic-opera/
|
|
|
138
152
|
- `lib/index.js`: host-side no-op entry.
|
|
139
153
|
- `lib/client.js`: browser-side theme, decoration, and interaction implementation.
|
|
140
154
|
|
|
141
|
-
|
|
155
|
+
### License
|
|
156
|
+
|
|
157
|
+
MIT
|
|
158
|
+
|
|
159
|
+
<p align="right"><a href="#dsh-skin-galactic-opera">Back to top ↑</a></p>
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 简体中文
|
|
164
|
+
|
|
165
|
+
DSH Web GUI 的非官方电影感太空歌剧暗色皮肤插件。
|
|
166
|
+
|
|
167
|
+
它使用通用科幻视觉语言:深空背景、霓虹 HUD、中央黑洞吸积盘、行星与轨道元素、扫描器界面、彗星轨迹、能量束、克制的战机剪影、遥测信息面板,以及发送消息时的超空间风格特效。
|
|
168
|
+
|
|
169
|
+
> 本插件不隶属于、不受认可于、也不派生自任何特定影视或游戏系列。它**不包含也不复刻**任何官方 logo、角色、飞船设计、台词、专有名称或受保护视觉设计。
|
|
170
|
+
|
|
171
|
+
### 功能特性
|
|
172
|
+
|
|
173
|
+
- 注册并启用 `galactic-opera` 暗色主题。
|
|
174
|
+
- 覆盖 DSH Web GUI 的主题 token,包括背景、边框、文本、品牌色、状态色、滚动条和侧边栏表面。
|
|
175
|
+
- 添加全局太空歌剧风格:
|
|
176
|
+
- 深空背景层;
|
|
177
|
+
- 斜向超空间航道;
|
|
178
|
+
- 按钮、输入框、消息和代码块的悬停辉光;
|
|
179
|
+
- 科幻风格文本选中与代码块辉光。
|
|
180
|
+
- 添加装饰性视觉元素:
|
|
181
|
+
- 带轻微吸入粒子的中央黑洞吸积盘;
|
|
182
|
+
- 右上角行星、卫星和椭圆卫星轨道;
|
|
183
|
+
- 左下角旋转扫描盘 HUD 和全息路线图;
|
|
184
|
+
- 红、青、金三色能量束;
|
|
185
|
+
- 稀疏闪烁星点、彗星和通用 V 形战机剪影;
|
|
186
|
+
- 金色任务简报滚动面板。
|
|
187
|
+
- 添加交互效果:
|
|
188
|
+
- 轻微鼠标视差;
|
|
189
|
+
- 点击能量脉冲;
|
|
190
|
+
- 根据点击位置投影到扫描盘的目标 ping;
|
|
191
|
+
- 提交新指令或消息后的自动超空间爆发;
|
|
192
|
+
- 固定在右下角的 telemetry / 状态 HUD 面板。
|
|
193
|
+
- 装饰层使用 Shadow DOM,减少宿主应用样式对行星、扫描盘、点击脉冲等几何形态的污染。
|
|
194
|
+
- 遵循 `prefers-reduced-motion: reduce`,会关闭主要动画。
|
|
195
|
+
|
|
196
|
+
### Telemetry 面板
|
|
197
|
+
|
|
198
|
+
当 DSH Web 暴露底部状态/用量信息时,皮肤会保留原始 UI 布局,并将检测到的全局 telemetry 镜像到右下角的非交互 HUD 面板中。
|
|
199
|
+
|
|
200
|
+
面板目标是稳定显示五行状态信息:
|
|
201
|
+
|
|
202
|
+
```text
|
|
203
|
+
312 轮 · 8732 步
|
|
204
|
+
LLM 2253m42s · 工具调用 972m8s
|
|
205
|
+
首 token 平均 10.5s · 58 tok/s
|
|
206
|
+
缓存命中 97%
|
|
207
|
+
输入 1369M tok · 输出 2.5M tok
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
皮肤会把原始底栏中用竖线分隔的每一段都视为完整信息块,因此 `首 token 平均 ... · ... tok/s`、`输入 ... · 输出 ...` 这类组合信息不会被拆散。同时也会过滤附近的单条消息耗时、设置菜单文本等内容,让面板聚焦于全局会话 telemetry。
|
|
211
|
+
|
|
212
|
+
### 安装
|
|
213
|
+
|
|
214
|
+
#### 通过 npm 安装
|
|
215
|
+
|
|
216
|
+
推荐大多数用户使用:
|
|
217
|
+
|
|
218
|
+
```powershell
|
|
219
|
+
dsh plugin --profile web add dsh-skin-galactic-opera
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
npm 包页面:
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
https://www.npmjs.com/package/dsh-skin-galactic-opera
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### 通过 GitHub 安装
|
|
229
|
+
|
|
230
|
+
```powershell
|
|
231
|
+
dsh plugin --profile web add https://github.com/xmnathan/dsh-skin-galactic-opera.git
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
#### 通过本地源码安装
|
|
235
|
+
|
|
236
|
+
在本包的上级目录执行:
|
|
237
|
+
|
|
238
|
+
```powershell
|
|
239
|
+
dsh plugin --profile web add ./dsh-skin-galactic-opera
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
也可以使用绝对路径:
|
|
243
|
+
|
|
244
|
+
```powershell
|
|
245
|
+
dsh plugin --profile web add D:\path\to\dsh-skin-galactic-opera
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
然后刷新 DSH Web GUI,通常地址为:
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
http://127.0.0.1:3080
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
如果浏览器仍然缓存旧的客户端 bundle,请使用硬刷新:
|
|
255
|
+
|
|
256
|
+
```text
|
|
257
|
+
Ctrl + F5
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### 卸载
|
|
261
|
+
|
|
262
|
+
```powershell
|
|
263
|
+
dsh plugin --profile web remove dsh-skin-galactic-opera
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
卸载后刷新 Web GUI。
|
|
267
|
+
|
|
268
|
+
### 开发
|
|
269
|
+
|
|
270
|
+
检查浏览器端 JavaScript 语法:
|
|
271
|
+
|
|
272
|
+
```powershell
|
|
273
|
+
npm run check
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
发布前预览 npm 包内容:
|
|
277
|
+
|
|
278
|
+
```powershell
|
|
279
|
+
npm run pack:dry
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
发布到 npm:
|
|
283
|
+
|
|
284
|
+
```powershell
|
|
285
|
+
npm publish
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### 包结构
|
|
289
|
+
|
|
290
|
+
```text
|
|
291
|
+
dsh-skin-galactic-opera/
|
|
292
|
+
├─ package.json
|
|
293
|
+
├─ cordis.patch.yml
|
|
294
|
+
├─ README.md
|
|
295
|
+
├─ LICENSE
|
|
296
|
+
├─ CHANGELOG.md
|
|
297
|
+
└─ lib/
|
|
298
|
+
├─ index.js
|
|
299
|
+
└─ client.js
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
- `package.json`:包元数据、npm 发布设置、DSH bundle 声明和 Web client 插件声明。
|
|
303
|
+
- `cordis.patch.yml`:将 `dsh-skin-galactic-opera` client 插件插入 Web profile。
|
|
304
|
+
- `lib/index.js`:宿主侧空实现入口。
|
|
305
|
+
- `lib/client.js`:浏览器侧主题、装饰层和交互实现。
|
|
306
|
+
|
|
307
|
+
### 许可证
|
|
142
308
|
|
|
143
309
|
MIT
|
|
310
|
+
|
|
311
|
+
<p align="right"><a href="#dsh-skin-galactic-opera">返回顶部 ↑</a></p>
|
package/lib/client.js
CHANGED
|
@@ -11,6 +11,7 @@ window.__ModuleLoader__.load({
|
|
|
11
11
|
const STYLE_ID = "dsh-skin-galactic-opera-style";
|
|
12
12
|
const DECOR_ID = "dsh-skin-galactic-opera-decor";
|
|
13
13
|
const DECOR_HOST_CLASS = "dsh-skin-galactic-opera-decor-host";
|
|
14
|
+
const PAGE_HIDDEN_CLASS = "dsh-skin-galactic-opera-page-hidden";
|
|
14
15
|
const CSS_TAG_ID = `${PLUGIN_ID}/global.css`;
|
|
15
16
|
|
|
16
17
|
const TOKENS = Object.freeze({
|
|
@@ -170,6 +171,16 @@ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active :is(.dsh-skin-
|
|
|
170
171
|
opacity: 0.16 !important;
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden::before,
|
|
175
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden::after,
|
|
176
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden #root::before,
|
|
177
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden .dsh-skin-galactic-opera-decor::before,
|
|
178
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden .dsh-skin-galactic-opera-decor *,
|
|
179
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden .dsh-skin-galactic-opera-decor *::before,
|
|
180
|
+
body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden .dsh-skin-galactic-opera-decor *::after {
|
|
181
|
+
animation-play-state: paused !important;
|
|
182
|
+
}
|
|
183
|
+
|
|
173
184
|
body.dsh-skin-galactic-opera #root > *,
|
|
174
185
|
body.dsh-skin-galactic-opera main,
|
|
175
186
|
body.dsh-skin-galactic-opera aside,
|
|
@@ -1149,6 +1160,7 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1149
1160
|
return `${CSS
|
|
1150
1161
|
.replace(/body\.dsh-skin-galactic-opera\.dsh-skin-galactic-opera-input-active\s+/g, ":host-context(body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active) ")
|
|
1151
1162
|
.replace(/body\.dsh-skin-galactic-opera\.dsh-skin-galactic-opera-hyperspace\s+/g, ":host-context(body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-hyperspace) ")
|
|
1163
|
+
.replace(/body\.dsh-skin-galactic-opera\.dsh-skin-galactic-opera-page-hidden\s+/g, ":host-context(body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-page-hidden) ")
|
|
1152
1164
|
.replace(/body\.dsh-skin-galactic-opera\s+/g, "")}
|
|
1153
1165
|
|
|
1154
1166
|
.dsh-skin-galactic-opera-decor {
|
|
@@ -1249,6 +1261,20 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1249
1261
|
}
|
|
1250
1262
|
|
|
1251
1263
|
const EDITABLE_CONTENT_SELECTOR = `[contenteditable]:not([contenteditable="false"])`;
|
|
1264
|
+
|
|
1265
|
+
function installVisibilityState() {
|
|
1266
|
+
if (typeof document === "undefined" || typeof window === "undefined") return () => {};
|
|
1267
|
+
const syncVisibilityClass = () => {
|
|
1268
|
+
document.body.classList.toggle(PAGE_HIDDEN_CLASS, document.hidden);
|
|
1269
|
+
};
|
|
1270
|
+
syncVisibilityClass();
|
|
1271
|
+
document.addEventListener("visibilitychange", syncVisibilityClass);
|
|
1272
|
+
return () => {
|
|
1273
|
+
document.removeEventListener("visibilitychange", syncVisibilityClass);
|
|
1274
|
+
document.body.classList.remove(PAGE_HIDDEN_CLASS);
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1252
1278
|
let reducedMotionQuery;
|
|
1253
1279
|
let reducedMotionMatches = false;
|
|
1254
1280
|
let reducedMotionListener;
|
|
@@ -1452,9 +1478,14 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1452
1478
|
let currentSources = new Set();
|
|
1453
1479
|
let lastText = "";
|
|
1454
1480
|
let frame = 0;
|
|
1481
|
+
let frameIgnoresTelemetryPause = false;
|
|
1455
1482
|
let forceTelemetryRescan = true;
|
|
1456
1483
|
let telemetryRefreshesSinceFullScan = 0;
|
|
1484
|
+
let lastTelemetryLocationKey = typeof window.location === "undefined" ? "" : `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
1485
|
+
const telemetryNavigationTimers = new Set();
|
|
1457
1486
|
const TELEMETRY_UPDATE_DELAY = 300;
|
|
1487
|
+
const TELEMETRY_NAV_UPDATE_DELAY = 48;
|
|
1488
|
+
const TELEMETRY_NAV_FOLLOWUP_DELAY = 220;
|
|
1458
1489
|
const TELEMETRY_FULL_RESCAN_UPDATES = 7;
|
|
1459
1490
|
let collapsed = false;
|
|
1460
1491
|
try {
|
|
@@ -1668,9 +1699,10 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1668
1699
|
if (!sources.every((source) => source.isConnected && getCandidateInfo(source) !== undefined)) return false;
|
|
1669
1700
|
return splitTelemetryRows(getSourcesText(currentSources)).length > 0;
|
|
1670
1701
|
};
|
|
1671
|
-
const update = () => {
|
|
1702
|
+
const update = ({ ignorePause = false } = {}) => {
|
|
1672
1703
|
frame = 0;
|
|
1673
|
-
|
|
1704
|
+
frameIgnoresTelemetryPause = false;
|
|
1705
|
+
if (document.hidden || (!ignorePause && isTelemetryPaused())) return;
|
|
1674
1706
|
let nextSources = currentSources;
|
|
1675
1707
|
let text = getSourcesText(nextSources);
|
|
1676
1708
|
const needsFullScan = forceTelemetryRescan || telemetryRefreshesSinceFullScan >= TELEMETRY_FULL_RESCAN_UPDATES || !areCachedSourcesUsable();
|
|
@@ -1689,13 +1721,78 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1689
1721
|
lastText = text;
|
|
1690
1722
|
renderPanel(text);
|
|
1691
1723
|
};
|
|
1692
|
-
const schedule = () => {
|
|
1693
|
-
if (isTelemetryPaused()) return;
|
|
1694
|
-
if (
|
|
1724
|
+
const schedule = ({ delay = TELEMETRY_UPDATE_DELAY, force = false, ignorePause = false } = {}) => {
|
|
1725
|
+
if (document.hidden || (!ignorePause && isTelemetryPaused())) return;
|
|
1726
|
+
if (force) forceTelemetryRescan = true;
|
|
1727
|
+
if (frame !== 0) {
|
|
1728
|
+
if (!force && delay >= TELEMETRY_UPDATE_DELAY) return;
|
|
1729
|
+
window.clearTimeout(frame);
|
|
1730
|
+
frameIgnoresTelemetryPause = false;
|
|
1731
|
+
}
|
|
1732
|
+
frameIgnoresTelemetryPause = ignorePause;
|
|
1733
|
+
frame = window.setTimeout(() => update({ ignorePause }), delay);
|
|
1734
|
+
};
|
|
1735
|
+
const getTelemetryLocationKey = () => `${window.location.pathname}${window.location.search}${window.location.hash}`;
|
|
1736
|
+
const setTelemetryNavigationTimer = (callback, delay) => {
|
|
1737
|
+
const timer = window.setTimeout(() => {
|
|
1738
|
+
telemetryNavigationTimers.delete(timer);
|
|
1739
|
+
callback();
|
|
1740
|
+
}, delay);
|
|
1741
|
+
telemetryNavigationTimers.add(timer);
|
|
1742
|
+
return timer;
|
|
1695
1743
|
};
|
|
1744
|
+
const refreshTelemetryForNavigation = () => {
|
|
1745
|
+
lastTelemetryLocationKey = getTelemetryLocationKey();
|
|
1746
|
+
schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
|
|
1747
|
+
setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
|
|
1748
|
+
};
|
|
1749
|
+
const checkTelemetryLocation = () => {
|
|
1750
|
+
const nextKey = getTelemetryLocationKey();
|
|
1751
|
+
if (nextKey !== lastTelemetryLocationKey) refreshTelemetryForNavigation();
|
|
1752
|
+
};
|
|
1753
|
+
const onTelemetryNavigationClick = (event) => {
|
|
1754
|
+
if (isSkinOwnedNode(event.target) || isEditableTarget(event.target)) return;
|
|
1755
|
+
const target = event.target instanceof Element ? event.target.closest("a[href], button, [role=button], [aria-current], [data-active]") : null;
|
|
1756
|
+
if (target === null) return;
|
|
1757
|
+
schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
|
|
1758
|
+
setTelemetryNavigationTimer(checkTelemetryLocation, 0);
|
|
1759
|
+
setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
|
|
1760
|
+
};
|
|
1761
|
+
const isPotentialTelemetryNavigationMutation = (mutation) => {
|
|
1762
|
+
if (mutation.type !== "childList") return false;
|
|
1763
|
+
const nodes = [...mutation.addedNodes, ...mutation.removedNodes];
|
|
1764
|
+
return nodes.some((node) => {
|
|
1765
|
+
const element = getMutationElement(node);
|
|
1766
|
+
if (!(element instanceof Element) || isSkinOwnedNode(element) || isEditableTarget(element)) return false;
|
|
1767
|
+
const text = normalizeTelemetryText(element.textContent || "");
|
|
1768
|
+
return element.matches?.("main, section, article, aside, nav, [role=main], [role=navigation], [data-active], [aria-current]")
|
|
1769
|
+
|| element.querySelector?.("main, section, article, aside, nav, [role=main], [role=navigation], [data-active], [aria-current]") !== null
|
|
1770
|
+
|| telemetryPattern.test(text);
|
|
1771
|
+
});
|
|
1772
|
+
};
|
|
1773
|
+
const originalPushState = window.history?.pushState;
|
|
1774
|
+
const originalReplaceState = window.history?.replaceState;
|
|
1775
|
+
let telemetryPushState;
|
|
1776
|
+
let telemetryReplaceState;
|
|
1777
|
+
if (typeof originalPushState === "function") {
|
|
1778
|
+
telemetryPushState = function dshSkinTelemetryPushState(...args) {
|
|
1779
|
+
const result = originalPushState.apply(this, args);
|
|
1780
|
+
setTelemetryNavigationTimer(checkTelemetryLocation, 0);
|
|
1781
|
+
return result;
|
|
1782
|
+
};
|
|
1783
|
+
window.history.pushState = telemetryPushState;
|
|
1784
|
+
}
|
|
1785
|
+
if (typeof originalReplaceState === "function") {
|
|
1786
|
+
telemetryReplaceState = function dshSkinTelemetryReplaceState(...args) {
|
|
1787
|
+
const result = originalReplaceState.apply(this, args);
|
|
1788
|
+
setTelemetryNavigationTimer(checkTelemetryLocation, 0);
|
|
1789
|
+
return result;
|
|
1790
|
+
};
|
|
1791
|
+
window.history.replaceState = telemetryReplaceState;
|
|
1792
|
+
}
|
|
1696
1793
|
const onTelemetryFocusIn = (event) => {
|
|
1697
1794
|
if (!isInstructionInputTarget(event.target)) return;
|
|
1698
|
-
if (frame !== 0) {
|
|
1795
|
+
if (frame !== 0 && !frameIgnoresTelemetryPause) {
|
|
1699
1796
|
window.clearTimeout(frame);
|
|
1700
1797
|
frame = 0;
|
|
1701
1798
|
}
|
|
@@ -1707,21 +1804,53 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1707
1804
|
forceTelemetryRescan = true;
|
|
1708
1805
|
schedule();
|
|
1709
1806
|
};
|
|
1807
|
+
const onTelemetryVisibilityChange = () => {
|
|
1808
|
+
if (document.hidden) {
|
|
1809
|
+
if (frame !== 0) {
|
|
1810
|
+
window.clearTimeout(frame);
|
|
1811
|
+
frame = 0;
|
|
1812
|
+
}
|
|
1813
|
+
frameIgnoresTelemetryPause = false;
|
|
1814
|
+
for (const timer of telemetryNavigationTimers) window.clearTimeout(timer);
|
|
1815
|
+
telemetryNavigationTimers.clear();
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
schedule({ delay: 0, force: true, ignorePause: true });
|
|
1819
|
+
setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
|
|
1820
|
+
};
|
|
1710
1821
|
const observer = typeof MutationObserver === "undefined" ? undefined : new MutationObserver((mutations) => {
|
|
1711
1822
|
if (mutations.every(isSkinOwnedMutation)) return;
|
|
1823
|
+
if (isTelemetryPaused() && mutations.some(isPotentialTelemetryNavigationMutation)) {
|
|
1824
|
+
schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
|
|
1825
|
+
setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1712
1828
|
schedule();
|
|
1713
1829
|
});
|
|
1714
1830
|
schedule();
|
|
1715
1831
|
observer?.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
1716
1832
|
window.addEventListener("resize", onTelemetryResize, { passive: true });
|
|
1833
|
+
document.addEventListener("visibilitychange", onTelemetryVisibilityChange);
|
|
1834
|
+
window.addEventListener("popstate", checkTelemetryLocation, { passive: true });
|
|
1835
|
+
window.addEventListener("hashchange", checkTelemetryLocation, { passive: true });
|
|
1836
|
+
document.addEventListener("click", onTelemetryNavigationClick, true);
|
|
1717
1837
|
document.addEventListener("focusin", onTelemetryFocusIn);
|
|
1718
1838
|
document.addEventListener("focusout", onTelemetryFocusOut);
|
|
1719
1839
|
return () => {
|
|
1720
1840
|
observer?.disconnect();
|
|
1841
|
+
if (telemetryPushState !== undefined && window.history.pushState === telemetryPushState) window.history.pushState = originalPushState;
|
|
1842
|
+
if (telemetryReplaceState !== undefined && window.history.replaceState === telemetryReplaceState) window.history.replaceState = originalReplaceState;
|
|
1721
1843
|
window.removeEventListener("resize", onTelemetryResize);
|
|
1844
|
+
document.removeEventListener("visibilitychange", onTelemetryVisibilityChange);
|
|
1845
|
+
window.removeEventListener("popstate", checkTelemetryLocation);
|
|
1846
|
+
window.removeEventListener("hashchange", checkTelemetryLocation);
|
|
1847
|
+
document.removeEventListener("click", onTelemetryNavigationClick, true);
|
|
1722
1848
|
document.removeEventListener("focusin", onTelemetryFocusIn);
|
|
1723
1849
|
document.removeEventListener("focusout", onTelemetryFocusOut);
|
|
1724
1850
|
if (frame !== 0) window.clearTimeout(frame);
|
|
1851
|
+
frameIgnoresTelemetryPause = false;
|
|
1852
|
+
for (const timer of telemetryNavigationTimers) window.clearTimeout(timer);
|
|
1853
|
+
telemetryNavigationTimers.clear();
|
|
1725
1854
|
for (const source of currentSources) source.classList.remove("dsh-skin-telemetry-source-hidden");
|
|
1726
1855
|
toggle.remove();
|
|
1727
1856
|
panel.remove();
|
|
@@ -1734,12 +1863,14 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
|
|
|
1734
1863
|
ctx.effect(() => {
|
|
1735
1864
|
const style = ensureStyle();
|
|
1736
1865
|
if (typeof document !== "undefined") document.body.classList.add("dsh-skin-galactic-opera");
|
|
1866
|
+
const disposeVisibilityState = installVisibilityState();
|
|
1737
1867
|
const decor = ensureDecor();
|
|
1738
1868
|
const disposeInteractions = installInteractions(decor);
|
|
1739
1869
|
const disposeTelemetryPanel = installTelemetryPanel();
|
|
1740
1870
|
return () => {
|
|
1741
1871
|
disposeTelemetryPanel();
|
|
1742
1872
|
disposeInteractions();
|
|
1873
|
+
disposeVisibilityState();
|
|
1743
1874
|
disposeReducedMotionCache();
|
|
1744
1875
|
if (typeof document !== "undefined") document.body.classList.remove("dsh-skin-galactic-opera");
|
|
1745
1876
|
decor?.remove();
|