dsh-mobile-access 1.1.5 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/client.js +71 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ iPhone 打开「设置 → 无线局域网」,确认和 Mac 连的是同一个
|
|
|
79
79
|
### 第 2 步:在 Mac 终端执行一条命令
|
|
80
80
|
|
|
81
81
|
```bash
|
|
82
|
-
dsh plugin --profile web add dsh-mobile-access@1.1.
|
|
82
|
+
dsh plugin --profile web add dsh-mobile-access@1.1.6 --registry=https://registry.npmjs.org/
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
这条命令做三件事:
|
|
@@ -190,6 +190,19 @@ iOS Safari 会把第一次触摸先用去聚焦,第二次才派发 `click`。
|
|
|
190
190
|
如果左侧栏仍然是窄窄的图标条,第一下是展开侧栏——这是官方布局,不是会话行的问题;
|
|
191
191
|
展开后每个会话只需单击一次。
|
|
192
192
|
|
|
193
|
+
### iPhone 上左右滑动展开 / 收起左侧栏
|
|
194
|
+
|
|
195
|
+
从 `1.1.6` 起,iPhone / iPad 上还支持:
|
|
196
|
+
|
|
197
|
+
- 在对话内容区**向右滑**:展开左侧栏(仅在左侧栏已收起时生效);
|
|
198
|
+
- 在对话内容区**向左滑**:收起左侧栏(仅在左侧栏已展开时生效);
|
|
199
|
+
- 滑动需要水平距离至少 70px,且明显大于上下移动,避免和滚动、
|
|
200
|
+
横向代码块、输入框、模型菜单和右侧面板冲突。
|
|
201
|
+
|
|
202
|
+
普通 Safari 标签页里,手势会避开屏幕左右各 24px 的边缘,以免和 Safari
|
|
203
|
+
自带的“后退 / 前进”边缘手势抢事件;添加到主屏幕的独立窗口里没有这个
|
|
204
|
+
系统手势,因此边缘也可以滑动。Mac 没有触摸事件,完全不受影响。
|
|
205
|
+
|
|
193
206
|
`1.1.3` 的旧实现只移除 `tabindex`,在部分 iOS Safari 版本上仍可能被第一次触摸吃掉;
|
|
194
207
|
如果更新到 `1.1.4` 后仍是两次,请彻底关闭这个 Safari 标签页再重新打开(不要只刷新),
|
|
195
208
|
以排除旧的 `client.js` 缓存。
|
|
@@ -370,7 +383,7 @@ iPhone 软键盘没有可用的 Shift 键,因此插件在 **iOS / iPadOS** 上
|
|
|
370
383
|
### 推荐:npm 官方命令
|
|
371
384
|
|
|
372
385
|
```bash
|
|
373
|
-
dsh plugin --profile web add dsh-mobile-access@1.1.
|
|
386
|
+
dsh plugin --profile web add dsh-mobile-access@1.1.6 --registry=https://registry.npmjs.org/
|
|
374
387
|
```
|
|
375
388
|
|
|
376
389
|
### 使用 `@latest`
|
|
@@ -500,7 +513,8 @@ dsh plugin --profile web remove dsh-mobile-access
|
|
|
500
513
|
- `1.1.0` — 回环监听自动局域网网关(macOS / Windows,HTTP + `/api/remote.mux` WebSocket)。
|
|
501
514
|
- `1.1.1` — iPhone / iPad 上模型选择页 16px 缩放守卫。
|
|
502
515
|
- `1.1.2` — 打开模型选择时不自动弹键盘、不整体上移。
|
|
503
|
-
- `1.1.
|
|
516
|
+
- `1.1.6` — iPhone / iPad 上右滑展开、左滑收起左侧栏;当前 npm `latest`。
|
|
517
|
+
- `1.1.5` — Tailscale Serve 经 HTTPS 访问时,允许带 Tailscale 身份头的 `*.ts.net` Host(仅限本机回环转发)。
|
|
504
518
|
- `1.1.4` — iPhone / iPad 上第一次点击直接切换会话,并在切换后自动收起左侧栏。
|
|
505
519
|
- `1.1.3` — 首次尝试临时移除会话行 `tabindex`。
|
|
506
520
|
|
package/client.js
CHANGED
|
@@ -291,6 +291,71 @@ function installIOSSidebarTapGuard(layout) {
|
|
|
291
291
|
timers.clear();
|
|
292
292
|
};
|
|
293
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Horizontal swipes on iPhone: right opens the left sidebar, left closes it.
|
|
296
|
+
* The gesture is limited to the content area and ignores vertical scrolling,
|
|
297
|
+
* editable controls, menus, code blocks and the right panel. On a normal Safari
|
|
298
|
+
* tab we stay 24px away from the screen edges so the system back/forward gesture
|
|
299
|
+
* keeps priority; an installed PWA has no such gesture, so edge starts are
|
|
300
|
+
* allowed there. Mac never installs this listener.
|
|
301
|
+
*/
|
|
302
|
+
function installIOSSidebarSwipeGuard(layout) {
|
|
303
|
+
if (!isAppleMobile() || layout === undefined)
|
|
304
|
+
return () => undefined;
|
|
305
|
+
const doc = document;
|
|
306
|
+
let pending = null;
|
|
307
|
+
const isBlocked = (target) => target.closest('input, textarea, select, [contenteditable="true"], [data-composer-card], pre, code, [role="slider"], [data-rightbar], [role="menu"], [role="listbox"], button, a, [role="button"]') !== null;
|
|
308
|
+
const point = (event) => {
|
|
309
|
+
const touches = event.changedTouches ?? event.touches;
|
|
310
|
+
const touch = touches?.[0];
|
|
311
|
+
return touch === undefined ? null : { x: touch.clientX, y: touch.clientY };
|
|
312
|
+
};
|
|
313
|
+
const onTouchStart = (event) => {
|
|
314
|
+
pending = null;
|
|
315
|
+
const touches = event.touches;
|
|
316
|
+
if (touches !== undefined && touches.length !== 1)
|
|
317
|
+
return;
|
|
318
|
+
const target = event.target;
|
|
319
|
+
if (target === null || typeof target.closest !== 'function' || isBlocked(target))
|
|
320
|
+
return;
|
|
321
|
+
const at = point(event);
|
|
322
|
+
if (at === null)
|
|
323
|
+
return;
|
|
324
|
+
const standalone = navigator.standalone === true;
|
|
325
|
+
if (!standalone && (at.x < 24 || at.x > window.innerWidth - 24))
|
|
326
|
+
return;
|
|
327
|
+
pending = { x: at.x, y: at.y, startedAt: Date.now() };
|
|
328
|
+
};
|
|
329
|
+
const onTouchEnd = (event) => {
|
|
330
|
+
if (pending === null)
|
|
331
|
+
return;
|
|
332
|
+
const { x, y, startedAt } = pending;
|
|
333
|
+
pending = null;
|
|
334
|
+
if (Date.now() - startedAt > 800)
|
|
335
|
+
return;
|
|
336
|
+
const at = point(event);
|
|
337
|
+
if (at === null)
|
|
338
|
+
return;
|
|
339
|
+
const dx = at.x - x;
|
|
340
|
+
const dy = at.y - y;
|
|
341
|
+
if (Math.abs(dx) < 70 || Math.abs(dx) <= Math.abs(dy) * 1.5)
|
|
342
|
+
return;
|
|
343
|
+
const collapsed = doc.querySelector('[data-sidebar-collapsed]') !== null;
|
|
344
|
+
if (dx > 0 ? !collapsed : collapsed)
|
|
345
|
+
return;
|
|
346
|
+
try {
|
|
347
|
+
layout.toggleSidebar();
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
doc.addEventListener('touchstart', onTouchStart, true);
|
|
353
|
+
doc.addEventListener('touchend', onTouchEnd, true);
|
|
354
|
+
return () => {
|
|
355
|
+
doc.removeEventListener('touchstart', onTouchStart, true);
|
|
356
|
+
doc.removeEventListener('touchend', onTouchEnd, true);
|
|
357
|
+
};
|
|
358
|
+
}
|
|
294
359
|
/**
|
|
295
360
|
* The official model menu can move focus into its search field while it opens.
|
|
296
361
|
* On iPhone that opens the software keyboard and shifts the fixed-position menu
|
|
@@ -637,6 +702,12 @@ function factory(require) {
|
|
|
637
702
|
catch (error) {
|
|
638
703
|
ctx.logger?.warn?.(`[mobile-access] iOS sidebar tap guard unavailable: ${String(error)}`);
|
|
639
704
|
}
|
|
705
|
+
try {
|
|
706
|
+
cleanups.push(installIOSSidebarSwipeGuard(ctx.layout));
|
|
707
|
+
}
|
|
708
|
+
catch (error) {
|
|
709
|
+
ctx.logger?.warn?.(`[mobile-access] iOS sidebar swipe guard unavailable: ${String(error)}`);
|
|
710
|
+
}
|
|
640
711
|
return () => {
|
|
641
712
|
for (const cleanup of cleanups.reverse()) {
|
|
642
713
|
try {
|
package/package.json
CHANGED