dsh-mobile 0.1.0-alpha.21 → 0.1.0-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +28 -209
- package/lib/client.js.map +1 -1
- package/lib/mobile-layout.js +30 -37
- package/lib/mobile-layout.js.map +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -90,7 +90,7 @@ The Host face owns discovery, pairing, HTTPS, and the proxy. The Client face rep
|
|
|
90
90
|
|
|
91
91
|
| DSH Mobile | Verified DeepSeek Harness releases |
|
|
92
92
|
| --- | --- |
|
|
93
|
-
| `0.1.0-alpha.
|
|
93
|
+
| `0.1.0-alpha.23` | `0.1.0-rc.5`, `0.1.0-rc.6` |
|
|
94
94
|
|
|
95
95
|
At startup, the plugin verifies the DSH Host version and the frontend dependencies required by the mobile layout. An unverified release fails with a clear error instead of serving a broken page. CI also tracks the DSH main branch layout slots and mobile semantic markers. If a DSH upgrade reports an incompatibility, update DSH Mobile first.
|
|
96
96
|
|
package/README.md
CHANGED
|
@@ -129,7 +129,7 @@ flowchart LR
|
|
|
129
129
|
|
|
130
130
|
| DSH Mobile | 已验证的 DeepSeek Harness |
|
|
131
131
|
| --- | --- |
|
|
132
|
-
| `0.1.0-alpha.
|
|
132
|
+
| `0.1.0-alpha.23` | `0.1.0-rc.5`、`0.1.0-rc.6` |
|
|
133
133
|
|
|
134
134
|
插件会在启动时检查 DSH Host 版本和移动布局所需的前端依赖;遇到未经验证的版本会直接给出错误,不会带着不兼容页面继续启动。CI 也会持续检查 DSH 主分支的布局插槽和移动端语义标记。升级 DSH 后如遇兼容提示,请先升级 DSH Mobile。
|
|
135
135
|
|
package/lib/client.js
CHANGED
|
@@ -12,12 +12,19 @@ window.__ModuleLoader__.load({
|
|
|
12
12
|
html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }
|
|
13
13
|
html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }
|
|
14
14
|
html.dsh-native-mobile-active :is(a,button,[role="button"],[role="tab"],[tabindex]) { -webkit-tap-highlight-color:transparent; }
|
|
15
|
+
html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role="treeitem"] { -webkit-tap-highlight-color:transparent; touch-action:manipulation; }
|
|
15
16
|
html.dsh-native-mobile-active[data-dsh-mobile-input="touch"] :is(a,button,[role="button"],[role="tab"],[tabindex]):focus { outline:none !important; }
|
|
17
|
+
html.dsh-native-mobile-active [role="tooltip"] { display:none !important; }
|
|
18
|
+
/* Touch has no persistent hover affordance: keep workspace rows neutral after a tap. */
|
|
19
|
+
html.dsh-native-mobile-active [data-dsh-mobile-sidebar] { --dsw-alias-interactive-bg-hover:transparent !important; }
|
|
20
|
+
html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role="treeitem"]:is(:hover,:active,:focus,[aria-selected="true"]),
|
|
21
|
+
html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*="_sessionRow"][class*="_selected"],
|
|
22
|
+
html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*="_searchResultRow"][class*="_selected"] { background:transparent !important; outline:0 !important; box-shadow:none !important; }
|
|
16
23
|
[data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }
|
|
17
24
|
[data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }
|
|
18
25
|
[data-dsh-mobile-center] > * { min-width:0 !important; }
|
|
19
|
-
[data-dsh-mobile-header] { min-width:0; padding-right:
|
|
20
|
-
[data-dsh-mobile-header] [class*="_titleRow"] { box-sizing:border-box !important; min-width:0; min-height:
|
|
26
|
+
[data-dsh-mobile-header] { box-sizing:border-box !important; width:calc(100% - 16px) !important; margin:0 8px !important; min-width:0; padding-top:4px !important; padding-right:8px !important; padding-left:42px !important; }
|
|
27
|
+
[data-dsh-mobile-header] [class*="_titleRow"] { box-sizing:border-box !important; display:flex !important; align-items:center !important; min-width:0; min-height:32px !important; height:32px !important; gap:6px !important; padding:0 6px !important; }
|
|
21
28
|
[data-dsh-mobile-header] [class*="_titleCluster"] { min-width:0; }
|
|
22
29
|
[data-dsh-mobile-header] [class*="_crumbs"] { min-width:0; overflow:hidden; }
|
|
23
30
|
[data-dsh-mobile-header] [class*="_crumb"] { max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
@@ -27,18 +34,18 @@ window.__ModuleLoader__.load({
|
|
|
27
34
|
[data-dsh-mobile-header] [class*="_sessionLogButton"] { width:40px; min-width:40px; padding:0 !important; overflow:hidden; color:transparent; font-size:0 !important; }
|
|
28
35
|
[data-dsh-mobile-header] [class*="_sessionLogButton"] > * { display:none !important; }
|
|
29
36
|
[data-dsh-mobile-header] [class*="_sessionLogButton"]::after { color:var(--dsw-text, #171a21); content:"日志"; font-size:11px; font-weight:600; }
|
|
30
|
-
[data-dsh-mobile-header] [class*="_tabs"] { min-height:
|
|
37
|
+
[data-dsh-mobile-header] [class*="_tabs"] { box-sizing:border-box !important; width:max-content !important; max-width:calc(100% - 58px) !important; min-height:28px !important; height:28px !important; margin-top:0 !important; padding-left:6px !important; padding-right:6px !important; overflow-x:auto; scrollbar-width:none; }
|
|
38
|
+
[data-dsh-mobile-header] [class*="_tab"] { padding-bottom:5px !important; }
|
|
31
39
|
[data-dsh-mobile-header] [class*="_tabs"]::-webkit-scrollbar { display:none; }
|
|
32
40
|
[data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }
|
|
33
41
|
[data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:0 auto 0 0 !important; height:100dvh !important; transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease) !important; }
|
|
34
42
|
[data-dsh-mobile-sidebar][data-open="true"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }
|
|
35
43
|
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }
|
|
36
44
|
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }
|
|
37
|
-
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }
|
|
45
|
+
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; box-sizing:border-box !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }
|
|
38
46
|
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }
|
|
39
47
|
[data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }
|
|
40
|
-
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-toggle] svg {
|
|
41
|
-
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-toggle]::after { width:20px; height:2px; border-radius:2px; background:currentColor; box-shadow:0 -6px 0 currentColor,0 6px 0 currentColor; content:""; }
|
|
48
|
+
[data-dsh-mobile-sidebar][data-open="false"] [data-dsh-mobile-toggle] > svg[class*="_railFish"] { transform:translateY(-4px) !important; }
|
|
42
49
|
.dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:0; border:0; background:rgb(15 23 42 / 32%); }
|
|
43
50
|
.dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }
|
|
44
51
|
.dsh-native-mobile-backdrop[hidden] { display:none; }
|
|
@@ -69,52 +76,37 @@ window.__ModuleLoader__.load({
|
|
|
69
76
|
[data-dsh-mobile-center] table { display:block; max-width:100%; overflow-x:auto; }
|
|
70
77
|
[data-dsh-mobile-center] pre { max-width:100%; overflow-x:auto; }
|
|
71
78
|
[data-dsh-mobile-center] :is(img,video,canvas,svg) { max-width:100%; }
|
|
72
|
-
[data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:
|
|
73
|
-
[data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:
|
|
79
|
+
[data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:8px 10px 20px !important; }
|
|
80
|
+
[data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:10px !important; }
|
|
74
81
|
[data-dsh-mobile-message-column] > * { width:100% !important; max-width:100% !important; }
|
|
75
|
-
[data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:
|
|
82
|
+
[data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:40px !important; padding:4px 0 !important; }
|
|
76
83
|
[data-dsh-mobile-message-column] [data-disclosure-row] > [class*="_leading"] { grid-column:1 !important; grid-row:1 !important; margin-right:0 !important; }
|
|
77
84
|
[data-dsh-mobile-message-column] [data-disclosure-row] > [class*="_title"] { grid-column:2 !important; grid-row:1 !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }
|
|
78
85
|
[data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*="_sep"],[class*="_separator"]) { display:none !important; }
|
|
79
|
-
[data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*="_summary"],[class*="_fileLink"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:
|
|
86
|
+
[data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*="_summary"],[class*="_fileLink"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:19px !important; text-overflow:ellipsis !important; white-space:nowrap !important; }
|
|
80
87
|
[data-dsh-mobile-message-column] [data-disclosure-row] > [class*="_summarySuffix"] { grid-column:2 !important; grid-row:3 !important; margin-left:0 !important; }
|
|
81
88
|
[data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }
|
|
82
89
|
[data-dsh-mobile-message-column] [class*="_ioSection"] { grid-template-columns:1fr !important; row-gap:4px !important; }
|
|
83
90
|
[data-dsh-mobile-message-column] [class*="_body"] { max-width:100% !important; overflow-wrap:anywhere; }
|
|
91
|
+
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"],
|
|
92
|
+
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }
|
|
93
|
+
[data-dsh-mobile-center] [data-composer-card] ~ [class*="_root"] [class*="_sep"],
|
|
94
|
+
[data-dsh-mobile-center] [data-composer-card] ~ * [class*="_root"] [class*="_sep"] { margin:0 6px !important; }
|
|
84
95
|
[data-dsh-mobile-center] [class*="_composer"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }
|
|
85
96
|
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_row"] { display:flex !important; align-items:center !important; gap:4px !important; }
|
|
86
97
|
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_tools"] { flex:0 0 auto !important; width:auto !important; min-width:0 !important; gap:6px !important; }
|
|
87
|
-
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_trailing"] { flex:1 1 auto !important; min-width:0 !important; gap:6px !important; }
|
|
88
|
-
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_trailing"] [class*="_root"]:has(button[aria-label^="选择模型"]) { flex:
|
|
89
|
-
[data-dsh-mobile-center] [class*="_card"]:has(textarea) button[aria-label^="选择模型"] { width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }
|
|
90
|
-
[data-dsh-mobile-center] [class*="_card"]:has(textarea) button[aria-label^="选择模型"] [class*="_triggerLabel"] { max-width:
|
|
98
|
+
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_trailing"] { flex:1 1 auto !important; min-width:0 !important; gap:6px !important; margin-left:auto !important; justify-content:flex-end !important; }
|
|
99
|
+
[data-dsh-mobile-center] [class*="_card"]:has(textarea) [class*="_trailing"] [class*="_root"]:has(button[aria-label^="选择模型"]) { flex:0 1 auto !important; width:auto !important; max-width:min(55vw,220px) !important; min-width:0 !important; }
|
|
100
|
+
[data-dsh-mobile-center] [class*="_card"]:has(textarea) button[aria-label^="选择模型"] { width:auto !important; max-width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }
|
|
101
|
+
[data-dsh-mobile-center] [class*="_card"]:has(textarea) button[aria-label^="选择模型"] [class*="_triggerLabel"] { max-width:clamp(120px,36vw,210px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
91
102
|
[data-dsh-mobile-center] [class*="_root"]:has(> [class*="_card"] textarea) { box-sizing:border-box !important; width:100% !important; padding:0 0 8px !important; }
|
|
92
103
|
[data-dsh-mobile-center] [class*="_root"]:has(> [class*="_card"] textarea) > [class=""]:last-child { display:none !important; }
|
|
93
|
-
.dsh-native-mobile-attach { display:inline-flex; align-items:center; justify-content:center; flex:0 0 44px; width:44px; height:44px; padding:0; border:0; border-radius:12px; background:transparent; color:var(--dsw-text-secondary,#5e6673); cursor:pointer; }
|
|
94
|
-
.dsh-native-mobile-attach:active { background:var(--dsw-bg-subtle,#f1f3f6); }
|
|
95
|
-
.dsh-native-mobile-attach:focus-visible { outline:2px solid var(--dsw-accent,#4c7eea); outline-offset:2px; }
|
|
96
|
-
.dsh-native-mobile-attach:disabled { cursor:not-allowed; opacity:.38; }
|
|
97
|
-
.dsh-native-mobile-attach svg { width:22px; height:22px; }
|
|
98
|
-
.dsh-native-mobile-sheet-mask { position:fixed; z-index:1080; inset:0; border:0; background:rgb(15 23 42 / 32%); }
|
|
99
|
-
.dsh-native-mobile-sheet-mask[hidden] { display:none; }
|
|
100
|
-
.dsh-native-mobile-sheet { position:fixed; z-index:1081; right:0; bottom:0; left:0; display:flex; flex-direction:column; gap:8px; max-height:min(78dvh,680px); padding:8px 16px max(18px,env(safe-area-inset-bottom)); overflow-y:auto; border-radius:22px 22px 0 0; background:var(--dsw-alias-bg-layer-2,#fff); box-shadow:0 -16px 44px rgb(15 23 42 / 16%); animation:dsh-mobile-sheet-in 220ms var(--dsh-mobile-motion-ease); }
|
|
101
|
-
.dsh-native-mobile-sheet[hidden] { display:none; }
|
|
102
|
-
.dsh-native-mobile-sheet__header { position:sticky; z-index:1; top:-8px; display:flex; align-items:center; justify-content:space-between; min-height:48px; padding:8px 0; background:var(--dsw-alias-bg-layer-2,#fff); }
|
|
103
|
-
.dsh-native-mobile-sheet__header strong { font-size:17px; font-weight:600; }
|
|
104
|
-
.dsh-native-mobile-sheet__close { width:44px; height:44px; border:0; border-radius:12px; background:transparent; color:inherit; font-size:24px; }
|
|
105
|
-
.dsh-native-mobile-sheet__path { margin:0 0 4px; overflow-wrap:anywhere; color:var(--dsw-alias-label-secondary,#6b7280); font-size:12px; }
|
|
106
|
-
.dsh-native-mobile-sheet__choice { display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%; min-height:56px; padding:10px 14px; border:1px solid var(--dsw-alias-border-subtle,#e2e6eb); border-radius:14px; background:var(--dsw-alias-bg-layer-2,#fff); color:inherit; text-align:left; }
|
|
107
|
-
.dsh-native-mobile-sheet__choice:active { background:var(--dsw-alias-interactive-bg-hover,#f1f3f6); }
|
|
108
|
-
.dsh-native-mobile-sheet__choice small { color:var(--dsw-alias-label-secondary,#6b7280); }
|
|
109
|
-
.dsh-native-mobile-sheet__error { margin:4px 0; color:var(--dsw-alias-status-error,#b42318); font-size:13px; }
|
|
110
104
|
}
|
|
111
105
|
@keyframes dsh-mobile-fade-in { from { opacity:0; } }
|
|
112
106
|
@keyframes dsh-mobile-panel-in { from { opacity:.72; transform:translateY(6px); } }
|
|
113
107
|
@keyframes dsh-mobile-view-in { from { opacity:.58; transform:translateY(5px); } }
|
|
114
|
-
@keyframes dsh-mobile-sheet-in { from { opacity:.7; transform:translateY(18px); } }
|
|
115
108
|
@media (max-width:420px) {
|
|
116
109
|
[data-dsh-mobile-header] [class*="_headerActions"] { max-width:42vw; }
|
|
117
|
-
[data-dsh-mobile-header] [class*="_titleRow"] { min-height:50px; }
|
|
118
110
|
[data-dsh-mobile-settings-options] [data-slot="settings.general.item"] [class*="_selector"] { align-self:stretch !important; width:100% !important; }
|
|
119
111
|
[data-dsh-mobile-message-column] [data-context-fields] > * { grid-template-columns:1fr !important; }
|
|
120
112
|
}
|
|
@@ -122,8 +114,7 @@ window.__ModuleLoader__.load({
|
|
|
122
114
|
[data-dsh-mobile-sidebar-root],[data-dsh-mobile-details] { transition:none !important; }
|
|
123
115
|
.dsh-native-mobile-backdrop:not([hidden]),[data-dsh-mobile-settings],
|
|
124
116
|
[data-dsh-mobile-settings-content][data-dsh-mobile-view-transition="true"],
|
|
125
|
-
[data-dsh-mobile-view][data-dsh-mobile-view-transition="true"]
|
|
126
|
-
.dsh-native-mobile-sheet { animation:none !important; }
|
|
117
|
+
[data-dsh-mobile-view][data-dsh-mobile-view-transition="true"] { animation:none !important; }
|
|
127
118
|
}
|
|
128
119
|
`;
|
|
129
120
|
function classToken(element, suffix) {
|
|
@@ -132,27 +123,7 @@ window.__ModuleLoader__.load({
|
|
|
132
123
|
function firstByClassSuffix(root, suffix) {
|
|
133
124
|
return Array.from(root.querySelectorAll("[class]")).find((element) => classToken(element, suffix));
|
|
134
125
|
}
|
|
135
|
-
|
|
136
|
-
let candidate = textarea.parentElement;
|
|
137
|
-
while (candidate !== null && !classToken(candidate, "_card")) candidate = candidate.parentElement;
|
|
138
|
-
return candidate ?? void 0;
|
|
139
|
-
}
|
|
140
|
-
function paperclipIcon() {
|
|
141
|
-
const namespace = "http://www.w3.org/2000/svg";
|
|
142
|
-
const svg = document.createElementNS(namespace, "svg");
|
|
143
|
-
svg.setAttribute("viewBox", "0 0 24 24");
|
|
144
|
-
svg.setAttribute("fill", "none");
|
|
145
|
-
svg.setAttribute("stroke", "currentColor");
|
|
146
|
-
svg.setAttribute("stroke-width", "2");
|
|
147
|
-
svg.setAttribute("stroke-linecap", "round");
|
|
148
|
-
svg.setAttribute("stroke-linejoin", "round");
|
|
149
|
-
svg.setAttribute("aria-hidden", "true");
|
|
150
|
-
const path = document.createElementNS(namespace, "path");
|
|
151
|
-
path.setAttribute("d", "m21.4 11.6-8.9 8.9a6 6 0 0 1-8.5-8.5l9.6-9.6a4 4 0 0 1 5.7 5.7l-9.7 9.6a2 2 0 0 1-2.8-2.8l8.9-8.9");
|
|
152
|
-
svg.append(path);
|
|
153
|
-
return svg;
|
|
154
|
-
}
|
|
155
|
-
/** Add mobile semantics and phone-local file actions without replacing feature trees. */
|
|
126
|
+
/** Add mobile semantics without replacing feature trees. */
|
|
156
127
|
function installNativeMobileSurface() {
|
|
157
128
|
document.documentElement.classList.add("dsh-native-mobile-active");
|
|
158
129
|
const setInputMode = (mode) => {
|
|
@@ -182,149 +153,6 @@ window.__ModuleLoader__.load({
|
|
|
182
153
|
let transitionRestartFrame = 0;
|
|
183
154
|
let transitionTimer = 0;
|
|
184
155
|
let transitionTarget;
|
|
185
|
-
const fileInput = document.createElement("input");
|
|
186
|
-
fileInput.type = "file";
|
|
187
|
-
fileInput.accept = "image/*";
|
|
188
|
-
fileInput.multiple = true;
|
|
189
|
-
fileInput.hidden = true;
|
|
190
|
-
fileInput.setAttribute("aria-hidden", "true");
|
|
191
|
-
const attach = document.createElement("button");
|
|
192
|
-
attach.type = "button";
|
|
193
|
-
attach.className = "dsh-native-mobile-attach";
|
|
194
|
-
attach.setAttribute("aria-label", "添加图片");
|
|
195
|
-
attach.setAttribute("title", "添加图片");
|
|
196
|
-
attach.append(paperclipIcon());
|
|
197
|
-
document.body.append(fileInput);
|
|
198
|
-
const sheetMask = document.createElement("button");
|
|
199
|
-
sheetMask.type = "button";
|
|
200
|
-
sheetMask.className = "dsh-native-mobile-sheet-mask";
|
|
201
|
-
sheetMask.hidden = true;
|
|
202
|
-
sheetMask.setAttribute("aria-label", "关闭图片选择");
|
|
203
|
-
const sheet = document.createElement("section");
|
|
204
|
-
sheet.className = "dsh-native-mobile-sheet";
|
|
205
|
-
sheet.hidden = true;
|
|
206
|
-
sheet.setAttribute("aria-label", "添加图片");
|
|
207
|
-
document.body.append(sheetMask, sheet);
|
|
208
|
-
const handFilesToComposer = (files) => {
|
|
209
|
-
const textarea = document.querySelector("[data-dsh-mobile-center] textarea");
|
|
210
|
-
if (textarea === null || files.length === 0) return;
|
|
211
|
-
const paste = new Event("paste", {
|
|
212
|
-
bubbles: true,
|
|
213
|
-
cancelable: true
|
|
214
|
-
});
|
|
215
|
-
Object.defineProperty(paste, "clipboardData", { value: Object.freeze({
|
|
216
|
-
files,
|
|
217
|
-
items: Object.freeze(files.map((file) => Object.freeze({
|
|
218
|
-
kind: "file",
|
|
219
|
-
type: file.type,
|
|
220
|
-
getAsFile: () => file
|
|
221
|
-
}))),
|
|
222
|
-
getData: () => ""
|
|
223
|
-
}) });
|
|
224
|
-
textarea.dispatchEvent(paste);
|
|
225
|
-
};
|
|
226
|
-
const closeSheet = () => {
|
|
227
|
-
sheet.hidden = true;
|
|
228
|
-
sheetMask.hidden = true;
|
|
229
|
-
sheet.replaceChildren();
|
|
230
|
-
};
|
|
231
|
-
const sheetHeader = (title) => {
|
|
232
|
-
const header = document.createElement("header");
|
|
233
|
-
header.className = "dsh-native-mobile-sheet__header";
|
|
234
|
-
const heading = document.createElement("strong");
|
|
235
|
-
heading.textContent = title;
|
|
236
|
-
const close = document.createElement("button");
|
|
237
|
-
close.type = "button";
|
|
238
|
-
close.className = "dsh-native-mobile-sheet__close";
|
|
239
|
-
close.setAttribute("aria-label", "关闭");
|
|
240
|
-
close.textContent = "×";
|
|
241
|
-
close.addEventListener("click", closeSheet);
|
|
242
|
-
header.append(heading, close);
|
|
243
|
-
sheet.append(header);
|
|
244
|
-
};
|
|
245
|
-
const choice = (title, detail, action) => {
|
|
246
|
-
const button = document.createElement("button");
|
|
247
|
-
button.type = "button";
|
|
248
|
-
button.className = "dsh-native-mobile-sheet__choice";
|
|
249
|
-
const label = document.createElement("span");
|
|
250
|
-
label.textContent = title;
|
|
251
|
-
const hint = document.createElement("small");
|
|
252
|
-
hint.textContent = detail;
|
|
253
|
-
button.append(label, hint);
|
|
254
|
-
button.addEventListener("click", action);
|
|
255
|
-
return button;
|
|
256
|
-
};
|
|
257
|
-
const showSheet = () => {
|
|
258
|
-
sheet.hidden = false;
|
|
259
|
-
sheetMask.hidden = false;
|
|
260
|
-
};
|
|
261
|
-
const openComputerImages = async (path) => {
|
|
262
|
-
sheet.replaceChildren();
|
|
263
|
-
sheetHeader("电脑图片");
|
|
264
|
-
const progress = document.createElement("p");
|
|
265
|
-
progress.className = "dsh-native-mobile-sheet__path";
|
|
266
|
-
progress.textContent = "正在读取电脑目录…";
|
|
267
|
-
sheet.append(progress);
|
|
268
|
-
showSheet();
|
|
269
|
-
try {
|
|
270
|
-
const suffix = path === void 0 ? "" : `?path=${encodeURIComponent(path)}`;
|
|
271
|
-
const response = await fetch(`/mobile-access/computer-images${suffix}`, {
|
|
272
|
-
credentials: "same-origin",
|
|
273
|
-
cache: "no-store"
|
|
274
|
-
});
|
|
275
|
-
if (!response.ok) throw new Error(`读取失败(${String(response.status)})`);
|
|
276
|
-
const listing = await response.json();
|
|
277
|
-
progress.textContent = listing.path;
|
|
278
|
-
if (listing.parent !== void 0) sheet.append(choice("返回上一级", listing.parent, () => {
|
|
279
|
-
openComputerImages(listing.parent);
|
|
280
|
-
}));
|
|
281
|
-
for (const entry of listing.entries) {
|
|
282
|
-
if (entry.kind === "directory") {
|
|
283
|
-
sheet.append(choice(entry.name, "文件夹", () => {
|
|
284
|
-
openComputerImages(entry.path);
|
|
285
|
-
}));
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
const row = choice(entry.name, "添加这张电脑图片", () => {
|
|
289
|
-
row.disabled = true;
|
|
290
|
-
fetch(`/mobile-access/computer-image?path=${encodeURIComponent(entry.path)}`, {
|
|
291
|
-
credentials: "same-origin",
|
|
292
|
-
cache: "no-store"
|
|
293
|
-
}).then(async (response) => {
|
|
294
|
-
if (!response.ok) throw new Error(`读取失败(${String(response.status)})`);
|
|
295
|
-
const blob = await response.blob();
|
|
296
|
-
handFilesToComposer([new File([blob], entry.name, { type: blob.type })]);
|
|
297
|
-
closeSheet();
|
|
298
|
-
}).catch((error) => {
|
|
299
|
-
row.disabled = false;
|
|
300
|
-
progress.className = "dsh-native-mobile-sheet__error";
|
|
301
|
-
progress.textContent = error instanceof Error ? error.message : String(error);
|
|
302
|
-
});
|
|
303
|
-
});
|
|
304
|
-
sheet.append(row);
|
|
305
|
-
}
|
|
306
|
-
} catch (error) {
|
|
307
|
-
progress.className = "dsh-native-mobile-sheet__error";
|
|
308
|
-
progress.textContent = error instanceof Error ? error.message : String(error);
|
|
309
|
-
}
|
|
310
|
-
};
|
|
311
|
-
const openAttachmentSources = () => {
|
|
312
|
-
sheet.replaceChildren();
|
|
313
|
-
sheetHeader("添加图片");
|
|
314
|
-
sheet.append(choice("从手机选择", "相册、相机或手机存储", () => {
|
|
315
|
-
closeSheet();
|
|
316
|
-
fileInput.click();
|
|
317
|
-
}), choice("从电脑选择", "在手机页面浏览电脑中的图片", () => {
|
|
318
|
-
openComputerImages();
|
|
319
|
-
}));
|
|
320
|
-
showSheet();
|
|
321
|
-
};
|
|
322
|
-
attach.addEventListener("click", openAttachmentSources);
|
|
323
|
-
sheetMask.addEventListener("click", closeSheet);
|
|
324
|
-
fileInput.addEventListener("change", () => {
|
|
325
|
-
handFilesToComposer([...fileInput.files ?? []]);
|
|
326
|
-
fileInput.value = "";
|
|
327
|
-
});
|
|
328
156
|
const animateNavigation = (event) => {
|
|
329
157
|
if (!(event.target instanceof Element)) return;
|
|
330
158
|
const trigger = event.target.closest("button,a,[role=\"tab\"],[aria-selected]");
|
|
@@ -362,7 +190,7 @@ window.__ModuleLoader__.load({
|
|
|
362
190
|
frame = firstByClassSuffix(document, "_frame");
|
|
363
191
|
const dedicatedCenter = document.querySelector(".dshm-main") ?? void 0;
|
|
364
192
|
if (frame !== void 0) frame.dataset.dshMobileFrame = "true";
|
|
365
|
-
sidebar = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_sidebarCol");
|
|
193
|
+
sidebar = frame === void 0 ? document.querySelector(".dshm-drawer") ?? void 0 : firstByClassSuffix(frame, "_sidebarCol");
|
|
366
194
|
const center = frame === void 0 ? dedicatedCenter : firstByClassSuffix(frame, "_centerCol");
|
|
367
195
|
const details = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_detailsCol");
|
|
368
196
|
const handle = frame === void 0 ? void 0 : firstByClassSuffix(frame, "_handle");
|
|
@@ -403,11 +231,6 @@ window.__ModuleLoader__.load({
|
|
|
403
231
|
firstByClassSuffix(content, "_options")?.setAttribute("data-dsh-mobile-settings-options", "true");
|
|
404
232
|
}
|
|
405
233
|
}
|
|
406
|
-
const textarea = center?.querySelector("textarea");
|
|
407
|
-
const card = textarea === null || textarea === void 0 ? void 0 : composerCard(textarea);
|
|
408
|
-
const tools = card === void 0 ? void 0 : firstByClassSuffix(card, "_tools");
|
|
409
|
-
attach.disabled = textarea === void 0 || textarea === null || textarea.disabled || textarea.readOnly;
|
|
410
|
-
if (tools !== void 0 && attach.parentElement !== tools) tools.append(attach);
|
|
411
234
|
if (sidebar === void 0) return;
|
|
412
235
|
sidebar.dataset.dshMobileSidebar = "true";
|
|
413
236
|
toggle = firstByClassSuffix(sidebar, "_toggle");
|
|
@@ -446,10 +269,6 @@ window.__ModuleLoader__.load({
|
|
|
446
269
|
document.removeEventListener("keydown", onKeyDown, true);
|
|
447
270
|
document.removeEventListener("click", animateNavigation);
|
|
448
271
|
backdrop.remove();
|
|
449
|
-
attach.remove();
|
|
450
|
-
fileInput.remove();
|
|
451
|
-
sheet.remove();
|
|
452
|
-
sheetMask.remove();
|
|
453
272
|
document.documentElement.classList.remove("dsh-native-mobile-active");
|
|
454
273
|
delete document.documentElement.dataset.dshMobileInput;
|
|
455
274
|
};
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["createElement"],"sources":["../src/native-mobile.ts","../src/client.ts"],"sourcesContent":["/** Mobile feature and compatibility rules applied to DSH React surfaces. */\nexport const NATIVE_MOBILE_STYLES = `\n@media (max-width:720px) {\n html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }\n html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }\n html.dsh-native-mobile-active :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]) { -webkit-tap-highlight-color:transparent; }\n html.dsh-native-mobile-active[data-dsh-mobile-input=\"touch\"] :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]):focus { outline:none !important; }\n [data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }\n [data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }\n [data-dsh-mobile-center] > * { min-width:0 !important; }\n [data-dsh-mobile-header] { min-width:0; padding-right:12px !important; padding-left:50px !important; }\n [data-dsh-mobile-header] [class*=\"_titleRow\"] { box-sizing:border-box !important; min-width:0; min-height:52px !important; height:52px !important; gap:6px !important; padding:4px 8px !important; }\n [data-dsh-mobile-header] [class*=\"_titleCluster\"] { min-width:0; }\n [data-dsh-mobile-header] [class*=\"_crumbs\"] { min-width:0; overflow:hidden; }\n [data-dsh-mobile-header] [class*=\"_crumb\"] { max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { min-width:0; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-header] [class*=\"_headerUtilities\"] { gap:2px !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] { width:40px; min-width:40px; padding:0 !important; overflow:hidden; color:transparent; font-size:0 !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] > * { display:none !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"]::after { color:var(--dsw-text, #171a21); content:\"日志\"; font-size:11px; font-weight:600; }\n [data-dsh-mobile-header] [class*=\"_tabs\"] { min-height:42px; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_tabs\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:0 auto 0 0 !important; height:100dvh !important; transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease) !important; }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }\n [data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-toggle] svg { display:none !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-toggle]::after { width:20px; height:2px; border-radius:2px; background:currentColor; box-shadow:0 -6px 0 currentColor,0 6px 0 currentColor; content:\"\"; }\n .dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:0; border:0; background:rgb(15 23 42 / 32%); }\n .dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }\n .dsh-native-mobile-backdrop[hidden] { display:none; }\n [data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-bg, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-details][data-open=\"true\"] { transform:translateX(0); }\n [data-dsh-mobile-handle] { display:none !important; }\n [data-dsh-mobile-settings] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-settings-nav] { flex:none !important; width:100% !important; padding:max(14px,env(safe-area-inset-top)) 12px 8px !important; gap:10px !important; border-bottom:1px solid var(--dsw-alias-border-subtle,#e8ebef); }\n [data-dsh-mobile-settings-nav] [class*=\"_navTitle\"] { padding:0 8px !important; font-size:18px !important; line-height:28px !important; }\n [data-dsh-mobile-settings-list] { flex-direction:row !important; gap:4px !important; overflow-x:auto !important; scrollbar-width:none; }\n [data-dsh-mobile-settings-list]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-settings-list] [class*=\"_navCell\"] { flex:0 0 auto !important; min-width:max-content !important; height:44px !important; padding:10px 12px !important; }\n [data-dsh-mobile-settings-list] [aria-current=\"true\"] { border-color:transparent !important; outline:0 !important; box-shadow:none !important; }\n [data-dsh-mobile-settings-content] { flex:1 1 auto !important; width:100% !important; min-height:0 !important; }\n [data-dsh-mobile-settings-header] { height:48px !important; min-height:48px !important; padding:10px 12px 6px !important; }\n [data-dsh-mobile-settings-header] [class*=\"_close\"] { width:36px !important; height:36px !important; }\n [data-dsh-mobile-settings-options] { box-sizing:border-box !important; width:100% !important; padding:4px 16px max(24px,env(safe-area-inset-bottom)) !important; overflow-x:hidden !important; }\n [data-dsh-mobile-settings-options] > * { width:100% !important; min-width:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] > [class*=\"_row\"] { flex-direction:column !important; align-items:stretch !important; gap:12px !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_rowText\"] { width:100% !important; padding-right:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { box-sizing:border-box !important; align-self:flex-start !important; justify-content:space-between !important; min-width:0 !important; min-height:44px !important; max-width:100% !important; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea,button) { max-width:100%; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea) { box-sizing:border-box; width:100%; min-width:0; }\n [data-dsh-mobile-settings-options] [class*=\"_head\"] { min-width:0; flex-wrap:wrap; }\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-center] textarea { font-size:16px !important; }\n [data-dsh-mobile-center] table { display:block; max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] pre { max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] :is(img,video,canvas,svg) { max-width:100%; }\n [data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:12px 16px 20px !important; }\n [data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:14px !important; }\n [data-dsh-mobile-message-column] > * { width:100% !important; max-width:100% !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:44px !important; padding:5px 0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_leading\"] { grid-column:1 !important; grid-row:1 !important; margin-right:0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_title\"] { grid-column:2 !important; grid-row:1 !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_sep\"],[class*=\"_separator\"]) { display:none !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_summary\"],[class*=\"_fileLink\"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:20px !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_summarySuffix\"] { grid-column:2 !important; grid-row:3 !important; margin-left:0 !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }\n [data-dsh-mobile-message-column] [class*=\"_ioSection\"] { grid-template-columns:1fr !important; row-gap:4px !important; }\n [data-dsh-mobile-message-column] [class*=\"_body\"] { max-width:100% !important; overflow-wrap:anywhere; }\n [data-dsh-mobile-center] [class*=\"_composer\"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_row\"] { display:flex !important; align-items:center !important; gap:4px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_tools\"] { flex:0 0 auto !important; width:auto !important; min-width:0 !important; gap:6px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_trailing\"] { flex:1 1 auto !important; min-width:0 !important; gap:6px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_trailing\"] [class*=\"_root\"]:has(button[aria-label^=\"选择模型\"]) { flex:1 1 auto !important; min-width:0 !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) button[aria-label^=\"选择模型\"] { width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) button[aria-label^=\"选择模型\"] [class*=\"_triggerLabel\"] { max-width:78px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) { box-sizing:border-box !important; width:100% !important; padding:0 0 8px !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) > [class=\"\"]:last-child { display:none !important; }\n .dsh-native-mobile-attach { display:inline-flex; align-items:center; justify-content:center; flex:0 0 44px; width:44px; height:44px; padding:0; border:0; border-radius:12px; background:transparent; color:var(--dsw-text-secondary,#5e6673); cursor:pointer; }\n .dsh-native-mobile-attach:active { background:var(--dsw-bg-subtle,#f1f3f6); }\n .dsh-native-mobile-attach:focus-visible { outline:2px solid var(--dsw-accent,#4c7eea); outline-offset:2px; }\n .dsh-native-mobile-attach:disabled { cursor:not-allowed; opacity:.38; }\n .dsh-native-mobile-attach svg { width:22px; height:22px; }\n .dsh-native-mobile-sheet-mask { position:fixed; z-index:1080; inset:0; border:0; background:rgb(15 23 42 / 32%); }\n .dsh-native-mobile-sheet-mask[hidden] { display:none; }\n .dsh-native-mobile-sheet { position:fixed; z-index:1081; right:0; bottom:0; left:0; display:flex; flex-direction:column; gap:8px; max-height:min(78dvh,680px); padding:8px 16px max(18px,env(safe-area-inset-bottom)); overflow-y:auto; border-radius:22px 22px 0 0; background:var(--dsw-alias-bg-layer-2,#fff); box-shadow:0 -16px 44px rgb(15 23 42 / 16%); animation:dsh-mobile-sheet-in 220ms var(--dsh-mobile-motion-ease); }\n .dsh-native-mobile-sheet[hidden] { display:none; }\n .dsh-native-mobile-sheet__header { position:sticky; z-index:1; top:-8px; display:flex; align-items:center; justify-content:space-between; min-height:48px; padding:8px 0; background:var(--dsw-alias-bg-layer-2,#fff); }\n .dsh-native-mobile-sheet__header strong { font-size:17px; font-weight:600; }\n .dsh-native-mobile-sheet__close { width:44px; height:44px; border:0; border-radius:12px; background:transparent; color:inherit; font-size:24px; }\n .dsh-native-mobile-sheet__path { margin:0 0 4px; overflow-wrap:anywhere; color:var(--dsw-alias-label-secondary,#6b7280); font-size:12px; }\n .dsh-native-mobile-sheet__choice { display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%; min-height:56px; padding:10px 14px; border:1px solid var(--dsw-alias-border-subtle,#e2e6eb); border-radius:14px; background:var(--dsw-alias-bg-layer-2,#fff); color:inherit; text-align:left; }\n .dsh-native-mobile-sheet__choice:active { background:var(--dsw-alias-interactive-bg-hover,#f1f3f6); }\n .dsh-native-mobile-sheet__choice small { color:var(--dsw-alias-label-secondary,#6b7280); }\n .dsh-native-mobile-sheet__error { margin:4px 0; color:var(--dsw-alias-status-error,#b42318); font-size:13px; }\n}\n@keyframes dsh-mobile-fade-in { from { opacity:0; } }\n@keyframes dsh-mobile-panel-in { from { opacity:.72; transform:translateY(6px); } }\n@keyframes dsh-mobile-view-in { from { opacity:.58; transform:translateY(5px); } }\n@keyframes dsh-mobile-sheet-in { from { opacity:.7; transform:translateY(18px); } }\n@media (max-width:420px) {\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { max-width:42vw; }\n [data-dsh-mobile-header] [class*=\"_titleRow\"] { min-height:50px; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { align-self:stretch !important; width:100% !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { grid-template-columns:1fr !important; }\n}\n@media (prefers-reduced-motion:reduce) {\n [data-dsh-mobile-sidebar-root],[data-dsh-mobile-details] { transition:none !important; }\n .dsh-native-mobile-backdrop:not([hidden]),[data-dsh-mobile-settings],\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"],\n .dsh-native-mobile-sheet { animation:none !important; }\n}\n`\n\nfunction classToken(element: Element, suffix: string): boolean {\n return Array.from(element.classList).some(value => value.endsWith(suffix))\n}\n\nfunction firstByClassSuffix(root: ParentNode, suffix: string): HTMLElement | undefined {\n return Array.from(root.querySelectorAll<HTMLElement>('[class]')).find(element => classToken(element, suffix))\n}\n\nfunction composerCard(textarea: HTMLTextAreaElement): HTMLElement | undefined {\n let candidate: HTMLElement | null = textarea.parentElement\n while (candidate !== null && !classToken(candidate, '_card')) candidate = candidate.parentElement\n return candidate ?? undefined\n}\n\nfunction paperclipIcon(): SVGSVGElement {\n const namespace = 'http://www.w3.org/2000/svg'\n const svg = document.createElementNS(namespace, 'svg')\n svg.setAttribute('viewBox', '0 0 24 24')\n svg.setAttribute('fill', 'none')\n svg.setAttribute('stroke', 'currentColor')\n svg.setAttribute('stroke-width', '2')\n svg.setAttribute('stroke-linecap', 'round')\n svg.setAttribute('stroke-linejoin', 'round')\n svg.setAttribute('aria-hidden', 'true')\n const path = document.createElementNS(namespace, 'path')\n path.setAttribute('d', 'm21.4 11.6-8.9 8.9a6 6 0 0 1-8.5-8.5l9.6-9.6a4 4 0 0 1 5.7 5.7l-9.7 9.6a2 2 0 0 1-2.8-2.8l8.9-8.9')\n svg.append(path)\n return svg\n}\n\n/** Add mobile semantics and phone-local file actions without replacing feature trees. */\nexport function installNativeMobileSurface(): () => void {\n document.documentElement.classList.add('dsh-native-mobile-active')\n const setInputMode = (mode: 'keyboard' | 'touch'): void => {\n document.documentElement.dataset.dshMobileInput = mode\n }\n const onPointerDown = (event: PointerEvent): void => {\n if (event.pointerType === 'touch' || event.pointerType === 'pen') setInputMode('touch')\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Tab' || event.key.startsWith('Arrow')) setInputMode('keyboard')\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n const backdrop = document.createElement('button')\n backdrop.type = 'button'\n backdrop.className = 'dsh-native-mobile-backdrop'\n backdrop.hidden = true\n backdrop.setAttribute('aria-label', '关闭工作区导航')\n document.body.append(backdrop)\n let frame: HTMLElement | undefined\n let sidebar: HTMLElement | undefined\n let sidebarRoot: HTMLElement | undefined\n let toggle: HTMLButtonElement | undefined\n let viewArea: HTMLElement | undefined\n let scheduled = 0\n let transitionFrame = 0\n let transitionRestartFrame = 0\n let transitionTimer = 0\n let transitionTarget: HTMLElement | undefined\n const fileInput = document.createElement('input')\n fileInput.type = 'file'\n fileInput.accept = 'image/*'\n fileInput.multiple = true\n fileInput.hidden = true\n fileInput.setAttribute('aria-hidden', 'true')\n const attach = document.createElement('button')\n attach.type = 'button'\n attach.className = 'dsh-native-mobile-attach'\n attach.setAttribute('aria-label', '添加图片')\n attach.setAttribute('title', '添加图片')\n attach.append(paperclipIcon())\n document.body.append(fileInput)\n const sheetMask = document.createElement('button')\n sheetMask.type = 'button'\n sheetMask.className = 'dsh-native-mobile-sheet-mask'\n sheetMask.hidden = true\n sheetMask.setAttribute('aria-label', '关闭图片选择')\n const sheet = document.createElement('section')\n sheet.className = 'dsh-native-mobile-sheet'\n sheet.hidden = true\n sheet.setAttribute('aria-label', '添加图片')\n document.body.append(sheetMask, sheet)\n\n const handFilesToComposer = (files: readonly File[]): void => {\n const textarea = document.querySelector<HTMLTextAreaElement>('[data-dsh-mobile-center] textarea')\n if (textarea === null || files.length === 0) return\n const paste = new Event('paste', { bubbles: true, cancelable: true })\n Object.defineProperty(paste, 'clipboardData', {\n value: Object.freeze({\n files,\n items: Object.freeze(files.map(file => Object.freeze({\n kind: 'file',\n type: file.type,\n getAsFile: () => file,\n }))),\n getData: () => '',\n }),\n })\n textarea.dispatchEvent(paste)\n }\n\n const closeSheet = (): void => {\n sheet.hidden = true\n sheetMask.hidden = true\n sheet.replaceChildren()\n }\n const sheetHeader = (title: string): void => {\n const header = document.createElement('header')\n header.className = 'dsh-native-mobile-sheet__header'\n const heading = document.createElement('strong')\n heading.textContent = title\n const close = document.createElement('button')\n close.type = 'button'\n close.className = 'dsh-native-mobile-sheet__close'\n close.setAttribute('aria-label', '关闭')\n close.textContent = '×'\n close.addEventListener('click', closeSheet)\n header.append(heading, close)\n sheet.append(header)\n }\n const choice = (title: string, detail: string, action: () => void): HTMLButtonElement => {\n const button = document.createElement('button')\n button.type = 'button'\n button.className = 'dsh-native-mobile-sheet__choice'\n const label = document.createElement('span')\n label.textContent = title\n const hint = document.createElement('small')\n hint.textContent = detail\n button.append(label, hint)\n button.addEventListener('click', action)\n return button\n }\n const showSheet = (): void => {\n sheet.hidden = false\n sheetMask.hidden = false\n }\n const openComputerImages = async (path?: string): Promise<void> => {\n sheet.replaceChildren()\n sheetHeader('电脑图片')\n const progress = document.createElement('p')\n progress.className = 'dsh-native-mobile-sheet__path'\n progress.textContent = '正在读取电脑目录…'\n sheet.append(progress)\n showSheet()\n try {\n const suffix = path === undefined ? '' : `?path=${encodeURIComponent(path)}`\n const response = await fetch(`/mobile-access/computer-images${suffix}`, { credentials: 'same-origin', cache: 'no-store' })\n if (!response.ok) throw new Error(`读取失败(${String(response.status)})`)\n const listing = await response.json() as {\n readonly path: string\n readonly parent?: string\n readonly entries: readonly { readonly kind: 'directory' | 'image'; readonly name: string; readonly path: string }[]\n }\n progress.textContent = listing.path\n if (listing.parent !== undefined) sheet.append(choice('返回上一级', listing.parent, () => { void openComputerImages(listing.parent) }))\n for (const entry of listing.entries) {\n if (entry.kind === 'directory') {\n sheet.append(choice(entry.name, '文件夹', () => { void openComputerImages(entry.path) }))\n continue\n }\n const row = choice(entry.name, '添加这张电脑图片', () => {\n row.disabled = true\n void fetch(`/mobile-access/computer-image?path=${encodeURIComponent(entry.path)}`, { credentials: 'same-origin', cache: 'no-store' })\n .then(async response => {\n if (!response.ok) throw new Error(`读取失败(${String(response.status)})`)\n const blob = await response.blob()\n handFilesToComposer([new File([blob], entry.name, { type: blob.type })])\n closeSheet()\n })\n .catch(error => {\n row.disabled = false\n progress.className = 'dsh-native-mobile-sheet__error'\n progress.textContent = error instanceof Error ? error.message : String(error)\n })\n })\n sheet.append(row)\n }\n } catch (error) {\n progress.className = 'dsh-native-mobile-sheet__error'\n progress.textContent = error instanceof Error ? error.message : String(error)\n }\n }\n const openAttachmentSources = (): void => {\n sheet.replaceChildren()\n sheetHeader('添加图片')\n sheet.append(\n choice('从手机选择', '相册、相机或手机存储', () => { closeSheet(); fileInput.click() }),\n choice('从电脑选择', '在手机页面浏览电脑中的图片', () => { void openComputerImages() }),\n )\n showSheet()\n }\n attach.addEventListener('click', openAttachmentSources)\n sheetMask.addEventListener('click', closeSheet)\n fileInput.addEventListener('change', () => {\n handFilesToComposer([...(fileInput.files ?? [])])\n fileInput.value = ''\n })\n\n const animateNavigation = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const trigger = event.target.closest<HTMLElement>('button,a,[role=\"tab\"],[aria-selected]')\n if (trigger === null || trigger.hasAttribute('disabled') || trigger.getAttribute('aria-disabled') === 'true') return\n if (trigger.getAttribute('aria-selected') === 'true' || trigger.getAttribute('aria-current') === 'true') return\n const settingsNavigation = trigger.closest('[data-dsh-mobile-settings-list]') !== null\n const conversationNavigation = trigger.matches('[role=\"tab\"]')\n const sidebarNavigation = trigger.closest('[data-dsh-mobile-sidebar-root]') !== null\n && trigger.closest('[data-dsh-mobile-toggle]') === null\n if (!settingsNavigation && !conversationNavigation && !sidebarNavigation) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n transitionFrame = requestAnimationFrame(() => {\n transitionFrame = 0\n const target = settingsNavigation\n ? document.querySelector<HTMLElement>('[data-dsh-mobile-settings-content]')\n : viewArea\n if (target === null || target === undefined) return\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n target.removeAttribute('data-dsh-mobile-view-transition')\n transitionRestartFrame = requestAnimationFrame(() => {\n transitionRestartFrame = 0\n transitionTarget = target\n target.dataset.dshMobileViewTransition = 'true'\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTimer = window.setTimeout(() => {\n target.removeAttribute('data-dsh-mobile-view-transition')\n if (transitionTarget === target) transitionTarget = undefined\n transitionTimer = 0\n }, 240)\n })\n })\n }\n document.addEventListener('click', animateNavigation)\n\n const sync = (): void => {\n scheduled = 0\n frame = firstByClassSuffix(document, '_frame')\n const dedicatedCenter = document.querySelector<HTMLElement>('.dshm-main') ?? undefined\n if (frame !== undefined) frame.dataset.dshMobileFrame = 'true'\n sidebar = frame === undefined ? undefined : firstByClassSuffix(frame, '_sidebarCol')\n const center = frame === undefined ? dedicatedCenter : firstByClassSuffix(frame, '_centerCol')\n const details = frame === undefined ? undefined : firstByClassSuffix(frame, '_detailsCol')\n const handle = frame === undefined ? undefined : firstByClassSuffix(frame, '_handle')\n if (center === undefined) return\n if (center !== undefined) {\n center.dataset.dshMobileCenter = 'true'\n center.querySelector<HTMLElement>('header')?.setAttribute('data-dsh-mobile-header', 'true')\n viewArea = firstByClassSuffix(center, '_viewArea')\n if (viewArea !== undefined) viewArea.dataset.dshMobileView = 'true'\n const conversation = center.querySelector<HTMLElement>('[data-conversation-scroll]')\n const messageColumn = conversation === null ? undefined : firstByClassSuffix(conversation, '_column')\n const messageScroll = messageColumn?.parentElement\n if (messageColumn !== undefined && messageScroll !== null && messageScroll !== undefined && classToken(messageScroll, '_scroll')) {\n messageColumn.dataset.dshMobileMessageColumn = 'true'\n messageScroll.dataset.dshMobileMessageScroll = 'true'\n }\n }\n if (handle !== undefined) handle.dataset.dshMobileHandle = 'true'\n if (details !== undefined) {\n details.dataset.dshMobileDetails = 'true'\n const lastColumn = frame?.style.gridTemplateColumns.trim().split(/\\s+/).at(-1)\n details.dataset.open = String(lastColumn !== undefined && lastColumn !== '0px' && lastColumn !== '0')\n }\n const settings = Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"]')).find(dialog => {\n const directNav = Array.from(dialog.children).find(child => child instanceof HTMLElement && classToken(child, '_nav'))\n return directNav !== undefined\n })\n if (settings !== undefined) {\n settings.dataset.dshMobileSettings = 'true'\n const nav = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_nav')) as HTMLElement | undefined\n const content = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_content')) as HTMLElement | undefined\n if (nav !== undefined) {\n nav.dataset.dshMobileSettingsNav = 'true'\n firstByClassSuffix(nav, '_navList')?.setAttribute('data-dsh-mobile-settings-list', 'true')\n }\n if (content !== undefined) {\n content.dataset.dshMobileSettingsContent = 'true'\n firstByClassSuffix(content, '_header')?.setAttribute('data-dsh-mobile-settings-header', 'true')\n firstByClassSuffix(content, '_options')?.setAttribute('data-dsh-mobile-settings-options', 'true')\n }\n }\n const textarea = center?.querySelector<HTMLTextAreaElement>('textarea')\n const card = textarea === null || textarea === undefined ? undefined : composerCard(textarea)\n const tools = card === undefined ? undefined : firstByClassSuffix(card, '_tools')\n attach.disabled = textarea === undefined || textarea === null || textarea.disabled || textarea.readOnly\n if (tools !== undefined && attach.parentElement !== tools) tools.append(attach)\n if (sidebar === undefined) return\n sidebar.dataset.dshMobileSidebar = 'true'\n toggle = firstByClassSuffix(sidebar, '_toggle') as HTMLButtonElement | undefined\n let candidate = toggle?.parentElement\n while (candidate !== undefined && candidate !== null && candidate !== sidebar && !classToken(candidate, '_root')) candidate = candidate.parentElement\n sidebarRoot = candidate !== sidebar && candidate !== null ? candidate : undefined\n if (sidebarRoot === undefined) return\n sidebarRoot.dataset.dshMobileSidebarRoot = 'true'\n if (toggle !== undefined) toggle.dataset.dshMobileToggle = 'true'\n const collapsed = classToken(sidebarRoot, '_collapsed')\n sidebar.dataset.open = String(!collapsed)\n backdrop.hidden = collapsed\n }\n const schedule = (): void => { if (scheduled === 0) scheduled = requestAnimationFrame(sync) }\n const observer = new MutationObserver(schedule)\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] })\n backdrop.addEventListener('click', () => { if (sidebar?.dataset.open === 'true') toggle?.click() })\n sync()\n return () => {\n observer.disconnect()\n if (scheduled !== 0) cancelAnimationFrame(scheduled)\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n document.removeEventListener('click', animateNavigation)\n backdrop.remove()\n attach.remove()\n fileInput.remove()\n sheet.remove()\n sheetMask.remove()\n document.documentElement.classList.remove('dsh-native-mobile-active')\n delete document.documentElement.dataset.dshMobileInput\n }\n}\n","import { createElement } from 'react'\nimport { installNativeMobileSurface, NATIVE_MOBILE_STYLES } from './native-mobile.js'\n\ninterface ClientContext {\n effect(effect: () => void | (() => void), label?: string): void\n slots: {\n inject(key: string, callback: () => (() => void)): () => void\n register(options: { name: string; id: string }, component: (props: { wide: boolean }) => unknown): () => void\n }\n}\n\ninterface MobileExtensionContext {\n readonly document: Document\n readonly request: (path: string, init?: RequestInit) => Promise<Response>\n readonly root: HTMLElement\n readonly window: Window\n}\n\ntype MobileExtensionMount = (context: MobileExtensionContext) => void | (() => void)\n\ndeclare global {\n interface Window {\n dshMobile?: { register(mount: MobileExtensionMount): void }\n __DSH_MOBILE_FRONTEND__?: 'dedicated'\n }\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]'\n}\n\nfunction element<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag)\n if (className !== undefined) node.className = className\n return node\n}\n\nasync function requestJson(path: string, init?: RequestInit): Promise<Record<string, unknown>> {\n const response = await fetch(path, { ...init, headers: { 'content-type': 'application/json', ...init?.headers } })\n const body = await response.json() as Record<string, unknown>\n if (!response.ok) throw new Error(typeof body.error === 'string' ? body.error : `HTTP ${String(response.status)}`)\n return body\n}\n\nfunction installControl(): { remove: () => void; toggle: () => void } {\n const root = element('div', 'dsh-mobile-control')\n const panel = element('section', 'dsh-mobile-control__panel'); panel.hidden = true\n panel.setAttribute('aria-label', '移动访问')\n const header = element('header', 'dsh-mobile-control__header')\n const title = element('h2'); title.textContent = '移动访问'\n const close = element('button', 'dsh-mobile-control__close'); close.type = 'button'; close.textContent = '×'; close.setAttribute('aria-label', '收起移动访问')\n const access = element('div', 'dsh-mobile-control__access'); access.hidden = true\n const accessLabel = element('span', 'dsh-mobile-control__access-label'); accessLabel.textContent = '浏览器访问'\n const accessLink = element('a', 'dsh-mobile-control__access-link'); accessLink.target = '_blank'; accessLink.rel = 'noreferrer'\n access.append(accessLabel, accessLink)\n const status = element('p', 'dsh-mobile-control__status'); status.textContent = '正在读取状态…'\n const actions = element('div', 'dsh-mobile-control__actions')\n const toggle = element('button', 'dsh-mobile-control__secondary'); toggle.type = 'button'\n const pair = element('button', 'dsh-mobile-control__primary'); pair.type = 'button'; pair.textContent = '生成并复制密钥'\n header.append(title, close); actions.append(toggle, pair); panel.append(header, access, status, actions); root.append(panel); document.body.append(root)\n let running = false\n let origin = ''\n const setOpen = (open: boolean): void => {\n panel.hidden = !open\n for (const trigger of document.querySelectorAll('.dsh-mobile-control__trigger')) trigger.setAttribute('aria-expanded', String(open))\n }\n const render = (data: Record<string, unknown>): void => {\n running = data.running === true\n origin = running && typeof data.origin === 'string' ? data.origin : ''\n access.hidden = origin === ''\n accessLink.href = origin\n accessLink.textContent = origin\n accessLink.title = origin\n status.classList.toggle('is-running', running)\n status.textContent = running ? '移动访问已开启。' : '已关闭。DSH 仍只在本机可用。'\n toggle.textContent = running ? '关闭移动访问' : '开启移动访问'; pair.disabled = !running\n }\n toggle.addEventListener('click', () => { toggle.disabled = true; void requestJson('/api/mobile-access/control', { method: 'POST', body: JSON.stringify({ running: !running }) }).then(render, error => { status.textContent = String(error) }).finally(() => { toggle.disabled = false }) })\n pair.addEventListener('click', () => { pair.disabled = true; void requestJson('/api/mobile-access/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const key = typeof data.appKey === 'string' ? data.appKey : ''\n if (key === '') { status.textContent = '无法生成配对密钥。'; return }\n try {\n await navigator.clipboard.writeText(key)\n status.textContent = '配对密钥已复制,请粘贴到 Android App。'\n } catch {\n status.textContent = `请复制配对密钥:${key}`\n status.classList.add('is-key')\n }\n }, error => { status.textContent = String(error) }).finally(() => { pair.disabled = !running }) })\n close.addEventListener('click', () => { setOpen(false) })\n const dismiss = (event: PointerEvent): void => {\n if (panel.hidden || !(event.target instanceof Node)) return\n if (!panel.contains(event.target) && !document.querySelector('.dsh-mobile-control__trigger')?.contains(event.target)) setOpen(false)\n }\n document.addEventListener('pointerdown', dismiss)\n void requestJson('/api/mobile-access/control').then(render, error => { status.textContent = String(error) })\n return { remove: () => { document.removeEventListener('pointerdown', dismiss); root.remove() }, toggle: () => { setOpen(panel.hidden !== false) } }\n}\n\nfunction mobileRequest(path: string, init: RequestInit = {}): Promise<Response> {\n const target = new URL(path, location.href)\n if (target.origin !== location.origin) throw new TypeError('mobile extension requests must stay on the DSH origin')\n const headers = new Headers(init.headers)\n const method = (init.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const csrf = document.cookie.split(';').map(value => value.trim()).find(value => value.startsWith('dsh_ma_csrf='))?.slice(12)\n if (csrf !== undefined) headers.set('x-dsh-mobile-csrf', csrf)\n }\n return fetch(target, { ...init, headers, credentials: 'same-origin', cache: 'no-store', redirect: 'error' })\n}\n\nfunction installCustomAssets(): () => void {\n const style = element('style'); style.dataset.plugin = 'dsh-mobile-custom'; document.head.append(style)\n let cssLoading = false\n const refreshCss = async (): Promise<void> => { if (cssLoading || document.visibilityState === 'hidden') return; cssLoading = true; try { const response = await fetch('/mobile-access/custom.css', { cache: 'no-store', credentials: 'same-origin' }); if (response.ok) { const css = await response.text(); if (style.textContent !== css) style.textContent = css } } finally { cssLoading = false } }\n let activeRoot: HTMLElement | undefined; let disposeActive: (() => void) | undefined; let source = ''; let pending: MobileExtensionMount | undefined\n const previous = window.dshMobile\n window.dshMobile = Object.freeze({ register: (mount: MobileExtensionMount) => { pending = mount } })\n const registeredMount = (): MobileExtensionMount | undefined => pending\n const refreshJs = async (): Promise<void> => { try { const response = await fetch('/mobile-access/custom.js', { cache: 'no-store', credentials: 'same-origin' }); if (!response.ok) return; const next = await response.text(); if (next === source) return; source = next; pending = undefined; const script = element('script'); script.textContent = `${next}\\n//# sourceURL=dsh-mobile-custom.js`; document.head.append(script); script.remove(); const mount = registeredMount(); if (mount === undefined) return; const nextRoot = element('div'); nextRoot.dataset.dshMobileExtension = 'true'; document.body.append(nextRoot); const nextDispose = mount({ document, request: mobileRequest, root: nextRoot, window }); disposeActive?.(); activeRoot?.remove(); activeRoot = nextRoot; disposeActive = typeof nextDispose === 'function' ? nextDispose : undefined } catch { /* Preserve the last good customization during reconnects. */ } }\n void refreshCss(); void refreshJs()\n const timer = window.setInterval(() => { void refreshCss(); void refreshJs() }, 1_000)\n return () => { clearInterval(timer); disposeActive?.(); activeRoot?.remove(); style.remove(); if (previous === undefined) delete window.dshMobile; else window.dshMobile = previous }\n}\n\nconst CONTROL_STYLES = `\n.dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:64px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}\n.dsh-mobile-control__panel{box-sizing:border-box;width:min(328px,calc(100vw - 32px));padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}\n.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}\n.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:\":\"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}\n.dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:\"\"}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}\n.dsh-mobile-control__actions{display:flex;flex-wrap:wrap;gap:8px}.dsh-mobile-control__actions button{min-height:40px;padding:8px 12px;border-radius:11px;font:inherit;cursor:pointer}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font:14px/22px system-ui;cursor:pointer}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;border-radius:50%}.dsh-mobile-control__trigger-icon{position:relative;box-sizing:border-box;flex:none;width:14px;height:19px;border:1.7px solid currentColor;border-radius:3px}.dsh-mobile-control__trigger-icon::after{position:absolute;right:4px;bottom:2px;width:4px;height:1.5px;border-radius:2px;background:currentColor;content:\"\"}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n`\n\n/** Mount the desktop control or mobile feature enhancements. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n const loopback = isLoopbackHost(location.hostname) && !new URLSearchParams(location.search).has('dsh-mobile-preview')\n const style = element('style'); style.dataset.plugin = 'dsh-mobile'; style.textContent = loopback\n ? CONTROL_STYLES\n : NATIVE_MOBILE_STYLES\n document.head.append(style)\n if (!loopback) {\n const removeCustom = installCustomAssets()\n const removeSurface = installNativeMobileSurface()\n return () => { removeCustom(); removeSurface(); style.remove() }\n }\n const control = installControl()\n const disposeSlot = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({ name: 'sidebar.footer.action', id: 'dsh-mobile' }, ({ wide }) => createElement('button', {\n 'aria-expanded': false,\n 'aria-label': '移动访问',\n className: `dsh-mobile-control__trigger${wide ? '' : ' is-rail'}`,\n type: 'button',\n title: '移动访问',\n onClick: control.toggle,\n }, createElement('span', { 'aria-hidden': true, className: 'dsh-mobile-control__trigger-icon' }), wide ? createElement('span', { className: 'dsh-mobile-control__trigger-label' }, '移动访问') : undefined)))\n return () => { disposeSlot(); control.remove(); style.remove() }\n }, 'dsh-mobile: stock mobile adaptation and local control')\n}\n\n/** Client services required by the mobile adaptation. */\nexport const inject: readonly string[] = ['slots']\n"],"mappings":";;;;;;;;;EACA,MAAa,uBAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwHpC,SAAS,WAAW,SAAkB,QAAyB;GAC7D,OAAO,MAAM,KAAK,QAAQ,SAAS,CAAC,CAAC,MAAK,UAAS,MAAM,SAAS,MAAM,CAAC;EAC3E;EAEA,SAAS,mBAAmB,MAAkB,QAAyC;GACrF,OAAO,MAAM,KAAK,KAAK,iBAA8B,SAAS,CAAC,CAAC,CAAC,MAAK,YAAW,WAAW,SAAS,MAAM,CAAC;EAC9G;EAEA,SAAS,aAAa,UAAwD;GAC5E,IAAI,YAAgC,SAAS;GAC7C,OAAO,cAAc,QAAQ,CAAC,WAAW,WAAW,OAAO,GAAG,YAAY,UAAU;GACpF,OAAO,aAAa,KAAA;EACtB;EAEA,SAAS,gBAA+B;GACtC,MAAM,YAAY;GAClB,MAAM,MAAM,SAAS,gBAAgB,WAAW,KAAK;GACrD,IAAI,aAAa,WAAW,WAAW;GACvC,IAAI,aAAa,QAAQ,MAAM;GAC/B,IAAI,aAAa,UAAU,cAAc;GACzC,IAAI,aAAa,gBAAgB,GAAG;GACpC,IAAI,aAAa,kBAAkB,OAAO;GAC1C,IAAI,aAAa,mBAAmB,OAAO;GAC3C,IAAI,aAAa,eAAe,MAAM;GACtC,MAAM,OAAO,SAAS,gBAAgB,WAAW,MAAM;GACvD,KAAK,aAAa,KAAK,mGAAmG;GAC1H,IAAI,OAAO,IAAI;GACf,OAAO;EACT;;EAGA,SAAgB,6BAAyC;GACvD,SAAS,gBAAgB,UAAU,IAAI,0BAA0B;GACjE,MAAM,gBAAgB,SAAqC;IACzD,SAAS,gBAAgB,QAAQ,iBAAiB;GACpD;GACA,MAAM,iBAAiB,UAA8B;IACnD,IAAI,MAAM,gBAAgB,WAAW,MAAM,gBAAgB,OAAO,aAAa,OAAO;GACxF;GACA,MAAM,aAAa,UAA+B;IAChD,IAAI,MAAM,QAAQ,SAAS,MAAM,IAAI,WAAW,OAAO,GAAG,aAAa,UAAU;GACnF;GACA,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC5D,SAAS,iBAAiB,WAAW,WAAW,IAAI;GACpD,MAAM,WAAW,SAAS,cAAc,QAAQ;GAChD,SAAS,OAAO;GAChB,SAAS,YAAY;GACrB,SAAS,SAAS;GAClB,SAAS,aAAa,cAAc,SAAS;GAC7C,SAAS,KAAK,OAAO,QAAQ;GAC7B,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI,YAAY;GAChB,IAAI,kBAAkB;GACtB,IAAI,yBAAyB;GAC7B,IAAI,kBAAkB;GACtB,IAAI;GACJ,MAAM,YAAY,SAAS,cAAc,OAAO;GAChD,UAAU,OAAO;GACjB,UAAU,SAAS;GACnB,UAAU,WAAW;GACrB,UAAU,SAAS;GACnB,UAAU,aAAa,eAAe,MAAM;GAC5C,MAAM,SAAS,SAAS,cAAc,QAAQ;GAC9C,OAAO,OAAO;GACd,OAAO,YAAY;GACnB,OAAO,aAAa,cAAc,MAAM;GACxC,OAAO,aAAa,SAAS,MAAM;GACnC,OAAO,OAAO,cAAc,CAAC;GAC7B,SAAS,KAAK,OAAO,SAAS;GAC9B,MAAM,YAAY,SAAS,cAAc,QAAQ;GACjD,UAAU,OAAO;GACjB,UAAU,YAAY;GACtB,UAAU,SAAS;GACnB,UAAU,aAAa,cAAc,QAAQ;GAC7C,MAAM,QAAQ,SAAS,cAAc,SAAS;GAC9C,MAAM,YAAY;GAClB,MAAM,SAAS;GACf,MAAM,aAAa,cAAc,MAAM;GACvC,SAAS,KAAK,OAAO,WAAW,KAAK;GAErC,MAAM,uBAAuB,UAAiC;IAC5D,MAAM,WAAW,SAAS,cAAmC,mCAAmC;IAChG,IAAI,aAAa,QAAQ,MAAM,WAAW,GAAG;IAC7C,MAAM,QAAQ,IAAI,MAAM,SAAS;KAAE,SAAS;KAAM,YAAY;IAAK,CAAC;IACpE,OAAO,eAAe,OAAO,iBAAiB,EAC5C,OAAO,OAAO,OAAO;KACnB;KACA,OAAO,OAAO,OAAO,MAAM,KAAI,SAAQ,OAAO,OAAO;MACnD,MAAM;MACN,MAAM,KAAK;MACX,iBAAiB;KACnB,CAAC,CAAC,CAAC;KACH,eAAe;IACjB,CAAC,EACH,CAAC;IACD,SAAS,cAAc,KAAK;GAC9B;GAEA,MAAM,mBAAyB;IAC7B,MAAM,SAAS;IACf,UAAU,SAAS;IACnB,MAAM,gBAAgB;GACxB;GACA,MAAM,eAAe,UAAwB;IAC3C,MAAM,SAAS,SAAS,cAAc,QAAQ;IAC9C,OAAO,YAAY;IACnB,MAAM,UAAU,SAAS,cAAc,QAAQ;IAC/C,QAAQ,cAAc;IACtB,MAAM,QAAQ,SAAS,cAAc,QAAQ;IAC7C,MAAM,OAAO;IACb,MAAM,YAAY;IAClB,MAAM,aAAa,cAAc,IAAI;IACrC,MAAM,cAAc;IACpB,MAAM,iBAAiB,SAAS,UAAU;IAC1C,OAAO,OAAO,SAAS,KAAK;IAC5B,MAAM,OAAO,MAAM;GACrB;GACA,MAAM,UAAU,OAAe,QAAgB,WAA0C;IACvF,MAAM,SAAS,SAAS,cAAc,QAAQ;IAC9C,OAAO,OAAO;IACd,OAAO,YAAY;IACnB,MAAM,QAAQ,SAAS,cAAc,MAAM;IAC3C,MAAM,cAAc;IACpB,MAAM,OAAO,SAAS,cAAc,OAAO;IAC3C,KAAK,cAAc;IACnB,OAAO,OAAO,OAAO,IAAI;IACzB,OAAO,iBAAiB,SAAS,MAAM;IACvC,OAAO;GACT;GACA,MAAM,kBAAwB;IAC5B,MAAM,SAAS;IACf,UAAU,SAAS;GACrB;GACA,MAAM,qBAAqB,OAAO,SAAiC;IACjE,MAAM,gBAAgB;IACtB,YAAY,MAAM;IAClB,MAAM,WAAW,SAAS,cAAc,GAAG;IAC3C,SAAS,YAAY;IACrB,SAAS,cAAc;IACvB,MAAM,OAAO,QAAQ;IACrB,UAAU;IACV,IAAI;KACF,MAAM,SAAS,SAAS,KAAA,IAAY,KAAK,SAAS,mBAAmB,IAAI;KACzE,MAAM,WAAW,MAAM,MAAM,iCAAiC,UAAU;MAAE,aAAa;MAAe,OAAO;KAAW,CAAC;KACzH,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,QAAQ,OAAO,SAAS,MAAM,EAAE,EAAE;KACpE,MAAM,UAAU,MAAM,SAAS,KAAK;KAKpC,SAAS,cAAc,QAAQ;KAC/B,IAAI,QAAQ,WAAW,KAAA,GAAW,MAAM,OAAO,OAAO,SAAS,QAAQ,cAAc;MAAE,mBAAwB,QAAQ,MAAM;KAAE,CAAC,CAAC;KACjI,KAAK,MAAM,SAAS,QAAQ,SAAS;MACnC,IAAI,MAAM,SAAS,aAAa;OAC9B,MAAM,OAAO,OAAO,MAAM,MAAM,aAAa;QAAE,mBAAwB,MAAM,IAAI;OAAE,CAAC,CAAC;OACrF;MACF;MACA,MAAM,MAAM,OAAO,MAAM,MAAM,kBAAkB;OAC/C,IAAI,WAAW;OACf,MAAW,sCAAsC,mBAAmB,MAAM,IAAI,KAAK;QAAE,aAAa;QAAe,OAAO;OAAW,CAAC,CAAC,CAClI,KAAK,OAAM,aAAY;QACtB,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,QAAQ,OAAO,SAAS,MAAM,EAAE,EAAE;QACpE,MAAM,OAAO,MAAM,SAAS,KAAK;QACjC,oBAAoB,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,MAAM,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC;QACvE,WAAW;OACb,CAAC,CAAC,CACD,OAAM,UAAS;QACd,IAAI,WAAW;QACf,SAAS,YAAY;QACrB,SAAS,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;OAC9E,CAAC;MACL,CAAC;MACD,MAAM,OAAO,GAAG;KAClB;IACF,SAAS,OAAO;KACd,SAAS,YAAY;KACrB,SAAS,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9E;GACF;GACA,MAAM,8BAAoC;IACxC,MAAM,gBAAgB;IACtB,YAAY,MAAM;IAClB,MAAM,OACJ,OAAO,SAAS,oBAAoB;KAAE,WAAW;KAAG,UAAU,MAAM;IAAE,CAAC,GACvE,OAAO,SAAS,uBAAuB;KAAE,mBAAwB;IAAE,CAAC,CACtE;IACA,UAAU;GACZ;GACA,OAAO,iBAAiB,SAAS,qBAAqB;GACtD,UAAU,iBAAiB,SAAS,UAAU;GAC9C,UAAU,iBAAiB,gBAAgB;IACzC,oBAAoB,CAAC,GAAI,UAAU,SAAS,CAAC,CAAE,CAAC;IAChD,UAAU,QAAQ;GACpB,CAAC;GAED,MAAM,qBAAqB,UAA4B;IACrD,IAAI,EAAE,MAAM,kBAAkB,UAAU;IACxC,MAAM,UAAU,MAAM,OAAO,QAAqB,yCAAuC;IACzF,IAAI,YAAY,QAAQ,QAAQ,aAAa,UAAU,KAAK,QAAQ,aAAa,eAAe,MAAM,QAAQ;IAC9G,IAAI,QAAQ,aAAa,eAAe,MAAM,UAAU,QAAQ,aAAa,cAAc,MAAM,QAAQ;IACzG,MAAM,qBAAqB,QAAQ,QAAQ,iCAAiC,MAAM;IAClF,MAAM,yBAAyB,QAAQ,QAAQ,gBAAc;IAC7D,MAAM,oBAAoB,QAAQ,QAAQ,gCAAgC,MAAM,QAC3E,QAAQ,QAAQ,0BAA0B,MAAM;IACrD,IAAI,CAAC,sBAAsB,CAAC,0BAA0B,CAAC,mBAAmB;IAC1E,IAAI,OAAO,WAAW,kCAAkC,CAAC,CAAC,SAAS;IACnE,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,kBAAkB,4BAA4B;KAC5C,kBAAkB;KAClB,MAAM,SAAS,qBACX,SAAS,cAA2B,oCAAoC,IACxE;KACJ,IAAI,WAAW,QAAQ,WAAW,KAAA,GAAW;KAC7C,kBAAkB,gBAAgB,iCAAiC;KACnE,OAAO,gBAAgB,iCAAiC;KACxD,yBAAyB,4BAA4B;MACnD,yBAAyB;MACzB,mBAAmB;MACnB,OAAO,QAAQ,0BAA0B;MACzC,IAAI,oBAAoB,GAAG,aAAa,eAAe;MACvD,kBAAkB,OAAO,iBAAiB;OACxC,OAAO,gBAAgB,iCAAiC;OACxD,IAAI,qBAAqB,QAAQ,mBAAmB,KAAA;OACpD,kBAAkB;MACpB,GAAG,GAAG;KACR,CAAC;IACH,CAAC;GACH;GACA,SAAS,iBAAiB,SAAS,iBAAiB;GAEpD,MAAM,aAAmB;IACvB,YAAY;IACZ,QAAQ,mBAAmB,UAAU,QAAQ;IAC7C,MAAM,kBAAkB,SAAS,cAA2B,YAAY,KAAK,KAAA;IAC7E,IAAI,UAAU,KAAA,GAAW,MAAM,QAAQ,iBAAiB;IACxD,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,aAAa;IACnF,MAAM,SAAS,UAAU,KAAA,IAAY,kBAAkB,mBAAmB,OAAO,YAAY;IAC7F,MAAM,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,aAAa;IACzF,MAAM,SAAS,UAAU,KAAA,IAAY,KAAA,IAAY,mBAAmB,OAAO,SAAS;IACpF,IAAI,WAAW,KAAA,GAAW;IAC1B,IAAI,WAAW,KAAA,GAAW;KACxB,OAAO,QAAQ,kBAAkB;KACjC,OAAO,cAA2B,QAAQ,CAAC,EAAE,aAAa,0BAA0B,MAAM;KAC1F,WAAW,mBAAmB,QAAQ,WAAW;KACjD,IAAI,aAAa,KAAA,GAAW,SAAS,QAAQ,gBAAgB;KAC7D,MAAM,eAAe,OAAO,cAA2B,4BAA4B;KACnF,MAAM,gBAAgB,iBAAiB,OAAO,KAAA,IAAY,mBAAmB,cAAc,SAAS;KACpG,MAAM,gBAAgB,eAAe;KACrC,IAAI,kBAAkB,KAAA,KAAa,kBAAkB,QAAQ,kBAAkB,KAAA,KAAa,WAAW,eAAe,SAAS,GAAG;MAChI,cAAc,QAAQ,yBAAyB;MAC/C,cAAc,QAAQ,yBAAyB;KACjD;IACF;IACA,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,IAAI,YAAY,KAAA,GAAW;KACzB,QAAQ,QAAQ,mBAAmB;KACnC,MAAM,aAAa,OAAO,MAAM,oBAAoB,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,GAAG,EAAE;KAC7E,QAAQ,QAAQ,OAAO,OAAO,eAAe,KAAA,KAAa,eAAe,SAAS,eAAe,GAAG;IACtG;IACA,MAAM,WAAW,MAAM,KAAK,SAAS,iBAA8B,mBAAiB,CAAC,CAAC,CAAC,MAAK,WAAU;KAEpG,OADkB,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CACrG,MAAM,KAAA;IACvB,CAAC;IACD,IAAI,aAAa,KAAA,GAAW;KAC1B,SAAS,QAAQ,oBAAoB;KACrC,MAAM,MAAM,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,MAAM,CAAC;KACjH,MAAM,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,MAAK,UAAS,iBAAiB,eAAe,WAAW,OAAO,UAAU,CAAC;KACzH,IAAI,QAAQ,KAAA,GAAW;MACrB,IAAI,QAAQ,uBAAuB;MACnC,mBAAmB,KAAK,UAAU,CAAC,EAAE,aAAa,iCAAiC,MAAM;KAC3F;KACA,IAAI,YAAY,KAAA,GAAW;MACzB,QAAQ,QAAQ,2BAA2B;MAC3C,mBAAmB,SAAS,SAAS,CAAC,EAAE,aAAa,mCAAmC,MAAM;MAC9F,mBAAmB,SAAS,UAAU,CAAC,EAAE,aAAa,oCAAoC,MAAM;KAClG;IACF;IACA,MAAM,WAAW,QAAQ,cAAmC,UAAU;IACtE,MAAM,OAAO,aAAa,QAAQ,aAAa,KAAA,IAAY,KAAA,IAAY,aAAa,QAAQ;IAC5F,MAAM,QAAQ,SAAS,KAAA,IAAY,KAAA,IAAY,mBAAmB,MAAM,QAAQ;IAChF,OAAO,WAAW,aAAa,KAAA,KAAa,aAAa,QAAQ,SAAS,YAAY,SAAS;IAC/F,IAAI,UAAU,KAAA,KAAa,OAAO,kBAAkB,OAAO,MAAM,OAAO,MAAM;IAC9E,IAAI,YAAY,KAAA,GAAW;IAC3B,QAAQ,QAAQ,mBAAmB;IACnC,SAAS,mBAAmB,SAAS,SAAS;IAC9C,IAAI,YAAY,QAAQ;IACxB,OAAO,cAAc,KAAA,KAAa,cAAc,QAAQ,cAAc,WAAW,CAAC,WAAW,WAAW,OAAO,GAAG,YAAY,UAAU;IACxI,cAAc,cAAc,WAAW,cAAc,OAAO,YAAY,KAAA;IACxE,IAAI,gBAAgB,KAAA,GAAW;IAC/B,YAAY,QAAQ,uBAAuB;IAC3C,IAAI,WAAW,KAAA,GAAW,OAAO,QAAQ,kBAAkB;IAC3D,MAAM,YAAY,WAAW,aAAa,YAAY;IACtD,QAAQ,QAAQ,OAAO,OAAO,CAAC,SAAS;IACxC,SAAS,SAAS;GACpB;GACA,MAAM,iBAAuB;IAAE,IAAI,cAAc,GAAG,YAAY,sBAAsB,IAAI;GAAE;GAC5F,MAAM,WAAW,IAAI,iBAAiB,QAAQ;GAC9C,SAAS,QAAQ,SAAS,MAAM;IAAE,WAAW;IAAM,SAAS;IAAM,YAAY;IAAM,iBAAiB,CAAC,SAAS,OAAO;GAAE,CAAC;GACzH,SAAS,iBAAiB,eAAe;IAAE,IAAI,SAAS,QAAQ,SAAS,QAAQ,QAAQ,MAAM;GAAE,CAAC;GAClG,KAAK;GACL,aAAa;IACX,SAAS,WAAW;IACpB,IAAI,cAAc,GAAG,qBAAqB,SAAS;IACnD,IAAI,oBAAoB,GAAG,qBAAqB,eAAe;IAC/D,IAAI,2BAA2B,GAAG,qBAAqB,sBAAsB;IAC7E,IAAI,oBAAoB,GAAG,aAAa,eAAe;IACvD,kBAAkB,gBAAgB,iCAAiC;IACnE,SAAS,oBAAoB,eAAe,eAAe,IAAI;IAC/D,SAAS,oBAAoB,WAAW,WAAW,IAAI;IACvD,SAAS,oBAAoB,SAAS,iBAAiB;IACvD,SAAS,OAAO;IAChB,OAAO,OAAO;IACd,UAAU,OAAO;IACjB,MAAM,OAAO;IACb,UAAU,OAAO;IACjB,SAAS,gBAAgB,UAAU,OAAO,0BAA0B;IACpE,OAAO,SAAS,gBAAgB,QAAQ;GAC1C;EACF;;;ECjaA,SAAS,eAAe,UAA2B;GACjD,OAAO,aAAa,eAAe,aAAa,eAAe,aAAa,SAAS,aAAa;EACpG;EAEA,SAAS,QAA+C,KAAQ,WAA8C;GAC5G,MAAM,OAAO,SAAS,cAAc,GAAG;GACvC,IAAI,cAAc,KAAA,GAAW,KAAK,YAAY;GAC9C,OAAO;EACT;EAEA,eAAe,YAAY,MAAc,MAAsD;GAC7F,MAAM,WAAW,MAAM,MAAM,MAAM;IAAE,GAAG;IAAM,SAAS;KAAE,gBAAgB;KAAoB,GAAG,MAAM;IAAQ;GAAE,CAAC;GACjH,MAAM,OAAO,MAAM,SAAS,KAAK;GACjC,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,QAAQ,OAAO,SAAS,MAAM,GAAG;GACjH,OAAO;EACT;EAEA,SAAS,iBAA6D;GACpE,MAAM,OAAO,QAAQ,OAAO,oBAAoB;GAChD,MAAM,QAAQ,QAAQ,WAAW,2BAA2B;GAAG,MAAM,SAAS;GAC9E,MAAM,aAAa,cAAc,MAAM;GACvC,MAAM,SAAS,QAAQ,UAAU,4BAA4B;GAC7D,MAAM,QAAQ,QAAQ,IAAI;GAAG,MAAM,cAAc;GACjD,MAAM,QAAQ,QAAQ,UAAU,2BAA2B;GAAG,MAAM,OAAO;GAAU,MAAM,cAAc;GAAK,MAAM,aAAa,cAAc,QAAQ;GACvJ,MAAM,SAAS,QAAQ,OAAO,4BAA4B;GAAG,OAAO,SAAS;GAC7E,MAAM,cAAc,QAAQ,QAAQ,kCAAkC;GAAG,YAAY,cAAc;GACnG,MAAM,aAAa,QAAQ,KAAK,iCAAiC;GAAG,WAAW,SAAS;GAAU,WAAW,MAAM;GACnH,OAAO,OAAO,aAAa,UAAU;GACrC,MAAM,SAAS,QAAQ,KAAK,4BAA4B;GAAG,OAAO,cAAc;GAChF,MAAM,UAAU,QAAQ,OAAO,6BAA6B;GAC5D,MAAM,SAAS,QAAQ,UAAU,+BAA+B;GAAG,OAAO,OAAO;GACjF,MAAM,OAAO,QAAQ,UAAU,6BAA6B;GAAG,KAAK,OAAO;GAAU,KAAK,cAAc;GACxG,OAAO,OAAO,OAAO,KAAK;GAAG,QAAQ,OAAO,QAAQ,IAAI;GAAG,MAAM,OAAO,QAAQ,QAAQ,QAAQ,OAAO;GAAG,KAAK,OAAO,KAAK;GAAG,SAAS,KAAK,OAAO,IAAI;GACvJ,IAAI,UAAU;GACd,IAAI,SAAS;GACb,MAAM,WAAW,SAAwB;IACvC,MAAM,SAAS,CAAC;IAChB,KAAK,MAAM,WAAW,SAAS,iBAAiB,8BAA8B,GAAG,QAAQ,aAAa,iBAAiB,OAAO,IAAI,CAAC;GACrI;GACA,MAAM,UAAU,SAAwC;IACtD,UAAU,KAAK,YAAY;IAC3B,SAAS,WAAW,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;IACpE,OAAO,SAAS,WAAW;IAC3B,WAAW,OAAO;IAClB,WAAW,cAAc;IACzB,WAAW,QAAQ;IACnB,OAAO,UAAU,OAAO,cAAc,OAAO;IAC7C,OAAO,cAAc,UAAU,aAAa;IAC5C,OAAO,cAAc,UAAU,WAAW;IAAU,KAAK,WAAW,CAAC;GACvE;GACA,OAAO,iBAAiB,eAAe;IAAE,OAAO,WAAW;IAAM,YAAiB,8BAA8B;KAAE,QAAQ;KAAQ,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC,QAAQ,CAAC;IAAE,CAAC,CAAC,CAAC,KAAK,SAAQ,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,OAAO,WAAW;IAAM,CAAC;GAAE,CAAC;GAC3R,KAAK,iBAAiB,eAAe;IAAE,KAAK,WAAW;IAAM,YAAiB,mCAAmC;KAAE,QAAQ;KAAQ,MAAM;IAAK,CAAC,CAAC,CAAC,KAAK,OAAM,SAAQ;KAClK,MAAM,MAAM,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;KAC5D,IAAI,QAAQ,IAAI;MAAE,OAAO,cAAc;MAAa;KAAO;KAC3D,IAAI;MACF,MAAM,UAAU,UAAU,UAAU,GAAG;MACvC,OAAO,cAAc;KACvB,QAAQ;MACN,OAAO,cAAc,WAAW;MAChC,OAAO,UAAU,IAAI,QAAQ;KAC/B;IACF,IAAG,UAAS;KAAE,OAAO,cAAc,OAAO,KAAK;IAAE,CAAC,CAAC,CAAC,cAAc;KAAE,KAAK,WAAW,CAAC;IAAQ,CAAC;GAAE,CAAC;GACjG,MAAM,iBAAiB,eAAe;IAAE,QAAQ,KAAK;GAAE,CAAC;GACxD,MAAM,WAAW,UAA8B;IAC7C,IAAI,MAAM,UAAU,EAAE,MAAM,kBAAkB,OAAO;IACrD,IAAI,CAAC,MAAM,SAAS,MAAM,MAAM,KAAK,CAAC,SAAS,cAAc,8BAA8B,CAAC,EAAE,SAAS,MAAM,MAAM,GAAG,QAAQ,KAAK;GACrI;GACA,SAAS,iBAAiB,eAAe,OAAO;GAChD,YAAiB,4BAA4B,CAAC,CAAC,KAAK,SAAQ,UAAS;IAAE,OAAO,cAAc,OAAO,KAAK;GAAE,CAAC;GAC3G,OAAO;IAAE,cAAc;KAAE,SAAS,oBAAoB,eAAe,OAAO;KAAG,KAAK,OAAO;IAAE;IAAG,cAAc;KAAE,QAAQ,MAAM,WAAW,KAAK;IAAE;GAAE;EACpJ;EAEA,SAAS,cAAc,MAAc,OAAoB,CAAC,GAAsB;GAC9E,MAAM,SAAS,IAAI,IAAI,MAAM,SAAS,IAAI;GAC1C,IAAI,OAAO,WAAW,SAAS,QAAQ,MAAM,IAAI,UAAU,uDAAuD;GAClH,MAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;GACxC,MAAM,UAAU,KAAK,UAAU,MAAA,CAAO,YAAY;GAClD,IAAI,WAAW,SAAS,WAAW,QAAQ;IACzC,MAAM,OAAO,SAAS,OAAO,MAAM,GAAG,CAAC,CAAC,KAAI,UAAS,MAAM,KAAK,CAAC,CAAC,CAAC,MAAK,UAAS,MAAM,WAAW,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE;IAC5H,IAAI,SAAS,KAAA,GAAW,QAAQ,IAAI,qBAAqB,IAAI;GAC/D;GACA,OAAO,MAAM,QAAQ;IAAE,GAAG;IAAM;IAAS,aAAa;IAAe,OAAO;IAAY,UAAU;GAAQ,CAAC;EAC7G;EAEA,SAAS,sBAAkC;GACzC,MAAM,QAAQ,QAAQ,OAAO;GAAG,MAAM,QAAQ,SAAS;GAAqB,SAAS,KAAK,OAAO,KAAK;GACtG,IAAI,aAAa;GACjB,MAAM,aAAa,YAA2B;IAAE,IAAI,cAAc,SAAS,oBAAoB,UAAU;IAAQ,aAAa;IAAM,IAAI;KAAE,MAAM,WAAW,MAAM,MAAM,6BAA6B;MAAE,OAAO;MAAY,aAAa;KAAc,CAAC;KAAG,IAAI,SAAS,IAAI;MAAE,MAAM,MAAM,MAAM,SAAS,KAAK;MAAG,IAAI,MAAM,gBAAgB,KAAK,MAAM,cAAc;KAAI;IAAE,UAAU;KAAE,aAAa;IAAM;GAAE;GACxY,IAAI;GAAqC,IAAI;GAAyC,IAAI,SAAS;GAAI,IAAI;GAC3G,MAAM,WAAW,OAAO;GACxB,OAAO,YAAY,OAAO,OAAO,EAAE,WAAW,UAAgC;IAAE,UAAU;GAAM,EAAE,CAAC;GACnG,MAAM,wBAA0D;GAChE,MAAM,YAAY,YAA2B;IAAE,IAAI;KAAE,MAAM,WAAW,MAAM,MAAM,4BAA4B;MAAE,OAAO;MAAY,aAAa;KAAc,CAAC;KAAG,IAAI,CAAC,SAAS,IAAI;KAAQ,MAAM,OAAO,MAAM,SAAS,KAAK;KAAG,IAAI,SAAS,QAAQ;KAAQ,SAAS;KAAM,UAAU,KAAA;KAAW,MAAM,SAAS,QAAQ,QAAQ;KAAG,OAAO,cAAc,GAAG,KAAK;KAAuC,SAAS,KAAK,OAAO,MAAM;KAAG,OAAO,OAAO;KAAG,MAAM,QAAQ,gBAAgB;KAAG,IAAI,UAAU,KAAA,GAAW;KAAQ,MAAM,WAAW,QAAQ,KAAK;KAAG,SAAS,QAAQ,qBAAqB;KAAQ,SAAS,KAAK,OAAO,QAAQ;KAAG,MAAM,cAAc,MAAM;MAAE;MAAU,SAAS;MAAe,MAAM;MAAU;KAAO,CAAC;KAAG,gBAAgB;KAAG,YAAY,OAAO;KAAG,aAAa;KAAU,gBAAgB,OAAO,gBAAgB,aAAa,cAAc,KAAA;IAAU,QAAQ,CAAgE;GAAE;GACt5B,WAAgB;GAAG,UAAe;GAClC,MAAM,QAAQ,OAAO,kBAAkB;IAAE,WAAgB;IAAG,UAAe;GAAE,GAAG,GAAK;GACrF,aAAa;IAAE,cAAc,KAAK;IAAG,gBAAgB;IAAG,YAAY,OAAO;IAAG,MAAM,OAAO;IAAG,IAAI,aAAa,KAAA,GAAW,OAAO,OAAO;SAAgB,OAAO,YAAY;GAAS;EACtL;EAEA,MAAM,iBAAiB;;;;;;;;;;EAWvB,SAAgB,MAAM,KAA0B;GAC9C,IAAI,aAAa;IACf,MAAM,WAAW,eAAe,SAAS,QAAQ,KAAK,CAAC,IAAI,gBAAgB,SAAS,MAAM,CAAC,CAAC,IAAI,oBAAoB;IACpH,MAAM,QAAQ,QAAQ,OAAO;IAAG,MAAM,QAAQ,SAAS;IAAc,MAAM,cAAc,WACrF,iBACA;IACJ,SAAS,KAAK,OAAO,KAAK;IAC1B,IAAI,CAAC,UAAU;KACb,MAAM,eAAe,oBAAoB;KACzC,MAAM,gBAAgB,2BAA2B;KACjD,aAAa;MAAE,aAAa;MAAG,cAAc;MAAG,MAAM,OAAO;KAAE;IACjE;IACA,MAAM,UAAU,eAAe;IAC/B,MAAM,cAAc,IAAI,MAAM,OAAO,+BAA+B,IAAI,MAAM,SAAS;KAAE,MAAM;KAAyB,IAAI;IAAa,IAAI,EAAE,YAAA,GAAWA,MAAAA,cAAAA,CAAc,UAAU;KAChL,iBAAiB;KACjB,cAAc;KACd,WAAW,8BAA8B,OAAO,KAAK;KACrD,MAAM;KACN,OAAO;KACP,SAAS,QAAQ;IACnB,IAAA,GAAGA,MAAAA,cAAAA,CAAc,QAAQ;KAAE,eAAe;KAAM,WAAW;IAAmC,CAAC,GAAG,QAAA,GAAOA,MAAAA,cAAAA,CAAc,QAAQ,EAAE,WAAW,oCAAoC,GAAG,MAAM,IAAI,KAAA,CAAS,CAAC,CAAC;IACxM,aAAa;KAAE,YAAY;KAAG,QAAQ,OAAO;KAAG,MAAM,OAAO;IAAE;GACjE,GAAG,uDAAuD;EAC5D;;EAGA,MAAa,SAA4B,CAAC,OAAO"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["createElement"],"sources":["../src/native-mobile.ts","../src/client.ts"],"sourcesContent":["/** Mobile feature and compatibility rules applied to DSH React surfaces. */\nexport const NATIVE_MOBILE_STYLES = `\n@media (max-width:720px) {\n html.dsh-native-mobile-active,html.dsh-native-mobile-active body { width:100%; height:100%; overflow:hidden; }\n html.dsh-native-mobile-active { --dsh-mobile-motion-duration:200ms; --dsh-mobile-motion-ease:cubic-bezier(.22,1,.36,1); }\n html.dsh-native-mobile-active :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]) { -webkit-tap-highlight-color:transparent; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"] { -webkit-tap-highlight-color:transparent; touch-action:manipulation; }\n html.dsh-native-mobile-active[data-dsh-mobile-input=\"touch\"] :is(a,button,[role=\"button\"],[role=\"tab\"],[tabindex]):focus { outline:none !important; }\n html.dsh-native-mobile-active [role=\"tooltip\"] { display:none !important; }\n /* Touch has no persistent hover affordance: keep workspace rows neutral after a tap. */\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] { --dsw-alias-interactive-bg-hover:transparent !important; }\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [role=\"treeitem\"]:is(:hover,:active,:focus,[aria-selected=\"true\"]),\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_sessionRow\"][class*=\"_selected\"],\n html.dsh-native-mobile-active [data-dsh-mobile-sidebar] [class*=\"_searchResultRow\"][class*=\"_selected\"] { background:transparent !important; outline:0 !important; box-shadow:none !important; }\n [data-dsh-mobile-frame] { grid-template-columns:0 minmax(0,1fr) 0 !important; width:100% !important; height:100dvh !important; overflow:hidden !important; }\n [data-dsh-mobile-center] { grid-column:2 !important; width:100vw !important; min-width:0 !important; }\n [data-dsh-mobile-center] > * { min-width:0 !important; }\n [data-dsh-mobile-header] { box-sizing:border-box !important; width:calc(100% - 16px) !important; margin:0 8px !important; min-width:0; padding-top:4px !important; padding-right:8px !important; padding-left:42px !important; }\n [data-dsh-mobile-header] [class*=\"_titleRow\"] { box-sizing:border-box !important; display:flex !important; align-items:center !important; min-width:0; min-height:32px !important; height:32px !important; gap:6px !important; padding:0 6px !important; }\n [data-dsh-mobile-header] [class*=\"_titleCluster\"] { min-width:0; }\n [data-dsh-mobile-header] [class*=\"_crumbs\"] { min-width:0; overflow:hidden; }\n [data-dsh-mobile-header] [class*=\"_crumb\"] { max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { min-width:0; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_headerActions\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-header] [class*=\"_headerUtilities\"] { gap:2px !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] { width:40px; min-width:40px; padding:0 !important; overflow:hidden; color:transparent; font-size:0 !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"] > * { display:none !important; }\n [data-dsh-mobile-header] [class*=\"_sessionLogButton\"]::after { color:var(--dsw-text, #171a21); content:\"日志\"; font-size:11px; font-weight:600; }\n [data-dsh-mobile-header] [class*=\"_tabs\"] { box-sizing:border-box !important; width:max-content !important; max-width:calc(100% - 58px) !important; min-height:28px !important; height:28px !important; margin-top:0 !important; padding-left:6px !important; padding-right:6px !important; overflow-x:auto; scrollbar-width:none; }\n [data-dsh-mobile-header] [class*=\"_tab\"] { padding-bottom:5px !important; }\n [data-dsh-mobile-header] [class*=\"_tabs\"]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-sidebar] { position:fixed !important; z-index:240 !important; inset:0 auto 0 0 !important; width:0 !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar-root] { position:fixed !important; z-index:241 !important; inset:0 auto 0 0 !important; height:100dvh !important; transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease) !important; }\n [data-dsh-mobile-sidebar][data-open=\"true\"] [data-dsh-mobile-sidebar-root] { width:min(88vw,340px) !important; box-shadow:18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] { width:0 !important; border:0 !important; background:transparent !important; box-shadow:none !important; overflow:visible !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :not(:has([data-dsh-mobile-toggle])) { display:none !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) { position:fixed !important; z-index:244 !important; top:env(safe-area-inset-top) !important; left:0 !important; box-sizing:border-box !important; width:50px !important; height:52px !important; padding:4px !important; border:0 !important; background:transparent !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-sidebar-root] > :has([data-dsh-mobile-toggle]) > :not([data-dsh-mobile-toggle]) { display:none !important; }\n [data-dsh-mobile-toggle] { width:44px !important; height:44px !important; min-width:44px !important; min-height:44px !important; }\n [data-dsh-mobile-sidebar][data-open=\"false\"] [data-dsh-mobile-toggle] > svg[class*=\"_railFish\"] { transform:translateY(-4px) !important; }\n .dsh-native-mobile-backdrop { position:fixed; z-index:235; inset:0; border:0; background:rgb(15 23 42 / 32%); }\n .dsh-native-mobile-backdrop:not([hidden]) { animation:dsh-mobile-fade-in var(--dsh-mobile-motion-duration) ease-out; }\n .dsh-native-mobile-backdrop[hidden] { display:none; }\n [data-dsh-mobile-details] { position:fixed !important; z-index:250 !important; inset:0 0 0 auto !important; width:min(94vw,460px) !important; max-width:none !important; transform:translateX(100%); transition:transform var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); background:var(--dsw-bg, #fff); box-shadow:-18px 0 46px rgb(15 23 42 / 18%); }\n [data-dsh-mobile-details][data-open=\"true\"] { transform:translateX(0); }\n [data-dsh-mobile-handle] { display:none !important; }\n [data-dsh-mobile-settings] { flex-direction:column !important; width:100vw !important; height:100dvh !important; max-width:none !important; border-radius:0 !important; animation:dsh-mobile-panel-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-settings-nav] { flex:none !important; width:100% !important; padding:max(14px,env(safe-area-inset-top)) 12px 8px !important; gap:10px !important; border-bottom:1px solid var(--dsw-alias-border-subtle,#e8ebef); }\n [data-dsh-mobile-settings-nav] [class*=\"_navTitle\"] { padding:0 8px !important; font-size:18px !important; line-height:28px !important; }\n [data-dsh-mobile-settings-list] { flex-direction:row !important; gap:4px !important; overflow-x:auto !important; scrollbar-width:none; }\n [data-dsh-mobile-settings-list]::-webkit-scrollbar { display:none; }\n [data-dsh-mobile-settings-list] [class*=\"_navCell\"] { flex:0 0 auto !important; min-width:max-content !important; height:44px !important; padding:10px 12px !important; }\n [data-dsh-mobile-settings-list] [aria-current=\"true\"] { border-color:transparent !important; outline:0 !important; box-shadow:none !important; }\n [data-dsh-mobile-settings-content] { flex:1 1 auto !important; width:100% !important; min-height:0 !important; }\n [data-dsh-mobile-settings-header] { height:48px !important; min-height:48px !important; padding:10px 12px 6px !important; }\n [data-dsh-mobile-settings-header] [class*=\"_close\"] { width:36px !important; height:36px !important; }\n [data-dsh-mobile-settings-options] { box-sizing:border-box !important; width:100% !important; padding:4px 16px max(24px,env(safe-area-inset-bottom)) !important; overflow-x:hidden !important; }\n [data-dsh-mobile-settings-options] > * { width:100% !important; min-width:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] > [class*=\"_row\"] { flex-direction:column !important; align-items:stretch !important; gap:12px !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_rowText\"] { width:100% !important; padding-right:0 !important; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { box-sizing:border-box !important; align-self:flex-start !important; justify-content:space-between !important; min-width:0 !important; min-height:44px !important; max-width:100% !important; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea,button) { max-width:100%; }\n [data-dsh-mobile-settings-options] :is(input,select,textarea) { box-sizing:border-box; width:100%; min-width:0; }\n [data-dsh-mobile-settings-options] [class*=\"_head\"] { min-width:0; flex-wrap:wrap; }\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:dsh-mobile-view-in var(--dsh-mobile-motion-duration) var(--dsh-mobile-motion-ease); }\n [data-dsh-mobile-center] textarea { font-size:16px !important; }\n [data-dsh-mobile-center] table { display:block; max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] pre { max-width:100%; overflow-x:auto; }\n [data-dsh-mobile-center] :is(img,video,canvas,svg) { max-width:100%; }\n [data-dsh-mobile-message-scroll] { box-sizing:border-box !important; width:100% !important; padding:8px 10px 20px !important; }\n [data-dsh-mobile-message-column] { box-sizing:border-box !important; width:100% !important; max-width:none !important; margin:0 !important; padding:0 !important; gap:10px !important; }\n [data-dsh-mobile-message-column] > * { width:100% !important; max-width:100% !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] { box-sizing:border-box !important; display:grid !important; grid-template-columns:16px minmax(0,1fr) !important; grid-auto-rows:auto !important; align-items:center !important; column-gap:6px !important; width:100% !important; height:auto !important; min-height:40px !important; padding:4px 0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_leading\"] { grid-column:1 !important; grid-row:1 !important; margin-right:0 !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_title\"] { grid-column:2 !important; grid-row:1 !important; min-width:0 !important; overflow:hidden !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_sep\"],[class*=\"_separator\"]) { display:none !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > :is([class*=\"_summary\"],[class*=\"_fileLink\"]) { grid-column:2 !important; grid-row:2 !important; width:100% !important; min-width:0 !important; max-width:100% !important; overflow:hidden !important; line-height:19px !important; text-overflow:ellipsis !important; white-space:nowrap !important; }\n [data-dsh-mobile-message-column] [data-disclosure-row] > [class*=\"_summarySuffix\"] { grid-column:2 !important; grid-row:3 !important; margin-left:0 !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { display:grid !important; grid-template-columns:minmax(72px,30%) minmax(0,1fr) !important; gap:4px 10px !important; }\n [data-dsh-mobile-message-column] [class*=\"_ioSection\"] { grid-template-columns:1fr !important; row-gap:4px !important; }\n [data-dsh-mobile-message-column] [class*=\"_body\"] { max-width:100% !important; overflow-wrap:anywhere; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] { box-sizing:border-box !important; width:100% !important; max-width:100% !important; margin-bottom:-6px !important; padding:3px 4px 0 !important; font-size:11px !important; line-height:18px !important; white-space:normal !important; overflow:visible !important; text-overflow:clip !important; }\n [data-dsh-mobile-center] [data-composer-card] ~ [class*=\"_root\"] [class*=\"_sep\"],\n [data-dsh-mobile-center] [data-composer-card] ~ * [class*=\"_root\"] [class*=\"_sep\"] { margin:0 6px !important; }\n [data-dsh-mobile-center] [class*=\"_composer\"] { padding-left:8px !important; padding-right:8px !important; padding-bottom:max(8px,env(safe-area-inset-bottom)) !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_row\"] { display:flex !important; align-items:center !important; gap:4px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_tools\"] { flex:0 0 auto !important; width:auto !important; min-width:0 !important; gap:6px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_trailing\"] { flex:1 1 auto !important; min-width:0 !important; gap:6px !important; margin-left:auto !important; justify-content:flex-end !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) [class*=\"_trailing\"] [class*=\"_root\"]:has(button[aria-label^=\"选择模型\"]) { flex:0 1 auto !important; width:auto !important; max-width:min(55vw,220px) !important; min-width:0 !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) button[aria-label^=\"选择模型\"] { width:auto !important; max-width:100% !important; min-width:0 !important; padding-left:6px !important; padding-right:4px !important; }\n [data-dsh-mobile-center] [class*=\"_card\"]:has(textarea) button[aria-label^=\"选择模型\"] [class*=\"_triggerLabel\"] { max-width:clamp(120px,36vw,210px); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) { box-sizing:border-box !important; width:100% !important; padding:0 0 8px !important; }\n [data-dsh-mobile-center] [class*=\"_root\"]:has(> [class*=\"_card\"] textarea) > [class=\"\"]:last-child { display:none !important; }\n}\n@keyframes dsh-mobile-fade-in { from { opacity:0; } }\n@keyframes dsh-mobile-panel-in { from { opacity:.72; transform:translateY(6px); } }\n@keyframes dsh-mobile-view-in { from { opacity:.58; transform:translateY(5px); } }\n@media (max-width:420px) {\n [data-dsh-mobile-header] [class*=\"_headerActions\"] { max-width:42vw; }\n [data-dsh-mobile-settings-options] [data-slot=\"settings.general.item\"] [class*=\"_selector\"] { align-self:stretch !important; width:100% !important; }\n [data-dsh-mobile-message-column] [data-context-fields] > * { grid-template-columns:1fr !important; }\n}\n@media (prefers-reduced-motion:reduce) {\n [data-dsh-mobile-sidebar-root],[data-dsh-mobile-details] { transition:none !important; }\n .dsh-native-mobile-backdrop:not([hidden]),[data-dsh-mobile-settings],\n [data-dsh-mobile-settings-content][data-dsh-mobile-view-transition=\"true\"],\n [data-dsh-mobile-view][data-dsh-mobile-view-transition=\"true\"] { animation:none !important; }\n}\n`\n\nfunction classToken(element: Element, suffix: string): boolean {\n return Array.from(element.classList).some(value => value.endsWith(suffix))\n}\n\nfunction firstByClassSuffix(root: ParentNode, suffix: string): HTMLElement | undefined {\n return Array.from(root.querySelectorAll<HTMLElement>('[class]')).find(element => classToken(element, suffix))\n}\n\n/** Add mobile semantics without replacing feature trees. */\nexport function installNativeMobileSurface(): () => void {\n document.documentElement.classList.add('dsh-native-mobile-active')\n const setInputMode = (mode: 'keyboard' | 'touch'): void => {\n document.documentElement.dataset.dshMobileInput = mode\n }\n const onPointerDown = (event: PointerEvent): void => {\n if (event.pointerType === 'touch' || event.pointerType === 'pen') setInputMode('touch')\n }\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Tab' || event.key.startsWith('Arrow')) setInputMode('keyboard')\n }\n document.addEventListener('pointerdown', onPointerDown, true)\n document.addEventListener('keydown', onKeyDown, true)\n const backdrop = document.createElement('button')\n backdrop.type = 'button'\n backdrop.className = 'dsh-native-mobile-backdrop'\n backdrop.hidden = true\n backdrop.setAttribute('aria-label', '关闭工作区导航')\n document.body.append(backdrop)\n let frame: HTMLElement | undefined\n let sidebar: HTMLElement | undefined\n let sidebarRoot: HTMLElement | undefined\n let toggle: HTMLButtonElement | undefined\n let viewArea: HTMLElement | undefined\n let scheduled = 0\n let transitionFrame = 0\n let transitionRestartFrame = 0\n let transitionTimer = 0\n let transitionTarget: HTMLElement | undefined\n const animateNavigation = (event: MouseEvent): void => {\n if (!(event.target instanceof Element)) return\n const trigger = event.target.closest<HTMLElement>('button,a,[role=\"tab\"],[aria-selected]')\n if (trigger === null || trigger.hasAttribute('disabled') || trigger.getAttribute('aria-disabled') === 'true') return\n if (trigger.getAttribute('aria-selected') === 'true' || trigger.getAttribute('aria-current') === 'true') return\n const settingsNavigation = trigger.closest('[data-dsh-mobile-settings-list]') !== null\n const conversationNavigation = trigger.matches('[role=\"tab\"]')\n const sidebarNavigation = trigger.closest('[data-dsh-mobile-sidebar-root]') !== null\n && trigger.closest('[data-dsh-mobile-toggle]') === null\n if (!settingsNavigation && !conversationNavigation && !sidebarNavigation) return\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n transitionFrame = requestAnimationFrame(() => {\n transitionFrame = 0\n const target = settingsNavigation\n ? document.querySelector<HTMLElement>('[data-dsh-mobile-settings-content]')\n : viewArea\n if (target === null || target === undefined) return\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n target.removeAttribute('data-dsh-mobile-view-transition')\n transitionRestartFrame = requestAnimationFrame(() => {\n transitionRestartFrame = 0\n transitionTarget = target\n target.dataset.dshMobileViewTransition = 'true'\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTimer = window.setTimeout(() => {\n target.removeAttribute('data-dsh-mobile-view-transition')\n if (transitionTarget === target) transitionTarget = undefined\n transitionTimer = 0\n }, 240)\n })\n })\n }\n document.addEventListener('click', animateNavigation)\n\n const sync = (): void => {\n scheduled = 0\n frame = firstByClassSuffix(document, '_frame')\n const dedicatedCenter = document.querySelector<HTMLElement>('.dshm-main') ?? undefined\n if (frame !== undefined) frame.dataset.dshMobileFrame = 'true'\n sidebar = frame === undefined\n ? document.querySelector<HTMLElement>('.dshm-drawer') ?? undefined\n : firstByClassSuffix(frame, '_sidebarCol')\n const center = frame === undefined ? dedicatedCenter : firstByClassSuffix(frame, '_centerCol')\n const details = frame === undefined ? undefined : firstByClassSuffix(frame, '_detailsCol')\n const handle = frame === undefined ? undefined : firstByClassSuffix(frame, '_handle')\n if (center === undefined) return\n if (center !== undefined) {\n center.dataset.dshMobileCenter = 'true'\n center.querySelector<HTMLElement>('header')?.setAttribute('data-dsh-mobile-header', 'true')\n viewArea = firstByClassSuffix(center, '_viewArea')\n if (viewArea !== undefined) viewArea.dataset.dshMobileView = 'true'\n const conversation = center.querySelector<HTMLElement>('[data-conversation-scroll]')\n const messageColumn = conversation === null ? undefined : firstByClassSuffix(conversation, '_column')\n const messageScroll = messageColumn?.parentElement\n if (messageColumn !== undefined && messageScroll !== null && messageScroll !== undefined && classToken(messageScroll, '_scroll')) {\n messageColumn.dataset.dshMobileMessageColumn = 'true'\n messageScroll.dataset.dshMobileMessageScroll = 'true'\n }\n }\n if (handle !== undefined) handle.dataset.dshMobileHandle = 'true'\n if (details !== undefined) {\n details.dataset.dshMobileDetails = 'true'\n const lastColumn = frame?.style.gridTemplateColumns.trim().split(/\\s+/).at(-1)\n details.dataset.open = String(lastColumn !== undefined && lastColumn !== '0px' && lastColumn !== '0')\n }\n const settings = Array.from(document.querySelectorAll<HTMLElement>('[role=\"dialog\"]')).find(dialog => {\n const directNav = Array.from(dialog.children).find(child => child instanceof HTMLElement && classToken(child, '_nav'))\n return directNav !== undefined\n })\n if (settings !== undefined) {\n settings.dataset.dshMobileSettings = 'true'\n const nav = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_nav')) as HTMLElement | undefined\n const content = Array.from(settings.children).find(child => child instanceof HTMLElement && classToken(child, '_content')) as HTMLElement | undefined\n if (nav !== undefined) {\n nav.dataset.dshMobileSettingsNav = 'true'\n firstByClassSuffix(nav, '_navList')?.setAttribute('data-dsh-mobile-settings-list', 'true')\n }\n if (content !== undefined) {\n content.dataset.dshMobileSettingsContent = 'true'\n firstByClassSuffix(content, '_header')?.setAttribute('data-dsh-mobile-settings-header', 'true')\n firstByClassSuffix(content, '_options')?.setAttribute('data-dsh-mobile-settings-options', 'true')\n }\n }\n if (sidebar === undefined) return\n sidebar.dataset.dshMobileSidebar = 'true'\n toggle = firstByClassSuffix(sidebar, '_toggle') as HTMLButtonElement | undefined\n let candidate = toggle?.parentElement\n while (candidate !== undefined && candidate !== null && candidate !== sidebar && !classToken(candidate, '_root')) candidate = candidate.parentElement\n sidebarRoot = candidate !== sidebar && candidate !== null ? candidate : undefined\n if (sidebarRoot === undefined) return\n sidebarRoot.dataset.dshMobileSidebarRoot = 'true'\n if (toggle !== undefined) toggle.dataset.dshMobileToggle = 'true'\n const collapsed = classToken(sidebarRoot, '_collapsed')\n sidebar.dataset.open = String(!collapsed)\n backdrop.hidden = collapsed\n }\n const schedule = (): void => { if (scheduled === 0) scheduled = requestAnimationFrame(sync) }\n const observer = new MutationObserver(schedule)\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'style'] })\n backdrop.addEventListener('click', () => { if (sidebar?.dataset.open === 'true') toggle?.click() })\n sync()\n return () => {\n observer.disconnect()\n if (scheduled !== 0) cancelAnimationFrame(scheduled)\n if (transitionFrame !== 0) cancelAnimationFrame(transitionFrame)\n if (transitionRestartFrame !== 0) cancelAnimationFrame(transitionRestartFrame)\n if (transitionTimer !== 0) clearTimeout(transitionTimer)\n transitionTarget?.removeAttribute('data-dsh-mobile-view-transition')\n document.removeEventListener('pointerdown', onPointerDown, true)\n document.removeEventListener('keydown', onKeyDown, true)\n document.removeEventListener('click', animateNavigation)\n backdrop.remove()\n document.documentElement.classList.remove('dsh-native-mobile-active')\n delete document.documentElement.dataset.dshMobileInput\n }\n}\n","import { createElement } from 'react'\nimport { installNativeMobileSurface, NATIVE_MOBILE_STYLES } from './native-mobile.js'\n\ninterface ClientContext {\n effect(effect: () => void | (() => void), label?: string): void\n slots: {\n inject(key: string, callback: () => (() => void)): () => void\n register(options: { name: string; id: string }, component: (props: { wide: boolean }) => unknown): () => void\n }\n}\n\ninterface MobileExtensionContext {\n readonly document: Document\n readonly request: (path: string, init?: RequestInit) => Promise<Response>\n readonly root: HTMLElement\n readonly window: Window\n}\n\ntype MobileExtensionMount = (context: MobileExtensionContext) => void | (() => void)\n\ndeclare global {\n interface Window {\n dshMobile?: { register(mount: MobileExtensionMount): void }\n __DSH_MOBILE_FRONTEND__?: 'dedicated'\n }\n}\n\nfunction isLoopbackHost(hostname: string): boolean {\n return hostname === 'localhost' || hostname === '127.0.0.1' || hostname === '::1' || hostname === '[::1]'\n}\n\nfunction element<K extends keyof HTMLElementTagNameMap>(tag: K, className?: string): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag)\n if (className !== undefined) node.className = className\n return node\n}\n\nasync function requestJson(path: string, init?: RequestInit): Promise<Record<string, unknown>> {\n const response = await fetch(path, { ...init, headers: { 'content-type': 'application/json', ...init?.headers } })\n const body = await response.json() as Record<string, unknown>\n if (!response.ok) throw new Error(typeof body.error === 'string' ? body.error : `HTTP ${String(response.status)}`)\n return body\n}\n\nfunction installControl(): { remove: () => void; toggle: () => void } {\n const root = element('div', 'dsh-mobile-control')\n const panel = element('section', 'dsh-mobile-control__panel'); panel.hidden = true\n panel.setAttribute('aria-label', '移动访问')\n const header = element('header', 'dsh-mobile-control__header')\n const title = element('h2'); title.textContent = '移动访问'\n const close = element('button', 'dsh-mobile-control__close'); close.type = 'button'; close.textContent = '×'; close.setAttribute('aria-label', '收起移动访问')\n const access = element('div', 'dsh-mobile-control__access'); access.hidden = true\n const accessLabel = element('span', 'dsh-mobile-control__access-label'); accessLabel.textContent = '浏览器访问'\n const accessLink = element('a', 'dsh-mobile-control__access-link'); accessLink.target = '_blank'; accessLink.rel = 'noreferrer'\n access.append(accessLabel, accessLink)\n const status = element('p', 'dsh-mobile-control__status'); status.textContent = '正在读取状态…'\n const actions = element('div', 'dsh-mobile-control__actions')\n const toggle = element('button', 'dsh-mobile-control__secondary'); toggle.type = 'button'\n const pair = element('button', 'dsh-mobile-control__primary'); pair.type = 'button'; pair.textContent = '生成并复制密钥'\n header.append(title, close); actions.append(toggle, pair); panel.append(header, access, status, actions); root.append(panel); document.body.append(root)\n let running = false\n let origin = ''\n const setOpen = (open: boolean): void => {\n panel.hidden = !open\n for (const trigger of document.querySelectorAll('.dsh-mobile-control__trigger')) trigger.setAttribute('aria-expanded', String(open))\n }\n const render = (data: Record<string, unknown>): void => {\n running = data.running === true\n origin = running && typeof data.origin === 'string' ? data.origin : ''\n access.hidden = origin === ''\n accessLink.href = origin\n accessLink.textContent = origin\n accessLink.title = origin\n status.classList.toggle('is-running', running)\n status.textContent = running ? '移动访问已开启。' : '已关闭。DSH 仍只在本机可用。'\n toggle.textContent = running ? '关闭移动访问' : '开启移动访问'; pair.disabled = !running\n }\n toggle.addEventListener('click', () => { toggle.disabled = true; void requestJson('/api/mobile-access/control', { method: 'POST', body: JSON.stringify({ running: !running }) }).then(render, error => { status.textContent = String(error) }).finally(() => { toggle.disabled = false }) })\n pair.addEventListener('click', () => { pair.disabled = true; void requestJson('/api/mobile-access/pairing/open', { method: 'POST', body: '{}' }).then(async data => {\n const key = typeof data.appKey === 'string' ? data.appKey : ''\n if (key === '') { status.textContent = '无法生成配对密钥。'; return }\n try {\n await navigator.clipboard.writeText(key)\n status.textContent = '配对密钥已复制,请粘贴到 Android App。'\n } catch {\n status.textContent = `请复制配对密钥:${key}`\n status.classList.add('is-key')\n }\n }, error => { status.textContent = String(error) }).finally(() => { pair.disabled = !running }) })\n close.addEventListener('click', () => { setOpen(false) })\n const dismiss = (event: PointerEvent): void => {\n if (panel.hidden || !(event.target instanceof Node)) return\n if (!panel.contains(event.target) && !document.querySelector('.dsh-mobile-control__trigger')?.contains(event.target)) setOpen(false)\n }\n document.addEventListener('pointerdown', dismiss)\n void requestJson('/api/mobile-access/control').then(render, error => { status.textContent = String(error) })\n return { remove: () => { document.removeEventListener('pointerdown', dismiss); root.remove() }, toggle: () => { setOpen(panel.hidden !== false) } }\n}\n\nfunction mobileRequest(path: string, init: RequestInit = {}): Promise<Response> {\n const target = new URL(path, location.href)\n if (target.origin !== location.origin) throw new TypeError('mobile extension requests must stay on the DSH origin')\n const headers = new Headers(init.headers)\n const method = (init.method ?? 'GET').toUpperCase()\n if (method !== 'GET' && method !== 'HEAD') {\n const csrf = document.cookie.split(';').map(value => value.trim()).find(value => value.startsWith('dsh_ma_csrf='))?.slice(12)\n if (csrf !== undefined) headers.set('x-dsh-mobile-csrf', csrf)\n }\n return fetch(target, { ...init, headers, credentials: 'same-origin', cache: 'no-store', redirect: 'error' })\n}\n\nfunction installCustomAssets(): () => void {\n const style = element('style'); style.dataset.plugin = 'dsh-mobile-custom'; document.head.append(style)\n let cssLoading = false\n const refreshCss = async (): Promise<void> => { if (cssLoading || document.visibilityState === 'hidden') return; cssLoading = true; try { const response = await fetch('/mobile-access/custom.css', { cache: 'no-store', credentials: 'same-origin' }); if (response.ok) { const css = await response.text(); if (style.textContent !== css) style.textContent = css } } finally { cssLoading = false } }\n let activeRoot: HTMLElement | undefined; let disposeActive: (() => void) | undefined; let source = ''; let pending: MobileExtensionMount | undefined\n const previous = window.dshMobile\n window.dshMobile = Object.freeze({ register: (mount: MobileExtensionMount) => { pending = mount } })\n const registeredMount = (): MobileExtensionMount | undefined => pending\n const refreshJs = async (): Promise<void> => { try { const response = await fetch('/mobile-access/custom.js', { cache: 'no-store', credentials: 'same-origin' }); if (!response.ok) return; const next = await response.text(); if (next === source) return; source = next; pending = undefined; const script = element('script'); script.textContent = `${next}\\n//# sourceURL=dsh-mobile-custom.js`; document.head.append(script); script.remove(); const mount = registeredMount(); if (mount === undefined) return; const nextRoot = element('div'); nextRoot.dataset.dshMobileExtension = 'true'; document.body.append(nextRoot); const nextDispose = mount({ document, request: mobileRequest, root: nextRoot, window }); disposeActive?.(); activeRoot?.remove(); activeRoot = nextRoot; disposeActive = typeof nextDispose === 'function' ? nextDispose : undefined } catch { /* Preserve the last good customization during reconnects. */ } }\n void refreshCss(); void refreshJs()\n const timer = window.setInterval(() => { void refreshCss(); void refreshJs() }, 1_000)\n return () => { clearInterval(timer); disposeActive?.(); activeRoot?.remove(); style.remove(); if (previous === undefined) delete window.dshMobile; else window.dshMobile = previous }\n}\n\nconst CONTROL_STYLES = `\n.dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:64px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}\n.dsh-mobile-control__panel{box-sizing:border-box;width:min(328px,calc(100vw - 32px));padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}\n.dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;font-size:24px;line-height:1;cursor:pointer}.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}\n.dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:\":\"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}\n.dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:\"\"}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}\n.dsh-mobile-control__actions{display:flex;flex-wrap:wrap;gap:8px}.dsh-mobile-control__actions button{min-height:40px;padding:8px 12px;border-radius:11px;font:inherit;cursor:pointer}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}\n.dsh-mobile-control__trigger{box-sizing:border-box;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px;padding:6px 2px 6px 10px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font:14px/22px system-ui;cursor:pointer}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;border-radius:50%}.dsh-mobile-control__trigger-icon{position:relative;box-sizing:border-box;flex:none;width:14px;height:19px;border:1.7px solid currentColor;border-radius:3px}.dsh-mobile-control__trigger-icon::after{position:absolute;right:4px;bottom:2px;width:4px;height:1.5px;border-radius:2px;background:currentColor;content:\"\"}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}\n`\n\n/** Mount the desktop control or mobile feature enhancements. */\nexport function apply(ctx: ClientContext): void {\n ctx.effect(() => {\n const loopback = isLoopbackHost(location.hostname) && !new URLSearchParams(location.search).has('dsh-mobile-preview')\n const style = element('style'); style.dataset.plugin = 'dsh-mobile'; style.textContent = loopback\n ? CONTROL_STYLES\n : NATIVE_MOBILE_STYLES\n document.head.append(style)\n if (!loopback) {\n const removeCustom = installCustomAssets()\n const removeSurface = installNativeMobileSurface()\n return () => { removeCustom(); removeSurface(); style.remove() }\n }\n const control = installControl()\n const disposeSlot = ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({ name: 'sidebar.footer.action', id: 'dsh-mobile' }, ({ wide }) => createElement('button', {\n 'aria-expanded': false,\n 'aria-label': '移动访问',\n className: `dsh-mobile-control__trigger${wide ? '' : ' is-rail'}`,\n type: 'button',\n title: '移动访问',\n onClick: control.toggle,\n }, createElement('span', { 'aria-hidden': true, className: 'dsh-mobile-control__trigger-icon' }), wide ? createElement('span', { className: 'dsh-mobile-control__trigger-label' }, '移动访问') : undefined)))\n return () => { disposeSlot(); control.remove(); style.remove() }\n }, 'dsh-mobile: stock mobile adaptation and local control')\n}\n\n/** Client services required by the mobile adaptation. */\nexport const inject: readonly string[] = ['slots']\n"],"mappings":"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"}
|
package/lib/mobile-layout.js
CHANGED
|
@@ -72,14 +72,11 @@ html,body,#root{width:100%;height:100%;overflow:hidden}
|
|
|
72
72
|
.dshm-shell{position:relative;display:grid;width:100%;height:100dvh;min-width:0;overflow:hidden;background:var(--dsw-alias-bg-base,#fff)}
|
|
73
73
|
.dshm-main{grid-area:1/1;min-width:0;min-height:0;overflow:hidden}
|
|
74
74
|
.dshm-main>*,.dshm-main>*>*{min-width:0}
|
|
75
|
-
.dshm-
|
|
76
|
-
.dshm-
|
|
77
|
-
.dshm-
|
|
78
|
-
.dshm-menu svg,.dshm-close svg{width:22px;height:22px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}
|
|
79
|
-
.dshm-drawer{position:fixed;z-index:70;inset:0 auto 0 0;box-sizing:border-box;width:min(88vw,340px);max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#f8fafc);box-shadow:18px 0 46px rgb(15 23 42 / 18%);left:-104%;transition:left 190ms cubic-bezier(.22,1,.36,1)}
|
|
80
|
-
.dshm-drawer[data-open=true]{left:0}
|
|
81
|
-
.dshm-drawer[data-open=false]{pointer-events:none;visibility:hidden;transition:left 190ms cubic-bezier(.22,1,.36,1),visibility 0s linear 190ms}
|
|
75
|
+
.dshm-drawer{position:fixed;z-index:70;inset:0 auto 0 0;box-sizing:border-box;width:56px;max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#f8fafc);box-shadow:none;transition:width 190ms cubic-bezier(.22,1,.36,1)}
|
|
76
|
+
.dshm-drawer[data-open=true]{width:min(88vw,340px);box-shadow:18px 0 46px rgb(15 23 42 / 18%)}
|
|
77
|
+
.dshm-drawer[data-open=false]{pointer-events:auto;visibility:visible}
|
|
82
78
|
.dshm-drawer>*{width:100%!important;height:100%!important}
|
|
79
|
+
.dshm-drawer[data-open=false]>*{width:56px!important}
|
|
83
80
|
.dshm-details{position:fixed;z-index:80;inset:0 0 0 auto;box-sizing:border-box;width:min(94vw,460px);max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:-18px 0 46px rgb(15 23 42 / 18%);transform:translateX(104%);transition:transform 190ms cubic-bezier(.22,1,.36,1)}
|
|
84
81
|
.dshm-details[data-open=true]{transform:translateX(0)}
|
|
85
82
|
.dshm-details[data-open=false]{pointer-events:none;visibility:hidden;transition:transform 190ms cubic-bezier(.22,1,.36,1),visibility 0s linear 190ms}
|
|
@@ -98,17 +95,9 @@ html,body,#root{width:100%;height:100%;overflow:hidden}
|
|
|
98
95
|
@media(max-width:420px){.dshm-shell [data-context-fields]>*{display:grid;grid-template-columns:1fr!important;gap:4px}.dshm-shell [class*="_ioSection"]{grid-template-columns:1fr!important}}
|
|
99
96
|
@media(prefers-reduced-motion:reduce){.dshm-drawer,.dshm-details,.dshm-scrim{transition:none!important}}
|
|
100
97
|
`;
|
|
101
|
-
function icon(paths) {
|
|
102
|
-
return (0, react.createElement)("svg", {
|
|
103
|
-
"aria-hidden": true,
|
|
104
|
-
viewBox: "0 0 24 24"
|
|
105
|
-
}, ...paths.map((path, index) => (0, react.createElement)("path", {
|
|
106
|
-
d: path,
|
|
107
|
-
key: index
|
|
108
|
-
})));
|
|
109
|
-
}
|
|
110
98
|
function MobileAppFrame(props) {
|
|
111
99
|
const state = (0, react.useSyncExternalStore)(props.controller.subscribe, props.controller.getSnapshot);
|
|
100
|
+
const suppressKeyboardUntil = (0, react.useRef)(0);
|
|
112
101
|
const hasSession = props.useSessions((session) => {
|
|
113
102
|
const current = session.current;
|
|
114
103
|
return current !== void 0 && session.byId[current]?.blank === false;
|
|
@@ -116,27 +105,32 @@ html,body,#root{width:100%;height:100%;overflow:hidden}
|
|
|
116
105
|
(0, react.useEffect)(() => {
|
|
117
106
|
if (!hasSession) props.controller.closeDetails();
|
|
118
107
|
}, [hasSession, props.controller]);
|
|
119
|
-
|
|
108
|
+
(0, react.useEffect)(() => {
|
|
109
|
+
const suppressAutofocus = (event) => {
|
|
110
|
+
if (performance.now() >= suppressKeyboardUntil.current) return;
|
|
111
|
+
const target = event.target;
|
|
112
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) target.blur();
|
|
113
|
+
};
|
|
114
|
+
document.addEventListener("focusin", suppressAutofocus, true);
|
|
115
|
+
return () => {
|
|
116
|
+
document.removeEventListener("focusin", suppressAutofocus, true);
|
|
117
|
+
};
|
|
118
|
+
}, []);
|
|
119
|
+
const closeDrawerAfterSessionAction = (event) => {
|
|
120
120
|
if (!(event.target instanceof Element)) return;
|
|
121
|
-
const
|
|
122
|
-
|
|
121
|
+
const row = event.target.closest("[role=\"treeitem\"][aria-selected]");
|
|
122
|
+
const action = event.target.closest("button,[role=\"button\"]");
|
|
123
|
+
const startsSession = action?.matches("button[class*=\"_newSession\"],button[class*=\"_brand\"]") ?? false;
|
|
124
|
+
if (row === null && !startsSession) return;
|
|
125
|
+
if (row !== null && action !== null && action !== row) return;
|
|
126
|
+
suppressKeyboardUntil.current = performance.now() + 500;
|
|
123
127
|
window.setTimeout(() => {
|
|
124
128
|
props.controller.closeSidebar();
|
|
125
|
-
|
|
129
|
+
const active = document.activeElement;
|
|
130
|
+
if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) active.blur();
|
|
131
|
+
}, 0);
|
|
126
132
|
};
|
|
127
133
|
return (0, react.createElement)("div", { className: "dshm-shell" }, (0, react.createElement)("main", { className: "dshm-main" }, props.renderSlot("conversation", {})), (0, react.createElement)("button", {
|
|
128
|
-
"aria-expanded": state.sidebarOpen,
|
|
129
|
-
"aria-label": state.sidebarOpen ? "关闭导航" : "打开导航",
|
|
130
|
-
className: "dshm-menu",
|
|
131
|
-
onClick: () => {
|
|
132
|
-
props.controller.toggleSidebar();
|
|
133
|
-
},
|
|
134
|
-
type: "button"
|
|
135
|
-
}, icon([
|
|
136
|
-
"M4 6h16",
|
|
137
|
-
"M4 12h16",
|
|
138
|
-
"M4 18h16"
|
|
139
|
-
])), (0, react.createElement)("button", {
|
|
140
134
|
"aria-label": "关闭浮层",
|
|
141
135
|
className: "dshm-scrim",
|
|
142
136
|
"data-open": state.sidebarOpen || state.detailsOpen,
|
|
@@ -146,14 +140,13 @@ html,body,#root{width:100%;height:100%;overflow:hidden}
|
|
|
146
140
|
tabIndex: state.sidebarOpen || state.detailsOpen ? 0 : -1,
|
|
147
141
|
type: "button"
|
|
148
142
|
}), (0, react.createElement)("aside", {
|
|
149
|
-
"aria-
|
|
143
|
+
"aria-label": "工作区与会话导航",
|
|
150
144
|
className: "dshm-drawer",
|
|
151
145
|
"data-open": state.sidebarOpen,
|
|
152
|
-
onClickCapture:
|
|
153
|
-
...state.sidebarOpen ? {} : { inert: "" }
|
|
146
|
+
onClickCapture: closeDrawerAfterSessionAction
|
|
154
147
|
}, props.renderSlot("sidebar", {
|
|
155
|
-
collapsed:
|
|
156
|
-
width: 340
|
|
148
|
+
collapsed: !state.sidebarOpen,
|
|
149
|
+
width: state.sidebarOpen ? 340 : 56
|
|
157
150
|
})), (0, react.createElement)("aside", {
|
|
158
151
|
"aria-hidden": !state.detailsOpen,
|
|
159
152
|
className: "dshm-details",
|
package/lib/mobile-layout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-layout.js","names":["createElement","useSyncExternalStore"],"sources":["../src/mobile-layout.ts"],"sourcesContent":["import { createElement, useEffect, useSyncExternalStore } from 'react'\nimport type { ReactNode } from 'react'\n\ninterface SessionState {\n readonly current?: string\n readonly byId: Readonly<Record<string, { readonly blank?: boolean } | undefined>>\n}\n\ninterface MobileRootProps {\n readonly renderSlot: (name: string, owner: Record<string, unknown>) => ReactNode\n readonly useSessions: <T>(selector: (state: SessionState) => T) => T\n}\n\ninterface MobileClientContext {\n readonly effect: (effect: () => void | (() => void), label?: string) => void\n readonly on: (event: string, listener: (value: ThemeSnapshot) => void) => () => void\n readonly reflect: { provide: (name: string, value: unknown) => () => void | Promise<void> }\n readonly slots: {\n register: (options: Record<string, unknown>, component: (props: MobileRootProps) => ReactNode) => () => void\n }\n readonly theme: { getTheme: () => ThemeSnapshot }\n}\n\ninterface ThemeSnapshot {\n readonly active: {\n readonly colorScheme: 'dark' | 'light'\n readonly tokens: Readonly<Record<string, string>>\n }\n}\n\ninterface LayoutSnapshot {\n readonly sidebarOpen: boolean\n readonly detailsOpen: boolean\n}\n\nclass MobileLayoutController {\n private snapshot: LayoutSnapshot = Object.freeze({ sidebarOpen: false, detailsOpen: false })\n private readonly listeners = new Set<() => void>()\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n readonly getSnapshot = (): LayoutSnapshot => this.snapshot\n\n toggleSidebar(): void {\n this.update({ sidebarOpen: !this.snapshot.sidebarOpen })\n }\n\n openDetails(): void {\n this.update({ detailsOpen: true })\n }\n\n closeDetails(): void {\n this.update({ detailsOpen: false })\n }\n\n closeSidebar(): void {\n this.update({ sidebarOpen: false })\n }\n\n private update(next: Partial<LayoutSnapshot>): void {\n const snapshot = Object.freeze({ ...this.snapshot, ...next })\n if (snapshot.sidebarOpen === this.snapshot.sidebarOpen && snapshot.detailsOpen === this.snapshot.detailsOpen) return\n this.snapshot = snapshot\n for (const listener of this.listeners) listener()\n }\n}\n\nclass ThemePresenter {\n private appliedTokens: string[] = []\n private readonly meta = document.createElement('meta')\n\n constructor() {\n this.meta.name = 'theme-color'\n }\n\n apply(snapshot: ThemeSnapshot): void {\n const scheme = snapshot.active.colorScheme\n document.documentElement.style.colorScheme = scheme\n document.body.toggleAttribute('data-ds-dark-theme', scheme === 'dark')\n for (const name of this.appliedTokens) document.body.style.removeProperty(name)\n this.appliedTokens = []\n for (const [name, value] of Object.entries(snapshot.active.tokens)) {\n document.body.style.setProperty(name, value)\n this.appliedTokens.push(name)\n }\n this.meta.content = getComputedStyle(document.body).backgroundColor\n if (!this.meta.isConnected) document.head.append(this.meta)\n }\n\n dispose(): void {\n document.documentElement.style.removeProperty('color-scheme')\n document.body.removeAttribute('data-ds-dark-theme')\n for (const name of this.appliedTokens) document.body.style.removeProperty(name)\n this.meta.remove()\n }\n}\n\nconst MOBILE_LAYOUT_STYLES = `\nhtml,body,#root{width:100%;height:100%;overflow:hidden}\n.dshm-shell{position:relative;display:grid;width:100%;height:100dvh;min-width:0;overflow:hidden;background:var(--dsw-alias-bg-base,#fff)}\n.dshm-main{grid-area:1/1;min-width:0;min-height:0;overflow:hidden}\n.dshm-main>*,.dshm-main>*>*{min-width:0}\n.dshm-menu{position:fixed;z-index:62;top:max(4px,env(safe-area-inset-top));left:4px;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#171a21);cursor:pointer;-webkit-tap-highlight-color:transparent}\n.dshm-menu:hover,.dshm-menu:active{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}\n.dshm-menu:focus-visible,.dshm-close:focus-visible{outline:2px solid var(--dsw-alias-border-focus,#2563eb);outline-offset:2px}\n.dshm-menu svg,.dshm-close svg{width:22px;height:22px;stroke:currentColor;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round}\n.dshm-drawer{position:fixed;z-index:70;inset:0 auto 0 0;box-sizing:border-box;width:min(88vw,340px);max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#f8fafc);box-shadow:18px 0 46px rgb(15 23 42 / 18%);left:-104%;transition:left 190ms cubic-bezier(.22,1,.36,1)}\n.dshm-drawer[data-open=true]{left:0}\n.dshm-drawer[data-open=false]{pointer-events:none;visibility:hidden;transition:left 190ms cubic-bezier(.22,1,.36,1),visibility 0s linear 190ms}\n.dshm-drawer>*{width:100%!important;height:100%!important}\n.dshm-details{position:fixed;z-index:80;inset:0 0 0 auto;box-sizing:border-box;width:min(94vw,460px);max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:-18px 0 46px rgb(15 23 42 / 18%);transform:translateX(104%);transition:transform 190ms cubic-bezier(.22,1,.36,1)}\n.dshm-details[data-open=true]{transform:translateX(0)}\n.dshm-details[data-open=false]{pointer-events:none;visibility:hidden;transition:transform 190ms cubic-bezier(.22,1,.36,1),visibility 0s linear 190ms}\n.dshm-scrim{position:fixed;z-index:65;inset:0;border:0;background:rgb(15 23 42 / 40%);opacity:0;pointer-events:none;transition:opacity 180ms ease-out}\n.dshm-scrim[data-open=true]{opacity:1;pointer-events:auto}\n.dshm-overlay{position:fixed;z-index:90;inset:0;pointer-events:none}.dshm-overlay>*{pointer-events:auto}\n.dshm-shell header{min-width:0;padding-left:52px}\n.dshm-shell textarea{font-size:16px}\n.dshm-shell table{display:block;max-width:100%;overflow-x:auto}\n.dshm-shell pre{max-width:100%;overflow-x:auto}\n.dshm-shell img,.dshm-shell video,.dshm-shell canvas,.dshm-shell svg{max-width:100%}\n.dshm-shell [data-disclosure-row]{min-width:0;max-width:100%}\n.dshm-shell [data-disclosure-row]>*{min-width:0;overflow-wrap:anywhere}\n.dshm-shell [data-context-fields]>*{min-width:0}\n.dshm-shell [class*=\"_body\"]{max-width:100%;overflow-wrap:anywhere}\n@media(max-width:420px){.dshm-shell [data-context-fields]>*{display:grid;grid-template-columns:1fr!important;gap:4px}.dshm-shell [class*=\"_ioSection\"]{grid-template-columns:1fr!important}}\n@media(prefers-reduced-motion:reduce){.dshm-drawer,.dshm-details,.dshm-scrim{transition:none!important}}\n`\n\nfunction icon(paths: readonly string[]): ReactNode {\n return createElement('svg', { 'aria-hidden': true, viewBox: '0 0 24 24' },\n ...paths.map((path, index) => createElement('path', { d: path, key: index })))\n}\n\nfunction MobileAppFrame(props: MobileRootProps & { readonly controller: MobileLayoutController }): ReactNode {\n const state = useSyncExternalStore(props.controller.subscribe, props.controller.getSnapshot)\n const hasSession = props.useSessions(session => {\n const current = session.current\n return current !== undefined && session.byId[current]?.blank === false\n })\n\n useEffect(() => {\n if (!hasSession) props.controller.closeDetails()\n }, [hasSession, props.controller])\n\n const closeDrawerAfterAction = (event: { readonly target: EventTarget | null; readonly currentTarget: EventTarget & HTMLElement }): void => {\n if (!(event.target instanceof Element)) return\n const action = event.target.closest('button,a,[role=\"button\"],[role=\"option\"],[role=\"treeitem\"]')\n if (action === null || action.closest('[data-dshm-keep-open],[aria-haspopup=\"dialog\"]') !== null) return\n window.setTimeout(() => { props.controller.closeSidebar() }, 80)\n }\n\n return createElement('div', { className: 'dshm-shell' },\n createElement('main', { className: 'dshm-main' }, props.renderSlot('conversation', {})),\n createElement('button', {\n 'aria-expanded': state.sidebarOpen,\n 'aria-label': state.sidebarOpen ? '关闭导航' : '打开导航',\n className: 'dshm-menu',\n onClick: () => { props.controller.toggleSidebar() },\n type: 'button',\n }, icon(['M4 6h16', 'M4 12h16', 'M4 18h16'])),\n createElement('button', {\n 'aria-label': '关闭浮层',\n className: 'dshm-scrim',\n 'data-open': state.sidebarOpen || state.detailsOpen,\n onClick: () => { state.detailsOpen ? props.controller.closeDetails() : props.controller.closeSidebar() },\n tabIndex: state.sidebarOpen || state.detailsOpen ? 0 : -1,\n type: 'button',\n }),\n createElement('aside', {\n 'aria-hidden': !state.sidebarOpen,\n className: 'dshm-drawer',\n 'data-open': state.sidebarOpen,\n onClickCapture: closeDrawerAfterAction,\n ...(state.sidebarOpen ? {} : { inert: '' }),\n }, props.renderSlot('sidebar', { collapsed: false, width: 340 })),\n createElement('aside', {\n 'aria-hidden': !state.detailsOpen,\n className: 'dshm-details',\n 'data-open': state.detailsOpen,\n ...(state.detailsOpen ? {} : { inert: '' }),\n }, hasSession ? props.renderSlot('details', {}) : undefined),\n createElement('div', { className: 'dshm-overlay', 'data-shell-overlay': true }, props.renderSlot('shell.overlay', {})),\n )\n}\n\n/** Replace the desktop layout module on the authenticated mobile surface. */\nexport function apply(ctx: MobileClientContext): void {\n const controller = new MobileLayoutController()\n ctx.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = 'dsh-mobile-layout'\n style.textContent = MOBILE_LAYOUT_STYLES\n document.head.append(style)\n const disposeService = ctx.reflect.provide('layout', controller)\n const disposeRoot = ctx.slots.register({\n name: 'root',\n children: {\n sidebar: { kind: 'single', scope: 'root' },\n conversation: { kind: 'single', scope: 'session-maybe' },\n details: { kind: 'single', scope: 'session' },\n 'shell.overlay': { kind: 'list', scope: 'root' },\n },\n }, props => createElement(MobileAppFrame, { ...props, controller }))\n return () => {\n disposeRoot()\n void disposeService()\n style.remove()\n }\n }, 'dsh-mobile: dedicated root layout')\n\n ctx.effect(() => {\n const presenter = new ThemePresenter()\n presenter.apply(ctx.theme.getTheme())\n const off = ctx.on('theme/change', snapshot => { presenter.apply(snapshot) })\n return () => { off(); presenter.dispose() }\n }, 'dsh-mobile: theme presenter')\n}\n\n/** Preserve the official layout module's dependency ordering. */\nexport const inject: readonly string[] = ['slots', 'theme']\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"mobile-layout.js","names":["useSyncExternalStore","useRef","createElement"],"sources":["../src/mobile-layout.ts"],"sourcesContent":["import { createElement, useEffect, useRef, useSyncExternalStore } from 'react'\nimport type { ReactNode } from 'react'\n\ninterface SessionState {\n readonly current?: string\n readonly byId: Readonly<Record<string, { readonly blank?: boolean } | undefined>>\n}\n\ninterface MobileRootProps {\n readonly renderSlot: (name: string, owner: Record<string, unknown>) => ReactNode\n readonly useSessions: <T>(selector: (state: SessionState) => T) => T\n}\n\ninterface MobileClientContext {\n readonly effect: (effect: () => void | (() => void), label?: string) => void\n readonly on: (event: string, listener: (value: ThemeSnapshot) => void) => () => void\n readonly reflect: { provide: (name: string, value: unknown) => () => void | Promise<void> }\n readonly slots: {\n register: (options: Record<string, unknown>, component: (props: MobileRootProps) => ReactNode) => () => void\n }\n readonly theme: { getTheme: () => ThemeSnapshot }\n}\n\ninterface ThemeSnapshot {\n readonly active: {\n readonly colorScheme: 'dark' | 'light'\n readonly tokens: Readonly<Record<string, string>>\n }\n}\n\ninterface LayoutSnapshot {\n readonly sidebarOpen: boolean\n readonly detailsOpen: boolean\n}\n\nclass MobileLayoutController {\n private snapshot: LayoutSnapshot = Object.freeze({ sidebarOpen: false, detailsOpen: false })\n private readonly listeners = new Set<() => void>()\n\n readonly subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener)\n return () => { this.listeners.delete(listener) }\n }\n\n readonly getSnapshot = (): LayoutSnapshot => this.snapshot\n\n toggleSidebar(): void {\n this.update({ sidebarOpen: !this.snapshot.sidebarOpen })\n }\n\n openDetails(): void {\n this.update({ detailsOpen: true })\n }\n\n closeDetails(): void {\n this.update({ detailsOpen: false })\n }\n\n closeSidebar(): void {\n this.update({ sidebarOpen: false })\n }\n\n private update(next: Partial<LayoutSnapshot>): void {\n const snapshot = Object.freeze({ ...this.snapshot, ...next })\n if (snapshot.sidebarOpen === this.snapshot.sidebarOpen && snapshot.detailsOpen === this.snapshot.detailsOpen) return\n this.snapshot = snapshot\n for (const listener of this.listeners) listener()\n }\n}\n\nclass ThemePresenter {\n private appliedTokens: string[] = []\n private readonly meta = document.createElement('meta')\n\n constructor() {\n this.meta.name = 'theme-color'\n }\n\n apply(snapshot: ThemeSnapshot): void {\n const scheme = snapshot.active.colorScheme\n document.documentElement.style.colorScheme = scheme\n document.body.toggleAttribute('data-ds-dark-theme', scheme === 'dark')\n for (const name of this.appliedTokens) document.body.style.removeProperty(name)\n this.appliedTokens = []\n for (const [name, value] of Object.entries(snapshot.active.tokens)) {\n document.body.style.setProperty(name, value)\n this.appliedTokens.push(name)\n }\n this.meta.content = getComputedStyle(document.body).backgroundColor\n if (!this.meta.isConnected) document.head.append(this.meta)\n }\n\n dispose(): void {\n document.documentElement.style.removeProperty('color-scheme')\n document.body.removeAttribute('data-ds-dark-theme')\n for (const name of this.appliedTokens) document.body.style.removeProperty(name)\n this.meta.remove()\n }\n}\n\nconst MOBILE_LAYOUT_STYLES = `\nhtml,body,#root{width:100%;height:100%;overflow:hidden}\n.dshm-shell{position:relative;display:grid;width:100%;height:100dvh;min-width:0;overflow:hidden;background:var(--dsw-alias-bg-base,#fff)}\n.dshm-main{grid-area:1/1;min-width:0;min-height:0;overflow:hidden}\n.dshm-main>*,.dshm-main>*>*{min-width:0}\n.dshm-drawer{position:fixed;z-index:70;inset:0 auto 0 0;box-sizing:border-box;width:56px;max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#f8fafc);box-shadow:none;transition:width 190ms cubic-bezier(.22,1,.36,1)}\n.dshm-drawer[data-open=true]{width:min(88vw,340px);box-shadow:18px 0 46px rgb(15 23 42 / 18%)}\n.dshm-drawer[data-open=false]{pointer-events:auto;visibility:visible}\n.dshm-drawer>*{width:100%!important;height:100%!important}\n.dshm-drawer[data-open=false]>*{width:56px!important}\n.dshm-details{position:fixed;z-index:80;inset:0 0 0 auto;box-sizing:border-box;width:min(94vw,460px);max-width:100%;padding-top:env(safe-area-inset-top);overflow:hidden;background:var(--dsw-alias-bg-layer-1,#fff);box-shadow:-18px 0 46px rgb(15 23 42 / 18%);transform:translateX(104%);transition:transform 190ms cubic-bezier(.22,1,.36,1)}\n.dshm-details[data-open=true]{transform:translateX(0)}\n.dshm-details[data-open=false]{pointer-events:none;visibility:hidden;transition:transform 190ms cubic-bezier(.22,1,.36,1),visibility 0s linear 190ms}\n.dshm-scrim{position:fixed;z-index:65;inset:0;border:0;background:rgb(15 23 42 / 40%);opacity:0;pointer-events:none;transition:opacity 180ms ease-out}\n.dshm-scrim[data-open=true]{opacity:1;pointer-events:auto}\n.dshm-overlay{position:fixed;z-index:90;inset:0;pointer-events:none}.dshm-overlay>*{pointer-events:auto}\n.dshm-shell header{min-width:0;padding-left:52px}\n.dshm-shell textarea{font-size:16px}\n.dshm-shell table{display:block;max-width:100%;overflow-x:auto}\n.dshm-shell pre{max-width:100%;overflow-x:auto}\n.dshm-shell img,.dshm-shell video,.dshm-shell canvas,.dshm-shell svg{max-width:100%}\n.dshm-shell [data-disclosure-row]{min-width:0;max-width:100%}\n.dshm-shell [data-disclosure-row]>*{min-width:0;overflow-wrap:anywhere}\n.dshm-shell [data-context-fields]>*{min-width:0}\n.dshm-shell [class*=\"_body\"]{max-width:100%;overflow-wrap:anywhere}\n@media(max-width:420px){.dshm-shell [data-context-fields]>*{display:grid;grid-template-columns:1fr!important;gap:4px}.dshm-shell [class*=\"_ioSection\"]{grid-template-columns:1fr!important}}\n@media(prefers-reduced-motion:reduce){.dshm-drawer,.dshm-details,.dshm-scrim{transition:none!important}}\n`\n\nfunction MobileAppFrame(props: MobileRootProps & { readonly controller: MobileLayoutController }): ReactNode {\n const state = useSyncExternalStore(props.controller.subscribe, props.controller.getSnapshot)\n const suppressKeyboardUntil = useRef(0)\n const hasSession = props.useSessions(session => {\n const current = session.current\n return current !== undefined && session.byId[current]?.blank === false\n })\n\n useEffect(() => {\n if (!hasSession) props.controller.closeDetails()\n }, [hasSession, props.controller])\n\n useEffect(() => {\n const suppressAutofocus = (event: FocusEvent): void => {\n if (performance.now() >= suppressKeyboardUntil.current) return\n const target = event.target\n if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) target.blur()\n }\n document.addEventListener('focusin', suppressAutofocus, true)\n return () => { document.removeEventListener('focusin', suppressAutofocus, true) }\n }, [])\n\n const closeDrawerAfterSessionAction = (event: { readonly target: EventTarget | null }): void => {\n if (!(event.target instanceof Element)) return\n const row = event.target.closest<HTMLElement>('[role=\"treeitem\"][aria-selected]')\n const action = event.target.closest('button,[role=\"button\"]')\n const startsSession = action?.matches('button[class*=\"_newSession\"],button[class*=\"_brand\"]') ?? false\n if (row === null && !startsSession) return\n if (row !== null && action !== null && action !== row) return\n suppressKeyboardUntil.current = performance.now() + 500\n // Let the session row finish its own click handler before unmounting the drawer.\n window.setTimeout(() => {\n props.controller.closeSidebar()\n const active = document.activeElement\n if (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) active.blur()\n }, 0)\n }\n\n return createElement('div', { className: 'dshm-shell' },\n createElement('main', { className: 'dshm-main' }, props.renderSlot('conversation', {})),\n createElement('button', {\n 'aria-label': '关闭浮层',\n className: 'dshm-scrim',\n 'data-open': state.sidebarOpen || state.detailsOpen,\n onClick: () => { state.detailsOpen ? props.controller.closeDetails() : props.controller.closeSidebar() },\n tabIndex: state.sidebarOpen || state.detailsOpen ? 0 : -1,\n type: 'button',\n }),\n createElement('aside', {\n 'aria-label': '工作区与会话导航',\n className: 'dshm-drawer',\n 'data-open': state.sidebarOpen,\n onClickCapture: closeDrawerAfterSessionAction,\n }, props.renderSlot('sidebar', {\n collapsed: !state.sidebarOpen,\n width: state.sidebarOpen ? 340 : 56,\n })),\n createElement('aside', {\n 'aria-hidden': !state.detailsOpen,\n className: 'dshm-details',\n 'data-open': state.detailsOpen,\n ...(state.detailsOpen ? {} : { inert: '' }),\n }, hasSession ? props.renderSlot('details', {}) : undefined),\n createElement('div', { className: 'dshm-overlay', 'data-shell-overlay': true }, props.renderSlot('shell.overlay', {})),\n )\n}\n\n/** Replace the desktop layout module on the authenticated mobile surface. */\nexport function apply(ctx: MobileClientContext): void {\n const controller = new MobileLayoutController()\n ctx.effect(() => {\n const style = document.createElement('style')\n style.dataset.plugin = 'dsh-mobile-layout'\n style.textContent = MOBILE_LAYOUT_STYLES\n document.head.append(style)\n const disposeService = ctx.reflect.provide('layout', controller)\n const disposeRoot = ctx.slots.register({\n name: 'root',\n children: {\n sidebar: { kind: 'single', scope: 'root' },\n conversation: { kind: 'single', scope: 'session-maybe' },\n details: { kind: 'single', scope: 'session' },\n 'shell.overlay': { kind: 'list', scope: 'root' },\n },\n }, props => createElement(MobileAppFrame, { ...props, controller }))\n return () => {\n disposeRoot()\n void disposeService()\n style.remove()\n }\n }, 'dsh-mobile: dedicated root layout')\n\n ctx.effect(() => {\n const presenter = new ThemePresenter()\n presenter.apply(ctx.theme.getTheme())\n const off = ctx.on('theme/change', snapshot => { presenter.apply(snapshot) })\n return () => { off(); presenter.dispose() }\n }, 'dsh-mobile: theme presenter')\n}\n\n/** Preserve the official layout module's dependency ordering. */\nexport const inject: readonly string[] = ['slots', 'theme']\n"],"mappings":"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"}
|