@khorsheed/dsh-mobile 0.1.3 → 0.1.4
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 +11 -0
- package/README.en.md +9 -3
- package/README.i18n.yaml +2 -2
- package/README.md +9 -3
- package/lib/client.js +415 -47
- package/lib/types/client/MobileChrome.d.ts +3 -1
- package/lib/types/client/MobileChrome.js +23 -5
- package/lib/types/client/MobileIcon.d.ts +1 -1
- package/lib/types/client/MobileIcon.js +1 -0
- package/lib/types/client/MobilePanelNavigation.d.ts +12 -0
- package/lib/types/client/MobilePanelNavigation.js +65 -0
- package/lib/types/client/gestures.js +4 -1
- package/lib/types/client/index.js +16 -4
- package/lib/types/client/locales.d.ts +6 -0
- package/lib/types/client/locales.js +2 -0
- package/lib/types/client/messageMenu.d.ts +4 -5
- package/lib/types/client/messageMenu.js +14 -25
- package/lib/types/client/panels.d.ts +56 -0
- package/lib/types/client/panels.js +97 -0
- package/lib/types/client/presentation.js +7 -1
- package/lib/types/client/rooms.js +12 -1
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/client/styles.js +58 -2
- package/lib/types/client/surface.js +3 -1
- package/package.json +14 -19
- package/lib/invariant.js +0 -20
- package/lib/types/invariant.d.ts +0 -16
- package/lib/types/invariant.js +0 -17
package/lib/client.js
CHANGED
|
@@ -2952,6 +2952,8 @@ html[data-dsh-mobile] [data-slot="conversation.input.right"] { max-width: 100%;
|
|
|
2952
2952
|
[data-mobile-toolbar] small { color: var(--dsw-alias-label-tertiary, #778195); font-size: 11px; display: block; text-align: center; }
|
|
2953
2953
|
[data-mobile-toolbar] svg { display: block; }
|
|
2954
2954
|
[data-mobile-shade] { position: absolute; inset: var(--mobile-bar) 0 0 min(88vw, 360px); border: 0; background: #15244330; pointer-events: auto; }
|
|
2955
|
+
/* The overlay layer rises above an open panel; the drawer's shade must not. */
|
|
2956
|
+
html[data-mobile-panel-open] [data-mobile-shade] { display: none; }
|
|
2955
2957
|
[data-mobile-dialog] {
|
|
2956
2958
|
color: var(--dsw-alias-label-primary, #152443); background: var(--dsw-alias-bg-base, white);
|
|
2957
2959
|
border: 1px solid var(--dsw-alias-border-l3, #e6eaf2); border-radius: 28px;
|
|
@@ -3098,7 +3100,7 @@ html[data-dsh-mobile] [data-phase=hero] span:has(> [data-slot="conversation.hero
|
|
|
3098
3100
|
[data-mobile-welcome] small { color:var(--mobile-accent); letter-spacing:3px; font-size:13px; }
|
|
3099
3101
|
[data-mobile-welcome] h2 { font-size:25px; font-weight:500; line-height:1.4; margin:16px 0 9px; letter-spacing:-.6px; }
|
|
3100
3102
|
[data-mobile-welcome] p { font-size:13px; line-height:1.6; margin:0; color:var(--dsw-alias-label-tertiary,#74767c); }
|
|
3101
|
-
html[data-dsh-mobile]:has([data-phase=hero]) [data-mobile-toolbar][data-library=false] [data-mobile-new=true] {
|
|
3103
|
+
html[data-dsh-mobile]:has([data-phase=hero]) [data-mobile-toolbar][data-library=false] [data-mobile-new=true] { display:none; }
|
|
3102
3104
|
html[data-dsh-mobile] [data-phase=hero] div:has(> [data-slot="conversation.hero.workspace"]) { gap:6px; padding:6px 18px; flex-wrap:wrap; }
|
|
3103
3105
|
html[data-dsh-mobile] [data-phase=hero] div:has(> [data-slot="conversation.hero.workspace"]) > button, html[data-dsh-mobile] [data-slot="conversation.hero.agentPreset"] button[aria-haspopup] { border-radius:18px; min-height:40px; font-size:13px; background:var(--mobile-soft); }
|
|
3104
3106
|
/* Quiet, read-only metadata below the mobile title. */
|
|
@@ -3167,7 +3169,7 @@ html[data-dsh-mobile] [data-composer-seat]:has([data-mobile-room-queue]) [data-t
|
|
|
3167
3169
|
[data-mobile-message-menu] button:active { background:var(--mobile-soft); }
|
|
3168
3170
|
[data-mobile-message-menu] svg { width:20px; height:20px; flex:none; }
|
|
3169
3171
|
[data-mobile-message-menu] button:disabled { opacity:.45; }
|
|
3170
|
-
[data-mobile-toolbar]:has([data-mobile-members-open])
|
|
3172
|
+
[data-mobile-toolbar]:has([data-mobile-members-open]) [data-mobile-new] { display:none; }
|
|
3171
3173
|
[data-mobile-members-open] { position:relative; }
|
|
3172
3174
|
[data-mobile-members-open] small { position:absolute; bottom:-3px; right:-2px; min-width:16px; border-radius:10px; font-size:10px; background:var(--mobile-soft); color:var(--dsw-alias-label-primary); }
|
|
3173
3175
|
[data-mobile-room-dialog] { text-align:left; line-height:1.5; }
|
|
@@ -3196,6 +3198,10 @@ html[data-dsh-mobile] [data-slot="conversation.input.dock"] section > ul[aria-la
|
|
|
3196
3198
|
|
|
3197
3199
|
/* One mobile reading scale; derived from host text size without writing its preference. */
|
|
3198
3200
|
html[data-dsh-mobile] body { --mobile-text:max(17px,var(--dsh-content-font-size,14px)); --mobile-caption:max(14px,var(--dsh-content-font-size-secondary,13px)); }
|
|
3201
|
+
/* Touch values of the shared panel type tokens (ui-panel-kit reads them with
|
|
3202
|
+
desktop fallbacks; this package never imports it). Title and reading follow
|
|
3203
|
+
the mobile reading scale, so a larger host text size still wins. */
|
|
3204
|
+
html[data-dsh-mobile] body { --dsh-panel-text-title:var(--mobile-text); --dsh-panel-text-body:15px; --dsh-panel-text-meta:13px; --dsh-panel-text-reading:var(--mobile-text); --dsh-panel-reading-line-height:1.7; }
|
|
3199
3205
|
html[data-dsh-mobile] :is([data-mobile-library],[data-mobile-dialog],[data-mobile-tools-dialog],[data-mobile-message-menu]) { font-size:var(--mobile-text); line-height:1.55; }
|
|
3200
3206
|
html[data-dsh-mobile] :is([data-mobile-nav-title] strong,[data-mobile-session-copy] strong,[data-mobile-search] input,[data-composer-card] [contenteditable],[data-composer-seat] textarea,[data-mobile-member-chat] strong) { font-size:var(--mobile-text); line-height:1.55; }
|
|
3201
3207
|
html[data-dsh-mobile] :is([data-mobile-workspace-group] strong,[data-mobile-tools-grid] button,[data-mobile-tools-permission],[data-mobile-dialog] h3,[data-mobile-grouping] button) { font-size:16px!important; }
|
|
@@ -3349,6 +3355,56 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
3349
3355
|
[data-directory-location] input { width:18px; }
|
|
3350
3356
|
[data-mobile-directory] footer { flex:none; padding-top:10px; }
|
|
3351
3357
|
[data-mobile-directory] [data-mobile-done] { margin-top:0; background:var(--mobile-accent); color:white; min-height:48px; }
|
|
3358
|
+
|
|
3359
|
+
[data-mobile-message-menu] { -webkit-user-select:none; user-select:none; -webkit-touch-callout:none; }
|
|
3360
|
+
|
|
3361
|
+
/* Optional sidebar navigation: content stays in its official dock hosts. */
|
|
3362
|
+
[data-mobile-header-actions] { display:flex; flex:none; gap:4px; }
|
|
3363
|
+
html[data-dsh-mobile] [data-mobile-toolbar] [data-mobile-header-actions] button { box-shadow:none; background:transparent; }
|
|
3364
|
+
/* Panel chrome has its own compact metric; a chat connection banner must not
|
|
3365
|
+
stretch the tabs. Tabs are flat labels; the active one carries an accent
|
|
3366
|
+
underline spanning its label and its close button. */
|
|
3367
|
+
html[data-dsh-mobile] { --mobile-panel-bar:52px; --mobile-panel-offset:52px; }
|
|
3368
|
+
html[data-dsh-mobile]:has([data-mobile-connection-status]) { --mobile-panel-offset:92px; }
|
|
3369
|
+
html[data-dsh-mobile][data-mobile-panel-open] [data-mobile-connection-status] { top:var(--mobile-panel-bar); }
|
|
3370
|
+
[data-mobile-panel-navigation] { position:absolute; inset:0 0 auto; height:var(--mobile-panel-bar,52px); display:flex; align-items:center; gap:4px; padding:0 6px; box-sizing:border-box; background:var(--dsw-alias-bg-layer-1,var(--mobile-soft)); color:var(--dsw-alias-label-primary); box-shadow:inset 0 -1px var(--dsw-alias-border-l2); pointer-events:auto; }
|
|
3371
|
+
[data-mobile-panel-navigation] button { display:grid; place-items:center; flex:none; width:40px; height:44px; padding:0; border:0; border-radius:10px; background:transparent; color:inherit; cursor:pointer; }
|
|
3372
|
+
[data-mobile-panel-navigation] > button { color:var(--dsw-alias-label-secondary); }
|
|
3373
|
+
[data-mobile-panel-navigation] button:disabled { opacity:.35; }
|
|
3374
|
+
[data-mobile-panel-navigation] button:focus-visible { outline:2px solid var(--mobile-accent); outline-offset:-3px; }
|
|
3375
|
+
[data-mobile-panel-tabs] { display:flex; align-self:stretch; align-items:stretch; flex:1; min-width:0; gap:2px; overflow-x:auto; overscroll-behavior-x:contain; scrollbar-width:none; touch-action:pan-x; }
|
|
3376
|
+
[data-mobile-panel-tabs]::-webkit-scrollbar { display:none; }
|
|
3377
|
+
[data-mobile-panel-tab] { position:relative; display:flex; flex:none; align-items:center; max-width:220px; color:var(--dsw-alias-label-secondary); }
|
|
3378
|
+
[data-mobile-panel-tab][data-active=true] { color:var(--dsw-alias-label-primary); }
|
|
3379
|
+
[data-mobile-panel-tab][data-active=true]::after { content:""; position:absolute; left:12px; right:5px; bottom:0; height:2.5px; border-radius:2px; background:var(--mobile-accent); pointer-events:none; }
|
|
3380
|
+
[data-mobile-panel-navigation] [role=tab] { flex:0 1 auto; min-width:0; width:auto; height:100%; padding:0 12px; font:inherit; font-size:15px; line-height:20px; border-radius:8px; }
|
|
3381
|
+
[data-mobile-panel-navigation] [role=tab] span { display:block; max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
3382
|
+
[data-mobile-panel-navigation] [role=tab][aria-selected=true] { font-weight:600; padding-right:0; }
|
|
3383
|
+
[data-mobile-panel-navigation] [data-mobile-panel-tab-close] { width:24px; height:100%; border-radius:8px; color:var(--dsw-alias-label-tertiary); }
|
|
3384
|
+
@media (hover:hover) { [data-mobile-panel-navigation] button:hover:not(:disabled) { background:var(--dsw-alias-interactive-bg-hover); } }
|
|
3385
|
+
[data-mobile-panel-error] { position:absolute; inset:100% 8px auto; padding:6px 10px; font-size:13px; background:var(--mobile-face); border:1px solid var(--mobile-edge); border-radius:8px; }
|
|
3386
|
+
html[data-mobile-panel-open] [data-mobile-toolbar] { visibility:hidden; }
|
|
3387
|
+
html[data-dsh-mobile][data-mobile-panel-open] [data-mobile-frame] > [data-shell-overlay] { z-index:65; }
|
|
3388
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] { top:var(--mobile-panel-offset,52px); width:100%!important; max-width:none!important; bottom:0; }
|
|
3389
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-strip],
|
|
3390
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-divider],
|
|
3391
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-float-grip],
|
|
3392
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-float-resize] { display:none!important; }
|
|
3393
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-split] { grid-template-columns:minmax(0,1fr)!important; }
|
|
3394
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-host] { grid-column:1!important; grid-row:1!important; min-width:0; }
|
|
3395
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-host=float] { width:100%; height:100%; }
|
|
3396
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-host]:not(:has([data-dockkit-pane-active],[data-dockkit-float-active])) { display:none!important; }
|
|
3397
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-float] { position:relative!important; inset:0!important; width:100%!important; height:100%!important; min-width:0; border-radius:0; }
|
|
3398
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel]:not([data-sidebar-right-open]) [data-dockkit-host=float] { visibility:hidden; pointer-events:none; }
|
|
3399
|
+
html[data-dsh-mobile][data-mobile-panel-managed] [data-sidebar-right-panel] [data-dockkit-content] { border-radius:0; min-width:0; }
|
|
3400
|
+
/* Fullscreen may be drawn from a collapsed, zero-width frame track. Anchor to
|
|
3401
|
+
the whole frame rather than its third grid area; saved desktop tracks stay intact. */
|
|
3402
|
+
html[data-dsh-mobile][data-mobile-panel-open] [data-mobile-frame] > [data-rightbar-col] {
|
|
3403
|
+
position:absolute; inset:0; grid-area:auto; z-index:24; width:100%; min-width:0;
|
|
3404
|
+
background:var(--dsw-alias-bg-base,white);
|
|
3405
|
+
}
|
|
3406
|
+
/* Keep the host affordance as fallback whenever the mobile entry is unavailable. */
|
|
3407
|
+
html[data-dsh-mobile]:has([data-mobile-toolbar] [data-mobile-panel-entry]) [data-sidebar-right-expand] { display:none; }
|
|
3352
3408
|
`;
|
|
3353
3409
|
//#endregion
|
|
3354
3410
|
//#region src/client/surface.ts
|
|
@@ -3411,7 +3467,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
3411
3467
|
const split = img.closest("button")?.parentElement;
|
|
3412
3468
|
if (split && split.querySelectorAll("button").length === 2) this.mark(split, "data-mobile-header-hidden");
|
|
3413
3469
|
}
|
|
3414
|
-
for (const button of row.querySelectorAll("[data-sidebar-right-expand], [data-slot=\"conversation.session.header.utilities\"] > span > button[aria-haspopup=\"menu\"][aria-busy]")) if (button.hasAttribute("data-sidebar-right-expand")
|
|
3470
|
+
for (const button of row.querySelectorAll("[data-sidebar-right-expand], [data-slot=\"conversation.session.header.utilities\"] > span > button[aria-haspopup=\"menu\"][aria-busy]")) if (button.hasAttribute("data-sidebar-right-expand") ? this.doc.querySelector("[data-mobile-panel-entry]") !== null : /^(更多操作|More actions)$/i.test(button.getAttribute("aria-label") ?? "")) this.mark(button, "data-mobile-header-hidden");
|
|
3415
3471
|
if (this.doc.querySelector("[data-mobile-members-open]:not([disabled])")) {
|
|
3416
3472
|
for (const button of row.querySelectorAll("[data-slot=\"conversation.session.header.actions\"] button")) if (/^(+|\+)?\s*(邀请 agent|Invite agent)$/i.test(button.textContent?.trim() ?? "")) this.mark(button, "data-mobile-header-hidden");
|
|
3417
3473
|
}
|
|
@@ -3531,7 +3587,11 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
3531
3587
|
this.style.dataset.mobileOwned = "styles";
|
|
3532
3588
|
this.style.textContent = MOBILE_CSS;
|
|
3533
3589
|
win.document.head.append(this.style);
|
|
3534
|
-
this.observer = new MutationObserver(
|
|
3590
|
+
this.observer = new MutationObserver((records) => {
|
|
3591
|
+
if (records.some((record) => {
|
|
3592
|
+
return !(record.target instanceof Element ? record.target : record.target.parentElement)?.closest("[data-conversation-scroll] [data-slot=\"conversation.session\"]");
|
|
3593
|
+
})) this.schedule();
|
|
3594
|
+
});
|
|
3535
3595
|
this.observer.observe(win.document.body, {
|
|
3536
3596
|
subtree: true,
|
|
3537
3597
|
childList: true,
|
|
@@ -3652,6 +3712,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
3652
3712
|
//#endregion
|
|
3653
3713
|
//#region src/client/MobileIcon.tsx
|
|
3654
3714
|
const paths = {
|
|
3715
|
+
panel: "M4 4h16v16H4zM14 4v16",
|
|
3655
3716
|
edit: "m15 5 4 4M5 19l4-1L20 7a2 2 0 0 0-4-4L5 14l-1 6Z",
|
|
3656
3717
|
members: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M22 21v-2a4 4 0 0 0-3-3.87M9 3a4 4 0 1 0 0 8 4 4 0 0 0 0-8m8 .13a4 4 0 0 1 0 7.75",
|
|
3657
3718
|
plus: "M12 5v14M5 12h14",
|
|
@@ -4308,10 +4369,27 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
4308
4369
|
}
|
|
4309
4370
|
publish(id, state) {
|
|
4310
4371
|
if (!this.alive) return;
|
|
4372
|
+
const signature = JSON.stringify(state === null ? null : {
|
|
4373
|
+
members: state.members.map(({ name, kind, provider, instructions, cwd, childSessionId }) => [
|
|
4374
|
+
name,
|
|
4375
|
+
kind,
|
|
4376
|
+
provider,
|
|
4377
|
+
instructions,
|
|
4378
|
+
cwd,
|
|
4379
|
+
childSessionId
|
|
4380
|
+
]),
|
|
4381
|
+
runs: state.runs.map(({ member, state }) => [member, state])
|
|
4382
|
+
});
|
|
4383
|
+
const previous = this.cache.get(id);
|
|
4384
|
+
if (previous?.signature === signature) {
|
|
4385
|
+
previous.at = Date.now();
|
|
4386
|
+
return;
|
|
4387
|
+
}
|
|
4311
4388
|
this.cache.delete(id);
|
|
4312
4389
|
this.cache.set(id, {
|
|
4313
4390
|
state,
|
|
4314
|
-
at: Date.now()
|
|
4391
|
+
at: Date.now(),
|
|
4392
|
+
signature
|
|
4315
4393
|
});
|
|
4316
4394
|
if (this.cache.size > 200) this.cache.delete(this.cache.keys().next().value);
|
|
4317
4395
|
this.version++;
|
|
@@ -4655,7 +4733,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
4655
4733
|
doc.documentElement.removeAttribute("data-mobile-gesture");
|
|
4656
4734
|
doc.documentElement.style.removeProperty("--mobile-drag-offset");
|
|
4657
4735
|
};
|
|
4658
|
-
const blocked = "input,textarea,[contenteditable],select,pre,code,[role=dialog],[role=menu],[role=slider],[role=switch],[role=checkbox],[data-mobile-tools-dialog],[data-mobile-dialog]";
|
|
4736
|
+
const blocked = "input,textarea,[contenteditable],select,pre,code,[role=dialog],[role=menu],[role=slider],[role=switch],[role=checkbox],[data-mobile-tools-dialog],[data-mobile-dialog],[data-mobile-gesture-owner],.xterm";
|
|
4659
4737
|
const down = (event) => {
|
|
4660
4738
|
resetDrag();
|
|
4661
4739
|
start = void 0;
|
|
@@ -4669,6 +4747,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
4669
4747
|
const viewport = doc.documentElement.clientWidth || doc.defaultView.innerWidth;
|
|
4670
4748
|
if (viewport >= 960) return;
|
|
4671
4749
|
const right = target.closest("[data-sidebar-right-panel][data-sidebar-right-open]") ?? void 0;
|
|
4750
|
+
if (right && doc.documentElement.hasAttribute("data-mobile-panel-managed")) return;
|
|
4672
4751
|
if (right && !right.querySelector("[data-sidebar-right-toggle]")) return;
|
|
4673
4752
|
const sidebar = closeSidebar ? target.closest("[data-slot=sidebar]")?.parentElement : void 0;
|
|
4674
4753
|
const panel = right ? {
|
|
@@ -4857,6 +4936,141 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
4857
4936
|
}), document.body);
|
|
4858
4937
|
}
|
|
4859
4938
|
//#endregion
|
|
4939
|
+
//#region src/client/MobilePanelNavigation.tsx
|
|
4940
|
+
function MobilePanelNavigation({ panels, active, prepareNavigation, t }) {
|
|
4941
|
+
const state = (0, react.useSyncExternalStore)(panels.subscribe, panels.getSnapshot);
|
|
4942
|
+
const managed = active && state.managed;
|
|
4943
|
+
const navigation = (0, react.useRef)(null);
|
|
4944
|
+
const prepare = (0, react.useRef)(prepareNavigation);
|
|
4945
|
+
prepare.current = prepareNavigation;
|
|
4946
|
+
(0, react.useEffect)(() => {
|
|
4947
|
+
document.documentElement.toggleAttribute("data-mobile-panel-managed", managed);
|
|
4948
|
+
document.documentElement.toggleAttribute("data-mobile-panel-open", managed && state.expanded);
|
|
4949
|
+
return () => {
|
|
4950
|
+
document.documentElement.removeAttribute("data-mobile-panel-managed");
|
|
4951
|
+
document.documentElement.removeAttribute("data-mobile-panel-open");
|
|
4952
|
+
};
|
|
4953
|
+
}, [managed, state.expanded]);
|
|
4954
|
+
(0, react.useEffect)(() => {
|
|
4955
|
+
if (!managed || !state.expanded) return;
|
|
4956
|
+
const main = document.querySelector("[data-mobile-frame] > div:has(> [data-slot=\"main\"])");
|
|
4957
|
+
const previous = main?.inert;
|
|
4958
|
+
if (main) main.inert = true;
|
|
4959
|
+
const nav = navigation.current;
|
|
4960
|
+
nav?.querySelector("button")?.focus({ preventScroll: true });
|
|
4961
|
+
const escape = (event) => {
|
|
4962
|
+
if (event.key !== "Escape" || event.defaultPrevented || document.querySelector("dialog[open],[role=dialog],[role=menu]") || document.activeElement?.tagName === "SELECT") return;
|
|
4963
|
+
prepare.current();
|
|
4964
|
+
panels.hide();
|
|
4965
|
+
};
|
|
4966
|
+
window.addEventListener("keydown", escape);
|
|
4967
|
+
return () => {
|
|
4968
|
+
if (main) main.inert = previous ?? false;
|
|
4969
|
+
window.removeEventListener("keydown", escape);
|
|
4970
|
+
if (document.activeElement === document.body || document.activeElement && nav?.contains(document.activeElement)) document.querySelector("[data-mobile-panel-entry]")?.focus({ preventScroll: true });
|
|
4971
|
+
};
|
|
4972
|
+
}, [
|
|
4973
|
+
managed,
|
|
4974
|
+
state.expanded,
|
|
4975
|
+
panels
|
|
4976
|
+
]);
|
|
4977
|
+
(0, react.useEffect)(() => {
|
|
4978
|
+
if (!managed || !state.expanded) return;
|
|
4979
|
+
navigation.current?.querySelector("[data-mobile-panel-tab][data-active=true]")?.scrollIntoView?.({
|
|
4980
|
+
block: "nearest",
|
|
4981
|
+
inline: "nearest"
|
|
4982
|
+
});
|
|
4983
|
+
}, [
|
|
4984
|
+
managed,
|
|
4985
|
+
state.expanded,
|
|
4986
|
+
state.activeId
|
|
4987
|
+
]);
|
|
4988
|
+
if (!managed || !state.expanded) return null;
|
|
4989
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
|
|
4990
|
+
ref: navigation,
|
|
4991
|
+
"data-mobile-panel-navigation": true,
|
|
4992
|
+
"aria-label": t("panels"),
|
|
4993
|
+
children: [
|
|
4994
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4995
|
+
type: "button",
|
|
4996
|
+
"aria-label": t("backToChat"),
|
|
4997
|
+
onClick: () => {
|
|
4998
|
+
prepareNavigation();
|
|
4999
|
+
panels.hide();
|
|
5000
|
+
},
|
|
5001
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileIcon, { name: "back" })
|
|
5002
|
+
}),
|
|
5003
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5004
|
+
role: "tablist",
|
|
5005
|
+
"aria-label": t("switchPanel"),
|
|
5006
|
+
"data-mobile-panel-tabs": true,
|
|
5007
|
+
onKeyDown: (event) => {
|
|
5008
|
+
const index = state.tabs.findIndex((tab) => tab.id === state.activeId);
|
|
5009
|
+
const next = event.key === "ArrowRight" ? (index + 1) % state.tabs.length : event.key === "ArrowLeft" ? (index + state.tabs.length - 1) % state.tabs.length : event.key === "Home" ? 0 : event.key === "End" ? state.tabs.length - 1 : -1;
|
|
5010
|
+
const target = state.tabs[next];
|
|
5011
|
+
if (!target) return;
|
|
5012
|
+
event.preventDefault();
|
|
5013
|
+
panels.select(target.id);
|
|
5014
|
+
event.currentTarget.querySelectorAll("[role=tab]")[next]?.focus({ preventScroll: true });
|
|
5015
|
+
},
|
|
5016
|
+
children: state.tabs.map((tab) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5017
|
+
role: "presentation",
|
|
5018
|
+
"data-mobile-panel-tab": true,
|
|
5019
|
+
"data-active": tab.id === state.activeId,
|
|
5020
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5021
|
+
type: "button",
|
|
5022
|
+
role: "tab",
|
|
5023
|
+
title: tab.title || tab.kind,
|
|
5024
|
+
"aria-selected": tab.id === state.activeId,
|
|
5025
|
+
tabIndex: tab.id === state.activeId ? 0 : -1,
|
|
5026
|
+
onClick: () => panels.select(tab.id),
|
|
5027
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tab.title || tab.kind })
|
|
5028
|
+
}), tab.id === state.activeId && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5029
|
+
type: "button",
|
|
5030
|
+
"data-mobile-panel-tab-close": true,
|
|
5031
|
+
"aria-label": t("closePanel"),
|
|
5032
|
+
disabled: state.tabs.length === 1 && tab.kind === "guide",
|
|
5033
|
+
onClick: panels.close,
|
|
5034
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileIcon, {
|
|
5035
|
+
name: "close",
|
|
5036
|
+
size: 14
|
|
5037
|
+
})
|
|
5038
|
+
})]
|
|
5039
|
+
}, tab.id))
|
|
5040
|
+
}),
|
|
5041
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5042
|
+
type: "button",
|
|
5043
|
+
"aria-label": t("addPanel"),
|
|
5044
|
+
onClick: panels.add,
|
|
5045
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileIcon, {
|
|
5046
|
+
name: "plus",
|
|
5047
|
+
size: 20
|
|
5048
|
+
})
|
|
5049
|
+
}),
|
|
5050
|
+
state.failed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5051
|
+
role: "alert",
|
|
5052
|
+
"data-mobile-panel-error": true,
|
|
5053
|
+
children: t("panelError")
|
|
5054
|
+
})
|
|
5055
|
+
]
|
|
5056
|
+
});
|
|
5057
|
+
}
|
|
5058
|
+
function MobilePanelEntry({ panels, beforeOpen, t }) {
|
|
5059
|
+
const state = (0, react.useSyncExternalStore)(panels.subscribe, panels.getSnapshot);
|
|
5060
|
+
if (!state.available) return null;
|
|
5061
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5062
|
+
type: "button",
|
|
5063
|
+
"data-mobile-panel-entry": true,
|
|
5064
|
+
"aria-label": t("panels"),
|
|
5065
|
+
"aria-expanded": state.expanded,
|
|
5066
|
+
onClick: () => {
|
|
5067
|
+
beforeOpen();
|
|
5068
|
+
panels.toggle();
|
|
5069
|
+
},
|
|
5070
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileIcon, { name: "panel" })
|
|
5071
|
+
});
|
|
5072
|
+
}
|
|
5073
|
+
//#endregion
|
|
4860
5074
|
//#region src/client/catalogReads.ts
|
|
4861
5075
|
/** Bound optional catalog enrichment so cold log reads cannot fan out across the library. */
|
|
4862
5076
|
var CatalogReads = class {
|
|
@@ -5191,7 +5405,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5191
5405
|
] });
|
|
5192
5406
|
}
|
|
5193
5407
|
/** One visible navigation bar, with native connection sheets when supported. */
|
|
5194
|
-
function MobileChrome({ presentation, toggleSidebar, connection, navigation, rooms, t }) {
|
|
5408
|
+
function MobileChrome({ presentation, toggleSidebar, connection, navigation, rooms, panels, t }) {
|
|
5195
5409
|
const state = (0, react.useSyncExternalStore)(presentation.subscribe, presentation.getSnapshot);
|
|
5196
5410
|
const wire = (0, react.useSyncExternalStore)(connection.state.subscribe, connection.state.getSnapshot);
|
|
5197
5411
|
const available = (0, react.useSyncExternalStore)(navigation.subscribe, navigation.getSnapshot);
|
|
@@ -5226,8 +5440,15 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5226
5440
|
if (available && !activated.current) {
|
|
5227
5441
|
activated.current = true;
|
|
5228
5442
|
setLibrary(true);
|
|
5229
|
-
if (state.drawer) toggleSidebar();
|
|
5230
5443
|
}
|
|
5444
|
+
}, [state.active, available]);
|
|
5445
|
+
const drawerWanted = (0, react.useRef)(false);
|
|
5446
|
+
(0, react.useEffect)(() => {
|
|
5447
|
+
if (!state.drawer) {
|
|
5448
|
+
drawerWanted.current = false;
|
|
5449
|
+
return;
|
|
5450
|
+
}
|
|
5451
|
+
if (state.active && available && !drawerWanted.current) toggleSidebar();
|
|
5231
5452
|
}, [
|
|
5232
5453
|
state.active,
|
|
5233
5454
|
state.drawer,
|
|
@@ -5275,6 +5496,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5275
5496
|
toggleSidebar
|
|
5276
5497
|
]);
|
|
5277
5498
|
const openLibrary = () => {
|
|
5499
|
+
panels?.hide();
|
|
5278
5500
|
if (!available) {
|
|
5279
5501
|
toggleSidebar();
|
|
5280
5502
|
return;
|
|
@@ -5283,6 +5505,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5283
5505
|
setLibrary(true);
|
|
5284
5506
|
};
|
|
5285
5507
|
const startSession = () => {
|
|
5508
|
+
panels?.hide();
|
|
5286
5509
|
presentation.prepareNavigation();
|
|
5287
5510
|
available?.workspace.startSession();
|
|
5288
5511
|
if (state.drawer) toggleSidebar();
|
|
@@ -5380,11 +5603,22 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5380
5603
|
children: t(wire ?? "connecting")
|
|
5381
5604
|
})]
|
|
5382
5605
|
}),
|
|
5383
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
5384
|
-
"data-mobile-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5606
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5607
|
+
"data-mobile-header-actions": true,
|
|
5608
|
+
children: [panels && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobilePanelEntry, {
|
|
5609
|
+
panels,
|
|
5610
|
+
t,
|
|
5611
|
+
beforeOpen: () => {
|
|
5612
|
+
presentation.prepareNavigation();
|
|
5613
|
+
setLibrary(false);
|
|
5614
|
+
if (state.drawer) toggleSidebar();
|
|
5615
|
+
}
|
|
5616
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
5617
|
+
"data-mobile-new": !!available,
|
|
5618
|
+
"aria-label": available ? t("newSession") : t("settings"),
|
|
5619
|
+
onClick: available ? startSession : openSettings,
|
|
5620
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileIcon, { name: available ? "compose" : "settings" })
|
|
5621
|
+
})]
|
|
5388
5622
|
}),
|
|
5389
5623
|
available && rooms && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobileRoomNavigation, {
|
|
5390
5624
|
rooms,
|
|
@@ -5394,6 +5628,12 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5394
5628
|
})
|
|
5395
5629
|
]
|
|
5396
5630
|
}),
|
|
5631
|
+
panels && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MobilePanelNavigation, {
|
|
5632
|
+
panels,
|
|
5633
|
+
active: state.active,
|
|
5634
|
+
prepareNavigation: presentation.prepareNavigation,
|
|
5635
|
+
t
|
|
5636
|
+
}),
|
|
5397
5637
|
wire !== "connected" && connectionExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5398
5638
|
"data-mobile-connection-status": true,
|
|
5399
5639
|
role: "status",
|
|
@@ -5420,7 +5660,10 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5420
5660
|
onClick: () => {
|
|
5421
5661
|
setSettings(false);
|
|
5422
5662
|
setLibrary(false);
|
|
5423
|
-
if (!state.drawer)
|
|
5663
|
+
if (!state.drawer) {
|
|
5664
|
+
drawerWanted.current = true;
|
|
5665
|
+
toggleSidebar();
|
|
5666
|
+
}
|
|
5424
5667
|
},
|
|
5425
5668
|
children: t("workspaces")
|
|
5426
5669
|
}),
|
|
@@ -5465,6 +5708,128 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5465
5708
|
] });
|
|
5466
5709
|
}
|
|
5467
5710
|
//#endregion
|
|
5711
|
+
//#region src/client/panels.ts
|
|
5712
|
+
const EMPTY = {
|
|
5713
|
+
available: false,
|
|
5714
|
+
managed: false,
|
|
5715
|
+
expanded: false,
|
|
5716
|
+
sessionId: void 0,
|
|
5717
|
+
activeId: "",
|
|
5718
|
+
tabs: [],
|
|
5719
|
+
failed: false
|
|
5720
|
+
};
|
|
5721
|
+
/** Public services do actions; checked DOM anchors supply presentation-only change notifications. */
|
|
5722
|
+
var MobilePanels = class {
|
|
5723
|
+
doc;
|
|
5724
|
+
service;
|
|
5725
|
+
releases = [];
|
|
5726
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5727
|
+
snapshot = EMPTY;
|
|
5728
|
+
observer;
|
|
5729
|
+
disposed = false;
|
|
5730
|
+
scheduled = false;
|
|
5731
|
+
failed = false;
|
|
5732
|
+
constructor(doc) {
|
|
5733
|
+
this.doc = doc;
|
|
5734
|
+
this.observer = new MutationObserver((records) => {
|
|
5735
|
+
if (this.scheduled || !records.some((record) => {
|
|
5736
|
+
return !(record.target instanceof Element ? record.target : record.target.parentElement)?.closest("[data-conversation-scroll] [data-slot=\"conversation.session\"]");
|
|
5737
|
+
})) return;
|
|
5738
|
+
this.scheduled = true;
|
|
5739
|
+
queueMicrotask(() => {
|
|
5740
|
+
this.scheduled = false;
|
|
5741
|
+
if (!this.disposed) this.sync();
|
|
5742
|
+
});
|
|
5743
|
+
});
|
|
5744
|
+
this.observer.observe(doc.body, {
|
|
5745
|
+
subtree: true,
|
|
5746
|
+
childList: true,
|
|
5747
|
+
attributes: true,
|
|
5748
|
+
attributeFilter: [
|
|
5749
|
+
"data-sidebar-right-open",
|
|
5750
|
+
"data-dockkit-pane-active",
|
|
5751
|
+
"data-dockkit-float-active",
|
|
5752
|
+
"aria-selected",
|
|
5753
|
+
"hidden"
|
|
5754
|
+
]
|
|
5755
|
+
});
|
|
5756
|
+
}
|
|
5757
|
+
getSnapshot = () => this.snapshot;
|
|
5758
|
+
subscribe = (listener) => {
|
|
5759
|
+
this.listeners.add(listener);
|
|
5760
|
+
return () => {
|
|
5761
|
+
this.listeners.delete(listener);
|
|
5762
|
+
};
|
|
5763
|
+
};
|
|
5764
|
+
set(value) {
|
|
5765
|
+
for (const release of this.releases) release();
|
|
5766
|
+
this.releases = [];
|
|
5767
|
+
const service = value;
|
|
5768
|
+
this.service = service && typeof service.toggleExpanded === "function" && typeof service.isExpanded === "function" && typeof service.active === "function" && typeof service.mounted?.subscribe === "function" && typeof service.mounted.getSnapshot === "function" ? service : void 0;
|
|
5769
|
+
this.failed = false;
|
|
5770
|
+
if (this.service) {
|
|
5771
|
+
this.releases.push(this.service.mounted.subscribe(this.sync));
|
|
5772
|
+
if (typeof this.service.openTabs?.subscribe === "function") this.releases.push(this.service.openTabs.subscribe(this.sync));
|
|
5773
|
+
}
|
|
5774
|
+
this.sync();
|
|
5775
|
+
}
|
|
5776
|
+
sync = () => {
|
|
5777
|
+
let next = EMPTY;
|
|
5778
|
+
try {
|
|
5779
|
+
const service = this.service, sessionId = service?.mounted.getSnapshot();
|
|
5780
|
+
if (service && sessionId) {
|
|
5781
|
+
const panel = Array.from(this.doc.querySelectorAll("[data-sidebar-right-panel][data-sidebar-right-session]")).find((element) => element.dataset.sidebarRightSession === sessionId);
|
|
5782
|
+
const tabs = service.tabsIn?.(sessionId) ?? [];
|
|
5783
|
+
const active = service.active();
|
|
5784
|
+
next = {
|
|
5785
|
+
available: true,
|
|
5786
|
+
managed: !!panel && !!panel.querySelector("[data-dockkit-host]") && tabs.length > 0 && typeof service.focus === "function" && typeof service.close === "function" && typeof service.openTab === "function" && !!active && tabs.some((tab) => tab.id === active.id),
|
|
5787
|
+
sessionId,
|
|
5788
|
+
expanded: service.isExpanded(),
|
|
5789
|
+
activeId: active?.id ?? "",
|
|
5790
|
+
tabs: tabs.map(({ id, title, kind }) => ({
|
|
5791
|
+
id,
|
|
5792
|
+
title,
|
|
5793
|
+
kind
|
|
5794
|
+
})),
|
|
5795
|
+
failed: this.failed
|
|
5796
|
+
};
|
|
5797
|
+
}
|
|
5798
|
+
} catch {}
|
|
5799
|
+
if (JSON.stringify(next) !== JSON.stringify(this.snapshot)) {
|
|
5800
|
+
this.snapshot = next;
|
|
5801
|
+
for (const listener of this.listeners) listener();
|
|
5802
|
+
}
|
|
5803
|
+
};
|
|
5804
|
+
run(action) {
|
|
5805
|
+
if (!this.service || !this.snapshot.available) return;
|
|
5806
|
+
try {
|
|
5807
|
+
action(this.service);
|
|
5808
|
+
this.failed = false;
|
|
5809
|
+
} catch {
|
|
5810
|
+
this.failed = true;
|
|
5811
|
+
}
|
|
5812
|
+
this.sync();
|
|
5813
|
+
}
|
|
5814
|
+
toggle = () => this.run((service) => service.toggleExpanded());
|
|
5815
|
+
hide = () => this.run((service) => {
|
|
5816
|
+
if (service.isExpanded()) service.toggleExpanded();
|
|
5817
|
+
});
|
|
5818
|
+
select = (id) => this.run((service) => {
|
|
5819
|
+
if (this.snapshot.tabs.some((tab) => tab.id === id)) service.focus?.(id);
|
|
5820
|
+
});
|
|
5821
|
+
close = () => this.run((service) => {
|
|
5822
|
+
if (this.snapshot.activeId) service.close?.(this.snapshot.activeId);
|
|
5823
|
+
});
|
|
5824
|
+
add = () => this.run((service) => service.openTab?.("guide"));
|
|
5825
|
+
dispose() {
|
|
5826
|
+
this.disposed = true;
|
|
5827
|
+
this.observer.disconnect();
|
|
5828
|
+
this.set(void 0);
|
|
5829
|
+
this.listeners.clear();
|
|
5830
|
+
}
|
|
5831
|
+
};
|
|
5832
|
+
//#endregion
|
|
5468
5833
|
//#region src/client/MobileQueue.tsx
|
|
5469
5834
|
/** Room's takeover hides the official QueueDock. Restore its mutation verbs
|
|
5470
5835
|
* through the same scoped Conversation API, without touching the Room composer. */
|
|
@@ -5626,20 +5991,17 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5626
5991
|
}
|
|
5627
5992
|
//#endregion
|
|
5628
5993
|
//#region src/client/messageMenu.ts
|
|
5629
|
-
/** A
|
|
5994
|
+
/** A pointer context-menu presentation of the rendered message's own actions. The source
|
|
5630
5995
|
* button stays mounted; its plugin still owns edits, confirmations and errors. */
|
|
5631
5996
|
var MessageMenu = class {
|
|
5632
5997
|
doc;
|
|
5633
|
-
|
|
5634
|
-
point;
|
|
5998
|
+
touch = false;
|
|
5635
5999
|
menu;
|
|
5636
6000
|
constructor(doc) {
|
|
5637
6001
|
this.doc = doc;
|
|
5638
6002
|
doc.addEventListener("pointerdown", this.down, true);
|
|
5639
|
-
doc.addEventListener("
|
|
5640
|
-
doc.addEventListener("
|
|
5641
|
-
doc.addEventListener("pointercancel", this.cancel, true);
|
|
5642
|
-
doc.addEventListener("scroll", this.cancel, true);
|
|
6003
|
+
doc.addEventListener("selectionchange", this.selectionChanged);
|
|
6004
|
+
doc.addEventListener("scroll", this.close, true);
|
|
5643
6005
|
doc.addEventListener("contextmenu", this.context, true);
|
|
5644
6006
|
}
|
|
5645
6007
|
row(target) {
|
|
@@ -5652,28 +6014,15 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5652
6014
|
actions(row) {
|
|
5653
6015
|
return [...row.querySelectorAll(row.hasAttribute("data-turn-tail") ? "button[aria-label]" : ":scope > div > button[aria-label], :scope > div > span > button[aria-label]")].filter((b) => /^(复制|已复制|编辑|撤回|点赞|点踩|不喜欢|分支|好的回答|有问题的回答|在新对话中分支|Copy|Copied|Edit|Withdraw|Like|Dislike|Branch)/i.test(b.getAttribute("aria-label") ?? ""));
|
|
5654
6016
|
}
|
|
5655
|
-
down = (
|
|
5656
|
-
this.
|
|
5657
|
-
const row = this.row(e.target);
|
|
5658
|
-
if (!row || e.pointerType === "mouse" || !this.actions(row).length) return;
|
|
5659
|
-
this.point = {
|
|
5660
|
-
x: e.clientX,
|
|
5661
|
-
y: e.clientY,
|
|
5662
|
-
row
|
|
5663
|
-
};
|
|
5664
|
-
this.timer = setTimeout(() => {
|
|
5665
|
-
if (this.point) this.open(row, e.clientX, e.clientY);
|
|
5666
|
-
}, 500);
|
|
5667
|
-
};
|
|
5668
|
-
move = (e) => {
|
|
5669
|
-
if (this.point && Math.hypot(e.clientX - this.point.x, e.clientY - this.point.y) > 10) this.cancel();
|
|
6017
|
+
down = (event) => {
|
|
6018
|
+
this.touch = event.pointerType === "touch" || event.pointerType === "pen";
|
|
5670
6019
|
};
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
this.
|
|
5674
|
-
this.point = void 0;
|
|
6020
|
+
hasSelection = () => !!this.doc.getSelection()?.toString().trim();
|
|
6021
|
+
selectionChanged = () => {
|
|
6022
|
+
if (this.hasSelection()) this.close();
|
|
5675
6023
|
};
|
|
5676
6024
|
context = (e) => {
|
|
6025
|
+
if (this.touch || this.hasSelection()) return;
|
|
5677
6026
|
const row = this.row(e.target);
|
|
5678
6027
|
if (row && this.actions(row).length) {
|
|
5679
6028
|
e.preventDefault();
|
|
@@ -5686,7 +6035,6 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5686
6035
|
this.menu = void 0;
|
|
5687
6036
|
};
|
|
5688
6037
|
open(row, x, y) {
|
|
5689
|
-
this.cancel();
|
|
5690
6038
|
this.close();
|
|
5691
6039
|
const actions = this.actions(row);
|
|
5692
6040
|
if (!actions.length) return;
|
|
@@ -5722,13 +6070,10 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5722
6070
|
menu.style.top = `${Math.max(12, Math.min(y + 12, height - bounds.height - 12))}px`;
|
|
5723
6071
|
}
|
|
5724
6072
|
dispose() {
|
|
5725
|
-
this.cancel();
|
|
5726
6073
|
this.close();
|
|
5727
6074
|
this.doc.removeEventListener("pointerdown", this.down, true);
|
|
5728
|
-
this.doc.removeEventListener("
|
|
5729
|
-
this.doc.removeEventListener("
|
|
5730
|
-
this.doc.removeEventListener("pointercancel", this.cancel, true);
|
|
5731
|
-
this.doc.removeEventListener("scroll", this.cancel, true);
|
|
6075
|
+
this.doc.removeEventListener("selectionchange", this.selectionChanged);
|
|
6076
|
+
this.doc.removeEventListener("scroll", this.close, true);
|
|
5732
6077
|
this.doc.removeEventListener("contextmenu", this.context, true);
|
|
5733
6078
|
}
|
|
5734
6079
|
};
|
|
@@ -5872,6 +6217,12 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
5872
6217
|
/** Copy for controls owned by mobile; all conversation copy stays with its owner. */
|
|
5873
6218
|
const NS = "mobile";
|
|
5874
6219
|
const en = {
|
|
6220
|
+
panels: "Panels",
|
|
6221
|
+
backToChat: "Back to conversation",
|
|
6222
|
+
switchPanel: "Switch panel",
|
|
6223
|
+
addPanel: "Add panel",
|
|
6224
|
+
closePanel: "Close current panel",
|
|
6225
|
+
panelError: "Could not change this panel. Try again.",
|
|
5875
6226
|
connectPhone: "Connect phone",
|
|
5876
6227
|
connectIntro: "Continue your conversations in DSH Mobile.",
|
|
5877
6228
|
connectQR: "Scan with DSH Mobile to sign in",
|
|
@@ -6009,6 +6360,12 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
6009
6360
|
cancel: "Cancel"
|
|
6010
6361
|
};
|
|
6011
6362
|
const zh = {
|
|
6363
|
+
panels: "面板",
|
|
6364
|
+
backToChat: "返回聊天",
|
|
6365
|
+
switchPanel: "切换面板",
|
|
6366
|
+
addPanel: "添加面板",
|
|
6367
|
+
closePanel: "关闭当前面板",
|
|
6368
|
+
panelError: "暂时无法操作面板,请重试。",
|
|
6012
6369
|
connectPhone: "连接手机",
|
|
6013
6370
|
connectIntro: "在 DSH Mobile 中继续你的会话。",
|
|
6014
6371
|
connectQR: "使用 DSH Mobile 扫码登录",
|
|
@@ -6172,6 +6529,12 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
6172
6529
|
const messages = new MessageMenu(document);
|
|
6173
6530
|
ctx.effect(() => () => messages.dispose(), "mobile: message actions");
|
|
6174
6531
|
const navigation = new MobileNavigation();
|
|
6532
|
+
const panels = new MobilePanels(document);
|
|
6533
|
+
ctx.effect(() => () => panels.dispose(), "mobile: optional panels");
|
|
6534
|
+
ctx.inject(["sidebarRight"], (scoped) => {
|
|
6535
|
+
panels.set(scoped.get("sidebarRight"));
|
|
6536
|
+
scoped.effect(() => () => panels.set(void 0), "mobile: sidebar capability");
|
|
6537
|
+
});
|
|
6175
6538
|
const directory = new MobileDirectory();
|
|
6176
6539
|
const presentation = new MobilePresentation(window, window.__DSH_MOBILE_SHELL__?.bridgeVersion === 1);
|
|
6177
6540
|
ctx.inject([
|
|
@@ -6236,6 +6599,7 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
6236
6599
|
connection,
|
|
6237
6600
|
navigation,
|
|
6238
6601
|
rooms,
|
|
6602
|
+
panels,
|
|
6239
6603
|
toggleSidebar: () => {
|
|
6240
6604
|
ctx.layout.toggleSidebar();
|
|
6241
6605
|
}
|
|
@@ -6248,11 +6612,15 @@ html[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] {
|
|
|
6248
6612
|
ctx.slots.inject("conversation.composer", () => {
|
|
6249
6613
|
let remove;
|
|
6250
6614
|
let timer;
|
|
6615
|
+
let lastRoom;
|
|
6251
6616
|
const refresh = () => {
|
|
6252
6617
|
const list = navigation.getSnapshot()?.sessions.list.getSnapshot();
|
|
6253
6618
|
const current = list === void 0 ? void 0 : mainSessionId(list);
|
|
6254
|
-
|
|
6619
|
+
const room = current && rooms.get(current) ? current : void 0;
|
|
6620
|
+
if (!presentation.getSnapshot().active || room === lastRoom) return;
|
|
6621
|
+
lastRoom = room;
|
|
6255
6622
|
clearTimeout(timer);
|
|
6623
|
+
if (!room) return;
|
|
6256
6624
|
timer = setTimeout(() => {
|
|
6257
6625
|
remove?.();
|
|
6258
6626
|
remove = ctx.slots.register({
|