dsh-bridge-gateway 0.2.2 → 0.3.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 +74 -0
- package/README.md +17 -3
- package/README.zh.md +18 -2
- package/assets/apple-touch-icon-180.png +0 -0
- package/assets/icon-192.png +0 -0
- package/assets/icon-512.png +0 -0
- package/assets/icon-maskable-192.png +0 -0
- package/assets/icon-maskable-512.png +0 -0
- package/client/client.js +302 -41
- package/client/index.js +438 -42
- package/docs/banner.jpg +0 -0
- package/docs/custom-tunnel.md +5 -5
- package/docs/platform-abstraction-design.md +1 -1
- package/docs/qq-usage.md +6 -6
- package/docs/screenshots/remote-auth-login-light.jpg +0 -0
- package/docs/screenshots/remote-auth-login.jpg +0 -0
- package/docs/wechat-usage.md +1 -1
- package/lib/auth/brand-assets.js +131 -0
- package/lib/auth/login-template.js +503 -361
- package/lib/auth/manager.js +47 -12
- package/lib/auth/theme-tokens.js +142 -0
- package/lib/bridge-rpc.js +2 -2
- package/lib/cloudflared-manager.mjs +1 -1
- package/lib/feishu/gateway.js +17 -17
- package/lib/feishu/index.js +3 -3
- package/lib/feishu/lark-bundled.mjs +288 -469
- package/lib/feishu/node.js +7 -7
- package/lib/gateway/cert.js +1 -1
- package/lib/index.js +210 -80
- package/lib/paths.js +43 -14
- package/lib/platform/base.js +2 -2
- package/lib/platform/conversation-bridge.js +17 -17
- package/lib/platform/index.js +1 -1
- package/lib/platform/manager.js +4 -4
- package/lib/qq/gateway.js +10 -10
- package/lib/qq/index.js +11 -11
- package/lib/qq/node.js +17 -17
- package/lib/telegram/gateway.js +10 -10
- package/lib/telegram/index.js +3 -3
- package/lib/telegram/node.js +5 -5
- package/lib/wechat/gateway.js +6 -6
- package/lib/wechat/index.js +4 -4
- package/lib/wechat/media.js +1 -1
- package/lib/wechat/node.js +13 -13
- package/package.json +6 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,80 @@
|
|
|
2
2
|
|
|
3
3
|
本项目 `dsh-bridge-gateway` 是基于 [dsh-bridge](https://github.com/wenbin-wb/dsh-bridge) 的移植增强分支,在保留原版能力之外,重点新增「公网直连网关」。
|
|
4
4
|
|
|
5
|
+
## [0.3.0] - 2026-10-17
|
|
6
|
+
|
|
7
|
+
### 新增:PWA 主屏图标(真 PNG + DSH 业务蓝)
|
|
8
|
+
|
|
9
|
+
此前 manifest 只声明了 `image/svg+xml` 图标,且 `/apple-touch-icon.png` 也返回 SVG。
|
|
10
|
+
**华为 HarmonyOS 与多数 Android 启动器不支持 SVG 图标**,于是「添加到桌面」后得到的是一块
|
|
11
|
+
空白图标。底色也由近黑 `#151517` 改为 DSH 业务蓝 `#4176e6` —— 近黑底在深色桌面上会糊成
|
|
12
|
+
一块「光板」,这也是「图标是空白的」观感来源之一。
|
|
13
|
+
|
|
14
|
+
- 新增 `scripts/generate-icons.mjs`:用无头 Chrome 渲染 192/512 的 `any` 与 `maskable` 两版,
|
|
15
|
+
外加 iOS 的 180;产物入库 `assets/`
|
|
16
|
+
- manifest 声明 4 个 PNG;`/apple-touch-icon.png` 改为返回真 PNG
|
|
17
|
+
- `maskable` 版满幅不留圆角 —— 启动器会按自己的形状裁切,自带圆角会被裁掉一半
|
|
18
|
+
|
|
19
|
+
### 新增:远程登录页改版(DSH 元素)
|
|
20
|
+
|
|
21
|
+
登录页重做为门厅式设计,与 DSH 本体同源同一枚鲸鱼。
|
|
22
|
+
|
|
23
|
+
- `lib/auth/brand-assets.js`:品牌资产单一来源,附 sha256 前缀校验
|
|
24
|
+
- `lib/auth/theme-tokens.js`:18 个 `--dsw-*` token 的静态十六进制回落 —— 登录页在 DSH
|
|
25
|
+
之前渲染、加载不到 token,**每个 token 都必须有回落**
|
|
26
|
+
- 响应头:`no-store` + CSP。其中 `connect-src 'self'` 是登录 `fetch` 的必需项,漏掉会登录失败
|
|
27
|
+
|
|
28
|
+
### 修复:移动端 8 项问题
|
|
29
|
+
|
|
30
|
+
| # | 症状 | 根因 |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| 1 | 主屏图标空白 | 见上:HarmonyOS 不支持 SVG 图标 |
|
|
33
|
+
| 2 | 打开渠道中心时面板标题被顶栏盖住 | 插件顶栏 `position:fixed` + `z-index:9998` 不感知面板状态(面板 `z-index:80`,其标题落在 y19,正被顶栏的 y0-40 覆盖) |
|
|
34
|
+
| 3 | 会话名恒为「新会话」 | DSH 0.1.7 起 sessions list 快照不再提供 `current` 字段,旧实现读它 → 恒 `undefined` → **静默回落**默认文案(不报错,很难发现)。改读 `retainedBy.mainView > 0` 的那一个(与 `dsh-client-ui-session` 的判据一致) |
|
|
35
|
+
| 4 | 轨迹视图内容被裁 | `table` 元素的 `overflow` 在 CSS 里**是被忽略的**,只写 `overflow-x:auto` 无效,必须配 `display:block`。另:工具调用参数列内容宽 3049px 而可见仅 180px(17×),横滑读不了,改为换行 |
|
|
36
|
+
| 5 | 输入框压住内容 | 见下「已知问题」(两次尝试均已回退) |
|
|
37
|
+
| 6 | 顶部两层头过高、挤压对话区 | **DSH 自带 `min-height:76px`**,只改 padding 压不下去;显式清零后内容区 +51px |
|
|
38
|
+
| 7 | 「对话」视图下拉被内容盖住 | 祖先链 `titleRow` 与 `wSkVaW_root` 都是 `overflow:hidden`,下拉落在头部下方被**整块裁掉**(z-index 再高也没用,裁剪发生在层叠之前)。改为 body 级 portal |
|
|
39
|
+
| 8 | **滚不到最新会话**(只渲染约 4 条消息) | 插件给 `_frame` 注入的 `height:100dvh` + `overflow:hidden` 组合使 DSH 的布局测量算错,驻留窗口塌缩成 4 条。去掉这两个属性组后 `scrollHeight` 由 996 恢复到 11295 |
|
|
40
|
+
|
|
41
|
+
### 已知问题:#5 输入框压住内容(未修)
|
|
42
|
+
|
|
43
|
+
`composerSeat` 是 `position:sticky` 且为 `scrollBody` 的直接 flex 子项,吸住时会盖在滚动内容
|
|
44
|
+
之上。**两次尝试修复(改 `fixed` + 补 padding;再用 `visualViewport` 算键盘高度)都破坏了 DSH
|
|
45
|
+
的滚动锚定,均已回退。**
|
|
46
|
+
|
|
47
|
+
DSH 另有「覆盖层模式」(`:has([data-conversation-composer-overlay])`:`composerSeat` 转
|
|
48
|
+
`absolute`、`viewArea` 自己滚),但那是 `dsh-client-ui-trajectory`(轨迹视图)在用的,对话
|
|
49
|
+
视图没有开。**要根治得走 DSH 侧,插件 CSS 补不了。**
|
|
50
|
+
|
|
51
|
+
### 新增:真机诊断能力(长期保留)
|
|
52
|
+
|
|
53
|
+
真机上稳定复现、桌面视口复现不出的问题,可以不改代码直接二分:
|
|
54
|
+
|
|
55
|
+
| 参数 | 作用 |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `?dsh-diag=1` | 只读指标叠加层(滚动容器几何、`scrollHeight` / `clientHeight`、输入框位置、视口三件套)。与 `dsh-mobile` 独立,因此可对比「移动层开/关」两态 |
|
|
58
|
+
| `?dsh-mobile=off` | 完全禁用移动端增强层(CSS + JS) |
|
|
59
|
+
| `?dsh-mobile=no-new` | 保留承重布局,只关掉最近新增的那批规则 |
|
|
60
|
+
| `?dsh-mobile=no-<分组>` | 关掉某一组规则(`no-frameLayout` / `no-centercol` / `no-pad` / `no-observer`),逗号分隔可叠加 |
|
|
61
|
+
| `?dsh-mobile=on` | 恢复正常 |
|
|
62
|
+
|
|
63
|
+
选择记进 `localStorage`,因此在没有地址栏的 PWA 里同样生效。
|
|
64
|
+
|
|
65
|
+
### 变更:品牌名统一为 dsh-bridge-gateway
|
|
66
|
+
|
|
67
|
+
插件自身标识、日志前缀、数据目录、cloudflared 缓存目录全部改名,并对旧名做**两级链自动迁移**
|
|
68
|
+
(`~/.dsh-bridge/` → `~/.dsh-bridge-cloudflared/` → `~/.dsh-bridge-gateway-cloudflared/`),
|
|
69
|
+
用户无需重下 cloudflared。
|
|
70
|
+
|
|
71
|
+
上游仓库名 `wenbin-wb/dsh-bridge` 与兼容性标识(`LEGACY_DATA_DIR_NAME`、
|
|
72
|
+
`BRIDGE_RPC_CHANNEL_LEGACY`、CHANGELOG 历史)按约定保留。
|
|
73
|
+
|
|
74
|
+
### 测试
|
|
75
|
+
|
|
76
|
+
269 项全绿;新增 12 条护栏,逐条用注入 bug 验证过会变红。每条护栏都写了「为什么」(踩过的坑)。
|
|
77
|
+
中英 README 同步(章节数 / 标题层级 / 逐章节条目数 / 表格行数零差异)。
|
|
78
|
+
|
|
5
79
|
## [0.2.2] - 2026-10-11
|
|
6
80
|
|
|
7
81
|
### 修复:旧内核浏览器打开后工作区永远加载不了
|
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ This project's **upstream is [wenbin-wb/dsh-bridge](https://github.com/wenbin-wb
|
|
|
14
14
|
|
|
15
15
|
### Who upstream is
|
|
16
16
|
|
|
17
|
-
| | |
|
|
17
|
+
| Field | Value |
|
|
18
18
|
|---|---|
|
|
19
19
|
| Repository | [wenbin-wb/dsh-bridge](https://github.com/wenbin-wb/dsh-bridge) |
|
|
20
20
|
| Role | Multi-channel remote access and security plugin for DSH |
|
|
@@ -74,7 +74,7 @@ The plugin was renamed from `dsh-bridge` to **`dsh-bridge-gateway`** (reflecting
|
|
|
74
74
|
| Path | Change |
|
|
75
75
|
|---|---|
|
|
76
76
|
| `<DSH_HOME>/dsh-bridge/` | → `<DSH_HOME>/dsh-bridge-gateway/` (migrated automatically at startup) |
|
|
77
|
-
| `~/.dsh-bridge/` | → `~/.dsh-bridge-cloudflared/` (cloudflared cache;
|
|
77
|
+
| `~/.dsh-bridge/` | → `~/.dsh-bridge-gateway-cloudflared/` (cloudflared cache; **two-hop auto-migration**, no 39MB re-download) |
|
|
78
78
|
| RPC channel `/dsh-bridge` | → `/dsh-bridge-gateway`, with **both channels served**, so stale cached pages keep working |
|
|
79
79
|
|
|
80
80
|
## Features
|
|
@@ -89,7 +89,7 @@ The plugin was renamed from `dsh-bridge` to **`dsh-bridge-gateway`** (reflecting
|
|
|
89
89
|
- **Visitor management.** See live who is currently connected (LAN / direct gateway / tunnel, with the real source IP behind a tunnel) plus an IP blacklist. **Viewing is open to every visitor**; disconnecting and blacklisting require admin rights.
|
|
90
90
|
- **IM bots.** WeChat / QQ / Feishu / Telegram bots connect through their own gateway links — no public IP needed. Per-platform workspace / agent preset / model selection is configurable. Guides live in [docs/](./docs).
|
|
91
91
|
- **Collapsible cards.** Cards in the Access and Security tabs collapse; only the first in each group is expanded by default, and a collapsed card keeps its status tag plus one line of key information.
|
|
92
|
-
- **Mobile-friendly web.** The remote web UI is deeply adapted for phone screens (drawer sidebar, ~44px touch targets, bottom-stuck composer, and more).
|
|
92
|
+
- **Mobile-friendly web.** The remote web UI is deeply adapted for phone screens (drawer sidebar, ~44px touch targets, bottom-stuck composer, and more). The gateway also serves real **PNG** home-screen icons (DSH business blue + white whale, in both `any` and `maskable` variants) together with a Web App Manifest, so "Add to Home Screen" yields a proper icon rather than a blank tile.
|
|
93
93
|
- **All configuration in the UI.** Every feature above is configured from DSH Web's remote-access panel; nothing is edited by hand.
|
|
94
94
|
|
|
95
95
|
## Interface
|
|
@@ -216,6 +216,20 @@ dsh plugin --profile web add .
|
|
|
216
216
|
|
|
217
217
|
Tests point `DSH_HOME` at a throwaway temporary directory via `test/isolate-home.mjs`, so they never touch your real environment.
|
|
218
218
|
|
|
219
|
+
### Diagnosing phone-only layout problems
|
|
220
|
+
|
|
221
|
+
Bugs that reproduce on a phone but never in a desktop viewport can be bisected without touching code. Append a query parameter to the remote URL; the choice is remembered in `localStorage`, so it also works inside an installed PWA (which has no address bar).
|
|
222
|
+
|
|
223
|
+
| Parameter | Effect |
|
|
224
|
+
|---|---|
|
|
225
|
+
| `?dsh-diag=1` | Overlays a read-only metrics panel (scroll-container geometry, `scrollHeight` / `clientHeight`, composer position, viewport triple). It is independent of `dsh-mobile`, so the layer can be compared on against off. |
|
|
226
|
+
| `?dsh-mobile=off` | Disables the whole mobile enhancement layer (CSS and JS). |
|
|
227
|
+
| `?dsh-mobile=no-new` | Keeps the load-bearing layout and drops only the most recently added rules. |
|
|
228
|
+
| `?dsh-mobile=no-<group>` | Drops one rule group: `no-frameLayout`, `no-centercol`, `no-pad`, `no-observer`. Comma-separate to combine. |
|
|
229
|
+
| `?dsh-mobile=on` | Restores normal behaviour. |
|
|
230
|
+
|
|
231
|
+
Start by capturing `?dsh-diag=1` twice — once as-is and once with `?dsh-mobile=off` — because the delta between those two states is usually enough to name the culprit.
|
|
232
|
+
|
|
219
233
|
This project is forked from [wenbin-wb/dsh-bridge](https://github.com/wenbin-wb/dsh-bridge). Report general issues upstream and direct-gateway issues to this repository.
|
|
220
234
|
|
|
221
235
|
## Release notes
|
package/README.zh.md
CHANGED
|
@@ -97,7 +97,7 @@ resolve、远程流层直接抛错 —— 于是外壳渲染得出来,工作
|
|
|
97
97
|
| 路径 | 变化 |
|
|
98
98
|
|---|---|
|
|
99
99
|
| `<DSH_HOME>/dsh-bridge/` | → `<DSH_HOME>/dsh-bridge-gateway/`(启动时自动迁移) |
|
|
100
|
-
| `~/.dsh-bridge/` | → `~/.dsh-bridge-cloudflared/`(cloudflared
|
|
100
|
+
| `~/.dsh-bridge/` | → `~/.dsh-bridge-gateway-cloudflared/`(cloudflared 缓存,**两级链自动迁移**,免重下 39MB) |
|
|
101
101
|
| RPC 通道 `/dsh-bridge` | → `/dsh-bridge-gateway`,**新旧双通道并存**,旧缓存页面仍可用 |
|
|
102
102
|
|
|
103
103
|
## 功能
|
|
@@ -123,7 +123,8 @@ resolve、远程流层直接抛错 —— 于是外壳渲染得出来,工作
|
|
|
123
123
|
- **卡片折叠。** 访问配置与安全认证两个 Tab 的卡片都可折叠,默认只展开首张,
|
|
124
124
|
折叠后仍保留状态标签与一行关键信息。
|
|
125
125
|
- **移动端适配。** 远程网页 UI 针对手机屏幕深度适配(抽屉化侧边栏、点击热区扩至约 44px、
|
|
126
|
-
|
|
126
|
+
输入框贴底等)。网关另外提供真实的 **PNG** 主屏图标(DSH 业务蓝 + 白色鲸鱼,含 `any`
|
|
127
|
+
与 `maskable` 两版)与 Web App Manifest,"添加到桌面"得到的是正常图标而非空白方块。
|
|
127
128
|
- **全界面配置。** 以上全部功能都在 DSH Web 远程访问面板里配置,无需手改任何文件。
|
|
128
129
|
|
|
129
130
|
## 界面
|
|
@@ -277,6 +278,21 @@ dsh plugin --profile web add .
|
|
|
277
278
|
测试会通过 `test/isolate-home.mjs` 把 `DSH_HOME` 指向一次性临时目录,不会污染你本机的
|
|
278
279
|
真实环境。
|
|
279
280
|
|
|
281
|
+
### 排查只在手机上出现的问题
|
|
282
|
+
|
|
283
|
+
桌面视口复现不出、真机稳定复现的问题,可以不改代码直接二分。在远程地址后加查询参数即可;
|
|
284
|
+
选择会记进 `localStorage`,所以在没有地址栏的 PWA 里同样生效。
|
|
285
|
+
|
|
286
|
+
| 参数 | 作用 |
|
|
287
|
+
|---|---|
|
|
288
|
+
| `?dsh-diag=1` | 叠加只读指标面板(滚动容器几何、`scrollHeight` / `clientHeight`、输入框位置、视口三件套)。它与 `dsh-mobile` 相互独立,因此能对比移动层「开」与「关」两种状态。 |
|
|
289
|
+
| `?dsh-mobile=off` | 完全禁用移动端增强层(CSS 与 JS)。 |
|
|
290
|
+
| `?dsh-mobile=no-new` | 保留承重布局,只关掉最近新增的那批规则。 |
|
|
291
|
+
| `?dsh-mobile=no-<分组>` | 关掉某一组规则:`no-frameLayout`、`no-centercol`、`no-pad`、`no-observer`,逗号分隔可叠加。 |
|
|
292
|
+
| `?dsh-mobile=on` | 恢复正常。 |
|
|
293
|
+
|
|
294
|
+
第一步先取两次 `?dsh-diag=1` —— 一次原样、一次带 `?dsh-mobile=off` —— 两者差值通常就足以定位元凶。
|
|
295
|
+
|
|
280
296
|
本项目 fork 自 [wenbin-wb/dsh-bridge](https://github.com/wenbin-wb/dsh-bridge)。
|
|
281
297
|
向上游反馈通用问题、向本仓库反馈直连网关相关问题。
|
|
282
298
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/client/client.js
CHANGED
|
@@ -2639,7 +2639,7 @@ function BackupRestoreWidget({ rpcCall, onUpdate }) {
|
|
|
2639
2639
|
const now = /* @__PURE__ */ new Date();
|
|
2640
2640
|
const dateStr = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}`;
|
|
2641
2641
|
a.href = url;
|
|
2642
|
-
a.download = `dsh-bridge-backup-${dateStr}.json`;
|
|
2642
|
+
a.download = `dsh-bridge-gateway-backup-${dateStr}.json`;
|
|
2643
2643
|
document.body.appendChild(a);
|
|
2644
2644
|
a.click();
|
|
2645
2645
|
document.body.removeChild(a);
|
|
@@ -3935,11 +3935,165 @@ function BridgePanel({ rpcCall }) {
|
|
|
3935
3935
|
)
|
|
3936
3936
|
);
|
|
3937
3937
|
}
|
|
3938
|
+
function setupMobileDiag() {
|
|
3939
|
+
if (document.getElementById("dsh-mobile-diag")) return;
|
|
3940
|
+
const box = document.createElement("div");
|
|
3941
|
+
box.id = "dsh-mobile-diag";
|
|
3942
|
+
box.style.cssText = [
|
|
3943
|
+
"position:fixed",
|
|
3944
|
+
"left:0",
|
|
3945
|
+
"right:0",
|
|
3946
|
+
"top:0",
|
|
3947
|
+
"z-index:2147483647",
|
|
3948
|
+
"background:rgba(0,0,0,.86)",
|
|
3949
|
+
"color:#0f0",
|
|
3950
|
+
"pointer-events:none",
|
|
3951
|
+
"font:11px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace",
|
|
3952
|
+
"padding:5px 7px",
|
|
3953
|
+
"white-space:pre-wrap",
|
|
3954
|
+
"word-break:break-all"
|
|
3955
|
+
].join(";");
|
|
3956
|
+
document.body.appendChild(box);
|
|
3957
|
+
const tick = () => {
|
|
3958
|
+
const sb = document.querySelector('[class*="wSkVaW_scrollBody"]');
|
|
3959
|
+
const seat = document.querySelector('[class*="wSkVaW_composerSeat"]');
|
|
3960
|
+
const vv = window.visualViewport;
|
|
3961
|
+
const L = [];
|
|
3962
|
+
if (sb) {
|
|
3963
|
+
const r = sb.getBoundingClientRect();
|
|
3964
|
+
const max = sb.scrollHeight - sb.clientHeight;
|
|
3965
|
+
L.push("scrollBody top=" + Math.round(r.top) + " h=" + Math.round(r.height) + " pad=" + getComputedStyle(sb).paddingBottom);
|
|
3966
|
+
L.push(" scrollTop=" + Math.round(sb.scrollTop) + " max=" + max + " atBottom=" + (sb.scrollTop >= max - 2));
|
|
3967
|
+
L.push(" scrollH=" + sb.scrollHeight + " clientH=" + sb.clientHeight + " children=" + sb.children.length);
|
|
3968
|
+
const idx = sb.querySelectorAll("[data-index]");
|
|
3969
|
+
L.push(" virtItems=" + idx.length);
|
|
3970
|
+
} else {
|
|
3971
|
+
L.push("scrollBody: NOT FOUND");
|
|
3972
|
+
}
|
|
3973
|
+
if (seat) {
|
|
3974
|
+
const r = seat.getBoundingClientRect();
|
|
3975
|
+
L.push("composer pos=" + getComputedStyle(seat).position + " top=" + Math.round(r.top) + " h=" + Math.round(r.height));
|
|
3976
|
+
}
|
|
3977
|
+
L.push("inner=" + window.innerHeight + " vv=" + (vv ? Math.round(vv.height) : "-") + " vvTop=" + (vv ? Math.round(vv.offsetTop) : "-") + " dpr=" + window.devicePixelRatio + " w=" + window.innerWidth);
|
|
3978
|
+
L.push("body=" + Array.from(document.body.classList).join("."));
|
|
3979
|
+
box.textContent = L.join("\n");
|
|
3980
|
+
};
|
|
3981
|
+
tick();
|
|
3982
|
+
window.setInterval(tick, 500);
|
|
3983
|
+
window.addEventListener("scroll", tick, true);
|
|
3984
|
+
window.addEventListener("resize", tick);
|
|
3985
|
+
}
|
|
3986
|
+
var SUSPECT_CSS = {
|
|
3987
|
+
// _frame 规则 —— 真机二分结论(2026-10-17):
|
|
3988
|
+
// ?dsh-mobile=no-frameSize (去掉 width:100vw + height:100dvh)→ scrollH 恢复正常
|
|
3989
|
+
// ?dsh-mobile=no-frameOverflow(去掉 overflow:hidden) → scrollH 恢复正常
|
|
3990
|
+
// 两个属性各自都能触发,说明是「固定高度 + 裁剪」这个组合在作怪:
|
|
3991
|
+
// height:100dvh 把主框架钉成固定高、overflow:hidden 又让它成为裁剪容器,
|
|
3992
|
+
// DSH 的布局测量因此算错,导致只渲染约 4 条消息(scrollH≈795,正常应 10 万+)。
|
|
3993
|
+
// 故**这两个属性组已删除**,不再注入。只保留 padding-top(本规则的目的:
|
|
3994
|
+
// 为固定顶栏腾出空间)与 display/flex-direction/position(抽屉化的前提)。
|
|
3995
|
+
// 注意 grid-template-columns:1fr 也已去掉 —— 它是 grid 属性,在 flex 容器里无效。
|
|
3996
|
+
// padding-top / box-sizing 是这条规则的**目的**(为固定顶栏腾空间),任何分组都保留
|
|
3997
|
+
frameBase: `
|
|
3998
|
+
div[class*="_frame"] {
|
|
3999
|
+
padding-top: var(--dsh-mobile-header-h) !important;
|
|
4000
|
+
margin: 0 !important;
|
|
4001
|
+
box-sizing: border-box !important;
|
|
4002
|
+
}`,
|
|
4003
|
+
frameLayout: `
|
|
4004
|
+
div[class*="_frame"] {
|
|
4005
|
+
display: flex !important;
|
|
4006
|
+
flex-direction: column !important;
|
|
4007
|
+
position: relative !important;
|
|
4008
|
+
}`,
|
|
4009
|
+
centercol: ` div[class*="_centerCol"] {
|
|
4010
|
+
flex: 1 1 100% !important;
|
|
4011
|
+
width: 100% !important;
|
|
4012
|
+
min-width: 0 !important;
|
|
4013
|
+
max-width: 100% !important;
|
|
4014
|
+
display: flex !important;
|
|
4015
|
+
height: 100% !important;
|
|
4016
|
+
}`,
|
|
4017
|
+
pad: ` div[class*="wSkVaW_scrollBody"] {
|
|
4018
|
+
padding-bottom: max(16px, env(safe-area-inset-bottom)) !important;
|
|
4019
|
+
}
|
|
4020
|
+
div[class*="wSkVaW_scrollBody"] {
|
|
4021
|
+
padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px)) !important;
|
|
4022
|
+
}`
|
|
4023
|
+
};
|
|
4024
|
+
function injectSuspectStyles(disabled) {
|
|
4025
|
+
const parts = Object.entries(SUSPECT_CSS).filter(([k]) => !disabled.has(k)).map(([, v]) => v);
|
|
4026
|
+
if (parts.length === 0) return;
|
|
4027
|
+
if (document.getElementById("dsh-bridge-gateway-mobile-styles-suspect")) return;
|
|
4028
|
+
const style = document.createElement("style");
|
|
4029
|
+
style.id = "dsh-bridge-gateway-mobile-styles-suspect";
|
|
4030
|
+
style.textContent = "@media (max-width: 768px) {\n" + parts.join("\n") + "\n}";
|
|
4031
|
+
document.head.appendChild(style);
|
|
4032
|
+
}
|
|
4033
|
+
var NEW_MOBILE_CSS = `
|
|
4034
|
+
/* #2 \u9762\u677F\u6253\u5F00\u65F6\u9876\u680F\u8BA9\u4F4D\uFF08body.dsh-panel-open \u7531 setupPanelAwareness \u6253\u4E0A\uFF09\u3002
|
|
4035
|
+
\u5B9E\u6D4B\uFF1A\u6E20\u9053\u4E2D\u5FC3\u9762\u677F\u6807\u9898\u5728 y19\uFF0C\u800C\u9876\u680F\u5360 y0-40 \u2192 \u4E0D\u6539\u5C31\u662F\u6807\u9898\u88AB\u76D6\u4F4F\u3002
|
|
4036
|
+
\u4E0D\u7528 :has() \u662F\u56E0\u4E3A\u6784\u5EFA\u76EE\u6807\u662F chrome100\uFF08:has() \u8981 105+\uFF09\u3002 */
|
|
4037
|
+
body.dsh-panel-open .dsh-mobile-app-header {
|
|
4038
|
+
display: none !important;
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
/* #6 \u53CC\u5C42\u5934\u538B\u7F29\uFF1ADSH \u81EA\u5E26 min-height:76px\uFF0C\u53EA\u6539 padding \u538B\u4E0D\u4E0B\u53BB \u2014\u2014 \u5B9E\u6D4B
|
|
4042
|
+
76px \u4E00\u76F4\u751F\u6548\u3001titleRow \u88AB\u62C9\u4F38\u586B\u6EE1\uFF0869px\uFF09\uFF0C\u4E24\u5C42\u5934\u5408\u8BA1\u5403\u6389 128px\uFF08\u5C4F\u5E55 15%\uFF09\u3002
|
|
4043
|
+
\u663E\u5F0F\u6E05\u96F6 + \u628A padding \u6536\u5230 2px\uFF0C\u5B9E\u6D4B\u5185\u5BB9\u533A +51px\u3002 */
|
|
4044
|
+
div[class*="_centerCol"] header,
|
|
4045
|
+
header[class*="wSkVaW_header"] {
|
|
4046
|
+
min-height: 0 !important;
|
|
4047
|
+
padding: 2px 16px !important;
|
|
4048
|
+
}
|
|
4049
|
+
div[class*="wSkVaW_titleRow"] {
|
|
4050
|
+
min-height: 0 !important;
|
|
4051
|
+
height: 32px !important;
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
/* #4-C \u8868\u683C\u6A2A\u5411\u6EDA\u52A8\uFF1Atable \u5143\u7D20\u7684 overflow \u5728 CSS \u91CC\u662F**\u88AB\u5FFD\u7565**\u7684\uFF0C\u5FC5\u987B\u914D
|
|
4055
|
+
display:block \u624D\u4F1A\u53D8\u6210\u53EF\u6EDA\u5757\u76D2\uFF08\u63D2\u4EF6\u539F\u6765\u53EA\u5199\u4E86 overflow-x:auto\uFF0C\u6240\u4EE5\u65E0\u6548\uFF09\u3002 */
|
|
4056
|
+
div[class*="wSkVaW_scrollBody"] table {
|
|
4057
|
+
display: block !important;
|
|
4058
|
+
max-width: 100% !important;
|
|
4059
|
+
width: 100% !important;
|
|
4060
|
+
overflow-x: auto !important;
|
|
4061
|
+
-webkit-overflow-scrolling: touch !important;
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
/* #4-E \u8F68\u8FF9\u91CC\u7684\u5DE5\u5177\u8C03\u7528\u53C2\u6570\u6362\u884C\uFF1A\u8BE5\u5217\u5185\u5BB9\u5BBD 3049px \u5374\u53EA\u6709 180px \u53EF\u89C1\uFF0817\xD7\uFF09\uFF0C
|
|
4065
|
+
\u6A2A\u6ED1\u8981\u5212 17 \u5C4F\u3001\u5B9E\u9645\u8BFB\u4E0D\u4E86\u3002overflow-wrap:anywhere \u662F\u5FC5\u987B\u7684 \u2014\u2014 bash \u547D\u4EE4\u91CC
|
|
4066
|
+
\u5E38\u6709\u8D85\u957F\u65E0\u7A7A\u683C token\u3002 */
|
|
4067
|
+
div[class*="wSkVaW_scrollBody"] [class*="resultRequest"] {
|
|
4068
|
+
white-space: normal !important;
|
|
4069
|
+
overflow-wrap: anywhere !important;
|
|
4070
|
+
word-break: break-word !important;
|
|
4071
|
+
text-overflow: clip !important;
|
|
4072
|
+
overflow: visible !important;
|
|
4073
|
+
}
|
|
4074
|
+
|
|
4075
|
+
/* #7 \u4E0B\u62C9\u6539 body \u7EA7 portal\uFF08position:fixed\uFF09\u3002\u4E3A\u4EC0\u4E48\u4E0D\u80FD absolute \u6302\u5728\u6309\u94AE\u91CC\uFF1A
|
|
4076
|
+
\u7956\u5148\u94FE titleRow \u4E0E wSkVaW_root \u90FD\u662F overflow:hidden\uFF08titleRow \u90A3\u6761\u8FD8\u662F\u63D2\u4EF6
|
|
4077
|
+
\u81EA\u5DF1\u4E3A\u4E86\u7701\u7565\u53F7\u8BBE\u7684\uFF09\u2192 \u4E0B\u62C9\u843D\u5728\u5934\u90E8\u4E0B\u65B9 y78 \u4F1A\u88AB**\u6574\u5757\u88C1\u6389**\uFF0C\u5B9E\u6D4B\u4E2D\u5FC3\u70B9\u547D\u4E2D
|
|
4078
|
+
\u7684\u662F\u6D88\u606F\u6587\u672C\u3002z-index \u518D\u9AD8\u4E5F\u6CA1\u7528\uFF0C\u88C1\u526A\u53D1\u751F\u5728\u5C42\u53E0\u4E4B\u524D\u3002
|
|
4079
|
+
\u6CE8\u610F\uFF1A**\u4E0D\u80FD**\u5199 top/left \u7684 !important \u2014\u2014 \u90A3\u4F1A\u538B\u8FC7 positionTabDropdown()
|
|
4080
|
+
\u5199\u7684\u5185\u8054\u5750\u6807\uFF0C\u628A\u4E0B\u62C9\u9489\u5728\u5DE6\u4E0A\u89D2\u3002 */
|
|
4081
|
+
.dsh-mobile-tab-dropdown {
|
|
4082
|
+
position: fixed !important;
|
|
4083
|
+
}
|
|
4084
|
+
`;
|
|
4085
|
+
function injectNewMobileStyles() {
|
|
4086
|
+
if (document.getElementById("dsh-bridge-gateway-mobile-styles-new")) return;
|
|
4087
|
+
const style = document.createElement("style");
|
|
4088
|
+
style.id = "dsh-bridge-gateway-mobile-styles-new";
|
|
4089
|
+
style.textContent = "@media (max-width: 768px) {\n" + NEW_MOBILE_CSS + "\n}";
|
|
4090
|
+
document.head.appendChild(style);
|
|
4091
|
+
}
|
|
3938
4092
|
function injectMobileStyles() {
|
|
3939
4093
|
if (typeof document === "undefined") return;
|
|
3940
|
-
if (document.getElementById("dsh-bridge-mobile-styles")) return;
|
|
4094
|
+
if (document.getElementById("dsh-bridge-gateway-mobile-styles")) return;
|
|
3941
4095
|
const style = document.createElement("style");
|
|
3942
|
-
style.id = "dsh-bridge-mobile-styles";
|
|
4096
|
+
style.id = "dsh-bridge-gateway-mobile-styles";
|
|
3943
4097
|
style.textContent = `
|
|
3944
4098
|
/* DSH Bridge \u9690\u85CF Tab \u680F\u539F\u751F\u6EDA\u52A8\u6761\u5E76\u4FDD\u6301\u5E73\u6ED1\u6ED1\u52A8 */
|
|
3945
4099
|
.dsh-tabbar-container {
|
|
@@ -3954,25 +4108,16 @@ function injectMobileStyles() {
|
|
|
3954
4108
|
|
|
3955
4109
|
/* DSH Bridge \u79FB\u52A8\u7AEF\u81EA\u9002\u5E94\u4E0E\u89E6\u63A7\u4EA4\u4E92\u589E\u5F3A\u6837\u5F0F */
|
|
3956
4110
|
:root {
|
|
3957
|
-
|
|
4111
|
+
/* \u9876\u680F\u9AD8\u5EA6 52 -> 40\uFF082026-10-16 \u771F\u673A\u53CD\u9988\uFF1A"\u4E0A\u9762\u9AD8\u5EA6\u592A\u9AD8\u4E86\uFF0C\u628A\u5BF9\u8BDD\u6846\u7684\u7A7A\u95F4\u538B\u7F29\u4E86"\uFF09\u3002
|
|
4112
|
+
40px \u4ECD\u80FD\u5BB9\u7EB3 32px \u7684 \u2630/\u2295 \u6309\u94AE\u4E0E\u4E00\u884C\u4F1A\u8BDD\u540D\u3002 */
|
|
4113
|
+
--dsh-mobile-header-h: 40px;
|
|
3958
4114
|
--dsh-mobile-safe-top: env(safe-area-inset-top, 0px);
|
|
3959
4115
|
--dsh-mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
|
|
3960
4116
|
}
|
|
3961
4117
|
|
|
3962
4118
|
@media (max-width: 768px) {
|
|
3963
4119
|
/* 1. \u4E3B\u6846\u67B6\u4E3A Header \u817E\u51FA\u9876\u90E8\u7A7A\u95F4 */
|
|
3964
|
-
|
|
3965
|
-
display: flex !important;
|
|
3966
|
-
flex-direction: column !important;
|
|
3967
|
-
width: 100vw !important;
|
|
3968
|
-
height: 100dvh !important;
|
|
3969
|
-
margin: 0 !important;
|
|
3970
|
-
padding-top: var(--dsh-mobile-header-h) !important;
|
|
3971
|
-
position: relative !important;
|
|
3972
|
-
grid-template-columns: 1fr !important;
|
|
3973
|
-
overflow: hidden !important;
|
|
3974
|
-
box-sizing: border-box !important;
|
|
3975
|
-
}
|
|
4120
|
+
|
|
3976
4121
|
|
|
3977
4122
|
/* 2. \u9876\u90E8\u539F\u751F\u5BFC\u822A\u6761\uFF1A100% \u8FD8\u539F DeepSeek App (\u5DE6\u4FA7\u53CC\u6A2A\u7EBF\uFF0C\u53F3\u4FA7(+)\uFF0C\u4E2D\u95F4\u7559\u767D\uFF0C\u65E0\u591A\u4F59\u8BBE\u7F6E\u6309\u94AE) */
|
|
3978
4123
|
.dsh-mobile-app-header {
|
|
@@ -4052,14 +4197,7 @@ function injectMobileStyles() {
|
|
|
4052
4197
|
}
|
|
4053
4198
|
|
|
4054
4199
|
/* 3. \u4E2D\u95F4\u4E3B\u5185\u5BB9\u533A\u4E0E\u8F93\u5165\u6846 */
|
|
4055
|
-
|
|
4056
|
-
flex: 1 1 100% !important;
|
|
4057
|
-
width: 100% !important;
|
|
4058
|
-
min-width: 0 !important;
|
|
4059
|
-
max-width: 100% !important;
|
|
4060
|
-
display: flex !important;
|
|
4061
|
-
height: 100% !important;
|
|
4062
|
-
}
|
|
4200
|
+
|
|
4063
4201
|
|
|
4064
4202
|
div[class*="_detailsCol"],
|
|
4065
4203
|
div[class*="toggleCluster"],
|
|
@@ -4450,9 +4588,7 @@ function injectMobileStyles() {
|
|
|
4450
4588
|
}
|
|
4451
4589
|
|
|
4452
4590
|
/* \u8F93\u5165\u6846\u5E95\u5EA7\uFF1ADeepSeek App \u5C45\u4E2D\u53CA\u5E95\u90E8\u56FA\u5B9A */
|
|
4453
|
-
|
|
4454
|
-
padding-bottom: max(16px, env(safe-area-inset-bottom)) !important;
|
|
4455
|
-
}
|
|
4591
|
+
|
|
4456
4592
|
|
|
4457
4593
|
/* \u8F93\u5165\u5361\u7247\uFF1ADeepSeek App \u5706\u89D2\u5927\u80F6\u56CA\u9020\u578B */
|
|
4458
4594
|
div[class*="uV2eYG_card"] {
|
|
@@ -4646,11 +4782,20 @@ function injectMobileStyles() {
|
|
|
4646
4782
|
}
|
|
4647
4783
|
|
|
4648
4784
|
/* \u8F93\u5165\u6846\u8D34\u5E95\uFF1AscrollBody \u7684 16px \u5E95\u90E8\u886C\u8DDD\u662F\u7A7A\u9699\u6765\u6E90\uFF0C\u6536\u6389\u53EA\u7559\u5B89\u5168\u533A\uFF1B
|
|
4649
|
-
\u518D\u57AB 6px \u8BA9\u7EDF\u8BA1\u836F\u4E38\u5B8C\u6574\u53EF\u89C1
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4785
|
+
\u518D\u57AB 6px \u8BA9\u7EDF\u8BA1\u836F\u4E38\u5B8C\u6574\u53EF\u89C1\u3002
|
|
4786
|
+
|
|
4787
|
+
\u26A0\uFE0F **\u4E0D\u8981**\u518D\u8BD5\u56FE\u5728\u8FD9\u91CC\u52A0 --dsh-composer-height\u3001\u4E5F\u4E0D\u8981\u7ED9 composerSeat \u52A0
|
|
4788
|
+
position:fixed\uFF082026-10-16 \u4E24\u6B21\u5C1D\u8BD5\uFF0C\u5747\u5DF2\u56DE\u9000\uFF09\u3002\u539F\u56E0\uFF1ADSH \u7684\u6EDA\u52A8\u951A\u5B9A
|
|
4789
|
+
\uFF08dsh-client-ui-conversation\uFF09\u662F**\u6309 DOM \u6D41\u5185\u4F4D\u7F6E**\u904D\u5386\u7956\u5148\u7B97\u504F\u79FB\u6765\u4FEE\u6B63
|
|
4790
|
+
scrollTop \u7684\uFF1B\u628A composer \u6458\u51FA\u6587\u6863\u6D41\u3001\u6216\u7ED9\u6EDA\u52A8\u5185\u5BB9\u52A0 padding\uFF0C\u951A\u5B9A\u5C31\u7B97\u9519\uFF0C
|
|
4791
|
+
\u771F\u673A\u75C7\u72B6\u662F\u300C\u8FDB\u53BB\u505C\u5728\u5F88\u4E45\u4EE5\u524D\u7684\u67D0\u6761\uFF0C\u70B9\u300E\u52A0\u8F7D\u66F4\u65E9\u300F\u540E\u518D\u4E5F\u56DE\u4E0D\u5230\u6700\u65B0\u300D\u3002
|
|
4792
|
+
\u8FD9\u4E2A\u906E\u6321\u662F DSH \u5BF9\u8BDD\u89C6\u56FE sticky \u5438\u5E95\u8BBE\u8BA1\u7684\u56FA\u6709\u4EE3\u4EF7\uFF1BDSH \u53E6\u6709"\u8986\u76D6\u5C42\u6A21\u5F0F"
|
|
4793
|
+
\uFF08:has([data-conversation-composer-overlay])\uFF1AcomposerSeat \u8F6C absolute\u3001
|
|
4794
|
+
viewArea \u81EA\u5DF1\u6EDA\uFF09\uFF0C\u4F46\u90A3\u662F **dsh-client-ui-trajectory\uFF08\u8F68\u8FF9\u89C6\u56FE\uFF09** \u5728\u7528\u7684\uFF0C
|
|
4795
|
+
\u5BF9\u8BDD\u89C6\u56FE\u6CA1\u6709\u5F00\u3002\u8981\u6839\u6CBB\u5F97\u8D70 DSH \u4FA7\uFF0C\u4E0D\u662F\u63D2\u4EF6 CSS \u80FD\u8865\u7684\u3002 */
|
|
4796
|
+
|
|
4797
|
+
|
|
4798
|
+
div[class*="wSkVaW_composerStack"] {
|
|
4654
4799
|
padding-bottom: env(safe-area-inset-bottom, 0px) !important;
|
|
4655
4800
|
}
|
|
4656
4801
|
|
|
@@ -4957,15 +5102,15 @@ function injectMobileStyles() {
|
|
|
4957
5102
|
box-sizing: border-box !important;
|
|
4958
5103
|
}
|
|
4959
5104
|
|
|
4960
|
-
/* 7. \u4EE3\u7801\u5757\
|
|
4961
|
-
pre, code, pre > code
|
|
5105
|
+
/* 7. \u4EE3\u7801\u5757\u4E0E\u5FBD\u6807\u81EA\u9002\u5E94 */
|
|
5106
|
+
pre, code, pre > code {
|
|
4962
5107
|
max-width: 100% !important;
|
|
4963
5108
|
overflow-x: auto !important;
|
|
4964
5109
|
-webkit-overflow-scrolling: touch !important;
|
|
4965
5110
|
font-size: 12.5px !important;
|
|
4966
5111
|
}
|
|
4967
5112
|
|
|
4968
|
-
|
|
5113
|
+
/* \u72B6\u6001\u5FBD\u6807\u4E0E\u836F\u4E38\u6309\u94AE\u6C38\u4E0D\u6298\u5B57 */
|
|
4969
5114
|
span[style*="border-radius: 999"],
|
|
4970
5115
|
span[style*="border-radius:999"] {
|
|
4971
5116
|
white-space: nowrap !important;
|
|
@@ -5181,10 +5326,82 @@ function createUpstreamBridge(ctx) {
|
|
|
5181
5326
|
}
|
|
5182
5327
|
};
|
|
5183
5328
|
}
|
|
5329
|
+
function setupPanelAwareness(ctx) {
|
|
5330
|
+
if (typeof document === "undefined") return () => {
|
|
5331
|
+
};
|
|
5332
|
+
const PANEL_SELECTORS = [
|
|
5333
|
+
".dshc-center-backdrop",
|
|
5334
|
+
// dsh-chanhub 渠道中心
|
|
5335
|
+
"[data-dsh-panel-host]",
|
|
5336
|
+
// dsh-better-sidebar(注意:常驻 DOM,需判可见)
|
|
5337
|
+
"[data-dsh-better-sidebar]"
|
|
5338
|
+
];
|
|
5339
|
+
const isPanelOpen = () => PANEL_SELECTORS.some((sel) => {
|
|
5340
|
+
const el = document.querySelector(sel);
|
|
5341
|
+
if (!el) return false;
|
|
5342
|
+
const cs = getComputedStyle(el);
|
|
5343
|
+
if (cs.display === "none" || cs.visibility === "hidden") return false;
|
|
5344
|
+
const r = el.getBoundingClientRect();
|
|
5345
|
+
return r.width > 0 && r.height > 0;
|
|
5346
|
+
});
|
|
5347
|
+
const sync = () => {
|
|
5348
|
+
const open = isPanelOpen();
|
|
5349
|
+
if (document.body.classList.contains("dsh-panel-open") !== open) {
|
|
5350
|
+
document.body.classList.toggle("dsh-panel-open", open);
|
|
5351
|
+
}
|
|
5352
|
+
};
|
|
5353
|
+
sync();
|
|
5354
|
+
const observer = new MutationObserver(sync);
|
|
5355
|
+
observer.observe(document.body, { childList: true });
|
|
5356
|
+
const timer = setInterval(sync, 1e3);
|
|
5357
|
+
const dispose = () => {
|
|
5358
|
+
observer.disconnect();
|
|
5359
|
+
clearInterval(timer);
|
|
5360
|
+
};
|
|
5361
|
+
ctx?.effect?.(() => dispose);
|
|
5362
|
+
return dispose;
|
|
5363
|
+
}
|
|
5184
5364
|
function setupMobileExperience(rpcCall, ctx) {
|
|
5185
5365
|
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
5186
|
-
|
|
5366
|
+
const MOBILE_FLAG_KEY = "dsh-bridge-gateway:mobile";
|
|
5367
|
+
const flag = new URLSearchParams(window.location.search).get("dsh-mobile");
|
|
5368
|
+
if (flag !== null) {
|
|
5369
|
+
try {
|
|
5370
|
+
window.localStorage.setItem(MOBILE_FLAG_KEY, flag);
|
|
5371
|
+
} catch {
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
let mobileFlag = "on";
|
|
5375
|
+
try {
|
|
5376
|
+
mobileFlag = window.localStorage.getItem(MOBILE_FLAG_KEY) || "on";
|
|
5377
|
+
} catch {
|
|
5378
|
+
}
|
|
5379
|
+
document.documentElement.dataset.dshMobile = mobileFlag;
|
|
5380
|
+
const diagOn = new URLSearchParams(window.location.search).get("dsh-diag") === "1";
|
|
5381
|
+
if (diagOn) window.setTimeout(setupMobileDiag, 1500);
|
|
5382
|
+
const flagSet = new Set(String(mobileFlag).split(",").map((x) => x.trim()).filter(Boolean));
|
|
5383
|
+
const disabledSuspects = new Set(
|
|
5384
|
+
[...flagSet].filter((f) => f.startsWith("no-")).map((f) => f.slice(3))
|
|
5385
|
+
);
|
|
5386
|
+
if (disabledSuspects.has("frame")) {
|
|
5387
|
+
for (const k of ["frameLayout", "frameSize", "frameOverflow"]) disabledSuspects.add(k);
|
|
5388
|
+
}
|
|
5389
|
+
const withCss = !flagSet.has("off") && !flagSet.has("no-css");
|
|
5390
|
+
const withJs = !flagSet.has("off") && !flagSet.has("no-js");
|
|
5391
|
+
const withNew = withCss && !flagSet.has("no-new");
|
|
5392
|
+
const MOBILE_NO_OBSERVER = flagSet.has("no-observer");
|
|
5393
|
+
if (!withCss && !withJs) {
|
|
5394
|
+
if (diagOn) window.setTimeout(setupMobileDiag, 1500);
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5397
|
+
if (withCss) {
|
|
5398
|
+
injectMobileStyles();
|
|
5399
|
+
injectSuspectStyles(disabledSuspects);
|
|
5400
|
+
}
|
|
5401
|
+
if (withNew) injectNewMobileStyles();
|
|
5402
|
+
if (!withJs) return;
|
|
5187
5403
|
const U = createUpstreamBridge(ctx);
|
|
5404
|
+
setupPanelAwareness(ctx);
|
|
5188
5405
|
let header = document.querySelector(".dsh-mobile-app-header");
|
|
5189
5406
|
let titleEl = document.querySelector(".dsh-mobile-header-title");
|
|
5190
5407
|
if (!header) {
|
|
@@ -5229,17 +5446,39 @@ function setupMobileExperience(rpcCall, ctx) {
|
|
|
5229
5446
|
header.appendChild(rightBtn);
|
|
5230
5447
|
document.body.appendChild(header);
|
|
5231
5448
|
}
|
|
5449
|
+
if (header && !header.dataset.dshVisibilityBound) {
|
|
5450
|
+
header.dataset.dshVisibilityBound = "1";
|
|
5451
|
+
header.style.display = "none";
|
|
5452
|
+
try {
|
|
5453
|
+
const mq = window.matchMedia("(max-width: 768px)");
|
|
5454
|
+
const syncHeaderVisibility = () => {
|
|
5455
|
+
header.style.display = mq.matches ? "" : "none";
|
|
5456
|
+
};
|
|
5457
|
+
syncHeaderVisibility();
|
|
5458
|
+
if (typeof mq.addEventListener === "function") mq.addEventListener("change", syncHeaderVisibility);
|
|
5459
|
+
else if (typeof mq.addListener === "function") mq.addListener(syncHeaderVisibility);
|
|
5460
|
+
} catch {
|
|
5461
|
+
}
|
|
5462
|
+
}
|
|
5463
|
+
const pickCurrentSession = (snap) => {
|
|
5464
|
+
const list = snap?.byId ? Object.values(snap.byId) : [];
|
|
5465
|
+
if (!list.length) return null;
|
|
5466
|
+
const retained = list.find((x) => (x?.retainedBy?.mainView ?? 0) > 0);
|
|
5467
|
+
if (retained) return retained;
|
|
5468
|
+
return list.find((x) => !x?.blank) || null;
|
|
5469
|
+
};
|
|
5232
5470
|
const syncMobileTitle = () => {
|
|
5233
5471
|
if (!titleEl) titleEl = document.querySelector(".dsh-mobile-header-title");
|
|
5234
5472
|
if (!titleEl) return;
|
|
5235
5473
|
const snap = ctx?.sessions?.list?.getSnapshot?.();
|
|
5236
5474
|
if (!snap) return;
|
|
5237
|
-
const cur = snap
|
|
5475
|
+
const cur = pickCurrentSession(snap);
|
|
5238
5476
|
if (!cur || cur.blank) {
|
|
5239
5477
|
titleEl.innerText = "\u65B0\u4F1A\u8BDD";
|
|
5240
5478
|
} else {
|
|
5241
5479
|
titleEl.innerText = cur.displayTitle || cur.title || "\u4F1A\u8BDD";
|
|
5242
5480
|
}
|
|
5481
|
+
titleEl.title = titleEl.innerText;
|
|
5243
5482
|
};
|
|
5244
5483
|
syncMobileTitle();
|
|
5245
5484
|
if (typeof ctx?.sessions?.list?.subscribe === "function") {
|
|
@@ -5279,9 +5518,21 @@ function setupMobileExperience(rpcCall, ctx) {
|
|
|
5279
5518
|
}
|
|
5280
5519
|
});
|
|
5281
5520
|
};
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5521
|
+
let panelCloseRaf = 0;
|
|
5522
|
+
const schedulePanelCloseButton = () => {
|
|
5523
|
+
if (panelCloseRaf) return;
|
|
5524
|
+
panelCloseRaf = window.requestAnimationFrame(() => {
|
|
5525
|
+
panelCloseRaf = 0;
|
|
5526
|
+
ensurePanelCloseButton();
|
|
5527
|
+
});
|
|
5528
|
+
};
|
|
5529
|
+
if (MOBILE_NO_OBSERVER) {
|
|
5530
|
+
document.documentElement.dataset.dshMobileObserver = "off";
|
|
5531
|
+
} else {
|
|
5532
|
+
const panelObserver = new MutationObserver(schedulePanelCloseButton);
|
|
5533
|
+
panelObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ["class"] });
|
|
5534
|
+
}
|
|
5535
|
+
window.addEventListener("resize", schedulePanelCloseButton);
|
|
5285
5536
|
const mobileTabState = { btn: null, dropdown: null };
|
|
5286
5537
|
const nativeTabs = () => [...document.querySelectorAll('[role="tablist"] [role="tab"]')];
|
|
5287
5538
|
const closeTabDropdown = () => {
|
|
@@ -5290,6 +5541,14 @@ function setupMobileExperience(rpcCall, ctx) {
|
|
|
5290
5541
|
mobileTabState.dropdown = null;
|
|
5291
5542
|
}
|
|
5292
5543
|
};
|
|
5544
|
+
const positionTabDropdown = () => {
|
|
5545
|
+
const dd = mobileTabState.dropdown;
|
|
5546
|
+
const btn = mobileTabState.btn;
|
|
5547
|
+
if (!dd || !btn || !btn.isConnected) return;
|
|
5548
|
+
const r = btn.getBoundingClientRect();
|
|
5549
|
+
dd.style.top = Math.round(r.bottom + 6) + "px";
|
|
5550
|
+
dd.style.left = Math.round(r.left) + "px";
|
|
5551
|
+
};
|
|
5293
5552
|
const renderTabDropdown = () => {
|
|
5294
5553
|
closeTabDropdown();
|
|
5295
5554
|
if (!mobileTabState.btn) return;
|
|
@@ -5326,8 +5585,9 @@ function setupMobileExperience(rpcCall, ctx) {
|
|
|
5326
5585
|
};
|
|
5327
5586
|
dropdown.appendChild(option);
|
|
5328
5587
|
});
|
|
5329
|
-
|
|
5588
|
+
document.body.appendChild(dropdown);
|
|
5330
5589
|
mobileTabState.dropdown = dropdown;
|
|
5590
|
+
positionTabDropdown();
|
|
5331
5591
|
};
|
|
5332
5592
|
const syncTabButtonLabel = () => {
|
|
5333
5593
|
if (!mobileTabState.btn || !mobileTabState.btn.isConnected) return;
|
|
@@ -5390,6 +5650,7 @@ function setupMobileExperience(rpcCall, ctx) {
|
|
|
5390
5650
|
titleExtrasObserver.observe(document.body, { childList: true, subtree: true });
|
|
5391
5651
|
window.addEventListener("resize", () => {
|
|
5392
5652
|
if (window.innerWidth > 768) closeTabDropdown();
|
|
5653
|
+
else positionTabDropdown();
|
|
5393
5654
|
});
|
|
5394
5655
|
document.addEventListener(
|
|
5395
5656
|
"click",
|