@skillbuilder/miniapp-simulator 0.0.0-beta-20261023084421

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.
Files changed (220) hide show
  1. package/README.md +214 -0
  2. package/assets/phones/Nexus-5X.png +0 -0
  3. package/assets/phones/iPhone-14ProMax.png +0 -0
  4. package/assets/rednote-preview/cover/homebar-1439.jpg +0 -0
  5. package/assets/rednote-preview/cover/homebar-1679.jpg +0 -0
  6. package/assets/rednote-preview/cover/homebar-1919.jpg +0 -0
  7. package/assets/rednote-preview/cover/homebar-2284.jpg +0 -0
  8. package/assets/rednote-preview/cover/homebar-2285.jpg +0 -0
  9. package/assets/rednote-preview/cover/like.png +0 -0
  10. package/assets/rednote-preview/cover/play.png +0 -0
  11. package/assets/rednote-preview/cover/topbar-1439.jpg +0 -0
  12. package/assets/rednote-preview/cover/topbar-1679.jpg +0 -0
  13. package/assets/rednote-preview/cover/topbar-1919.jpg +0 -0
  14. package/assets/rednote-preview/cover/topbar-2284.jpg +0 -0
  15. package/assets/rednote-preview/cover/topbar-2285.jpg +0 -0
  16. package/assets/workbench/index.html +77 -0
  17. package/dist/sw/miniapp-simulator-service-worker.js +855 -0
  18. package/dist/sw/miniapp-simulator-service-worker.min.js +1 -0
  19. package/docs/consumer-guide.md +143 -0
  20. package/docs/electron-review.md +21 -0
  21. package/docs/external-cli-workbench.md +197 -0
  22. package/docs/file-system-design.md +334 -0
  23. package/docs/host-external-api.md +235 -0
  24. package/docs/iframe-service-worker.md +190 -0
  25. package/docs/local-dev.md +106 -0
  26. package/docs/npm-integration-verification.md +45 -0
  27. package/docs/remote-architecture.md +403 -0
  28. package/docs/remote-load-observability.md +268 -0
  29. package/docs/remote-usage.md +371 -0
  30. package/docs/request-design.md +247 -0
  31. package/docs/sdk-usage.md +260 -0
  32. package/docs/server-playground-https-debugging.md +150 -0
  33. package/docs/storage-api-design.md +275 -0
  34. package/docs/tracker.md +339 -0
  35. package/lib/business-line-CMb3ehRn.mjs +15 -0
  36. package/lib/client-BZtD2VtP.mjs +772 -0
  37. package/lib/index-BW85h7kT.mjs +505 -0
  38. package/lib/index.js +10686 -0
  39. package/lib/preload/webview-preload.js +37 -0
  40. package/lib/remote-client.js +11 -0
  41. package/lib/types/business-line.d.ts +7 -0
  42. package/lib/types/capabilities/constants.d.ts +28 -0
  43. package/lib/types/capabilities/csp-snippet.d.ts +32 -0
  44. package/lib/types/capabilities/launch-options.d.ts +7 -0
  45. package/lib/types/capabilities/performance-policy.d.ts +5 -0
  46. package/lib/types/capabilities/security-head-snippet.d.ts +20 -0
  47. package/lib/types/capabilities/security.d.ts +25 -0
  48. package/lib/types/capabilities/style-snippet.d.ts +2 -0
  49. package/lib/types/core/controllers/game-playtest.d.ts +9 -0
  50. package/lib/types/core/controllers/gesture.d.ts +8 -0
  51. package/lib/types/core/controllers/host-api.d.ts +19 -0
  52. package/lib/types/core/controllers/index.d.ts +11 -0
  53. package/lib/types/core/controllers/inspector.d.ts +20 -0
  54. package/lib/types/core/controllers/note-preview.d.ts +9 -0
  55. package/lib/types/core/controllers/permission-sheet.d.ts +7 -0
  56. package/lib/types/core/controllers/widget-cover.d.ts +12 -0
  57. package/lib/types/core/lifecycle.d.ts +7 -0
  58. package/lib/types/core/options.d.ts +33 -0
  59. package/lib/types/core/simulator.d.ts +9 -0
  60. package/lib/types/errors.d.ts +11 -0
  61. package/lib/types/event-bus.d.ts +15 -0
  62. package/lib/types/gesture/host-bus.d.ts +113 -0
  63. package/lib/types/gesture/index.d.ts +27 -0
  64. package/lib/types/gesture/plugins/double-tap.d.ts +10 -0
  65. package/lib/types/gesture/plugins/index.d.ts +27 -0
  66. package/lib/types/gesture/plugins/long-press.d.ts +13 -0
  67. package/lib/types/gesture/plugins/multi-touch-hint.d.ts +11 -0
  68. package/lib/types/gesture/plugins/multi-touch-switch.d.ts +18 -0
  69. package/lib/types/gesture/plugins/selection-disabler.d.ts +11 -0
  70. package/lib/types/gesture/plugins/tap.d.ts +11 -0
  71. package/lib/types/gesture/plugins/touch-emitter.d.ts +11 -0
  72. package/lib/types/gesture/plugins/wheel-scroll.d.ts +11 -0
  73. package/lib/types/gesture/receiver-runtime.d.ts +10 -0
  74. package/lib/types/gesture/receiver-runtime.impl.d.ts +6 -0
  75. package/lib/types/gesture/touch-cursor.d.ts +78 -0
  76. package/lib/types/gesture/touch-dot.d.ts +12 -0
  77. package/lib/types/gesture/types.d.ts +206 -0
  78. package/lib/types/host/shadow-host.d.ts +40 -0
  79. package/lib/types/index.d.ts +49 -0
  80. package/lib/types/injection/guest-log-mark.d.ts +7 -0
  81. package/lib/types/injection/head-builder.d.ts +4 -0
  82. package/lib/types/injection/index.d.ts +19 -0
  83. package/lib/types/injection/modules/console-forward.d.ts +2 -0
  84. package/lib/types/injection/modules/gesture.d.ts +6 -0
  85. package/lib/types/injection/modules/inspector-guest-runtime.d.ts +5 -0
  86. package/lib/types/injection/modules/inspector-pause-runtime.d.ts +6 -0
  87. package/lib/types/injection/modules/inspector.d.ts +8 -0
  88. package/lib/types/injection/modules/jsapi-channel.d.ts +9 -0
  89. package/lib/types/injection/modules/jsapi.d.ts +22 -0
  90. package/lib/types/injection/modules/render-done.d.ts +2 -0
  91. package/lib/types/injection/modules/resource-guard.d.ts +7 -0
  92. package/lib/types/injection/modules/scroll-containment.d.ts +3 -0
  93. package/lib/types/injection/modules/security.d.ts +3 -0
  94. package/lib/types/injection/modules/widget-snapshot.d.ts +13 -0
  95. package/lib/types/injection/preload-builder.d.ts +41 -0
  96. package/lib/types/injection/registry.d.ts +20 -0
  97. package/lib/types/injection/types.d.ts +43 -0
  98. package/lib/types/inspector/host-inspector.d.ts +108 -0
  99. package/lib/types/inspector/index.d.ts +8 -0
  100. package/lib/types/inspector/selector.d.ts +18 -0
  101. package/lib/types/native-ui/devtools/CapabilitiesView.d.ts +18 -0
  102. package/lib/types/native-ui/devtools/DevtoolsPanel.d.ts +24 -0
  103. package/lib/types/native-ui/devtools/LogsView.d.ts +17 -0
  104. package/lib/types/native-ui/devtools/dom.d.ts +40 -0
  105. package/lib/types/native-ui/devtools/index.d.ts +19 -0
  106. package/lib/types/native-ui/devtools/log-entry.d.ts +8 -0
  107. package/lib/types/native-ui/devtools/shortcut.d.ts +12 -0
  108. package/lib/types/native-ui/devtools/tokens.d.ts +14 -0
  109. package/lib/types/native-ui/devtools/types.d.ts +51 -0
  110. package/lib/types/native-ui/index.d.ts +17 -0
  111. package/lib/types/native-ui/note-publish/defaults.d.ts +40 -0
  112. package/lib/types/native-ui/note-publish/index.d.ts +2 -0
  113. package/lib/types/native-ui/note-publish/miniapp-note-publish.d.ts +15 -0
  114. package/lib/types/native-ui/note-publish/note-publish-host.d.ts +15 -0
  115. package/lib/types/native-ui/note-publish/view-data.d.ts +21 -0
  116. package/lib/types/native-ui/permission-sheet/defaults.d.ts +12 -0
  117. package/lib/types/native-ui/permission-sheet/index.d.ts +4 -0
  118. package/lib/types/native-ui/permission-sheet/miniapp-permission-sheet.d.ts +19 -0
  119. package/lib/types/native-ui/permission-sheet/permission-sheet-host.d.ts +23 -0
  120. package/lib/types/native-ui/permission-sheet/types.d.ts +8 -0
  121. package/lib/types/native-ui/rednote-preview/chrome-tone.d.ts +44 -0
  122. package/lib/types/native-ui/rednote-preview/defaults.d.ts +30 -0
  123. package/lib/types/native-ui/rednote-preview/half-sheet-drag.d.ts +61 -0
  124. package/lib/types/native-ui/rednote-preview/index.d.ts +2 -0
  125. package/lib/types/native-ui/rednote-preview/register.d.ts +7 -0
  126. package/lib/types/native-ui/rednote-preview/styles.d.ts +4 -0
  127. package/lib/types/native-ui/rednote-preview/xhs-note-detail-shell.d.ts +70 -0
  128. package/lib/types/native-ui/rednote-preview/xhs-note-half-sheet.d.ts +100 -0
  129. package/lib/types/native-ui/rednote-preview/xhs-profile-shell.d.ts +31 -0
  130. package/lib/types/native-ui/toast/frame-toast-host.d.ts +18 -0
  131. package/lib/types/native-ui/toast/index.d.ts +19 -0
  132. package/lib/types/presets.d.ts +11 -0
  133. package/lib/types/remote/client.d.ts +89 -0
  134. package/lib/types/remote/jsapi-config.d.ts +9 -0
  135. package/lib/types/remote/load-timing.d.ts +46 -0
  136. package/lib/types/remote/protocol.d.ts +160 -0
  137. package/lib/types/remote/review-launch.d.ts +6 -0
  138. package/lib/types/remote/runtime-entry.d.ts +1 -0
  139. package/lib/types/remote/runtime.d.ts +14 -0
  140. package/lib/types/remote/simulator-prompt.d.ts +9 -0
  141. package/lib/types/remote/widget-snapshot-guest-runtime.d.ts +1 -0
  142. package/lib/types/remote-client.d.ts +5 -0
  143. package/lib/types/renderer/base.d.ts +8 -0
  144. package/lib/types/renderer/content-host/iframe-content-host.d.ts +83 -0
  145. package/lib/types/renderer/content-host/index.d.ts +3 -0
  146. package/lib/types/renderer/content-host/types.d.ts +89 -0
  147. package/lib/types/renderer/content-host/webview-content-host.d.ts +53 -0
  148. package/lib/types/renderer/iframe.d.ts +93 -0
  149. package/lib/types/renderer/index.d.ts +2 -0
  150. package/lib/types/renderer/rednote-shell.d.ts +73 -0
  151. package/lib/types/renderer/webview.d.ts +59 -0
  152. package/lib/types/runtime/context.d.ts +31 -0
  153. package/lib/types/runtime/jsapi-modules/context.d.ts +19 -0
  154. package/lib/types/runtime/jsapi-modules/filesystem.d.ts +19 -0
  155. package/lib/types/runtime/jsapi-modules/index.d.ts +9 -0
  156. package/lib/types/runtime/jsapi-modules/interaction.d.ts +4 -0
  157. package/lib/types/runtime/jsapi-modules/location.d.ts +3 -0
  158. package/lib/types/runtime/jsapi-modules/media.d.ts +13 -0
  159. package/lib/types/runtime/jsapi-modules/network.d.ts +3 -0
  160. package/lib/types/runtime/jsapi-modules/storage.d.ts +26 -0
  161. package/lib/types/runtime/jsapi-modules/system.d.ts +4 -0
  162. package/lib/types/runtime/jsapi-modules/types.d.ts +21 -0
  163. package/lib/types/runtime/jsapi-modules/window-info.d.ts +43 -0
  164. package/lib/types/runtime/request/host-request.d.ts +13 -0
  165. package/lib/types/runtime/request/request-manager-frame.d.ts +29 -0
  166. package/lib/types/runtime/request/request-runtime.d.ts +26 -0
  167. package/lib/types/runtime/request/request-types.d.ts +26 -0
  168. package/lib/types/runtime/request/sse-text-framer.d.ts +16 -0
  169. package/lib/types/seal-config.d.ts +134 -0
  170. package/lib/types/sw/index.d.ts +9 -0
  171. package/lib/types/sw/parse-raw.d.ts +34 -0
  172. package/lib/types/sw/protocol.d.ts +17 -0
  173. package/lib/types/sw/served-entry.d.ts +9 -0
  174. package/lib/types/sw/service-worker-content-host.d.ts +11 -0
  175. package/lib/types/sw/service-worker-host.d.ts +73 -0
  176. package/lib/types/sw/service-worker-renderer.d.ts +10 -0
  177. package/lib/types/sw/worker/fs-codec.d.ts +23 -0
  178. package/lib/types/sw/worker/fs-ops.d.ts +22 -0
  179. package/lib/types/sw/worker/fs-store.d.ts +29 -0
  180. package/lib/types/sw/worker/globals.d.ts +49 -0
  181. package/lib/types/sw/worker/main.d.ts +6 -0
  182. package/lib/types/sw/worker/mime.d.ts +2 -0
  183. package/lib/types/sw/worker/mount-store.d.ts +43 -0
  184. package/lib/types/sw/worker/paths.d.ts +4 -0
  185. package/lib/types/sw/worker/serve.d.ts +13 -0
  186. package/lib/types/tracker/constants.d.ts +14 -0
  187. package/lib/types/tracker/default-tracker.d.ts +19 -0
  188. package/lib/types/tracker/index.d.ts +70 -0
  189. package/lib/types/transport/bridge-protocol.d.ts +78 -0
  190. package/lib/types/transport/iframe-transport.d.ts +39 -0
  191. package/lib/types/transport/index.d.ts +14 -0
  192. package/lib/types/transport/jsapi-bridge-messages.d.ts +36 -0
  193. package/lib/types/transport/types.d.ts +48 -0
  194. package/lib/types/transport/webview-transport.d.ts +52 -0
  195. package/lib/types/types/events.d.ts +130 -0
  196. package/lib/types/types/index.d.ts +11 -0
  197. package/lib/types/types/inspector.d.ts +172 -0
  198. package/lib/types/types/jsapi.d.ts +18 -0
  199. package/lib/types/types/options.d.ts +844 -0
  200. package/lib/types/types/renderer.d.ts +145 -0
  201. package/lib/types/utils/ancestor-scroll.d.ts +11 -0
  202. package/lib/types/utils/error-svg.d.ts +12 -0
  203. package/lib/types/utils/frameless-shell.d.ts +114 -0
  204. package/lib/types/utils/miniapp-chrome-svg.d.ts +47 -0
  205. package/lib/types/utils/package-constants.d.ts +8 -0
  206. package/lib/types/utils/screenshot.d.ts +14 -0
  207. package/lib/types/utils/simulator-pc-guard.d.ts +10 -0
  208. package/lib/types/utils/stage-fit.d.ts +6 -0
  209. package/lib/types/utils/touch-emulate.d.ts +26 -0
  210. package/lib/types/utils/zip-entry.d.ts +13 -0
  211. package/lib/types/workbench/index.d.ts +63 -0
  212. package/lib/types/workbench/preview-transition.d.ts +8 -0
  213. package/lib/types/workbench/server/artifact.d.ts +8 -0
  214. package/lib/types/workbench/server/index.d.ts +19 -0
  215. package/lib/types/workbench/server/watch.d.ts +6 -0
  216. package/lib/types/workbench/view.d.ts +36 -0
  217. package/lib/workbench-server.mjs +183 -0
  218. package/lib/workbench.js +1404 -0
  219. package/package.json +63 -0
  220. package/scripts/mock-cli-dev.mjs +52 -0
@@ -0,0 +1,1404 @@
1
+ import { c as Mn } from "./client-BZtD2VtP.mjs";
2
+ function Sn(a, i) {
3
+ const e = /* @__PURE__ */ new Map();
4
+ let v = 0, l = !1, w, b, L, m, u;
5
+ const C = (s) => {
6
+ a.classList.toggle("is-visible", s), a.setAttribute("aria-hidden", String(!s)), i.setAttribute("aria-busy", String(s)), i.inert = s;
7
+ }, y = () => (m ?? (m = new Promise((s) => {
8
+ u = () => {
9
+ b !== void 0 && window.cancelAnimationFrame(b), window.clearTimeout(L), L = void 0, b = void 0, m = void 0, u = void 0, s();
10
+ }, b = window.requestAnimationFrame(() => {
11
+ b = window.requestAnimationFrame(() => u?.());
12
+ }), L = window.setTimeout(() => u?.(), 80);
13
+ })), m);
14
+ return {
15
+ isActive: (s) => e.has(s),
16
+ async run(s, z) {
17
+ if (l) return;
18
+ const k = ++v;
19
+ e.set(s, k), window.clearTimeout(w), C(!0);
20
+ try {
21
+ await y(), !l && e.get(s) === k && await z();
22
+ } finally {
23
+ !l && e.get(s) === k && (e.delete(s), e.size === 0 && (w = window.setTimeout(() => {
24
+ w = void 0, C(!1);
25
+ }, 100)));
26
+ }
27
+ },
28
+ destroy() {
29
+ l = !0, e.clear(), window.clearTimeout(w), b !== void 0 && window.cancelAnimationFrame(b), u?.(), C(!1);
30
+ }
31
+ };
32
+ }
33
+ const Ln = `:host {
34
+ --wb-page: #fbfbfc;
35
+ --wb-surface: rgba(255, 255, 255, 0.9);
36
+ --wb-surface-strong: #ffffff;
37
+ --wb-surface-muted: #f4f4f6;
38
+ --wb-text: #27262b;
39
+ --wb-text-secondary: #696771;
40
+ --wb-text-muted: #9a98a2;
41
+ --wb-border: rgba(35, 32, 45, 0.1);
42
+ --wb-border-strong: rgba(35, 32, 45, 0.16);
43
+ --wb-accent: #8068f5;
44
+ --wb-accent-soft: #e6e0ff;
45
+ --wb-success: #21a675;
46
+ --wb-warning: #d59022;
47
+ --wb-danger: #d84a61;
48
+ display: block;
49
+ width: 100%;
50
+ height: 100%;
51
+ min-width: 0;
52
+ min-height: 0;
53
+ color: var(--wb-text);
54
+ font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
55
+ sans-serif;
56
+ -webkit-font-smoothing: antialiased;
57
+ }
58
+
59
+ * {
60
+ box-sizing: border-box;
61
+ }
62
+
63
+ button {
64
+ font: inherit;
65
+ }
66
+
67
+ button,
68
+ .view-pill,
69
+ .runtime-state {
70
+ -webkit-tap-highlight-color: transparent;
71
+ }
72
+
73
+ svg {
74
+ display: block;
75
+ fill: none;
76
+ stroke: currentColor;
77
+ stroke-linecap: round;
78
+ stroke-linejoin: round;
79
+ stroke-width: 1.65;
80
+ }
81
+
82
+ .workbench-shell {
83
+ display: flex;
84
+ width: 100%;
85
+ height: 100%;
86
+ min-width: 0;
87
+ min-height: 0;
88
+ flex-direction: column;
89
+ overflow: hidden;
90
+ background: var(--wb-page);
91
+ }
92
+
93
+ .workbench-header {
94
+ z-index: 30;
95
+ display: flex;
96
+ height: 58px;
97
+ min-height: 58px;
98
+ align-items: center;
99
+ justify-content: space-between;
100
+ gap: 20px;
101
+ padding: 0 18px;
102
+ border-top: 3px solid #28272a;
103
+ background: rgba(255, 255, 255, 0.86);
104
+ box-shadow: 0 1px 0 var(--wb-border);
105
+ backdrop-filter: blur(18px) saturate(1.15);
106
+ }
107
+
108
+ .view-navigation,
109
+ .header-actions,
110
+ .view-pill,
111
+ .runtime-state,
112
+ .header-button,
113
+ .device-switcher,
114
+ .device-switcher button,
115
+ .preview-dock,
116
+ .diagnostics-header,
117
+ .section-title {
118
+ display: flex;
119
+ align-items: center;
120
+ }
121
+
122
+ .view-navigation {
123
+ min-width: 0;
124
+ gap: 5px;
125
+ }
126
+
127
+ .view-pill,
128
+ .header-button,
129
+ .runtime-state,
130
+ .device-switcher,
131
+ .preview-dock {
132
+ border: 1px solid rgba(42, 38, 56, 0.09);
133
+ background: rgba(248, 248, 250, 0.68);
134
+ box-shadow: inset 0 1px 2px rgba(15, 12, 24, 0.1), inset 0 -0.5px 0 rgba(255, 255, 255, 0.8);
135
+ backdrop-filter: blur(18px) saturate(1.15);
136
+ }
137
+
138
+ .view-pill {
139
+ height: 34px;
140
+ gap: 7px;
141
+ padding: 0 13px;
142
+ border-radius: 999px;
143
+ color: var(--wb-accent);
144
+ font-size: 13px;
145
+ font-weight: 650;
146
+ letter-spacing: 0.01em;
147
+ }
148
+
149
+ .view-pill.is-active {
150
+ border-color: rgba(128, 104, 245, 0.25);
151
+ background: linear-gradient(180deg, rgba(226, 219, 255, 0.96), rgba(237, 233, 255, 0.86));
152
+ box-shadow: inset 0 0 0 0.5px rgba(128, 104, 245, 0.16), 0 2px 7px rgba(84, 64, 184, 0.09);
153
+ }
154
+
155
+ .view-pill svg,
156
+ .view-icon svg {
157
+ width: 15px;
158
+ height: 15px;
159
+ }
160
+
161
+ .view-icon {
162
+ display: grid;
163
+ width: 32px;
164
+ height: 32px;
165
+ place-items: center;
166
+ color: var(--wb-text-muted);
167
+ }
168
+
169
+ .project-name {
170
+ max-width: 240px;
171
+ overflow: hidden;
172
+ margin-left: 3px;
173
+ color: var(--wb-text-secondary);
174
+ font-size: 12px;
175
+ text-overflow: ellipsis;
176
+ white-space: nowrap;
177
+ }
178
+
179
+ .header-actions {
180
+ gap: 8px;
181
+ }
182
+
183
+ .runtime-state,
184
+ .header-button {
185
+ height: 34px;
186
+ border-radius: 999px;
187
+ color: var(--wb-text-secondary);
188
+ font-size: 12px;
189
+ font-weight: 570;
190
+ }
191
+
192
+ .runtime-state {
193
+ gap: 7px;
194
+ padding: 0 12px;
195
+ }
196
+
197
+ .runtime-state i {
198
+ width: 7px;
199
+ height: 7px;
200
+ border-radius: 50%;
201
+ background: var(--wb-warning);
202
+ box-shadow: 0 0 0 4px rgba(213, 144, 34, 0.1);
203
+ }
204
+
205
+ .runtime-state[data-tone="ready"] i {
206
+ background: var(--wb-success);
207
+ box-shadow: 0 0 0 4px rgba(33, 166, 117, 0.1);
208
+ }
209
+
210
+ .runtime-state[data-tone="error"] i {
211
+ background: var(--wb-danger);
212
+ box-shadow: 0 0 0 4px rgba(216, 74, 97, 0.1);
213
+ }
214
+
215
+ .header-button {
216
+ justify-content: center;
217
+ gap: 7px;
218
+ padding: 0 14px;
219
+ cursor: pointer;
220
+ transition: color 160ms ease, background 160ms ease, transform 160ms ease;
221
+ }
222
+
223
+ .header-button svg {
224
+ width: 15px;
225
+ height: 15px;
226
+ }
227
+
228
+ .header-button:hover {
229
+ background: rgba(242, 242, 245, 0.92);
230
+ color: var(--wb-text);
231
+ }
232
+
233
+ .header-button.is-active {
234
+ border-color: rgba(128, 104, 245, 0.2);
235
+ background: linear-gradient(180deg, rgba(229, 223, 255, 0.82), rgba(240, 237, 255, 0.72));
236
+ color: var(--wb-accent);
237
+ box-shadow: inset 0 0 0 0.5px rgba(128, 104, 245, 0.1), 0 2px 8px rgba(79, 59, 166, 0.08);
238
+ }
239
+
240
+ .header-button:active {
241
+ transform: scale(0.98);
242
+ }
243
+
244
+ .header-button:disabled {
245
+ cursor: wait;
246
+ opacity: 0.45;
247
+ }
248
+
249
+ .stage {
250
+ position: relative;
251
+ min-width: 0;
252
+ min-height: 0;
253
+ flex: 1;
254
+ overflow: hidden;
255
+ background: radial-gradient(circle at 50% 42%, #fff 0, rgba(255, 255, 255, 0.92) 28%, transparent 62%),
256
+ linear-gradient(180deg, #fbfbfc 0%, #f8f8fa 100%);
257
+ }
258
+
259
+ .stage::after {
260
+ position: absolute;
261
+ right: 0;
262
+ bottom: 0;
263
+ left: 0;
264
+ height: 120px;
265
+ background: linear-gradient(180deg, transparent, rgba(248, 248, 250, 0.82));
266
+ content: "";
267
+ pointer-events: none;
268
+ }
269
+
270
+ .preview-controls {
271
+ position: absolute;
272
+ z-index: 20;
273
+ top: 16px;
274
+ left: 50%;
275
+ display: flex;
276
+ width: max-content;
277
+ max-width: calc(100% - 32px);
278
+ flex-wrap: wrap;
279
+ align-items: center;
280
+ justify-content: center;
281
+ gap: 10px;
282
+ transform: translateX(-50%);
283
+ }
284
+
285
+ .scene-switcher {
286
+ display: flex;
287
+ height: 38px;
288
+ align-items: center;
289
+ gap: 2px;
290
+ padding: 3px;
291
+ border: 1px solid var(--wb-border);
292
+ border-radius: 999px;
293
+ background: rgba(248, 248, 250, 0.9);
294
+ box-shadow: inset 0 1px 2px rgba(15, 12, 24, 0.08);
295
+ }
296
+
297
+ .scene-switcher button {
298
+ height: 30px;
299
+ padding: 0 10px;
300
+ border: 0;
301
+ border-radius: 999px;
302
+ background: transparent;
303
+ color: var(--wb-text-secondary);
304
+ cursor: pointer;
305
+ font-size: 11px;
306
+ font-weight: 600;
307
+ white-space: nowrap;
308
+ transition: background 180ms ease, color 180ms ease, box-shadow 180ms ease;
309
+ }
310
+
311
+ .scene-switcher button.is-active {
312
+ background: var(--wb-accent-soft);
313
+ box-shadow: inset 0 0 0 1px rgba(128, 104, 245, 0.18);
314
+ color: var(--wb-accent);
315
+ }
316
+
317
+ .scene-switcher button:disabled {
318
+ cursor: progress;
319
+ opacity: 0.65;
320
+ }
321
+
322
+ .device-switcher {
323
+ position: relative;
324
+ display: block;
325
+ width: 166px;
326
+ height: 38px;
327
+ padding: 0;
328
+ overflow: hidden;
329
+ border-radius: 999px;
330
+ flex: 0 0 166px;
331
+ }
332
+
333
+ .device-switcher-indicator {
334
+ position: absolute;
335
+ z-index: 1;
336
+ top: 3px;
337
+ bottom: 3px;
338
+ left: 3px;
339
+ width: 92px;
340
+ border: 1px solid rgba(128, 104, 245, 0.2);
341
+ border-radius: 999px;
342
+ background: linear-gradient(180deg, rgba(221, 213, 255, 0.96), rgba(235, 230, 255, 0.88));
343
+ box-shadow: 0 1px 2px rgba(48, 36, 107, 0.12), inset 0 0.5px 0 rgba(255, 255, 255, 0.68),
344
+ inset 0 0 0 0.5px rgba(128, 104, 245, 0.12);
345
+ pointer-events: none;
346
+ transition: transform 320ms cubic-bezier(0.32, 0.72, 0, 1);
347
+ will-change: transform;
348
+ }
349
+
350
+ .device-switcher button {
351
+ position: absolute;
352
+ z-index: 2;
353
+ top: 3px;
354
+ height: 30px;
355
+ justify-content: center;
356
+ gap: 6px;
357
+ padding: 0;
358
+ border: 0;
359
+ border-radius: 999px;
360
+ background: transparent;
361
+ color: var(--wb-text-muted);
362
+ cursor: pointer;
363
+ font-size: 12px;
364
+ font-weight: 600;
365
+ outline: none;
366
+ transition: left 320ms cubic-bezier(0.32, 0.72, 0, 1),
367
+ width 320ms cubic-bezier(0.32, 0.72, 0, 1), color 170ms ease;
368
+ will-change: left, width;
369
+ }
370
+
371
+ .device-switcher button svg {
372
+ width: 15px;
373
+ height: 15px;
374
+ flex: 0 0 auto;
375
+ }
376
+
377
+ .device-switcher button span {
378
+ max-width: 0;
379
+ overflow: hidden;
380
+ margin-left: -6px;
381
+ opacity: 0;
382
+ transition: max-width 220ms ease, margin-left 220ms ease, opacity 140ms ease;
383
+ white-space: nowrap;
384
+ }
385
+
386
+ .device-switcher button:hover {
387
+ color: var(--wb-text-secondary);
388
+ }
389
+
390
+ .device-switcher button.is-active {
391
+ color: var(--wb-accent);
392
+ }
393
+
394
+ .device-switcher button.is-active span {
395
+ max-width: 58px;
396
+ margin-left: 0;
397
+ opacity: 1;
398
+ transition: max-width 250ms ease 30ms, margin-left 250ms ease 30ms, opacity 180ms ease 70ms;
399
+ }
400
+
401
+ .device-switcher button:focus-visible,
402
+ .scene-switcher button:focus-visible,
403
+ .header-button:focus-visible,
404
+ .preview-dock button:focus-visible,
405
+ .diagnostics-header button:focus-visible {
406
+ outline: 2px solid rgba(128, 104, 245, 0.28);
407
+ outline-offset: 2px;
408
+ }
409
+
410
+ .stage-canvas {
411
+ position: absolute;
412
+ inset: 0;
413
+ display: flex;
414
+ min-width: 0;
415
+ min-height: 0;
416
+ align-items: center;
417
+ justify-content: center;
418
+ overflow: auto;
419
+ padding: calc(var(--preview-controls-height, 38px) + 32px) 42px 82px;
420
+ scrollbar-width: none;
421
+ }
422
+
423
+ .stage-canvas::-webkit-scrollbar {
424
+ display: none;
425
+ }
426
+
427
+ .device-slot {
428
+ position: relative;
429
+ flex: 0 0 auto;
430
+ }
431
+
432
+ .device-shell {
433
+ position: absolute;
434
+ top: 0;
435
+ left: 0;
436
+ background: transparent;
437
+ transform: scale(var(--device-scale, 1));
438
+ transform-origin: top left;
439
+ transition: transform 180ms ease-out;
440
+ will-change: transform;
441
+ }
442
+
443
+ .preview {
444
+ position: relative;
445
+ overflow: hidden;
446
+ background: transparent;
447
+ }
448
+
449
+ .preview-transition {
450
+ position: absolute;
451
+ z-index: 12;
452
+ inset: 0;
453
+ display: grid;
454
+ place-items: center;
455
+ background: rgba(250, 250, 252, 0.6);
456
+ opacity: 0;
457
+ visibility: hidden;
458
+ pointer-events: none;
459
+ backdrop-filter: blur(6px);
460
+ -webkit-backdrop-filter: blur(6px);
461
+ transition: opacity 140ms ease, visibility 0s linear 140ms;
462
+ }
463
+
464
+ .preview-transition.is-visible {
465
+ opacity: 1;
466
+ visibility: visible;
467
+ pointer-events: auto;
468
+ transition-delay: 0s;
469
+ }
470
+
471
+ .preview-transition-label {
472
+ display: flex;
473
+ align-items: center;
474
+ gap: 9px;
475
+ padding: 11px 16px;
476
+ border: 1px solid rgba(128, 104, 245, 0.12);
477
+ border-radius: 999px;
478
+ background: rgba(255, 255, 255, 0.88);
479
+ box-shadow: 0 6px 24px rgba(45, 35, 80, 0.06);
480
+ color: var(--wb-text-secondary);
481
+ font-size: 12px;
482
+ }
483
+
484
+ .preview-transition-label i {
485
+ width: 12px;
486
+ height: 12px;
487
+ border: 1.5px solid var(--wb-accent-soft);
488
+ border-top-color: var(--wb-accent);
489
+ border-radius: 50%;
490
+ animation: wb-spin 800ms linear infinite;
491
+ }
492
+
493
+ .preview-dock {
494
+ position: absolute;
495
+ z-index: 25;
496
+ bottom: 19px;
497
+ left: 50%;
498
+ height: 45px;
499
+ gap: 2px;
500
+ padding: 4px;
501
+ border-radius: 999px;
502
+ transform: translateX(-50%);
503
+ }
504
+
505
+ .preview-dock button {
506
+ position: relative;
507
+ display: grid;
508
+ width: 36px;
509
+ height: 36px;
510
+ padding: 0;
511
+ border: 0;
512
+ border-radius: 50%;
513
+ background: transparent;
514
+ color: var(--wb-text-muted);
515
+ cursor: pointer;
516
+ outline: none;
517
+ place-items: center;
518
+ transition: color 160ms ease, background 160ms ease, transform 160ms ease;
519
+ }
520
+
521
+ .preview-dock button svg {
522
+ width: 16px;
523
+ height: 16px;
524
+ }
525
+
526
+ .preview-dock button:hover {
527
+ background: rgba(42, 39, 52, 0.07);
528
+ color: var(--wb-text);
529
+ }
530
+
531
+ .preview-dock button.is-active {
532
+ background: linear-gradient(180deg, rgba(221, 213, 255, 0.9), rgba(237, 233, 255, 0.78));
533
+ color: var(--wb-accent);
534
+ box-shadow: inset 0 0 0 0.5px rgba(128, 104, 245, 0.2), 0 2px 6px rgba(79, 59, 166, 0.08);
535
+ }
536
+
537
+ .preview-dock button.is-acknowledged {
538
+ animation: wb-dock-acknowledged 360ms cubic-bezier(0.22, 1, 0.36, 1);
539
+ }
540
+
541
+ .preview-dock button:active {
542
+ transform: scale(0.94);
543
+ }
544
+
545
+ .preview-dock button:disabled {
546
+ cursor: wait;
547
+ opacity: 0.35;
548
+ }
549
+
550
+ .preview-dock button[data-action="reload"]:disabled {
551
+ background: rgba(128, 104, 245, 0.1);
552
+ color: var(--wb-accent);
553
+ opacity: 1;
554
+ }
555
+
556
+ .preview-dock button[data-action="reload"]:disabled svg {
557
+ animation: wb-spin 760ms linear infinite;
558
+ }
559
+
560
+ .preview-dock button::after {
561
+ position: absolute;
562
+ bottom: calc(100% + 8px);
563
+ left: 50%;
564
+ padding: 5px 8px;
565
+ border: 1px solid var(--wb-border);
566
+ border-radius: 7px;
567
+ background: rgba(255, 255, 255, 0.94);
568
+ box-shadow: 0 5px 16px rgba(24, 22, 32, 0.1);
569
+ color: var(--wb-text-secondary);
570
+ content: attr(data-tooltip);
571
+ font-size: 10px;
572
+ opacity: 0;
573
+ pointer-events: none;
574
+ transform: translate(-50%, 2px);
575
+ transition: opacity 120ms ease, transform 120ms ease;
576
+ white-space: nowrap;
577
+ }
578
+
579
+ .preview-dock button:hover::after,
580
+ .preview-dock button:focus-visible::after {
581
+ opacity: 1;
582
+ transform: translate(-50%, 0);
583
+ }
584
+
585
+ .diagnostics-panel {
586
+ position: absolute;
587
+ z-index: 40;
588
+ top: 14px;
589
+ right: 14px;
590
+ bottom: 14px;
591
+ display: flex;
592
+ width: min(336px, calc(100% - 28px));
593
+ min-height: 0;
594
+ flex-direction: column;
595
+ overflow: hidden;
596
+ border: 1px solid rgba(42, 38, 56, 0.11);
597
+ border-radius: 20px;
598
+ background: rgba(255, 255, 255, 0.9);
599
+ box-shadow: 0 22px 70px rgba(24, 22, 32, 0.15), 0 5px 18px rgba(24, 22, 32, 0.07);
600
+ opacity: 0;
601
+ pointer-events: none;
602
+ transform: translateX(18px) scale(0.985);
603
+ transition: opacity 180ms ease, transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
604
+ backdrop-filter: blur(24px) saturate(1.15);
605
+ }
606
+
607
+ .diagnostics-panel.is-open {
608
+ opacity: 1;
609
+ pointer-events: auto;
610
+ transform: translateX(0) scale(1);
611
+ }
612
+
613
+ .diagnostics-header {
614
+ min-height: 65px;
615
+ justify-content: space-between;
616
+ gap: 12px;
617
+ padding: 13px 14px 13px 17px;
618
+ border-bottom: 1px solid var(--wb-border);
619
+ }
620
+
621
+ .diagnostics-header > div {
622
+ display: grid;
623
+ gap: 3px;
624
+ }
625
+
626
+ .diagnostics-header strong {
627
+ font-size: 13px;
628
+ font-weight: 680;
629
+ }
630
+
631
+ .diagnostics-header span {
632
+ color: var(--wb-text-muted);
633
+ font-size: 10px;
634
+ }
635
+
636
+ .diagnostics-header button {
637
+ display: grid;
638
+ width: 32px;
639
+ height: 32px;
640
+ padding: 0;
641
+ border: 0;
642
+ border-radius: 50%;
643
+ background: var(--wb-surface-muted);
644
+ color: var(--wb-text-muted);
645
+ cursor: pointer;
646
+ outline: none;
647
+ place-items: center;
648
+ }
649
+
650
+ .diagnostics-header button:hover {
651
+ color: var(--wb-text);
652
+ }
653
+
654
+ .diagnostics-header button svg {
655
+ width: 14px;
656
+ height: 14px;
657
+ }
658
+
659
+ .diagnostics-content {
660
+ min-height: 0;
661
+ flex: 1;
662
+ overflow: auto;
663
+ padding: 14px;
664
+ scrollbar-color: #d8d7dc transparent;
665
+ scrollbar-width: thin;
666
+ }
667
+
668
+ .diagnostics-card {
669
+ display: grid;
670
+ grid-template-columns: repeat(2, minmax(0, 1fr));
671
+ gap: 1px;
672
+ overflow: hidden;
673
+ border: 1px solid var(--wb-border);
674
+ border-radius: 14px;
675
+ background: var(--wb-border);
676
+ }
677
+
678
+ .diagnostics-card > div {
679
+ display: grid;
680
+ min-width: 0;
681
+ gap: 5px;
682
+ padding: 12px;
683
+ background: rgba(255, 255, 255, 0.94);
684
+ }
685
+
686
+ .diagnostics-card .latest-event {
687
+ grid-column: 1 / -1;
688
+ }
689
+
690
+ .diagnostics-card span,
691
+ .section-title {
692
+ color: var(--wb-text-muted);
693
+ font-size: 10px;
694
+ }
695
+
696
+ .diagnostics-card strong {
697
+ min-width: 0;
698
+ overflow: hidden;
699
+ color: var(--wb-text-secondary);
700
+ font-size: 11px;
701
+ font-weight: 620;
702
+ text-overflow: ellipsis;
703
+ white-space: nowrap;
704
+ }
705
+
706
+ .diagnostics-section {
707
+ margin-top: 17px;
708
+ }
709
+
710
+ .section-title {
711
+ justify-content: space-between;
712
+ margin-bottom: 8px;
713
+ font-weight: 620;
714
+ }
715
+
716
+ .section-title span:last-child {
717
+ font-size: 9px;
718
+ font-weight: 500;
719
+ }
720
+
721
+ .capability-grid {
722
+ display: grid;
723
+ grid-template-columns: repeat(2, minmax(0, 1fr));
724
+ gap: 7px;
725
+ }
726
+
727
+ .capability-grid span {
728
+ position: relative;
729
+ padding: 10px 10px 10px 25px;
730
+ border: 1px solid var(--wb-border);
731
+ border-radius: 10px;
732
+ background: rgba(249, 249, 250, 0.9);
733
+ color: var(--wb-text-secondary);
734
+ font-size: 10px;
735
+ font-weight: 580;
736
+ }
737
+
738
+ .capability-grid span::before {
739
+ position: absolute;
740
+ top: 50%;
741
+ left: 10px;
742
+ width: 7px;
743
+ height: 7px;
744
+ border-radius: 50%;
745
+ background: var(--wb-success);
746
+ box-shadow: 0 0 0 3px rgba(33, 166, 117, 0.09);
747
+ content: "";
748
+ transform: translateY(-50%);
749
+ }
750
+
751
+ .events {
752
+ display: grid;
753
+ gap: 6px;
754
+ }
755
+
756
+ .event-empty {
757
+ display: grid;
758
+ min-height: 116px;
759
+ place-items: center;
760
+ align-content: center;
761
+ gap: 5px;
762
+ border: 1px dashed var(--wb-border-strong);
763
+ border-radius: 12px;
764
+ color: var(--wb-text-muted);
765
+ text-align: center;
766
+ }
767
+
768
+ .event-empty-icon {
769
+ display: grid;
770
+ width: 30px;
771
+ height: 30px;
772
+ margin-bottom: 2px;
773
+ place-items: center;
774
+ border-radius: 9px;
775
+ background: var(--wb-surface-muted);
776
+ }
777
+
778
+ .event-empty-icon svg {
779
+ width: 15px;
780
+ height: 15px;
781
+ }
782
+
783
+ .event-empty strong {
784
+ color: var(--wb-text-secondary);
785
+ font-size: 10px;
786
+ font-weight: 620;
787
+ }
788
+
789
+ .event-empty > span:last-child {
790
+ font-size: 9px;
791
+ }
792
+
793
+ .event {
794
+ display: grid;
795
+ grid-template-columns: 7px minmax(0, 1fr);
796
+ gap: 8px;
797
+ padding: 9px 10px;
798
+ border: 1px solid transparent;
799
+ border-radius: 10px;
800
+ background: rgba(246, 246, 248, 0.9);
801
+ }
802
+
803
+ .event-mark {
804
+ width: 7px;
805
+ height: 7px;
806
+ margin-top: 4px;
807
+ border-radius: 50%;
808
+ background: var(--wb-accent);
809
+ box-shadow: 0 0 0 3px rgba(128, 104, 245, 0.1);
810
+ }
811
+
812
+ .event[data-tone="error"] .event-mark {
813
+ background: var(--wb-danger);
814
+ box-shadow: 0 0 0 3px rgba(216, 74, 97, 0.1);
815
+ }
816
+
817
+ .event-name {
818
+ overflow: hidden;
819
+ font: 600 9px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
820
+ text-overflow: ellipsis;
821
+ white-space: nowrap;
822
+ }
823
+
824
+ .event-detail {
825
+ overflow: hidden;
826
+ margin-top: 2px;
827
+ color: var(--wb-text-muted);
828
+ font-size: 9px;
829
+ line-height: 1.35;
830
+ text-overflow: ellipsis;
831
+ white-space: nowrap;
832
+ }
833
+
834
+ @keyframes wb-dock-acknowledged {
835
+ 0% {
836
+ background: rgba(128, 104, 245, 0.05);
837
+ color: var(--wb-text-muted);
838
+ transform: scale(0.92);
839
+ }
840
+ 45% {
841
+ background: rgba(128, 104, 245, 0.14);
842
+ color: var(--wb-accent);
843
+ transform: scale(1.04);
844
+ }
845
+ 100% {
846
+ background: transparent;
847
+ color: var(--wb-text-muted);
848
+ transform: scale(1);
849
+ }
850
+ }
851
+
852
+ @keyframes wb-spin {
853
+ to {
854
+ transform: rotate(360deg);
855
+ }
856
+ }
857
+
858
+ @media (max-width: 760px) {
859
+ .project-name,
860
+ .runtime-state {
861
+ display: none;
862
+ }
863
+
864
+ .workbench-header {
865
+ padding: 0 10px;
866
+ }
867
+
868
+ .header-button {
869
+ width: 34px;
870
+ padding: 0;
871
+ }
872
+
873
+ .header-button span {
874
+ display: none;
875
+ }
876
+
877
+ .stage-canvas {
878
+ padding-right: 18px;
879
+ padding-left: 18px;
880
+ }
881
+ }
882
+
883
+ @media (max-height: 620px) {
884
+ .preview-controls {
885
+ top: 9px;
886
+ }
887
+
888
+ .stage-canvas {
889
+ padding-top: calc(var(--preview-controls-height, 38px) + 18px);
890
+ padding-bottom: 66px;
891
+ }
892
+
893
+ .preview-dock {
894
+ bottom: 10px;
895
+ }
896
+ }
897
+
898
+ @media (prefers-reduced-motion: reduce) {
899
+ .device-slot,
900
+ .device-switcher-indicator,
901
+ .device-shell,
902
+ .preview,
903
+ .device-switcher button span,
904
+ .device-switcher button,
905
+ .scene-switcher button,
906
+ .preview-transition,
907
+ .diagnostics-panel,
908
+ .header-button,
909
+ .preview-dock button {
910
+ transition: none;
911
+ }
912
+
913
+ .preview-transition-label i,
914
+ .preview-dock button.is-acknowledged,
915
+ .preview-dock button[data-action="reload"]:disabled svg {
916
+ animation: none;
917
+ }
918
+ }
919
+ `, Cn = `<div class="workbench-shell">
920
+ <header class="workbench-header">
921
+ <div class="view-navigation">
922
+ <span class="view-pill is-active">
923
+ <svg viewBox="0 0 20 20" aria-hidden="true">
924
+ <path d="M2.8 10s2.6-4.2 7.2-4.2 7.2 4.2 7.2 4.2-2.6 4.2-7.2 4.2S2.8 10 2.8 10Z" />
925
+ <circle cx="10" cy="10" r="2" />
926
+ </svg>
927
+ <span>Preview</span>
928
+ </span>
929
+ <span class="view-icon" title="小工具运行预览">
930
+ <svg viewBox="0 0 20 20" aria-hidden="true">
931
+ <path d="m7.4 6-4 4 4 4M12.6 6l4 4-4 4" />
932
+ </svg>
933
+ </span>
934
+ <span class="project-name" data-role="project-name"></span>
935
+ </div>
936
+
937
+ <div class="header-actions">
938
+ <span class="runtime-state" data-role="status" data-tone="pending" aria-live="polite">
939
+ <i></i>
940
+ <span data-role="status-text">正在连接</span>
941
+ </span>
942
+ <button class="header-button" type="button" data-action="diagnostics" aria-expanded="false">
943
+ <svg viewBox="0 0 20 20" aria-hidden="true">
944
+ <path d="M4 15.5V10M8 15.5V6M12 15.5v-3M16 15.5V4" />
945
+ </svg>
946
+ <span>运行诊断</span>
947
+ </button>
948
+ <button class="header-button" type="button" data-action="screenshot">
949
+ <svg viewBox="0 0 20 20" aria-hidden="true">
950
+ <path d="M3.4 6.7h2.1l1-1.8h7l1 1.8h2.1v8.4H3.4z" />
951
+ <circle cx="10" cy="10.9" r="2.5" />
952
+ </svg>
953
+ <span>截图</span>
954
+ </button>
955
+ </div>
956
+ </header>
957
+
958
+ <main class="stage" data-role="stage">
959
+ <div class="preview-controls" data-role="preview-controls">
960
+ <div class="device-switcher" role="group" aria-label="预览设备">
961
+ <span
962
+ class="device-switcher-indicator"
963
+ data-role="device-indicator"
964
+ aria-hidden="true"
965
+ ></span>
966
+ <button type="button" data-viewport="iphone" aria-label="iPhone 预览">
967
+ <svg viewBox="0 0 20 20" aria-hidden="true">
968
+ <rect x="6.2" y="2.5" width="7.6" height="15" rx="1.8" />
969
+ <path d="M9 4h2M9.2 15.7h1.6" />
970
+ </svg>
971
+ <span>iPhone</span>
972
+ </button>
973
+ <button type="button" data-viewport="ipad" aria-label="iPad 预览">
974
+ <svg viewBox="0 0 20 20" aria-hidden="true">
975
+ <rect x="4.2" y="2.8" width="11.6" height="14.4" rx="1.6" />
976
+ <circle cx="10" cy="14.9" r=".6" />
977
+ </svg>
978
+ <span>iPad</span>
979
+ </button>
980
+ <button type="button" data-viewport="desktop" aria-label="桌面预览">
981
+ <svg viewBox="0 0 20 20" aria-hidden="true">
982
+ <rect x="2.7" y="3.7" width="14.6" height="10" rx="1.4" />
983
+ <path d="M7.5 16.3h5M10 13.7v2.6" />
984
+ </svg>
985
+ <span>Desktop</span>
986
+ </button>
987
+ </div>
988
+ <div class="scene-switcher" role="group" aria-label="模拟场景">
989
+ <button type="button" data-scene="fullscreen" aria-pressed="true">全屏小工具</button>
990
+ <button type="button" data-scene="half" aria-pressed="false">半屏小工具</button>
991
+ <button type="button" data-scene="note" aria-pressed="false">笔记页</button>
992
+ <button type="button" data-scene="profile" aria-pressed="false">个人页</button>
993
+ </div>
994
+ </div>
995
+
996
+ <div class="stage-canvas" data-role="preview-canvas" aria-busy="false">
997
+ <div class="device-slot" data-role="device-slot">
998
+ <div class="device-shell" data-role="device-shell" data-form-factor="iphone">
999
+ <div class="preview" data-role="preview"></div>
1000
+ </div>
1001
+ </div>
1002
+ </div>
1003
+
1004
+ <div
1005
+ class="preview-transition"
1006
+ data-role="preview-transition"
1007
+ role="status"
1008
+ aria-live="polite"
1009
+ aria-hidden="true"
1010
+ >
1011
+ <span class="preview-transition-label">
1012
+ <i aria-hidden="true"></i>
1013
+ 正在切换预览
1014
+ </span>
1015
+ </div>
1016
+
1017
+ <div class="preview-dock" aria-label="预览工具">
1018
+ <button type="button" data-action="fit" aria-label="适应窗口" data-tooltip="适应窗口">
1019
+ <svg viewBox="0 0 20 20" aria-hidden="true">
1020
+ <path d="M7 3H3v4M13 3h4v4M7 17H3v-4M13 17h4v-4" />
1021
+ </svg>
1022
+ </button>
1023
+ <button type="button" data-action="reload" aria-label="重新运行" data-tooltip="重新运行">
1024
+ <svg viewBox="0 0 20 20" aria-hidden="true">
1025
+ <path d="M15.7 7.1A6.2 6.2 0 1 0 16 11" />
1026
+ <path d="M16 3.8v3.8h-3.8" />
1027
+ </svg>
1028
+ </button>
1029
+ <button
1030
+ type="button"
1031
+ data-action="diagnostics"
1032
+ aria-label="运行诊断"
1033
+ data-tooltip="运行诊断"
1034
+ aria-expanded="false"
1035
+ >
1036
+ <svg viewBox="0 0 20 20" aria-hidden="true">
1037
+ <path d="M4 15.5V10M8 15.5V6M12 15.5v-3M16 15.5V4" />
1038
+ </svg>
1039
+ </button>
1040
+ </div>
1041
+
1042
+ <aside
1043
+ class="diagnostics-panel"
1044
+ data-role="diagnostics"
1045
+ aria-label="运行诊断"
1046
+ aria-hidden="true"
1047
+ >
1048
+ <div class="diagnostics-header">
1049
+ <div>
1050
+ <strong>运行诊断</strong>
1051
+ <span>Remote Simulator</span>
1052
+ </div>
1053
+ <button type="button" data-action="close-diagnostics" aria-label="关闭运行诊断">
1054
+ <svg viewBox="0 0 20 20" aria-hidden="true"><path d="m5 5 10 10M15 5 5 15" /></svg>
1055
+ </button>
1056
+ </div>
1057
+
1058
+ <div class="diagnostics-content">
1059
+ <section class="diagnostics-card overview-card">
1060
+ <div>
1061
+ <span>逻辑视口</span>
1062
+ <strong data-role="viewport"></strong>
1063
+ </div>
1064
+ <div>
1065
+ <span>事件数量</span>
1066
+ <strong data-role="event-count">0 events</strong>
1067
+ </div>
1068
+ <div class="latest-event">
1069
+ <span>最近事件</span>
1070
+ <strong data-role="last-event">等待加载小工具产物</strong>
1071
+ </div>
1072
+ </section>
1073
+
1074
+ <section class="diagnostics-section">
1075
+ <div class="section-title">
1076
+ <span>调试能力</span>
1077
+ <span>4 / 4</span>
1078
+ </div>
1079
+ <div class="capability-grid">
1080
+ <span>产物加载</span>
1081
+ <span>交互截图</span>
1082
+ <span>场景结构</span>
1083
+ <span>日志诊断</span>
1084
+ </div>
1085
+ </section>
1086
+
1087
+ <section class="diagnostics-section event-section">
1088
+ <div class="section-title">
1089
+ <span>最近事件</span>
1090
+ <span>自动刷新</span>
1091
+ </div>
1092
+ <div class="events" data-role="events">
1093
+ <div class="event-empty">
1094
+ <span class="event-empty-icon">
1095
+ <svg viewBox="0 0 20 20" aria-hidden="true">
1096
+ <path d="M4 5h12v10H4z" />
1097
+ <path d="M7 8h6M7 11h4" />
1098
+ </svg>
1099
+ </span>
1100
+ <strong>暂无运行事件</strong>
1101
+ <span>加载小工具后将在这里显示</span>
1102
+ </div>
1103
+ </div>
1104
+ </section>
1105
+ </div>
1106
+ </aside>
1107
+ </main>
1108
+ </div>
1109
+ `;
1110
+ function r(a, i) {
1111
+ const e = a.querySelector(i);
1112
+ if (!e) throw new Error(`MiniAppWorkbench internal element missing: ${i}`);
1113
+ return e;
1114
+ }
1115
+ function G(a, i) {
1116
+ const e = Array.from(a.querySelectorAll(i));
1117
+ if (e.length === 0)
1118
+ throw new Error(`MiniAppWorkbench internal elements missing: ${i}`);
1119
+ return e;
1120
+ }
1121
+ function zn(a) {
1122
+ const i = document.createElement("div"), e = i.attachShadow({ mode: "open" }), v = document.createElement("style"), l = document.createElement("template");
1123
+ return v.textContent = Ln, l.innerHTML = Cn, e.append(v, l.content.cloneNode(!0)), r(e, '[data-role="project-name"]').textContent = a, {
1124
+ host: i,
1125
+ root: e,
1126
+ elements: {
1127
+ closeDiagnosticsButton: r(e, '[data-action="close-diagnostics"]'),
1128
+ deviceButtons: G(e, "[data-viewport]"),
1129
+ deviceIndicator: r(e, '[data-role="device-indicator"]'),
1130
+ deviceShell: r(e, '[data-role="device-shell"]'),
1131
+ deviceSlot: r(e, '[data-role="device-slot"]'),
1132
+ diagnosticsButtons: G(e, '[data-action="diagnostics"]'),
1133
+ diagnosticsPanel: r(e, '[data-role="diagnostics"]'),
1134
+ eventCount: r(e, '[data-role="event-count"]'),
1135
+ events: r(e, '[data-role="events"]'),
1136
+ fitButton: r(e, '[data-action="fit"]'),
1137
+ lastEvent: r(e, '[data-role="last-event"]'),
1138
+ preview: r(e, '[data-role="preview"]'),
1139
+ previewCanvas: r(e, '[data-role="preview-canvas"]'),
1140
+ previewControls: r(e, '[data-role="preview-controls"]'),
1141
+ reloadButton: r(e, '[data-action="reload"]'),
1142
+ sceneButtons: G(e, "[data-scene]"),
1143
+ screenshotButton: r(e, '[data-action="screenshot"]'),
1144
+ stage: r(e, '[data-role="stage"]'),
1145
+ status: r(e, '[data-role="status"]'),
1146
+ statusText: r(e, '[data-role="status-text"]'),
1147
+ transitionOverlay: r(e, '[data-role="preview-transition"]'),
1148
+ viewportLabel: r(e, '[data-role="viewport"]')
1149
+ }
1150
+ };
1151
+ }
1152
+ const J = {
1153
+ fullscreen: { contentMode: "fullscreen", route: "minitool" },
1154
+ half: { contentMode: "half", route: "minitool" },
1155
+ note: { contentMode: "fullscreen", route: "note" },
1156
+ profile: { contentMode: "fullscreen", route: "profile" }
1157
+ }, Tn = { width: 393, height: 852 }, f = 34, Q = 92, An = 3, bn = {
1158
+ iphone: { width: 393, height: 852 },
1159
+ ipad: { width: 834, height: 852 },
1160
+ desktop: { width: 1280, height: 852 }
1161
+ }, Bn = [
1162
+ "beforeLoad",
1163
+ "load",
1164
+ "renderDone",
1165
+ "error",
1166
+ "navigation",
1167
+ "console",
1168
+ "guestError",
1169
+ "network"
1170
+ ];
1171
+ function Fn(a) {
1172
+ const i = typeof a == "string" ? document.querySelector(a) : a;
1173
+ if (!i) throw new Error(`MiniAppWorkbench mount not found: ${String(a)}`);
1174
+ return i;
1175
+ }
1176
+ function H(a) {
1177
+ if (a == null) return "事件已触发";
1178
+ if (typeof a == "string") return a;
1179
+ if (typeof a == "object") {
1180
+ const i = a;
1181
+ for (const e of ["message", "reason", "url", "status", "code"])
1182
+ if (i[e] != null) return String(i[e]);
1183
+ }
1184
+ try {
1185
+ const i = JSON.stringify(a);
1186
+ return i.length > 92 ? `${i.slice(0, 89)}...` : i;
1187
+ } catch {
1188
+ return String(a);
1189
+ }
1190
+ }
1191
+ function Pn(a) {
1192
+ const i = document.createElement("a");
1193
+ i.href = a, i.download = `miniapp-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.png`, i.click();
1194
+ }
1195
+ function Dn(a) {
1196
+ const i = Fn(a.mount);
1197
+ let e = { ...a.viewport ?? Tn }, v = a.remote.options?.contentMode ?? "fullscreen", l = J[v].contentMode;
1198
+ const w = zn(a.projectName?.trim() || "本地小工具"), { host: b, elements: L } = w;
1199
+ i.appendChild(b);
1200
+ const {
1201
+ closeDiagnosticsButton: m,
1202
+ deviceButtons: u,
1203
+ deviceIndicator: C,
1204
+ deviceShell: y,
1205
+ deviceSlot: s,
1206
+ diagnosticsButtons: z,
1207
+ diagnosticsPanel: k,
1208
+ eventCount: vn,
1209
+ events: F,
1210
+ fitButton: E,
1211
+ lastEvent: P,
1212
+ preview: W,
1213
+ previewCanvas: un,
1214
+ previewControls: gn,
1215
+ reloadButton: $,
1216
+ sceneButtons: T,
1217
+ screenshotButton: D,
1218
+ stage: V,
1219
+ status: hn,
1220
+ statusText: wn,
1221
+ transitionOverlay: xn,
1222
+ viewportLabel: fn
1223
+ } = L;
1224
+ let M, S;
1225
+ const j = Sn(xn, un), mn = (n) => n.width >= 1024 ? "desktop" : n.width >= 700 ? "ipad" : "iphone", yn = () => {
1226
+ S = void 0;
1227
+ const n = e.width, t = e.height, o = Math.max(V.clientWidth - 84, 1), c = gn.offsetHeight;
1228
+ V.style.setProperty("--preview-controls-height", `${c}px`);
1229
+ const h = Math.max(V.clientHeight - c - 112, 1), p = Math.min(1, o / n, h / t);
1230
+ y.style.setProperty("--device-scale", String(p)), s.style.width = `${n * p}px`, s.style.height = `${t * p}px`;
1231
+ }, I = () => {
1232
+ S !== void 0 && window.cancelAnimationFrame(S), S = window.requestAnimationFrame(yn);
1233
+ }, nn = (n) => {
1234
+ e = { ...n };
1235
+ const t = mn(n), o = Math.max(
1236
+ 0,
1237
+ u.findIndex((c) => c.dataset.viewport === t)
1238
+ );
1239
+ W.style.width = `${n.width}px`, W.style.height = `${n.height}px`, y.style.width = `${n.width}px`, y.style.height = `${n.height}px`, y.dataset.formFactor = t, C.style.transform = `translateX(${o * f}px)`;
1240
+ for (const [c, h] of u.entries()) {
1241
+ const p = c === o, B = c < o ? c * f : o === 0 ? Q + (c - 1) * f : o * f + Q + (c - o - 1) * f, En = p ? o * f : B;
1242
+ h.style.left = `${An + En}px`, h.style.width = `${p ? Q : f}px`, h.classList.toggle("is-active", p), h.setAttribute("aria-pressed", String(p));
1243
+ }
1244
+ fn.textContent = `${n.width} × ${n.height}`, I();
1245
+ };
1246
+ nn(e);
1247
+ const { options: N, ...kn } = a.remote, d = Mn({
1248
+ ...kn,
1249
+ mount: W,
1250
+ options: {
1251
+ ...N,
1252
+ contentMode: l,
1253
+ shell: "rednote",
1254
+ viewport: e,
1255
+ phoneFrame: N?.phoneFrame ?? !1,
1256
+ touchEmulation: N?.touchEmulation ?? !0,
1257
+ stageFit: N?.stageFit ?? !0
1258
+ }
1259
+ }), _ = [];
1260
+ let q = 0, g = !1, X = !1;
1261
+ const K = (n) => {
1262
+ X = n, k.classList.toggle("is-open", n), k.setAttribute("aria-hidden", String(!n));
1263
+ for (const t of z)
1264
+ t.classList.toggle("is-active", n), t.setAttribute("aria-expanded", String(n));
1265
+ }, x = (n, t) => {
1266
+ hn.dataset.tone = n, wn.textContent = t;
1267
+ }, A = (n, t) => {
1268
+ q += 1, vn.textContent = `${q} ${q === 1 ? "event" : "events"}`, P.textContent = `${n} · ${H(t)}`, F.querySelector(".event-empty")?.remove();
1269
+ const o = document.createElement("div");
1270
+ o.className = "event", (n === "error" || n === "guestError") && (o.dataset.tone = "error");
1271
+ const c = document.createElement("span");
1272
+ c.className = "event-mark";
1273
+ const h = document.createElement("div"), p = document.createElement("div");
1274
+ p.className = "event-name", p.textContent = n;
1275
+ const B = document.createElement("div");
1276
+ for (B.className = "event-detail", B.textContent = H(t), h.append(p, B), o.append(c, h), F.prepend(o); F.children.length > 7; ) F.lastElementChild?.remove();
1277
+ (n === "error" || n === "guestError") && x("error", "运行异常"), (n === "load" || n === "renderDone") && x("ready", "小工具运行中");
1278
+ };
1279
+ for (const n of Bn)
1280
+ _.push(d.on(n, (t) => A(n, t)));
1281
+ x("pending", "正在连接远程模拟器"), d.ready.then(
1282
+ (n) => {
1283
+ g || (x("ready", "远程模拟器已连接"), P.textContent = `runtimeReady · ${n.runtimeVersion}`);
1284
+ },
1285
+ (n) => {
1286
+ g || (x("error", "远程模拟器连接失败"), P.textContent = H(n));
1287
+ }
1288
+ );
1289
+ const U = async (n, t) => {
1290
+ x("pending", n);
1291
+ try {
1292
+ await t();
1293
+ } catch (o) {
1294
+ throw x("error", "小工具加载失败"), P.textContent = H(o), o;
1295
+ }
1296
+ };
1297
+ let Z = !1, O;
1298
+ const Y = () => {
1299
+ for (const n of T) {
1300
+ const t = n.dataset.scene === v;
1301
+ n.classList.toggle("is-active", t), n.setAttribute("aria-pressed", String(t));
1302
+ }
1303
+ };
1304
+ Y(), _.push(
1305
+ d.on("routerChange", ({ to: n }) => {
1306
+ g || O || (v = n === "minitool" ? l : n, Y());
1307
+ })
1308
+ );
1309
+ const R = () => {
1310
+ if (g) return Promise.resolve();
1311
+ Z = !0, $.disabled = !0;
1312
+ for (const n of T) n.disabled = !0;
1313
+ return O ?? (O = j.run("reload", async () => {
1314
+ for (; Z && !g; ) {
1315
+ Z = !1;
1316
+ const t = J[v];
1317
+ x("pending", "正在重新加载");
1318
+ try {
1319
+ l !== t.contentMode && (await d.switchContentMode(t.contentMode), l = t.contentMode), a.onReload ? await a.onReload() : await d.reload(), await d.redirectTo(t.route, {
1320
+ sheetMode: t.contentMode === "half" ? "half" : "full"
1321
+ });
1322
+ } catch (o) {
1323
+ A("error", o);
1324
+ }
1325
+ }
1326
+ }).finally(() => {
1327
+ O = void 0, $.disabled = !1;
1328
+ for (const n of T) n.disabled = !1;
1329
+ })), O;
1330
+ }, en = (n) => Object.prototype.hasOwnProperty.call(J, n) ? g ? Promise.resolve() : (v = n, Y(), R()) : Promise.reject(new Error(`不支持的工作台场景:${n}`)), tn = (n) => {
1331
+ const t = n.currentTarget.dataset.scene;
1332
+ en(t);
1333
+ }, an = async () => {
1334
+ D.disabled = !0;
1335
+ try {
1336
+ const n = await d.screenShot();
1337
+ n.success ? Pn(n.base64) : A("error", { code: n.code, message: n.reason });
1338
+ } catch (n) {
1339
+ A("error", n);
1340
+ } finally {
1341
+ D.disabled = !1;
1342
+ }
1343
+ }, on = (n) => {
1344
+ const o = n.currentTarget.dataset.viewport;
1345
+ !o || !bn[o] || rn(bn[o]);
1346
+ }, rn = (n) => {
1347
+ if (!g) {
1348
+ if (n.width === e.width && n.height === e.height && !j.isActive("viewport")) {
1349
+ I();
1350
+ return;
1351
+ }
1352
+ j.run("viewport", async () => {
1353
+ nn(n), await d.invoke("setViewport", n);
1354
+ }).catch((t) => {
1355
+ g || A("error", t);
1356
+ });
1357
+ }
1358
+ }, sn = () => K(!X), dn = () => K(!1), cn = () => {
1359
+ I(), E.classList.remove("is-acknowledged"), E.offsetWidth, E.classList.add("is-acknowledged"), M !== void 0 && window.clearTimeout(M), M = window.setTimeout(() => {
1360
+ M = void 0, E.classList.remove("is-acknowledged");
1361
+ }, 360);
1362
+ }, ln = (n) => {
1363
+ n.key === "Escape" && X && K(!1);
1364
+ };
1365
+ $.addEventListener("click", R), D.addEventListener("click", an), E.addEventListener("click", cn), m.addEventListener("click", dn);
1366
+ for (const n of z)
1367
+ n.addEventListener("click", sn);
1368
+ for (const n of u) n.addEventListener("click", on);
1369
+ for (const n of T) n.addEventListener("click", tn);
1370
+ w.root.addEventListener("keydown", ln);
1371
+ const pn = new ResizeObserver(I);
1372
+ return pn.observe(V), {
1373
+ element: b,
1374
+ simulator: d,
1375
+ ready: d.ready,
1376
+ reload: R,
1377
+ setScene: en,
1378
+ async loadZip(n, t) {
1379
+ await U("正在加载小工具产物", () => d.loadZip(n, t));
1380
+ },
1381
+ async loadFiles(n, t) {
1382
+ await U("正在加载小工具文件", () => d.loadFiles(n, t));
1383
+ },
1384
+ async loadApp(n, t) {
1385
+ await U("正在加载小工具", () => d.loadApp(n, t));
1386
+ },
1387
+ setViewport: rn,
1388
+ destroy(n = "workbench-destroy") {
1389
+ if (!g) {
1390
+ g = !0, $.removeEventListener("click", R), D.removeEventListener("click", an), E.removeEventListener("click", cn), m.removeEventListener("click", dn);
1391
+ for (const t of z)
1392
+ t.removeEventListener("click", sn);
1393
+ for (const t of u) t.removeEventListener("click", on);
1394
+ for (const t of T) t.removeEventListener("click", tn);
1395
+ w.root.removeEventListener("keydown", ln), pn.disconnect(), S !== void 0 && window.cancelAnimationFrame(S), M !== void 0 && window.clearTimeout(M), j.destroy();
1396
+ for (const t of _) t();
1397
+ d.destroy(n), b.remove();
1398
+ }
1399
+ }
1400
+ };
1401
+ }
1402
+ export {
1403
+ Dn as createMiniAppWorkbench
1404
+ };