@monkey-mini-app/panel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2525 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+ var lucideReact = require('lucide-react');
6
+ var client = require('react-dom/client');
7
+ var i18next = require('i18next');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
28
+
29
+ var __defProp = Object.defineProperty;
30
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
31
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
32
+
33
+ // src/panel-host.ts
34
+ function capabilitiesOf(host) {
35
+ return {
36
+ history: !!host.history,
37
+ storage: !!host.storage,
38
+ config: !!host.config,
39
+ appTheme: !!host.appTheme,
40
+ customPalettes: !!host.palettes,
41
+ deleteApp: !!host.deleteApp
42
+ };
43
+ }
44
+
45
+ // src/rest.ts
46
+ function isRecord(value) {
47
+ return typeof value === "object" && value !== null && !Array.isArray(value);
48
+ }
49
+ async function readJson(url, init) {
50
+ let res;
51
+ try {
52
+ res = await fetch(url, init);
53
+ } catch (cause) {
54
+ throw new HostUnreachableError(url, cause);
55
+ }
56
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
57
+ return res.json();
58
+ }
59
+ var HostUnreachableError = class extends Error {
60
+ constructor(url, cause) {
61
+ super(`Cannot reach apps host: ${url}`);
62
+ __publicField(this, "url");
63
+ this.name = "HostUnreachableError";
64
+ this.url = url;
65
+ if (cause !== void 0) {
66
+ Object.defineProperty(this, "cause", { value: cause, configurable: true, writable: true });
67
+ }
68
+ }
69
+ };
70
+ function isHostUnreachable(e) {
71
+ return e instanceof HostUnreachableError;
72
+ }
73
+ function appFrameUrl(origin, appId, query) {
74
+ return `${origin}/app/${encodeURIComponent(appId)}?${new URLSearchParams(query).toString()}`;
75
+ }
76
+ function parseAppTheme(raw) {
77
+ if (raw === null) return null;
78
+ if (!isRecord(raw)) return void 0;
79
+ const theme = typeof raw.theme === "string" ? raw.theme : "";
80
+ const palette = typeof raw.palette === "string" ? raw.palette : "";
81
+ if (!theme && !palette) return null;
82
+ return { theme, palette };
83
+ }
84
+ function parseAppsResponse(raw) {
85
+ if (!isRecord(raw) || !Array.isArray(raw.apps)) return [];
86
+ const out = [];
87
+ for (const item of raw.apps) {
88
+ if (!isRecord(item) || typeof item.id !== "string") continue;
89
+ out.push({
90
+ id: item.id,
91
+ name: typeof item.name === "string" ? item.name : item.id,
92
+ description: typeof item.description === "string" ? item.description : void 0,
93
+ acronym: typeof item.acronym === "string" ? item.acronym : void 0,
94
+ commits: typeof item.commits === "number" ? item.commits : void 0,
95
+ version: typeof item.version === "string" ? item.version : void 0,
96
+ theme: parseAppTheme(item.theme)
97
+ });
98
+ }
99
+ return out;
100
+ }
101
+ function hostConfigToForm(raw, cardStyle) {
102
+ const rec = isRecord(raw) ? raw : {};
103
+ const llm = isRecord(rec.llm) ? rec.llm : null;
104
+ const locale = typeof rec.locale === "string" ? rec.locale : "";
105
+ const chatLanguage = typeof rec.chatLanguage === "string" ? rec.chatLanguage : "";
106
+ return {
107
+ hostPort: rec.hostPort != null ? String(rec.hostPort) : "",
108
+ locale: locale || chatLanguage,
109
+ chatLanguage: chatLanguage || locale,
110
+ theme: typeof rec.theme === "string" ? rec.theme : "",
111
+ palette: typeof rec.palette === "string" ? rec.palette : "",
112
+ cardStyle,
113
+ provider: llm && typeof llm.provider === "string" ? llm.provider : "",
114
+ model: llm && typeof llm.model === "string" ? llm.model : ""
115
+ };
116
+ }
117
+ function formToHostConfigBody(form) {
118
+ const provider = (form.provider ?? "").trim();
119
+ const model = (form.model ?? "").trim();
120
+ const locale = form.locale || form.chatLanguage;
121
+ const body = { locale, chatLanguage: form.chatLanguage || locale, theme: form.theme, palette: form.palette };
122
+ const port = Number(form.hostPort);
123
+ if (Number.isInteger(port) && port >= 0 && port <= 65535) body.hostPort = port;
124
+ if (provider && model) body.llm = { provider, model };
125
+ else if (!provider && !model) body.llm = null;
126
+ return body;
127
+ }
128
+ function asCommit(raw) {
129
+ if (!isRecord(raw) || typeof raw.id !== "string") return null;
130
+ const files = Array.isArray(raw.files) ? raw.files.flatMap((f) => {
131
+ if (!isRecord(f) || typeof f.path !== "string") return [];
132
+ return [{ path: f.path, add: typeof f.add === "number" ? f.add : void 0, del: typeof f.del === "number" ? f.del : void 0, preview: typeof f.preview === "string" ? f.preview : void 0 }];
133
+ }) : void 0;
134
+ return { id: raw.id, message: typeof raw.message === "string" ? raw.message : "", time: typeof raw.time === "string" ? raw.time : "", files };
135
+ }
136
+ function parseCommitList(raw) {
137
+ const rec = isRecord(raw) ? raw : {};
138
+ const list = Array.isArray(rec.commits) ? rec.commits : Array.isArray(rec.nodes) ? rec.nodes : [];
139
+ return list.map((c) => asCommit(c)).filter((c) => c !== null);
140
+ }
141
+ function parseCommitDetail(raw, id) {
142
+ const rec = isRecord(raw) ? raw : {};
143
+ const inner = isRecord(rec.commit) ? rec.commit : rec;
144
+ return asCommit(inner) ?? { id, message: "", time: "", files: [] };
145
+ }
146
+ function parseStorageTables(raw) {
147
+ const rec = isRecord(raw) ? raw : {};
148
+ const list = Array.isArray(rec.tables) ? rec.tables : [];
149
+ const out = [];
150
+ for (const row of list) {
151
+ if (!isRecord(row) || typeof row.name !== "string") continue;
152
+ out.push({
153
+ name: row.name,
154
+ size: typeof row.size === "number" ? row.size : void 0,
155
+ updatedAt: typeof row.updatedAt === "string" ? row.updatedAt : void 0
156
+ });
157
+ }
158
+ return out;
159
+ }
160
+ function parsePalettes(raw) {
161
+ const rec = isRecord(raw) ? raw : {};
162
+ const list = Array.isArray(rec.palettes) ? rec.palettes : [];
163
+ const out = [];
164
+ for (const p of list) {
165
+ if (!isRecord(p) || typeof p.id !== "string") continue;
166
+ if (p.custom === false) continue;
167
+ out.push({
168
+ id: p.id,
169
+ label: typeof p.label === "string" ? p.label : p.id,
170
+ swatch: typeof p.swatch === "string" ? p.swatch : "#888",
171
+ tokens: isRecord(p.tokens) ? p.tokens : void 0
172
+ });
173
+ }
174
+ return out;
175
+ }
176
+ function createRestPanelHost(opts) {
177
+ const storage = opts.storage ?? (typeof window !== "undefined" ? window.localStorage : null);
178
+ function origin() {
179
+ return (opts.getHostUrl ? opts.getHostUrl() : opts.hostUrl).replace(/\/$/, "");
180
+ }
181
+ const host = {
182
+ locale: opts.locale,
183
+ emptyText: opts.emptyText,
184
+ fetchApps: async () => parseAppsResponse(await readJson(`${origin()}/api/apps`)),
185
+ palettes: async () => {
186
+ try {
187
+ return parsePalettes(await readJson(`${origin()}/api/palettes`));
188
+ } catch {
189
+ return [];
190
+ }
191
+ },
192
+ openPanel: () => opts.onOpen?.(),
193
+ closePanel: () => opts.onClose?.(),
194
+ persistTheme: (theme, palette) => {
195
+ try {
196
+ storage?.setItem("mma-theme-mode", theme);
197
+ storage?.setItem("mma-palette", palette);
198
+ } catch {
199
+ }
200
+ void fetch(`${origin()}/api/host-config`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ theme, palette }) }).catch(() => {
201
+ });
202
+ },
203
+ appTheme: {
204
+ save: async (appId, t) => {
205
+ await fetch(`${origin()}/api/apps/${encodeURIComponent(appId)}/theme`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(t) }).catch(() => {
206
+ });
207
+ },
208
+ clear: async (appId) => {
209
+ await fetch(`${origin()}/api/apps/${encodeURIComponent(appId)}/theme`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ reset: true }) }).catch(() => {
210
+ });
211
+ }
212
+ },
213
+ config: {
214
+ load: async () => hostConfigToForm(await readJson(`${origin()}/api/host-config`), opts.getCardStyle?.() ?? opts.cardStyle ?? "stamp"),
215
+ save: async (cfg) => {
216
+ const body = formToHostConfigBody(cfg);
217
+ const res = await fetch(`${origin()}/api/host-config`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
218
+ const raw = await res.json().catch(() => ({}));
219
+ if (!res.ok || isRecord(raw) && raw.ok === false) {
220
+ throw new Error(isRecord(raw) && typeof raw.error === "string" ? raw.error : `HTTP ${res.status}`);
221
+ }
222
+ const hostPort = isRecord(raw) ? raw.hostPort : void 0;
223
+ if (typeof hostPort === "number" && Number.isInteger(hostPort) && hostPort > 0) {
224
+ const next = `${new URL(origin()).protocol}//${new URL(origin()).hostname}:${hostPort}`;
225
+ if (next !== origin()) opts.onHostChange?.(next);
226
+ }
227
+ opts.onConfigSaved?.(cfg);
228
+ }
229
+ },
230
+ history: {
231
+ list: async (appId) => parseCommitList(await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/history?limit=50`)),
232
+ detail: async (appId, id) => parseCommitDetail(await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/history/${encodeURIComponent(id)}`), id)
233
+ },
234
+ storage: {
235
+ listTables: async (appId) => parseStorageTables(await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/storage`)),
236
+ readTable: async (appId, name) => {
237
+ const raw = await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/storage/${encodeURIComponent(name)}`);
238
+ return isRecord(raw) && "value" in raw ? raw.value : raw;
239
+ }
240
+ },
241
+ deleteApp: opts.deleteApp ?? (async (appId) => {
242
+ await fetch(`${origin()}/api/app/${encodeURIComponent(appId)}`, { method: "DELETE" }).catch(() => {
243
+ });
244
+ }),
245
+ frame: opts.frameController ?? {
246
+ url: (appId) => `${origin()}/app/${encodeURIComponent(appId)}`,
247
+ mount: () => void 0,
248
+ unmount: () => void 0,
249
+ reload: () => void 0,
250
+ syncEnv: () => void 0
251
+ }
252
+ };
253
+ return host;
254
+ }
255
+ var none = {
256
+ history: false,
257
+ storage: false,
258
+ config: false,
259
+ appTheme: false,
260
+ customPalettes: false,
261
+ deleteApp: false
262
+ };
263
+ var initial = {
264
+ tabs: [{ id: "all", title: "\u5168\u90E8", kind: "all" }],
265
+ active: "all",
266
+ apps: [],
267
+ error: null,
268
+ loading: false,
269
+ query: "",
270
+ dock: "fill",
271
+ theme: "light",
272
+ palette: "default",
273
+ themeScope: "global",
274
+ customPalettes: {},
275
+ cardStyle: "stamp",
276
+ visible: false,
277
+ pendingDelete: null,
278
+ themePopOpen: false,
279
+ settingsOpen: false,
280
+ cfgMsg: "",
281
+ cfgVersion: 0,
282
+ cfg: {},
283
+ emptyText: void 0,
284
+ capabilities: none,
285
+ locale: "zh-CN",
286
+ browseOpen: false,
287
+ browseKind: "history",
288
+ browseAppId: null,
289
+ browseAppName: "",
290
+ browseLoading: false,
291
+ browseError: null,
292
+ browseList: [],
293
+ browseDetail: null,
294
+ browseTable: null,
295
+ browseTableValue: null,
296
+ browseOpenFile: null
297
+ };
298
+ var state = { ...initial, capabilities: { ...none } };
299
+ var listeners = /* @__PURE__ */ new Set();
300
+ function getPanelState() {
301
+ return state;
302
+ }
303
+ function setPanelState(patch) {
304
+ state = { ...state, ...patch };
305
+ for (const fn of listeners) fn();
306
+ return state;
307
+ }
308
+ function subscribePanel(listener) {
309
+ listeners.add(listener);
310
+ return () => {
311
+ listeners.delete(listener);
312
+ };
313
+ }
314
+ function resetPanelState(seed) {
315
+ state = {
316
+ ...initial,
317
+ capabilities: { ...none },
318
+ customPalettes: {},
319
+ cfg: {},
320
+ tabs: [{ id: "all", title: "\u5168\u90E8", kind: "all" }],
321
+ ...seed || {}
322
+ };
323
+ for (const fn of listeners) fn();
324
+ return state;
325
+ }
326
+ function usePanelState() {
327
+ return React.useSyncExternalStore(subscribePanel, getPanelState);
328
+ }
329
+
330
+ // src/themes.ts
331
+ var PALETTES = [
332
+ { id: "default", label: "\u9ED8\u8BA4", swatch: "#2563eb" },
333
+ { id: "tokyo", label: "\u4E1C\u4EAC\u591C", swatch: "#7aa2f7" },
334
+ { id: "forest", label: "\u82D4\u539F", swatch: "#a7c080" },
335
+ { id: "matcha", label: "\u8349\u8393\u62B9\u8336", swatch: "#ee9aa6" },
336
+ { id: "yellow", label: "\u836F\u4E38\u9EC4", swatch: "#facc15" },
337
+ { id: "zoro", label: "\u4E09\u5200\u6D41", swatch: "#4ade80" },
338
+ { id: "hokage", label: "\u706B\u5F71\u9ECE\u660E", swatch: "#f59e0b" },
339
+ { id: "slate", label: "\u77F3\u58A8", swatch: "#3f3f46" }
340
+ ];
341
+ var TOKENS = {
342
+ default: {
343
+ light: {
344
+ bg: "#f7f7f8",
345
+ fg: "#111111",
346
+ surface: "#ffffff",
347
+ surfaceFg: "#111111",
348
+ border: "#e5e7eb",
349
+ muted: "#f3f4f6",
350
+ mutedFg: "#6b7280",
351
+ primary: "#2563eb",
352
+ primaryFg: "#ffffff",
353
+ secondary: "#f3f4f6",
354
+ secondaryFg: "#111111",
355
+ accent: "#eff6ff",
356
+ accentFg: "#1e3a8a",
357
+ destructive: "#dc2626",
358
+ destructiveFg: "#ffffff",
359
+ ring: "#2563eb",
360
+ input: "#e5e7eb",
361
+ radius: "10px",
362
+ shadow: "rgba(15, 23, 42, 0.08)"
363
+ },
364
+ dark: {
365
+ bg: "#0b0b0c",
366
+ fg: "#f4f4f5",
367
+ surface: "#171717",
368
+ surfaceFg: "#f4f4f5",
369
+ border: "#2a2a2c",
370
+ muted: "#27272a",
371
+ mutedFg: "#a1a1aa",
372
+ primary: "#3b82f6",
373
+ primaryFg: "#ffffff",
374
+ secondary: "#27272a",
375
+ secondaryFg: "#f4f4f5",
376
+ accent: "#172554",
377
+ accentFg: "#bfdbfe",
378
+ destructive: "#ef4444",
379
+ destructiveFg: "#ffffff",
380
+ ring: "#3b82f6",
381
+ input: "#2a2a2c",
382
+ radius: "10px",
383
+ shadow: "rgba(0, 0, 0, 0.45)"
384
+ }
385
+ },
386
+ tokyo: {
387
+ light: {
388
+ bg: "#d5d6db",
389
+ fg: "#343b59",
390
+ surface: "#f2f3f8",
391
+ surfaceFg: "#343b59",
392
+ border: "#c9ccd9",
393
+ muted: "#e9eaf2",
394
+ mutedFg: "#7c82a4",
395
+ primary: "#2e7de9",
396
+ primaryFg: "#ffffff",
397
+ secondary: "#e3e5ef",
398
+ secondaryFg: "#343b59",
399
+ accent: "#dfe6f6",
400
+ accentFg: "#274a94",
401
+ destructive: "#db4b4b",
402
+ destructiveFg: "#ffffff",
403
+ ring: "#2e7de9",
404
+ input: "#e8eaf2",
405
+ radius: "10px",
406
+ shadow: "rgba(30, 40, 90, 0.12)"
407
+ },
408
+ dark: {
409
+ bg: "#1a1b26",
410
+ fg: "#a9b1d6",
411
+ surface: "#16161e",
412
+ surfaceFg: "#a9b1d6",
413
+ border: "#2b2e3d",
414
+ muted: "#1f2230",
415
+ mutedFg: "#787c99",
416
+ primary: "#7aa2f7",
417
+ primaryFg: "#1a1b26",
418
+ secondary: "#202330",
419
+ secondaryFg: "#a9b1d6",
420
+ accent: "#33467c",
421
+ accentFg: "#c0caf5",
422
+ destructive: "#f7768e",
423
+ destructiveFg: "#1a1b26",
424
+ ring: "#7aa2f7",
425
+ input: "#14141b",
426
+ radius: "10px",
427
+ shadow: "rgba(0, 0, 0, 0.5)"
428
+ }
429
+ },
430
+ forest: {
431
+ light: {
432
+ bg: "#fdf6e3",
433
+ fg: "#5c6a72",
434
+ surface: "#fefaf0",
435
+ surfaceFg: "#5c6a72",
436
+ border: "#e3ddc9",
437
+ muted: "#f2ecdb",
438
+ mutedFg: "#859289",
439
+ primary: "#93b259",
440
+ primaryFg: "#fdf6e3",
441
+ secondary: "#eae4d2",
442
+ secondaryFg: "#5c6a72",
443
+ accent: "#e0e6c8",
444
+ accentFg: "#4d6a3d",
445
+ destructive: "#e67e80",
446
+ destructiveFg: "#fdf6e3",
447
+ ring: "#93b259",
448
+ input: "#f7f1e0",
449
+ radius: "12px",
450
+ shadow: "rgba(70, 90, 60, 0.12)"
451
+ },
452
+ dark: {
453
+ bg: "#2d353b",
454
+ fg: "#d3c6aa",
455
+ surface: "#333c43",
456
+ surfaceFg: "#d3c6aa",
457
+ border: "#414c52",
458
+ muted: "#3d484d",
459
+ mutedFg: "#859289",
460
+ primary: "#a7c080",
461
+ primaryFg: "#2d353b",
462
+ secondary: "#3d484d",
463
+ secondaryFg: "#d3c6aa",
464
+ accent: "#475258",
465
+ accentFg: "#d3c6aa",
466
+ destructive: "#e67e80",
467
+ destructiveFg: "#2d353b",
468
+ ring: "#a7c080",
469
+ input: "#272e33",
470
+ radius: "12px",
471
+ shadow: "rgba(0, 0, 0, 0.4)"
472
+ }
473
+ },
474
+ matcha: {
475
+ light: {
476
+ bg: "#faf5f3",
477
+ fg: "#4c4147",
478
+ surface: "#ffffff",
479
+ surfaceFg: "#4c4147",
480
+ border: "#eadcd8",
481
+ muted: "#f3eae6",
482
+ mutedFg: "#98857f",
483
+ primary: "#e08a9c",
484
+ primaryFg: "#ffffff",
485
+ secondary: "#f0e4df",
486
+ secondaryFg: "#4c4147",
487
+ accent: "#e8f0da",
488
+ accentFg: "#5a7a3f",
489
+ destructive: "#d95f7f",
490
+ destructiveFg: "#ffffff",
491
+ ring: "#e08a9c",
492
+ input: "#f8f1ee",
493
+ radius: "14px",
494
+ shadow: "rgba(180, 90, 110, 0.12)"
495
+ },
496
+ dark: {
497
+ bg: "#28242b",
498
+ fg: "#e9d8d2",
499
+ surface: "#302b33",
500
+ surfaceFg: "#e9d8d2",
501
+ border: "#443a44",
502
+ muted: "#38313a",
503
+ mutedFg: "#b3a09f",
504
+ primary: "#ee9aa6",
505
+ primaryFg: "#28242b",
506
+ secondary: "#38313a",
507
+ secondaryFg: "#e9d8d2",
508
+ accent: "#3f4a38",
509
+ accentFg: "#c8e3b2",
510
+ destructive: "#e06c8a",
511
+ destructiveFg: "#28242b",
512
+ ring: "#ee9aa6",
513
+ input: "#231f26",
514
+ radius: "14px",
515
+ shadow: "rgba(0, 0, 0, 0.45)"
516
+ }
517
+ },
518
+ yellow: {
519
+ light: {
520
+ bg: "#faf6ef",
521
+ fg: "#3d3326",
522
+ surface: "#ffffff",
523
+ surfaceFg: "#3d3326",
524
+ border: "#e8dfcd",
525
+ muted: "#f2ecdf",
526
+ mutedFg: "#9a8a6f",
527
+ primary: "#a37b16",
528
+ primaryFg: "#ffffff",
529
+ secondary: "#ede5d3",
530
+ secondaryFg: "#3d3326",
531
+ accent: "#f7edcb",
532
+ accentFg: "#6b4e0a",
533
+ destructive: "#dc2626",
534
+ destructiveFg: "#ffffff",
535
+ ring: "#a37b16",
536
+ input: "#f7f1e4",
537
+ radius: "12px",
538
+ shadow: "rgba(140, 110, 40, 0.12)"
539
+ },
540
+ dark: {
541
+ bg: "#1c1917",
542
+ fg: "#f5f0e6",
543
+ surface: "#242019",
544
+ surfaceFg: "#f5f0e6",
545
+ border: "#3a332a",
546
+ muted: "#2a2520",
547
+ mutedFg: "#b3a68f",
548
+ primary: "#facc15",
549
+ primaryFg: "#1c1917",
550
+ secondary: "#2a2520",
551
+ secondaryFg: "#f5f0e6",
552
+ accent: "#3f3518",
553
+ accentFg: "#fde68a",
554
+ destructive: "#f87171",
555
+ destructiveFg: "#1c1917",
556
+ ring: "#facc15",
557
+ input: "#211d18",
558
+ radius: "12px",
559
+ shadow: "rgba(0, 0, 0, 0.5)"
560
+ }
561
+ },
562
+ zoro: {
563
+ light: {
564
+ bg: "#f2f6f0",
565
+ fg: "#24302a",
566
+ surface: "#ffffff",
567
+ surfaceFg: "#24302a",
568
+ border: "#d8e4d6",
569
+ muted: "#e9efe6",
570
+ mutedFg: "#7d907e",
571
+ primary: "#15803d",
572
+ primaryFg: "#ffffff",
573
+ secondary: "#e3ecdf",
574
+ secondaryFg: "#24302a",
575
+ accent: "#dcf2e2",
576
+ accentFg: "#166534",
577
+ destructive: "#dc2626",
578
+ destructiveFg: "#ffffff",
579
+ ring: "#15803d",
580
+ input: "#f4f8f2",
581
+ radius: "12px",
582
+ shadow: "rgba(30, 80, 50, 0.1)"
583
+ },
584
+ dark: {
585
+ bg: "#101512",
586
+ fg: "#d8e0d4",
587
+ surface: "#18211b",
588
+ surfaceFg: "#d8e0d4",
589
+ border: "#2c3a30",
590
+ muted: "#1d2720",
591
+ mutedFg: "#93a393",
592
+ primary: "#4ade80",
593
+ primaryFg: "#101512",
594
+ secondary: "#1d2720",
595
+ secondaryFg: "#d8e0d4",
596
+ accent: "#14532d",
597
+ accentFg: "#bbf7d0",
598
+ destructive: "#f87171",
599
+ destructiveFg: "#101512",
600
+ ring: "#4ade80",
601
+ input: "#141b16",
602
+ radius: "12px",
603
+ shadow: "rgba(0, 0, 0, 0.5)"
604
+ }
605
+ },
606
+ hokage: {
607
+ light: {
608
+ bg: "#faf3ea",
609
+ fg: "#4a3a2c",
610
+ surface: "#ffffff",
611
+ surfaceFg: "#4a3a2c",
612
+ border: "#eadcc8",
613
+ muted: "#f3e9db",
614
+ mutedFg: "#a0886a",
615
+ primary: "#c2660f",
616
+ primaryFg: "#ffffff",
617
+ secondary: "#efe2d0",
618
+ secondaryFg: "#4a3a2c",
619
+ accent: "#fbe6c8",
620
+ accentFg: "#7c4a10",
621
+ destructive: "#dc2626",
622
+ destructiveFg: "#ffffff",
623
+ ring: "#c2660f",
624
+ input: "#f8f0e4",
625
+ radius: "12px",
626
+ shadow: "rgba(150, 90, 30, 0.12)"
627
+ },
628
+ dark: {
629
+ bg: "#241a17",
630
+ fg: "#f0e3d8",
631
+ surface: "#2e211c",
632
+ surfaceFg: "#f0e3d8",
633
+ border: "#45372e",
634
+ muted: "#33251f",
635
+ mutedFg: "#b59f8c",
636
+ primary: "#f59e0b",
637
+ primaryFg: "#241a17",
638
+ secondary: "#33251f",
639
+ secondaryFg: "#f0e3d8",
640
+ accent: "#4a3024",
641
+ accentFg: "#fcd9b6",
642
+ destructive: "#ef4444",
643
+ destructiveFg: "#241a17",
644
+ ring: "#f59e0b",
645
+ input: "#201612",
646
+ radius: "12px",
647
+ shadow: "rgba(0, 0, 0, 0.5)"
648
+ }
649
+ },
650
+ slate: {
651
+ light: {
652
+ bg: "#ececee",
653
+ fg: "#09090b",
654
+ surface: "#ffffff",
655
+ surfaceFg: "#09090b",
656
+ border: "#c8c8ce",
657
+ muted: "#e0e0e5",
658
+ mutedFg: "#52525b",
659
+ primary: "#27272a",
660
+ primaryFg: "#fafafa",
661
+ secondary: "#e0e0e5",
662
+ secondaryFg: "#09090b",
663
+ accent: "#d4d4d8",
664
+ accentFg: "#18181b",
665
+ destructive: "#dc2626",
666
+ destructiveFg: "#ffffff",
667
+ ring: "#27272a",
668
+ input: "#c8c8ce",
669
+ radius: "8px",
670
+ shadow: "rgba(24, 24, 27, 0.12)"
671
+ },
672
+ dark: {
673
+ bg: "#050506",
674
+ fg: "#fafafa",
675
+ surface: "#141416",
676
+ surfaceFg: "#fafafa",
677
+ border: "#3f3f46",
678
+ muted: "#1f1f23",
679
+ mutedFg: "#a1a1aa",
680
+ primary: "#e4e4e7",
681
+ primaryFg: "#09090b",
682
+ secondary: "#1f1f23",
683
+ secondaryFg: "#fafafa",
684
+ accent: "#27272a",
685
+ accentFg: "#f4f4f5",
686
+ destructive: "#f87171",
687
+ destructiveFg: "#09090b",
688
+ ring: "#e4e4e7",
689
+ input: "#3f3f46",
690
+ radius: "8px",
691
+ shadow: "rgba(0, 0, 0, 0.6)"
692
+ }
693
+ }
694
+ };
695
+ var THEME_VAR_KEYS = [
696
+ "bg",
697
+ "fg",
698
+ "surface",
699
+ "surface-fg",
700
+ "border",
701
+ "muted",
702
+ "muted-fg",
703
+ "primary",
704
+ "primary-fg",
705
+ "secondary",
706
+ "secondary-fg",
707
+ "accent",
708
+ "accent-fg",
709
+ "destructive",
710
+ "destructive-fg",
711
+ "ring",
712
+ "input",
713
+ "radius",
714
+ "shadow"
715
+ ];
716
+ function kebabToCamel(k) {
717
+ return k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
718
+ }
719
+ function parseThemeCss(css, _id) {
720
+ const out = {};
721
+ const blockRe = /:root\[data-mode="(light|dark)"\]\s*\{([^}]*)\}/g;
722
+ let m;
723
+ while (m = blockRe.exec(String(css || ""))) {
724
+ const mode = m[1];
725
+ const vars = {};
726
+ for (const key of THEME_VAR_KEYS) {
727
+ const vm = new RegExp(`--${key}\\s*:\\s*([^;\\n]+)`).exec(m[2]);
728
+ if (vm) vars[kebabToCamel(key)] = vm[1].trim();
729
+ }
730
+ if (vars.bg && vars.fg && vars.primary) out[mode] = vars;
731
+ }
732
+ if (!out.light || !out.dark) return null;
733
+ const base = {
734
+ surfaceFg: out.light.fg,
735
+ secondary: out.light.muted,
736
+ secondaryFg: out.light.fg,
737
+ destructiveFg: "#ffffff",
738
+ radius: "12px",
739
+ shadow: "rgba(15, 23, 42, 0.1)"
740
+ };
741
+ const fill = (v) => Object.assign({}, base, v);
742
+ return { light: fill(out.light), dark: fill(out.dark) };
743
+ }
744
+ function themeLabelFromCss(css, fallback) {
745
+ const m = /\/\*\s*name\s*:\s*([^*]+)\*\//.exec(String(css || ""));
746
+ return m && m[1].trim() || fallback;
747
+ }
748
+ function clampPalette(value) {
749
+ if (value === "tokyo" || value === "forest" || value === "matcha" || value === "yellow" || value === "zoro" || value === "hokage" || value === "slate" || value === "default") {
750
+ return value;
751
+ }
752
+ if (value === "ocean" || value === "mist") return "tokyo";
753
+ if (value === "violet" || value === "ink") return "matcha";
754
+ if (value === "paper" || value === "noir") return "slate";
755
+ return "default";
756
+ }
757
+ function clampMode(value) {
758
+ return value === "dark" ? "dark" : "light";
759
+ }
760
+ function tokensOf(palette, mode) {
761
+ return TOKENS[clampPalette(palette)][clampMode(mode)];
762
+ }
763
+ function cssVars(t) {
764
+ return [
765
+ `--background:${t.bg}`,
766
+ `--foreground:${t.fg}`,
767
+ `--card:${t.surface}`,
768
+ `--card-foreground:${t.surfaceFg}`,
769
+ `--primary:${t.primary}`,
770
+ `--primary-foreground:${t.primaryFg}`,
771
+ `--secondary:${t.secondary}`,
772
+ `--secondary-foreground:${t.secondaryFg}`,
773
+ `--muted:${t.muted}`,
774
+ `--muted-foreground:${t.mutedFg}`,
775
+ `--accent:${t.accent}`,
776
+ `--accent-foreground:${t.accentFg}`,
777
+ `--destructive:${t.destructive}`,
778
+ `--destructive-foreground:${t.destructiveFg}`,
779
+ `--border:${t.border}`,
780
+ `--input:${t.input}`,
781
+ `--ring:${t.ring}`,
782
+ `--radius:${t.radius}`,
783
+ `--shadow:${t.shadow}`,
784
+ `--color-background:var(--background)`,
785
+ `--color-surface:var(--card)`,
786
+ `--color-foreground:var(--foreground)`,
787
+ `--color-primary:var(--primary)`,
788
+ `--color-primary-foreground:var(--primary-foreground)`,
789
+ `--color-muted:var(--muted)`,
790
+ `--color-muted-foreground:var(--muted-foreground)`,
791
+ `--color-border:var(--border)`,
792
+ `--radius-md:var(--radius)`,
793
+ `--space-4:16px`,
794
+ `--font-sans:ui-sans-serif,system-ui,-apple-system,sans-serif`
795
+ ].join(";");
796
+ }
797
+ function runnerThemeCss() {
798
+ const blocks = [
799
+ `:root,html[data-theme="light"]:not([data-palette]),html[data-theme="light"][data-palette="default"]{${cssVars(TOKENS.default.light)}}`,
800
+ `html[data-theme="dark"]:not([data-palette]),html[data-theme="dark"][data-palette="default"]{${cssVars(TOKENS.default.dark)}}`
801
+ ];
802
+ ["tokyo", "forest", "matcha", "yellow", "zoro", "hokage", "slate"].forEach((id) => {
803
+ blocks.push(`html[data-theme="light"][data-palette="${id}"]{${cssVars(TOKENS[id].light)}}`);
804
+ blocks.push(`html[data-theme="dark"][data-palette="${id}"]{${cssVars(TOKENS[id].dark)}}`);
805
+ });
806
+ blocks.push(`html[data-theme="dark"] input[type="date"],html[data-theme="dark"] input[type="time"],html[data-theme="dark"] input[type="datetime-local"],html[data-theme="dark"] input[type="month"],html[data-theme="dark"] input[type="week"]{color-scheme:dark}`);
807
+ blocks.push(`html[data-theme="light"] input[type="date"],html[data-theme="light"] input[type="time"],html[data-theme="light"] input[type="datetime-local"],html[data-theme="light"] input[type="month"],html[data-theme="light"] input[type="week"]{color-scheme:light}`);
808
+ return blocks.join("\n ");
809
+ }
810
+ function applyThemeTo(el, theme, palette, custom) {
811
+ const mode = clampMode(theme);
812
+ const c = custom && palette ? custom[String(palette)] : void 0;
813
+ const pal = c ? String(palette) : clampPalette(palette);
814
+ const t = c && c.tokens && c.tokens[mode] || tokensOf(pal, mode);
815
+ el.setAttribute("data-theme", mode);
816
+ el.setAttribute("data-palette", pal);
817
+ const map = {
818
+ "--dsw-alias-bg": t.bg,
819
+ "--dsw-alias-fg": t.fg,
820
+ "--dsw-alias-surface": t.surface,
821
+ "--dsw-alias-border": t.border,
822
+ "--dsw-alias-muted": t.muted,
823
+ "--dsw-alias-primary": t.primary,
824
+ "--dsw-alias-primary-fg": t.primaryFg,
825
+ "--dsw-alias-accent": t.accent,
826
+ "--dsw-alias-shadow": t.shadow,
827
+ "--background": t.bg,
828
+ "--foreground": t.fg,
829
+ "--card": t.surface,
830
+ "--card-foreground": t.surfaceFg,
831
+ "--primary": t.primary,
832
+ "--primary-foreground": t.primaryFg,
833
+ "--secondary": t.secondary,
834
+ "--secondary-foreground": t.secondaryFg,
835
+ "--muted": t.muted,
836
+ "--muted-foreground": t.mutedFg,
837
+ "--accent": t.accent,
838
+ "--accent-foreground": t.accentFg,
839
+ "--border": t.border,
840
+ "--input": t.input,
841
+ "--ring": t.ring,
842
+ "--destructive": t.destructive,
843
+ "--destructive-foreground": t.destructiveFg,
844
+ "--radius": t.radius,
845
+ "--shadow": t.shadow
846
+ };
847
+ for (const k of Object.keys(map)) el.style.setProperty(k, map[k]);
848
+ el.style.background = t.bg;
849
+ el.style.color = t.fg;
850
+ return { theme: mode, palette: pal };
851
+ }
852
+
853
+ // src/actions.ts
854
+ function activeAppFrom(state2) {
855
+ const tab = state2.tabs.find((t) => t.kind === "app" && t.id === state2.active) || state2.tabs.find((t) => t.kind === "app");
856
+ return tab?.app ?? null;
857
+ }
858
+ function errorMessage(err) {
859
+ return err instanceof Error ? err.message : String(err);
860
+ }
861
+ function pushAppTab(app) {
862
+ const s = getPanelState();
863
+ const id = "app:" + app.id;
864
+ if (!s.tabs.some((t) => t.id === id)) {
865
+ setPanelState({ tabs: [...s.tabs, { id, title: app.name || app.id, kind: "app", app }] });
866
+ }
867
+ return id;
868
+ }
869
+ function asCustomPalettes(value) {
870
+ return value;
871
+ }
872
+ function createPanelActions(host, getRootEl, i18n) {
873
+ setPanelState({ capabilities: capabilitiesOf(host), locale: i18n.locale, emptyText: host.emptyText });
874
+ return {
875
+ openAppTab: (app) => {
876
+ const id = pushAppTab(app);
877
+ setPanelState({ active: id });
878
+ host.frame.mount(app.id);
879
+ },
880
+ closeTab: (id) => {
881
+ if (id === "all") return;
882
+ const s = getPanelState();
883
+ const tab = s.tabs.find((t) => t.id === id);
884
+ setPanelState({
885
+ tabs: s.tabs.filter((t) => t.id !== id),
886
+ active: s.active === id ? "all" : s.active
887
+ });
888
+ if (tab?.app) host.frame.unmount(tab.app.id);
889
+ },
890
+ switchTab: (id) => {
891
+ setPanelState({ active: id });
892
+ const s = getPanelState();
893
+ const tab = s.tabs.find((t) => t.id === id && t.kind === "app");
894
+ if (tab?.app) host.frame.mount(tab.app.id);
895
+ },
896
+ setDock: (next) => {
897
+ setPanelState({ dock: next });
898
+ try {
899
+ localStorage.setItem("mma-dock", next);
900
+ } catch {
901
+ }
902
+ },
903
+ setQuery: (q) => setPanelState({ query: q }),
904
+ toggleThemePop: () => setPanelState({ themePopOpen: !getPanelState().themePopOpen }),
905
+ setAppearance: (next, scope) => {
906
+ const s = getPanelState();
907
+ const theme = next.theme ? String(next.theme) : s.theme;
908
+ const palette = next.palette ? String(next.palette) : s.palette;
909
+ setPanelState({ theme, palette });
910
+ const root = getRootEl();
911
+ if (root) {
912
+ applyThemeTo(root, theme, palette, asCustomPalettes(s.customPalettes));
913
+ }
914
+ if (scope === "app") {
915
+ const app = activeAppFrom(getPanelState());
916
+ if (app && host.appTheme) {
917
+ const nextTheme = { theme, palette };
918
+ host.appTheme.save(app.id, nextTheme).catch(() => {
919
+ });
920
+ const cur = getPanelState();
921
+ setPanelState({
922
+ apps: cur.apps.some((a) => a.id === app.id) ? cur.apps.map((a) => a.id === app.id ? { ...a, theme: nextTheme } : a) : [...cur.apps, { ...app, theme: nextTheme }],
923
+ tabs: cur.tabs.map(
924
+ (t) => t.app?.id === app.id ? { ...t, app: { ...t.app, theme: nextTheme } } : t
925
+ )
926
+ });
927
+ }
928
+ } else {
929
+ host.persistTheme?.(theme, palette);
930
+ }
931
+ host.frame.syncEnv?.();
932
+ },
933
+ setThemeScope: (scope) => setPanelState({ themeScope: scope }),
934
+ clearAppTheme: () => {
935
+ const app = activeAppFrom(getPanelState());
936
+ if (app && host.appTheme) {
937
+ host.appTheme.clear(app.id).catch(() => {
938
+ });
939
+ const cur = getPanelState();
940
+ setPanelState({
941
+ apps: cur.apps.map((a) => a.id === app.id ? { ...a, theme: null } : a),
942
+ tabs: cur.tabs.map(
943
+ (t) => t.app?.id === app.id ? { ...t, app: { ...t.app, theme: null } } : t
944
+ )
945
+ });
946
+ host.frame.syncEnv?.();
947
+ }
948
+ },
949
+ getActiveApp: () => activeAppFrom(getPanelState()),
950
+ toggleSettings: (open) => {
951
+ setPanelState({ settingsOpen: open, cfgMsg: open ? "" : getPanelState().cfgMsg });
952
+ if (open && host.config) {
953
+ host.config.load().then((cfg) => {
954
+ setPanelState({ cfg, cfgVersion: getPanelState().cfgVersion + 1 });
955
+ }).catch(() => {
956
+ });
957
+ }
958
+ },
959
+ getCfg: () => getPanelState().cfg,
960
+ saveHostConfig: (form) => {
961
+ if (!host.config) return;
962
+ host.config.save(form).then(() => {
963
+ setPanelState({
964
+ cfg: { ...form },
965
+ cfgMsg: i18n.t("config.saved"),
966
+ cfgVersion: getPanelState().cfgVersion + 1
967
+ });
968
+ }).catch((e) => {
969
+ setPanelState({ cfgMsg: i18n.t("config.error", { message: errorMessage(e) }) });
970
+ });
971
+ },
972
+ toggleBrowse: (kind) => {
973
+ const s = getPanelState();
974
+ if (s.browseOpen) {
975
+ setPanelState({ browseOpen: false });
976
+ return;
977
+ }
978
+ const app = activeAppFrom(s);
979
+ if (!app) return;
980
+ const k = kind === "storage" ? "storage" : "history";
981
+ if (k === "history" && !host.history) return;
982
+ if (k === "storage" && !host.storage) return;
983
+ setPanelState({
984
+ browseOpen: true,
985
+ browseKind: k,
986
+ browseAppId: app.id,
987
+ browseAppName: app.name || app.id,
988
+ browseDetail: null,
989
+ browseTable: null,
990
+ browseTableValue: null,
991
+ browseOpenFile: null,
992
+ browseError: null,
993
+ browseList: [],
994
+ browseLoading: true
995
+ });
996
+ if (k === "history" && host.history) {
997
+ host.history.list(app.id).then((list) => {
998
+ setPanelState({ browseList: list, browseLoading: false });
999
+ }).catch((e) => setPanelState({ browseError: errorMessage(e), browseLoading: false }));
1000
+ } else if (host.storage) {
1001
+ host.storage.listTables(app.id).then((list) => {
1002
+ setPanelState({ browseList: list, browseLoading: false });
1003
+ }).catch((e) => setPanelState({ browseError: errorMessage(e), browseLoading: false }));
1004
+ }
1005
+ },
1006
+ loadCommitDetail: (id) => {
1007
+ const s = getPanelState();
1008
+ if (!host.history || !s.browseAppId) return;
1009
+ setPanelState({ browseDetail: { id, loading: true } });
1010
+ host.history.detail(s.browseAppId, id).then((c) => {
1011
+ setPanelState({ browseDetail: c });
1012
+ }).catch((e) => setPanelState({ browseDetail: { id, error: errorMessage(e), files: [] } }));
1013
+ },
1014
+ loadTable: (name) => {
1015
+ const s = getPanelState();
1016
+ if (!host.storage || !s.browseAppId) return;
1017
+ setPanelState({ browseTable: name, browseTableValue: null, browseLoading: true });
1018
+ host.storage.readTable(s.browseAppId, name).then((v) => {
1019
+ setPanelState({ browseTableValue: v, browseLoading: false });
1020
+ }).catch(
1021
+ (e) => setPanelState({ browseTableValue: { __error__: errorMessage(e) }, browseLoading: false })
1022
+ );
1023
+ },
1024
+ browseBack: () => setPanelState({ browseDetail: null, browseTable: null, browseTableValue: null, browseOpenFile: null }),
1025
+ browseFile: (path) => setPanelState({ browseOpenFile: getPanelState().browseOpenFile === path ? null : path }),
1026
+ reloadActive: () => {
1027
+ const app = activeAppFrom(getPanelState());
1028
+ if (app) host.frame.reload(app.id);
1029
+ },
1030
+ askDelete: () => {
1031
+ const app = activeAppFrom(getPanelState());
1032
+ if (app) setPanelState({ pendingDelete: app.id });
1033
+ },
1034
+ hideModal: () => setPanelState({ pendingDelete: null }),
1035
+ confirmDelete: async () => {
1036
+ const s = getPanelState();
1037
+ const id = s.pendingDelete;
1038
+ if (!id) return;
1039
+ setPanelState({ pendingDelete: null });
1040
+ if (host.deleteApp) {
1041
+ await host.deleteApp(id).catch(() => {
1042
+ });
1043
+ }
1044
+ const tab = s.tabs.find((t) => t.id === "app:" + id);
1045
+ setPanelState({
1046
+ tabs: getPanelState().tabs.filter((t) => t.id !== "app:" + id),
1047
+ active: getPanelState().active === "app:" + id ? "all" : getPanelState().active,
1048
+ apps: getPanelState().apps.filter((a) => a.id !== id)
1049
+ });
1050
+ if (tab?.app) host.frame.unmount(tab.app.id);
1051
+ },
1052
+ closeDashboard: () => host.closePanel(),
1053
+ fetchApps: () => {
1054
+ setPanelState({ loading: true, error: null, emptyText: host.emptyText });
1055
+ host.fetchApps().then((apps) => {
1056
+ setPanelState({ apps, loading: false });
1057
+ }).catch((e) => {
1058
+ setPanelState({
1059
+ error: isHostUnreachable(e) ? i18n.t("list.hostUnreachable", { url: e.url }) : errorMessage(e),
1060
+ loading: false
1061
+ });
1062
+ });
1063
+ },
1064
+ setCardStyle: (v) => setPanelState({ cardStyle: v })
1065
+ };
1066
+ }
1067
+ function defaultHideThemePop() {
1068
+ if (!getPanelState().themePopOpen) return false;
1069
+ setPanelState({ themePopOpen: false });
1070
+ return true;
1071
+ }
1072
+ function clampPaletteId(v) {
1073
+ return clampPalette(v);
1074
+ }
1075
+ var PanelActionsContext = React__namespace.createContext(null);
1076
+ var PanelI18nContext = React__namespace.createContext(null);
1077
+ function PanelProvider({
1078
+ actions,
1079
+ i18n,
1080
+ children
1081
+ }) {
1082
+ return /* @__PURE__ */ jsxRuntime.jsx(PanelI18nContext.Provider, { value: i18n, children: /* @__PURE__ */ jsxRuntime.jsx(PanelActionsContext.Provider, { value: actions, children }) });
1083
+ }
1084
+ function usePanelActions() {
1085
+ const ctx = React__namespace.useContext(PanelActionsContext);
1086
+ if (!ctx) throw new Error("usePanelActions must be used inside <PanelProvider>");
1087
+ return ctx;
1088
+ }
1089
+ function usePanelI18n() {
1090
+ const ctx = React__namespace.useContext(PanelI18nContext);
1091
+ if (!ctx) throw new Error("usePanelI18n must be used inside <PanelProvider>");
1092
+ return ctx;
1093
+ }
1094
+
1095
+ // src/lib.ts
1096
+ function hue(id) {
1097
+ let h = 0;
1098
+ const s = String(id || "");
1099
+ for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) % 360;
1100
+ return h;
1101
+ }
1102
+ function appBlurb(a) {
1103
+ return String(a.description || a.id || "");
1104
+ }
1105
+ function monoOf(a) {
1106
+ return String(a.acronym || (a.name || "?").slice(0, 2) || "?");
1107
+ }
1108
+ function Loading() {
1109
+ const { t } = usePanelI18n();
1110
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-load", role: "status", "aria-label": t("load.label"), children: [
1111
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-load-art", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 88 64", fill: "none", children: [
1112
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "10", y: "8", width: "68", height: "48", rx: "10", stroke: "currentColor", strokeWidth: "1.6", opacity: ".35" }),
1113
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "10", y: "8", width: "68", height: "12", rx: "10", fill: "currentColor", opacity: ".08" }),
1114
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "20", cy: "14", r: "2.2", fill: "currentColor", opacity: ".35" }),
1115
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "26", y: "12.2", width: "18", height: "3.6", rx: "1.8", fill: "currentColor", opacity: ".22" }),
1116
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "20", y: "28", width: "28", height: "4", rx: "2", fill: "currentColor", opacity: ".16" }),
1117
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "20", y: "36", width: "40", height: "4", rx: "2", fill: "currentColor", opacity: ".1" }),
1118
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "20", y: "44", width: "22", height: "4", rx: "2", fill: "currentColor", opacity: ".08" }),
1119
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M62 40c6 0 10 5 10 10", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", opacity: ".85" }),
1120
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "72", cy: "50", r: "3.2", fill: "currentColor", opacity: ".9" })
1121
+ ] }) }),
1122
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-load-dots", children: [
1123
+ /* @__PURE__ */ jsxRuntime.jsx("i", {}),
1124
+ /* @__PURE__ */ jsxRuntime.jsx("i", {}),
1125
+ /* @__PURE__ */ jsxRuntime.jsx("i", {})
1126
+ ] })
1127
+ ] });
1128
+ }
1129
+ function Mark({ app, style }) {
1130
+ const mono = monoOf(app);
1131
+ if (style === "etch") {
1132
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-etch", style: { "--h": hue(app.id) }, children: mono });
1133
+ }
1134
+ if (style === "stamp") {
1135
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-stamp", style: { "--h": hue(app.id) }, children: mono });
1136
+ }
1137
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-mono", style: { "--h": hue(app.id) }, children: mono });
1138
+ }
1139
+ function AppCard({ app }) {
1140
+ const s = usePanelState();
1141
+ const actions = usePanelActions();
1142
+ const { t } = usePanelI18n();
1143
+ const open = s.tabs.some((tab) => tab.id === "app:" + app.id);
1144
+ const commits = Number(app.commits || 0);
1145
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1146
+ "button",
1147
+ {
1148
+ type: "button",
1149
+ className: "mma-card",
1150
+ style: { "--h": hue(app.id) },
1151
+ onClick: () => actions.openAppTab(app),
1152
+ children: [
1153
+ /* @__PURE__ */ jsxRuntime.jsx(Mark, { app, style: s.cardStyle }),
1154
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: app.name || app.id }),
1155
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: appBlurb(app) }),
1156
+ commits > 0 || open ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-meta", children: [
1157
+ commits > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-ver", children: t("list.commits", { count: commits }) }) : null,
1158
+ open ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-open", children: [
1159
+ /* @__PURE__ */ jsxRuntime.jsx("i", {}),
1160
+ t("list.open")
1161
+ ] }) : null
1162
+ ] }) : null
1163
+ ]
1164
+ }
1165
+ );
1166
+ }
1167
+ function AppRow({ app }) {
1168
+ const s = usePanelState();
1169
+ const actions = usePanelActions();
1170
+ const { t } = usePanelI18n();
1171
+ const open = s.tabs.some((tab) => tab.id === "app:" + app.id);
1172
+ const commits = Number(app.commits || 0);
1173
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1174
+ "button",
1175
+ {
1176
+ type: "button",
1177
+ className: "mma-row",
1178
+ style: { "--h": hue(app.id) },
1179
+ onClick: () => actions.openAppTab(app),
1180
+ children: [
1181
+ /* @__PURE__ */ jsxRuntime.jsx(Mark, { app, style: s.cardStyle }),
1182
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-twrap", children: [
1183
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-t", children: app.name || app.id }),
1184
+ /* @__PURE__ */ jsxRuntime.jsx("small", { children: appBlurb(app) })
1185
+ ] }),
1186
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-right", children: [
1187
+ open ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-open", children: [
1188
+ /* @__PURE__ */ jsxRuntime.jsx("i", {}),
1189
+ t("list.open")
1190
+ ] }) : commits > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-ver", children: t("list.commits", { count: commits }) }) : null,
1191
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "mma-chev", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.5 6l6 6-6 6" }) })
1192
+ ] })
1193
+ ]
1194
+ }
1195
+ );
1196
+ }
1197
+ function Search() {
1198
+ const s = usePanelState();
1199
+ const actions = usePanelActions();
1200
+ const { t } = usePanelI18n();
1201
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-search", children: [
1202
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1203
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
1204
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 20l-3-3" })
1205
+ ] }),
1206
+ /* @__PURE__ */ jsxRuntime.jsx("input", { type: "search", placeholder: t("list.search"), value: s.query, onChange: (e) => actions.setQuery(e.target.value) })
1207
+ ] });
1208
+ }
1209
+ function AppList() {
1210
+ const s = usePanelState();
1211
+ const actions = usePanelActions();
1212
+ const { t } = usePanelI18n();
1213
+ const q = String(s.query || "").trim().toLowerCase();
1214
+ const apps = q ? s.apps.filter((a) => [a.name, a.id, a.description].join(" ").toLowerCase().includes(q)) : s.apps;
1215
+ if (s.loading && !s.apps.length) return /* @__PURE__ */ jsxRuntime.jsx(Loading, {});
1216
+ if (s.error) {
1217
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-error", children: [
1218
+ t("list.loadError", { message: s.error }),
1219
+ " ",
1220
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-textbtn", onClick: () => actions.fetchApps(), children: t("list.retry") })
1221
+ ] });
1222
+ }
1223
+ if (!s.apps.length) {
1224
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-empty", children: s.emptyText || t("list.empty") });
1225
+ }
1226
+ if (!apps.length) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-empty", children: t("list.noMatch", { query: s.query }) });
1227
+ const Item = s.dock === "side" ? AppRow : AppCard;
1228
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-grid", children: apps.map((app) => /* @__PURE__ */ jsxRuntime.jsx(Item, { app }, app.id)) });
1229
+ }
1230
+ function ListRegion() {
1231
+ const s = usePanelState();
1232
+ const { t } = usePanelI18n();
1233
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-list", id: "mma-list", children: [
1234
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-list-head", children: [
1235
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: t("list.title") }),
1236
+ /* @__PURE__ */ jsxRuntime.jsx("span", { id: "mma-app-count", children: t("list.count", { count: s.apps.length }) })
1237
+ ] }),
1238
+ /* @__PURE__ */ jsxRuntime.jsx(Search, {}),
1239
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: "mma-list-body", children: /* @__PURE__ */ jsxRuntime.jsx(AppList, {}) })
1240
+ ] });
1241
+ }
1242
+ function isCommit(value) {
1243
+ return typeof value === "object" && value !== null && "id" in value && "message" in value;
1244
+ }
1245
+ function isStorageTable(value) {
1246
+ return typeof value === "object" && value !== null && "name" in value;
1247
+ }
1248
+ function DiffPreview({ text }) {
1249
+ const lines = text.replace(/\n$/, "").split("\n");
1250
+ return /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mma-preview mma-diff-preview", children: lines.map((line, i) => {
1251
+ const kind = line.startsWith("+") ? "add" : line.startsWith("-") ? "del" : "ctx";
1252
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `mma-diff-line mma-diff-line--${kind}`, children: [
1253
+ line || " ",
1254
+ "\n"
1255
+ ] }, i);
1256
+ }) });
1257
+ }
1258
+ function CommitItem({ c }) {
1259
+ const actions = usePanelActions();
1260
+ const { t } = usePanelI18n();
1261
+ const files = (c.files || []).length;
1262
+ let add = 0;
1263
+ let del = 0;
1264
+ for (const f of c.files || []) {
1265
+ if ((f.add || 0) > 0) add += f.add || 0;
1266
+ if ((f.del || 0) > 0) del += f.del || 0;
1267
+ }
1268
+ return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "mma-bitem", onClick: () => actions.loadCommitDetail(c.id), title: c.message, children: [
1269
+ /* @__PURE__ */ jsxRuntime.jsx("b", { className: "mma-commit-msg mma-commit-msg--clamp2", children: c.message }),
1270
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "meta", children: [
1271
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: String(c.id).slice(0, 7) }),
1272
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: c.time }),
1273
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("browse.files", { count: files }) }),
1274
+ add ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-plus", children: [
1275
+ "+",
1276
+ add
1277
+ ] }) : null,
1278
+ del ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-minus", children: [
1279
+ "-",
1280
+ del
1281
+ ] }) : null
1282
+ ] })
1283
+ ] });
1284
+ }
1285
+ function StorageItem({ table }) {
1286
+ const actions = usePanelActions();
1287
+ return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "mma-bitem", onClick: () => actions.loadTable(table.name), children: [
1288
+ /* @__PURE__ */ jsxRuntime.jsx("b", { children: table.name }),
1289
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "meta", children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1291
+ table.size || 0,
1292
+ " B"
1293
+ ] }),
1294
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: table.updatedAt || "" })
1295
+ ] })
1296
+ ] });
1297
+ }
1298
+ function CommitDetail() {
1299
+ const s = usePanelState();
1300
+ const actions = usePanelActions();
1301
+ const { t } = usePanelI18n();
1302
+ const [msgExpanded, setMsgExpanded] = React__namespace.useState(false);
1303
+ const d = s.browseDetail;
1304
+ React__namespace.useEffect(() => {
1305
+ setMsgExpanded(false);
1306
+ }, [d?.id]);
1307
+ if (!d) return null;
1308
+ if (d.loading) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-bempty", children: t("browse.loading") });
1309
+ if (d.error) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-berr", children: d.error });
1310
+ const longMsg = (d.message || "").length > 80 || (d.message || "").includes("\n");
1311
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1312
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-browse-head mma-browse-head--tools", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-btns", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => actions.browseBack(), children: t("browse.back") }) }) }),
1313
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-commit-meta", children: [
1314
+ /* @__PURE__ */ jsxRuntime.jsx(
1315
+ "p",
1316
+ {
1317
+ className: msgExpanded ? "mma-commit-msg" : "mma-commit-msg mma-commit-msg--clamp3",
1318
+ title: d.message,
1319
+ children: d.message
1320
+ }
1321
+ ),
1322
+ longMsg ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-commit-msg-toggle", onClick: () => setMsgExpanded((v) => !v), children: msgExpanded ? t("browse.collapseMsg") : t("browse.expandMsg") }) : null,
1323
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "meta mma-commit-ids", children: [
1324
+ /* @__PURE__ */ jsxRuntime.jsx("code", { children: String(d.id || "").slice(0, 7) }),
1325
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: d.time })
1326
+ ] })
1327
+ ] }),
1328
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-files", children: [
1329
+ (d.files || []).map((f) => {
1330
+ const open = s.browseOpenFile === f.path;
1331
+ const add = f.add || 0;
1332
+ const del = f.del || 0;
1333
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1334
+ /* @__PURE__ */ jsxRuntime.jsxs(
1335
+ "button",
1336
+ {
1337
+ type: "button",
1338
+ className: "mma-fitem",
1339
+ "data-open": open ? "1" : void 0,
1340
+ onClick: () => actions.browseFile(f.path),
1341
+ children: [
1342
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-diff", children: [
1343
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: add > 0 ? "mma-plus" : "mma-diff-zero", children: add > 0 ? `+${add}` : "\xB7" }),
1344
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: del > 0 ? "mma-minus" : "mma-diff-zero", children: del > 0 ? `-${del}` : "\xB7" })
1345
+ ] }),
1346
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "p", children: f.path }),
1347
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "mma-chevron", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.5 6l6 6-6 6" }) })
1348
+ ]
1349
+ }
1350
+ ),
1351
+ open && f.preview ? /* @__PURE__ */ jsxRuntime.jsx(DiffPreview, { text: f.preview }) : null
1352
+ ] }, f.path);
1353
+ }),
1354
+ !(d.files || []).length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-bempty", children: t("browse.noFiles") }) : null
1355
+ ] })
1356
+ ] });
1357
+ }
1358
+ function TableDetail() {
1359
+ const s = usePanelState();
1360
+ const actions = usePanelActions();
1361
+ const { t } = usePanelI18n();
1362
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1363
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-browse-head", children: [
1364
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-btns", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => actions.browseBack(), children: t("browse.back") }) }),
1365
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: s.browseTable })
1366
+ ] }),
1367
+ s.browseLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-bempty", children: t("browse.loading") }) : /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "mma-preview", style: { maxHeight: "none", whiteSpace: "pre-wrap", wordBreak: "break-all" }, children: JSON.stringify(s.browseTableValue, null, 2) })
1368
+ ] });
1369
+ }
1370
+ function Browse() {
1371
+ const s = usePanelState();
1372
+ const actions = usePanelActions();
1373
+ const { t } = usePanelI18n();
1374
+ if (!s.browseOpen) return null;
1375
+ let content;
1376
+ if (s.browseKind === "history" && s.browseDetail) content = /* @__PURE__ */ jsxRuntime.jsx(CommitDetail, {});
1377
+ else if (s.browseKind === "storage" && s.browseTable !== null) content = /* @__PURE__ */ jsxRuntime.jsx(TableDetail, {});
1378
+ else {
1379
+ content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1380
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-browse-head", children: [
1381
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { children: [
1382
+ s.browseKind === "history" ? t("browse.history") : t("browse.storage"),
1383
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sub", children: s.browseAppName })
1384
+ ] }),
1385
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-btns", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => actions.toggleBrowse(""), children: t("browse.close") }) })
1386
+ ] }),
1387
+ s.browseLoading && !s.browseList.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-bempty", children: t("browse.loading") }) : s.browseError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-berr", children: s.browseError }) : !s.browseList.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-bempty", children: s.browseKind === "history" ? t("browse.noCommits") : t("browse.noStorage") }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-blist", children: s.browseList.map(
1388
+ (item, i) => s.browseKind === "history" && isCommit(item) ? /* @__PURE__ */ jsxRuntime.jsx(CommitItem, { c: item }, i) : isStorageTable(item) ? /* @__PURE__ */ jsxRuntime.jsx(StorageItem, { table: item }, i) : null
1389
+ ) })
1390
+ ] });
1391
+ }
1392
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-browse", id: "mma-browse", "data-open": "1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-browse-body", id: "mma-browse-body", children: content }) });
1393
+ }
1394
+ function Modal() {
1395
+ const s = usePanelState();
1396
+ const actions = usePanelActions();
1397
+ const { t } = usePanelI18n();
1398
+ if (!s.pendingDelete) return null;
1399
+ const app = s.apps.find((a) => a.id === s.pendingDelete) || { id: s.pendingDelete, name: s.pendingDelete };
1400
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-modal", id: "mma-modal", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-dialog", children: [
1401
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: t("modal.title") }),
1402
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: t("modal.body", { name: app.name || app.id }) }),
1403
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-dialog-actions", children: [
1404
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", id: "mma-dialog-cancel", onClick: () => actions.hideModal(), children: t("modal.cancel") }),
1405
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", id: "mma-dialog-ok", className: "go", onClick: () => void actions.confirmDelete(), children: t("modal.confirm") })
1406
+ ] })
1407
+ ] }) });
1408
+ }
1409
+ function Settings() {
1410
+ const s = usePanelState();
1411
+ const actions = usePanelActions();
1412
+ const { t } = usePanelI18n();
1413
+ const [form, setForm] = React__namespace.useState({});
1414
+ React__namespace.useEffect(() => {
1415
+ if (!s.settingsOpen) return;
1416
+ setForm(s.cfg && Object.keys(s.cfg).length ? s.cfg : actions.getCfg());
1417
+ }, [s.settingsOpen, s.cfgVersion, s.cfg, actions]);
1418
+ if (!s.capabilities.config) return null;
1419
+ const set = (k) => (e) => setForm((prev) => ({ ...prev, [k]: e.target.value }));
1420
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings", id: "mma-settings", "data-open": s.settingsOpen ? "1" : "0", children: [
1421
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-head", children: [
1422
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: t("settings.title") }),
1423
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-iconbtn", id: "mma-cfg-close", onClick: () => actions.toggleSettings(false), children: "\u2715" })
1424
+ ] }),
1425
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1426
+ t("settings.hostPort"),
1427
+ /* @__PURE__ */ jsxRuntime.jsx("input", { id: "mma-cfg-port", type: "number", value: form.hostPort || "", onChange: set("hostPort") })
1428
+ ] }),
1429
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1430
+ t("settings.language"),
1431
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "mma-cfg-lang", value: form.locale || form.chatLanguage || "zh-CN", onChange: set("locale"), children: [
1432
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "zh-CN", children: t("settings.langZh") }),
1433
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "en", children: t("settings.langEn") })
1434
+ ] })
1435
+ ] }),
1436
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1437
+ t("settings.theme"),
1438
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "mma-cfg-theme", value: form.theme || "light", onChange: set("theme"), children: [
1439
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "light", children: t("theme.light") }),
1440
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "dark", children: t("theme.dark") })
1441
+ ] })
1442
+ ] }),
1443
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1444
+ t("settings.palette"),
1445
+ /* @__PURE__ */ jsxRuntime.jsx("select", { id: "mma-cfg-palette", value: form.palette || "default", onChange: set("palette"), children: PALETTES.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.id, children: t(`palette.${p.id}`) }, p.id)) })
1446
+ ] }),
1447
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1448
+ t("settings.cardStyle"),
1449
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { id: "mma-cfg-cardstyle", value: form.cardStyle || "stamp", onChange: set("cardStyle"), children: [
1450
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "stamp", children: t("settings.cardStamp") }),
1451
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "etch", children: t("settings.cardEtch") }),
1452
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "hero", children: t("settings.cardHero") }),
1453
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "list", children: t("settings.cardList") })
1454
+ ] })
1455
+ ] }),
1456
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1457
+ t("settings.llmProvider"),
1458
+ /* @__PURE__ */ jsxRuntime.jsx("input", { id: "mma-cfg-provider", value: form.provider || "", onChange: set("provider") })
1459
+ ] }),
1460
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
1461
+ t("settings.llmModel"),
1462
+ /* @__PURE__ */ jsxRuntime.jsx("input", { id: "mma-cfg-model", value: form.model || "", onChange: set("model") })
1463
+ ] }),
1464
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-actions", children: [
1465
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-textbtn", id: "mma-cfg-save", onClick: () => actions.saveHostConfig(form), children: t("settings.save") }),
1466
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-msg", id: "mma-cfg-msg", children: s.cfgMsg })
1467
+ ] })
1468
+ ] });
1469
+ }
1470
+ function Tabs() {
1471
+ const s = usePanelState();
1472
+ const actions = usePanelActions();
1473
+ const { t } = usePanelI18n();
1474
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-tabs", id: "mma-tabs", children: s.tabs.map((tb) => {
1475
+ const active = tb.id === s.active;
1476
+ const close = tb.id === "all" ? null : /* @__PURE__ */ jsxRuntime.jsx(
1477
+ "span",
1478
+ {
1479
+ className: "mma-tab-x",
1480
+ role: "button",
1481
+ "aria-label": t("tabs.close", { title: tb.title }),
1482
+ onClick: (e) => {
1483
+ e.stopPropagation();
1484
+ actions.closeTab(tb.id);
1485
+ },
1486
+ children: "\xD7"
1487
+ }
1488
+ );
1489
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1490
+ "button",
1491
+ {
1492
+ type: "button",
1493
+ className: "mma-tab",
1494
+ "data-active": active ? "1" : "0",
1495
+ title: tb.id === "all" ? t("tabs.allTitle") : tb.title,
1496
+ onClick: () => actions.switchTab(tb.id),
1497
+ children: [
1498
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: tb.title }),
1499
+ close
1500
+ ]
1501
+ },
1502
+ tb.id
1503
+ );
1504
+ }) });
1505
+ }
1506
+ function ThemePop() {
1507
+ const s = usePanelState();
1508
+ const actions = usePanelActions();
1509
+ const { t } = usePanelI18n();
1510
+ const app = actions.getActiveApp();
1511
+ const appTheme = app ? app.theme : null;
1512
+ const customs = s.customPalettes || {};
1513
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1514
+ s.themePopOpen ? /* @__PURE__ */ jsxRuntime.jsx(
1515
+ "div",
1516
+ {
1517
+ className: "mma-pop-scrim",
1518
+ "aria-hidden": "true",
1519
+ onPointerDown: (e) => {
1520
+ e.preventDefault();
1521
+ e.stopPropagation();
1522
+ defaultHideThemePop();
1523
+ }
1524
+ }
1525
+ ) : null,
1526
+ /* @__PURE__ */ jsxRuntime.jsxs(
1527
+ "div",
1528
+ {
1529
+ className: "mma-pop",
1530
+ id: "mma-theme-pop",
1531
+ role: "menu",
1532
+ "data-open": s.themePopOpen ? "1" : "0",
1533
+ onClick: (e) => e.stopPropagation(),
1534
+ onPointerDown: (e) => e.stopPropagation(),
1535
+ children: [
1536
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-seg", children: ["light", "dark"].map((mode) => /* @__PURE__ */ jsxRuntime.jsx(
1537
+ "button",
1538
+ {
1539
+ type: "button",
1540
+ "data-mode": mode,
1541
+ "data-on": s.theme === mode ? "1" : "0",
1542
+ onClick: () => actions.setAppearance({ theme: mode }, s.themeScope),
1543
+ children: t(`theme.${mode}`)
1544
+ },
1545
+ mode
1546
+ )) }),
1547
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-pop-list", children: [
1548
+ PALETTES.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
1549
+ "button",
1550
+ {
1551
+ type: "button",
1552
+ className: "mma-swatch",
1553
+ "data-palette": p.id,
1554
+ role: "menuitem",
1555
+ "data-on": s.palette === p.id ? "1" : "0",
1556
+ onClick: () => actions.setAppearance({ palette: p.id }, s.themeScope),
1557
+ children: [
1558
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: p.swatch } }),
1559
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t(`palette.${p.id}`) })
1560
+ ]
1561
+ },
1562
+ p.id
1563
+ )),
1564
+ Object.keys(customs).map((id) => /* @__PURE__ */ jsxRuntime.jsxs(
1565
+ "button",
1566
+ {
1567
+ type: "button",
1568
+ className: "mma-swatch",
1569
+ "data-palette": id,
1570
+ "data-custom": "1",
1571
+ role: "menuitem",
1572
+ "data-on": s.palette === id ? "1" : "0",
1573
+ onClick: () => actions.setAppearance({ palette: id }, s.themeScope),
1574
+ children: [
1575
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: customs[id].swatch || "#888" } }),
1576
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: customs[id].label || id }),
1577
+ /* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-custom-badge", children: t("theme.custom") })
1578
+ ]
1579
+ },
1580
+ id
1581
+ ))
1582
+ ] }),
1583
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-pop-seg mma-scope-seg", children: [
1584
+ /* @__PURE__ */ jsxRuntime.jsx(
1585
+ "button",
1586
+ {
1587
+ type: "button",
1588
+ "data-scope": "global",
1589
+ "data-on": s.themeScope === "global" ? "1" : "0",
1590
+ onClick: () => actions.setThemeScope("global"),
1591
+ children: t("theme.global")
1592
+ }
1593
+ ),
1594
+ /* @__PURE__ */ jsxRuntime.jsx(
1595
+ "button",
1596
+ {
1597
+ type: "button",
1598
+ "data-scope": "app",
1599
+ id: "mma-scope-app",
1600
+ title: app ? t("theme.saveTo", { name: app.name }) : t("theme.openAppFirst"),
1601
+ "data-on": s.themeScope === "app" ? "1" : "0",
1602
+ disabled: !app || !s.capabilities.appTheme,
1603
+ onClick: () => actions.setThemeScope("app"),
1604
+ children: app ? app.name : t("theme.currentApp")
1605
+ }
1606
+ )
1607
+ ] }),
1608
+ s.themeScope === "app" && appTheme ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-textbtn", id: "mma-clear-app-theme", onClick: () => actions.clearAppTheme(), children: t("theme.followGlobal") }) : null
1609
+ ]
1610
+ }
1611
+ )
1612
+ ] });
1613
+ }
1614
+ var iconProps = { size: 16, strokeWidth: 2, className: "mma-ico" };
1615
+ function Toolbar() {
1616
+ const s = usePanelState();
1617
+ const actions = usePanelActions();
1618
+ const { t } = usePanelI18n();
1619
+ const side = s.dock === "side";
1620
+ const appTab = s.tabs.some((tab) => tab.id === s.active && tab.kind === "app");
1621
+ const anyApp = s.tabs.some((tab) => tab.kind === "app");
1622
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-toolbar", children: [
1623
+ appTab && s.capabilities.deleteApp ? /* @__PURE__ */ jsxRuntime.jsx(
1624
+ "button",
1625
+ {
1626
+ type: "button",
1627
+ className: "mma-textbtn danger",
1628
+ id: "mma-delete",
1629
+ title: t("toolbar.delete"),
1630
+ onClick: () => actions.askDelete(),
1631
+ children: t("toolbar.delete")
1632
+ }
1633
+ ) : null,
1634
+ appTab ? /* @__PURE__ */ jsxRuntime.jsx(
1635
+ "button",
1636
+ {
1637
+ type: "button",
1638
+ className: "mma-iconbtn",
1639
+ id: "mma-reload",
1640
+ title: t("toolbar.reload"),
1641
+ "aria-label": t("toolbar.reload"),
1642
+ onClick: () => actions.reloadActive(),
1643
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCw, { ...iconProps })
1644
+ }
1645
+ ) : null,
1646
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-theme-wrap", id: "mma-theme-wrap", children: [
1647
+ /* @__PURE__ */ jsxRuntime.jsx(
1648
+ "button",
1649
+ {
1650
+ type: "button",
1651
+ className: "mma-iconbtn",
1652
+ id: "mma-theme-btn",
1653
+ title: t("toolbar.theme"),
1654
+ "aria-label": t("toolbar.theme"),
1655
+ "aria-haspopup": "menu",
1656
+ onClick: () => actions.toggleThemePop(),
1657
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { ...iconProps })
1658
+ }
1659
+ ),
1660
+ /* @__PURE__ */ jsxRuntime.jsx(ThemePop, {})
1661
+ ] }),
1662
+ anyApp && s.capabilities.history ? /* @__PURE__ */ jsxRuntime.jsx(
1663
+ "button",
1664
+ {
1665
+ type: "button",
1666
+ className: "mma-iconbtn",
1667
+ id: "mma-history-btn",
1668
+ title: t("toolbar.history"),
1669
+ "aria-label": t("toolbar.history"),
1670
+ onClick: () => actions.toggleBrowse("history"),
1671
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { ...iconProps })
1672
+ }
1673
+ ) : null,
1674
+ anyApp && s.capabilities.storage ? /* @__PURE__ */ jsxRuntime.jsx(
1675
+ "button",
1676
+ {
1677
+ type: "button",
1678
+ className: "mma-iconbtn",
1679
+ id: "mma-storage-btn",
1680
+ title: t("toolbar.storage"),
1681
+ "aria-label": t("toolbar.storage"),
1682
+ onClick: () => actions.toggleBrowse("storage"),
1683
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Database, { ...iconProps })
1684
+ }
1685
+ ) : null,
1686
+ s.capabilities.config ? /* @__PURE__ */ jsxRuntime.jsx(
1687
+ "button",
1688
+ {
1689
+ type: "button",
1690
+ className: "mma-iconbtn",
1691
+ id: "mma-settings-btn",
1692
+ title: t("toolbar.settings"),
1693
+ "aria-label": t("toolbar.settings"),
1694
+ onClick: () => actions.toggleSettings(true),
1695
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Settings, { ...iconProps })
1696
+ }
1697
+ ) : null,
1698
+ /* @__PURE__ */ jsxRuntime.jsx(
1699
+ "button",
1700
+ {
1701
+ type: "button",
1702
+ className: "mma-iconbtn",
1703
+ id: "mma-dock-host",
1704
+ title: side ? t("toolbar.dockFill") : t("toolbar.dockSide"),
1705
+ "aria-label": side ? t("toolbar.dockFill") : t("toolbar.dockSide"),
1706
+ onClick: () => actions.setDock(side ? "fill" : "side"),
1707
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRight, { ...iconProps })
1708
+ }
1709
+ ),
1710
+ /* @__PURE__ */ jsxRuntime.jsx(
1711
+ "button",
1712
+ {
1713
+ type: "button",
1714
+ className: "mma-iconbtn",
1715
+ id: "mma-close-host",
1716
+ title: t("toolbar.close"),
1717
+ "aria-label": t("toolbar.close"),
1718
+ onClick: () => actions.closeDashboard(),
1719
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { ...iconProps })
1720
+ }
1721
+ )
1722
+ ] });
1723
+ }
1724
+ function MiniAppPanel() {
1725
+ const s = usePanelState();
1726
+ const listVisible = s.active === "all";
1727
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1728
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-chrome", children: [
1729
+ /* @__PURE__ */ jsxRuntime.jsx(Tabs, {}),
1730
+ /* @__PURE__ */ jsxRuntime.jsx(Toolbar, {})
1731
+ ] }),
1732
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-stage", children: [
1733
+ listVisible ? /* @__PURE__ */ jsxRuntime.jsx(ListRegion, {}) : null,
1734
+ /* @__PURE__ */ jsxRuntime.jsx("div", { id: "mma-frames", className: "mma-frames", style: { display: listVisible ? "none" : "block" } })
1735
+ ] }),
1736
+ /* @__PURE__ */ jsxRuntime.jsx(Settings, {}),
1737
+ /* @__PURE__ */ jsxRuntime.jsx(Browse, {}),
1738
+ /* @__PURE__ */ jsxRuntime.jsx(Modal, {})
1739
+ ] });
1740
+ }
1741
+
1742
+ // src/errors.ts
1743
+ var PanelError = class extends Error {
1744
+ constructor(code, message, options) {
1745
+ super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
1746
+ __publicField(this, "code");
1747
+ this.name = new.target.name;
1748
+ this.code = code;
1749
+ }
1750
+ };
1751
+
1752
+ // src/frame.ts
1753
+ function escapeHtml(s) {
1754
+ return String(s == null ? "" : s).replace(/[&<>"']/g, (c) => {
1755
+ switch (c) {
1756
+ case "&":
1757
+ return "&amp;";
1758
+ case "<":
1759
+ return "&lt;";
1760
+ case ">":
1761
+ return "&gt;";
1762
+ case '"':
1763
+ return "&quot;";
1764
+ case "'":
1765
+ return "&#39;";
1766
+ default:
1767
+ return c;
1768
+ }
1769
+ });
1770
+ }
1771
+ function loadingMarkup() {
1772
+ return `<div class="mma-load" role="status" aria-label="\u52A0\u8F7D\u4E2D">
1773
+ <div class="mma-load-art" aria-hidden="true">
1774
+ <svg viewBox="0 0 88 64" fill="none">
1775
+ <rect x="10" y="8" width="68" height="48" rx="10" stroke="currentColor" stroke-width="1.6" opacity=".35"/>
1776
+ <rect x="10" y="8" width="68" height="12" rx="10" fill="currentColor" opacity=".08"/>
1777
+ <circle cx="20" cy="14" r="2.2" fill="currentColor" opacity=".35"/>
1778
+ <rect x="26" y="12.2" width="18" height="3.6" rx="1.8" fill="currentColor" opacity=".22"/>
1779
+ <rect x="20" y="28" width="28" height="4" rx="2" fill="currentColor" opacity=".16"/>
1780
+ <rect x="20" y="36" width="40" height="4" rx="2" fill="currentColor" opacity=".1"/>
1781
+ <rect x="20" y="44" width="22" height="4" rx="2" fill="currentColor" opacity=".08"/>
1782
+ <path d="M62 40c6 0 10 5 10 10" stroke="var(--primary,#3b82f6)" stroke-width="1.8" stroke-linecap="round" opacity=".85"/>
1783
+ <circle cx="72" cy="50" r="3.2" fill="var(--primary,#3b82f6)" opacity=".9"/>
1784
+ </svg>
1785
+ <div class="mma-load-dots"><i></i><i></i><i></i></div></div></div>`;
1786
+ }
1787
+ function createFrameController(opts) {
1788
+ const { container: initial2, urlOf, envOf } = opts;
1789
+ let container = initial2 ?? null;
1790
+ const map = /* @__PURE__ */ new Map();
1791
+ return {
1792
+ map,
1793
+ url: (appId) => urlOf(appId),
1794
+ setContainer(el) {
1795
+ container = el;
1796
+ },
1797
+ postEnv(appId) {
1798
+ const rec = map.get(appId);
1799
+ const w = rec?.iframe.contentWindow;
1800
+ if (!w) return;
1801
+ const env = envOf(appId);
1802
+ try {
1803
+ w.postMessage({ type: "mma-set-env", theme: env.theme, palette: env.palette, dock: env.dock }, "*");
1804
+ } catch {
1805
+ }
1806
+ },
1807
+ postEnvAll() {
1808
+ for (const id of map.keys()) this.postEnv(id);
1809
+ },
1810
+ mount(appId, title) {
1811
+ for (const rec2 of map.values()) rec2.wrap.style.display = "none";
1812
+ let rec = map.get(appId);
1813
+ if (!rec) {
1814
+ const wrap = document.createElement("div");
1815
+ wrap.className = "mma-frame";
1816
+ wrap.setAttribute("data-app", appId);
1817
+ wrap.innerHTML = `${loadingMarkup()}<iframe title="${escapeHtml(title || appId)}"></iframe>`;
1818
+ if (!container) return;
1819
+ container.appendChild(wrap);
1820
+ const iframe = wrap.querySelector("iframe");
1821
+ if (!iframe) return;
1822
+ iframe.src = urlOf(appId);
1823
+ iframe.addEventListener("load", () => {
1824
+ const overlay = wrap.querySelector(".mma-load");
1825
+ overlay?.parentNode?.removeChild(overlay);
1826
+ this.postEnvAll();
1827
+ });
1828
+ rec = { wrap, iframe };
1829
+ map.set(appId, rec);
1830
+ }
1831
+ rec.wrap.style.display = "flex";
1832
+ },
1833
+ unmount(appId) {
1834
+ const rec = map.get(appId);
1835
+ if (!rec) return;
1836
+ rec.wrap.parentNode?.removeChild(rec.wrap);
1837
+ map.delete(appId);
1838
+ },
1839
+ unmountAll() {
1840
+ for (const id of [...map.keys()]) this.unmount(id);
1841
+ },
1842
+ reload(appId) {
1843
+ const rec = map.get(appId);
1844
+ if (!rec) return;
1845
+ if (!rec.wrap.querySelector(".mma-load")) rec.wrap.insertAdjacentHTML("afterbegin", loadingMarkup());
1846
+ rec.iframe.src = `${urlOf(appId)}&_=${Date.now()}`;
1847
+ }
1848
+ };
1849
+ }
1850
+
1851
+ // src/locales/en.json
1852
+ var en_default = {
1853
+ tabs: {
1854
+ all: "All",
1855
+ allTitle: "All mini apps",
1856
+ close: "Close {{title}}"
1857
+ },
1858
+ toolbar: {
1859
+ delete: "Delete",
1860
+ reload: "Reload",
1861
+ theme: "Theme",
1862
+ history: "History",
1863
+ storage: "Storage",
1864
+ settings: "Settings",
1865
+ dockFill: "Fill main area",
1866
+ dockSide: "Pin to chat right",
1867
+ close: "Close"
1868
+ },
1869
+ theme: {
1870
+ light: "Light",
1871
+ dark: "Dark",
1872
+ custom: "Custom",
1873
+ global: "Global",
1874
+ currentApp: "Current app",
1875
+ openAppFirst: "Open an app first",
1876
+ saveTo: 'Save to "{{name}}"',
1877
+ followGlobal: "Follow global (clear app theme)"
1878
+ },
1879
+ palette: {
1880
+ default: "Default",
1881
+ tokyo: "Tokyo Night",
1882
+ forest: "Everforest",
1883
+ matcha: "Strawberry Matcha",
1884
+ yellow: "Yellow Pill",
1885
+ zoro: "Three Swords",
1886
+ hokage: "Hokage Dawn",
1887
+ slate: "Slate"
1888
+ },
1889
+ list: {
1890
+ title: "Mini apps",
1891
+ count: "{{count}} apps",
1892
+ search: "Search mini apps",
1893
+ open: "Open",
1894
+ commits: "{{count}} commits",
1895
+ loadError: "Failed to load list: {{message}}",
1896
+ hostUnreachable: "Cannot reach the mini-app host ({{url}}): the host is not running or the port is taken. Free the port, or set hostPort in runtime/host.json and restart.",
1897
+ retry: "Retry",
1898
+ empty: "No mini apps yet.",
1899
+ noMatch: 'No mini apps matching "{{query}}".'
1900
+ },
1901
+ settings: {
1902
+ title: "Settings",
1903
+ hostPort: "Host port",
1904
+ language: "Language",
1905
+ langZh: "Chinese",
1906
+ langEn: "English",
1907
+ theme: "Theme",
1908
+ palette: "Palette",
1909
+ cardStyle: "Card style",
1910
+ cardStamp: "Stamp",
1911
+ cardEtch: "Etch",
1912
+ cardHero: "Hero",
1913
+ cardList: "List",
1914
+ llmProvider: "LLM Provider",
1915
+ llmModel: "LLM model",
1916
+ save: "Save"
1917
+ },
1918
+ modal: {
1919
+ title: "Delete mini app",
1920
+ body: 'This will delete "{{name}}" and its local data. This cannot be undone.',
1921
+ cancel: "Cancel",
1922
+ confirm: "Delete"
1923
+ },
1924
+ browse: {
1925
+ history: "History",
1926
+ storage: "Storage",
1927
+ close: "Close",
1928
+ loading: "Loading\u2026",
1929
+ files: "{{count}} files",
1930
+ back: "\u2190 Back",
1931
+ noFiles: "No file changes",
1932
+ noCommits: "No commits yet",
1933
+ noStorage: "No storage files",
1934
+ expandMsg: "Show more",
1935
+ collapseMsg: "Show less"
1936
+ },
1937
+ load: {
1938
+ label: "Loading"
1939
+ },
1940
+ config: {
1941
+ saved: "Saved",
1942
+ error: "\u2717 {{message}}"
1943
+ }
1944
+ };
1945
+
1946
+ // src/locales/zh-CN.json
1947
+ var zh_CN_default = {
1948
+ tabs: {
1949
+ all: "\u5168\u90E8",
1950
+ allTitle: "\u5168\u90E8\u5C0F\u7A0B\u5E8F",
1951
+ close: "\u5173\u95ED {{title}}"
1952
+ },
1953
+ toolbar: {
1954
+ delete: "\u5220\u9664",
1955
+ reload: "\u91CD\u65B0\u52A0\u8F7D",
1956
+ theme: "\u4E3B\u9898",
1957
+ history: "\u63D0\u4EA4\u5386\u53F2",
1958
+ storage: "\u5B58\u50A8",
1959
+ settings: "\u8BBE\u7F6E",
1960
+ dockFill: "\u94FA\u6EE1\u4E3B\u533A",
1961
+ dockSide: "\u9489\u5230\u804A\u5929\u53F3\u4FA7",
1962
+ close: "\u5173\u95ED"
1963
+ },
1964
+ theme: {
1965
+ light: "\u6D45\u8272",
1966
+ dark: "\u6DF1\u8272",
1967
+ custom: "\u81EA\u5B9A\u4E49",
1968
+ global: "\u5168\u5C40",
1969
+ currentApp: "\u5F53\u524D\u5C0F\u7A0B\u5E8F",
1970
+ openAppFirst: "\u6253\u5F00\u5C0F\u7A0B\u5E8F\u540E\u53EF\u7528",
1971
+ saveTo: "\u4FDD\u5B58\u5230\u300C{{name}}\u300D",
1972
+ followGlobal: "\u8DDF\u968F\u5168\u5C40\uFF08\u6E05\u9664\u672C\u5E94\u7528\u4E3B\u9898\uFF09"
1973
+ },
1974
+ palette: {
1975
+ default: "\u9ED8\u8BA4",
1976
+ tokyo: "\u4E1C\u4EAC\u591C",
1977
+ forest: "\u82D4\u539F",
1978
+ matcha: "\u8349\u8393\u62B9\u8336",
1979
+ yellow: "\u836F\u4E38\u9EC4",
1980
+ zoro: "\u4E09\u5200\u6D41",
1981
+ hokage: "\u706B\u5F71\u9ECE\u660E",
1982
+ slate: "\u77F3\u58A8"
1983
+ },
1984
+ list: {
1985
+ title: "\u5C0F\u7A0B\u5E8F",
1986
+ count: "{{count}} \u4E2A",
1987
+ search: "\u641C\u7D22\u5C0F\u7A0B\u5E8F",
1988
+ open: "\u5DF2\u6253\u5F00",
1989
+ commits: "{{count}} commits",
1990
+ loadError: "\u5217\u8868\u52A0\u8F7D\u5931\u8D25\uFF1A{{message}}",
1991
+ hostUnreachable: "\u65E0\u6CD5\u8FDE\u63A5\u5C0F\u7A0B\u5E8F host\uFF08{{url}}\uFF09\uFF1Ahost \u672A\u542F\u52A8\u6216\u7AEF\u53E3\u88AB\u5360\u7528\u3002\u8BF7\u91CA\u653E\u7AEF\u53E3\uFF0C\u6216\u7F16\u8F91 runtime/host.json \u7684 hostPort \u540E\u91CD\u542F\u3002",
1992
+ retry: "\u91CD\u8BD5",
1993
+ empty: "\u8FD8\u6CA1\u6709\u5C0F\u7A0B\u5E8F\u3002",
1994
+ noMatch: "\u6CA1\u6709\u5339\u914D\u300C{{query}}\u300D\u7684\u5C0F\u7A0B\u5E8F\u3002"
1995
+ },
1996
+ settings: {
1997
+ title: "\u8BBE\u7F6E",
1998
+ hostPort: "Host \u7AEF\u53E3",
1999
+ language: "\u754C\u9762\u8BED\u8A00",
2000
+ langZh: "\u4E2D\u6587",
2001
+ langEn: "English",
2002
+ theme: "\u4E3B\u9898",
2003
+ palette: "\u8C03\u8272\u677F",
2004
+ cardStyle: "\u5361\u7247\u6837\u5F0F",
2005
+ cardStamp: "\u5370\u7AE0",
2006
+ cardEtch: "\u8680\u523B",
2007
+ cardHero: "\u6D77\u62A5",
2008
+ cardList: "\u5217\u8868",
2009
+ llmProvider: "LLM Provider",
2010
+ llmModel: "LLM \u6A21\u578B",
2011
+ save: "\u4FDD\u5B58"
2012
+ },
2013
+ modal: {
2014
+ title: "\u5220\u9664\u5C0F\u7A0B\u5E8F",
2015
+ body: "\u5C06\u5220\u9664\u300C{{name}}\u300D\u53CA\u5176\u672C\u5730\u6570\u636E\uFF0C\u65E0\u6CD5\u64A4\u9500\u3002",
2016
+ cancel: "\u53D6\u6D88",
2017
+ confirm: "\u5220\u9664"
2018
+ },
2019
+ browse: {
2020
+ history: "\u63D0\u4EA4\u5386\u53F2",
2021
+ storage: "\u5B58\u50A8",
2022
+ close: "\u5173\u95ED",
2023
+ loading: "\u52A0\u8F7D\u4E2D\u2026",
2024
+ files: "{{count}} \u4E2A\u6587\u4EF6",
2025
+ back: "\u2190 \u8FD4\u56DE",
2026
+ noFiles: "\u65E0\u6587\u4EF6\u6539\u52A8",
2027
+ noCommits: "\u6682\u65E0\u63D0\u4EA4\u8BB0\u5F55",
2028
+ noStorage: "\u6682\u65E0\u5B58\u50A8\u6587\u4EF6",
2029
+ expandMsg: "\u5C55\u5F00\u5168\u6587",
2030
+ collapseMsg: "\u6536\u8D77"
2031
+ },
2032
+ load: {
2033
+ label: "\u52A0\u8F7D\u4E2D"
2034
+ },
2035
+ config: {
2036
+ saved: "\u5DF2\u4FDD\u5B58",
2037
+ error: "\u2717 {{message}}"
2038
+ }
2039
+ };
2040
+
2041
+ // src/types.ts
2042
+ var LOCALE_IDS = ["zh-CN", "en"];
2043
+
2044
+ // src/i18n.ts
2045
+ var resources = {
2046
+ "zh-CN": { translation: zh_CN_default },
2047
+ en: { translation: en_default }
2048
+ };
2049
+ function isLocaleId(value) {
2050
+ return LOCALE_IDS.includes(value);
2051
+ }
2052
+ function nodeEnv() {
2053
+ const g = globalThis;
2054
+ return g.process?.env?.NODE_ENV;
2055
+ }
2056
+ function failOnMissingKey() {
2057
+ return nodeEnv() !== "production";
2058
+ }
2059
+ function createPanelI18n(locale) {
2060
+ if (!isLocaleId(locale)) {
2061
+ throw new PanelError("I18N_INVALID_LOCALE", `unsupported locale: ${String(locale)}`);
2062
+ }
2063
+ const i18n = i18next.createInstance();
2064
+ void i18n.init({
2065
+ lng: locale,
2066
+ fallbackLng: false,
2067
+ supportedLngs: [...LOCALE_IDS],
2068
+ nonExplicitSupportedLngs: false,
2069
+ load: "currentOnly",
2070
+ defaultNS: "translation",
2071
+ ns: ["translation"],
2072
+ resources,
2073
+ interpolation: { escapeValue: false },
2074
+ returnNull: false,
2075
+ returnEmptyString: false,
2076
+ initImmediate: false,
2077
+ showSupportNotice: false
2078
+ });
2079
+ if (!i18n.isInitialized) {
2080
+ throw new PanelError("I18N_INIT_FAILED", `i18n failed to initialize for locale: ${locale}`);
2081
+ }
2082
+ return {
2083
+ locale,
2084
+ t(key, params) {
2085
+ if (!i18n.exists(key)) {
2086
+ if (failOnMissingKey()) {
2087
+ throw new PanelError("I18N_MISSING_KEY", `missing i18n key: ${key}`);
2088
+ }
2089
+ return key;
2090
+ }
2091
+ const value = i18n.t(key, params ?? {});
2092
+ if (typeof value !== "string") {
2093
+ throw new PanelError("I18N_INVALID_VALUE", `i18n key did not resolve to a string: ${key}`);
2094
+ }
2095
+ return value;
2096
+ }
2097
+ };
2098
+ }
2099
+ function resolvePanelLocale(value) {
2100
+ if (value === void 0) return "zh-CN";
2101
+ if (!isLocaleId(value)) {
2102
+ throw new PanelError("I18N_INVALID_LOCALE", `unsupported locale: ${String(value)}`);
2103
+ }
2104
+ return value;
2105
+ }
2106
+
2107
+ // src/styles.ts
2108
+ var PANEL_CSS_TAG = "panel";
2109
+ var CSS = [
2110
+ "#mma-host{color:var(--dsw-alias-fg,#111);background:var(--dsw-alias-bg,#f7f7f8);overflow:hidden;}",
2111
+ "#mma-host button,#mma-host input,#mma-host select{color:inherit;font:inherit;}",
2112
+ "#mma-host .mma-chrome{display:flex;align-items:center;gap:8px;height:46px;padding:0 10px;border-bottom:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);flex:0 0 auto;}",
2113
+ "#mma-host .mma-tabs{display:flex;align-items:center;gap:2px;flex:1;min-width:0;overflow-x:auto;flex-wrap:nowrap;scrollbar-width:thin;}",
2114
+ "#mma-host .mma-tab{display:inline-flex;align-items:center;flex:0 0 auto;max-width:140px;height:32px;padding:0 10px;border:0;border-bottom:2px solid transparent;background:transparent;cursor:pointer;font-size:13px;font-weight:500;color:inherit;opacity:.7;white-space:nowrap;border-radius:8px 8px 0 0;}",
2115
+ "#mma-host .mma-tab[data-active='1']{font-weight:600;opacity:1;border-bottom-color:var(--dsw-alias-primary,#3b82f6);color:var(--dsw-alias-primary,#3b82f6);}",
2116
+ "#mma-host .mma-tab>span{display:inline-flex;align-items:center;gap:5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
2117
+ "#mma-host .mma-tab-x{margin-left:6px;border:0;background:transparent;cursor:pointer;opacity:.55;color:inherit;padding:0 2px;line-height:1;font-size:14px;flex:0 0 auto;}",
2118
+ "#mma-host [hidden]{display:none !important;}",
2119
+ "#mma-host .mma-iconbtn{width:32px;height:32px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:inherit;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;}",
2120
+ "#mma-host .mma-iconbtn:hover{background:var(--dsw-alias-muted,#f3f4f6);}",
2121
+ "#mma-host .mma-toolbar{display:flex;align-items:center;gap:2px;flex:0 0 auto;}",
2122
+ "#mma-host .mma-toolbar .mma-iconbtn{width:30px;height:30px;}",
2123
+ "#mma-host .mma-toolbar .mma-ico{display:block;}",
2124
+ "#mma-host .mma-theme-wrap{position:relative;flex:0 0 auto;}",
2125
+ "#mma-host .mma-pop-scrim{position:fixed;inset:0;z-index:7;background:transparent;}",
2126
+ "#mma-host .mma-pop{display:none;position:absolute;right:0;top:40px;z-index:8;width:232px;padding:12px 14px 14px;border-radius:12px;border:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);box-shadow:0 12px 32px var(--dsw-alias-shadow,rgba(0,0,0,.14));}",
2127
+ "#mma-host .mma-pop[data-open='1']{display:block;}",
2128
+ "#mma-host .mma-pop-seg{display:flex;gap:4px;margin:0 0 12px;padding:3px;border-radius:9px;background:var(--dsw-alias-muted,#f3f4f6);}",
2129
+ "#mma-host .mma-pop-seg button{flex:1;height:28px;padding:0;line-height:1;border:0;border-radius:7px;background:transparent;cursor:pointer;font-size:12px;color:inherit;display:flex;align-items:center;justify-content:center;}",
2130
+ "#mma-host .mma-pop-seg button[data-on='1']{background:var(--dsw-alias-surface,#fff);font-weight:600;box-shadow:0 1px 2px var(--dsw-alias-shadow,rgba(0,0,0,.06));color:var(--dsw-alias-primary,#2563eb);}",
2131
+ "#mma-host .mma-pop-list{margin:0 0 12px;display:flex;flex-direction:column;gap:6px!important;max-height:280px;overflow-y:auto;padding:4px 0;}",
2132
+ "#mma-host .mma-swatch{display:flex;align-items:center;gap:10px;width:100%;min-height:34px;padding:0 10px;border:0;border-radius:8px;background:transparent;cursor:pointer;color:inherit;font-size:13px;text-align:left;white-space:nowrap;overflow:hidden;}",
2133
+ "#mma-host .mma-swatch:hover{background:var(--dsw-alias-accent,var(--dsw-alias-muted,#f3f4f6));}",
2134
+ "#mma-host .mma-swatch[data-on='1']{background:var(--dsw-alias-accent,var(--dsw-alias-muted,#f3f4f6));font-weight:600;}",
2135
+ "#mma-host .mma-dot{display:inline-block;width:14px;height:14px;border-radius:99px;border:1px solid var(--dsw-alias-border,#e5e7eb);flex:0 0 14px;box-shadow:inset 0 0 0 1px rgba(255,255,255,.25);}",
2136
+ "#mma-host .mma-custom-badge{margin-left:auto;font-size:10px;padding:1px 6px;border-radius:99px;background:var(--dsw-alias-muted,#f3f4f6);color:var(--dsw-alias-fg,#111);opacity:.7;flex:0 0 auto;}",
2137
+ "#mma-host .mma-swatch span{overflow:hidden;text-overflow:ellipsis;}",
2138
+ "#mma-host .mma-swatch{border-bottom:1px solid var(--dsw-alias-border,#e5e7eb);}",
2139
+ "#mma-host .mma-swatch:last-child{border-bottom:none;}",
2140
+ "#mma-host .mma-swatch + .mma-swatch{border-top:0;}",
2141
+ "#mma-host .mma-swatch:hover{border-radius:8px;}",
2142
+ "#mma-host .mma-scope-seg{margin-top:0;padding:4px 5px 5px;border-top:1px solid var(--dsw-alias-border,#e5e7eb);}",
2143
+ "#mma-host .mma-scope-seg button:disabled{opacity:.45;cursor:not-allowed;}",
2144
+ "#mma-host .mma-textbtn{height:28px;padding:0 8px;border:0;border-radius:6px;background:transparent;cursor:pointer;color:inherit;opacity:.7;font-size:12px;}",
2145
+ "#mma-host .mma-textbtn:hover{opacity:1;background:var(--dsw-alias-muted,#f3f4f6);}",
2146
+ "#mma-host .mma-toolbar .mma-delete-btn{font-size:13px;font-weight:400;color:inherit;opacity:.8;}",
2147
+ "#mma-host .mma-toolbar .mma-delete-btn:hover{opacity:1;color:#dc2626;background:transparent;}",
2148
+ "#mma-host .mma-textbtn.danger:hover{color:#dc2626;}",
2149
+ "#mma-host .mma-stage{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;position:relative;}",
2150
+ "#mma-host .mma-list,#mma-host .mma-frames{flex:1;min-height:0;overflow:auto;}",
2151
+ "#mma-host .mma-frames{display:none;position:relative;}",
2152
+ "#mma-host .mma-frame{position:absolute;inset:0;display:none;flex-direction:column;}",
2153
+ "#mma-host .mma-frame>iframe{flex:1;height:100%;min-height:0;width:100%;border:0;background:transparent;display:block;}",
2154
+ "#mma-host .mma-list-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:18px 18px 8px;}",
2155
+ "#mma-host .mma-list-head h2{margin:0;font-size:16px;font-weight:650;}",
2156
+ "#mma-host .mma-list-head span{font-size:12px;opacity:.5;}",
2157
+ "#mma-host .mma-search{margin:0 18px 12px;position:relative;}",
2158
+ "#mma-host .mma-search input{width:100%;height:34px;box-sizing:border-box;padding:0 12px 0 32px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:8px;background:var(--dsw-alias-surface,#fff);color:inherit;font-size:13px;outline:none;}",
2159
+ "#mma-host .mma-search input:focus{border-color:var(--dsw-alias-primary,#3b82f6);}",
2160
+ "#mma-host .mma-search svg{position:absolute;left:10px;top:9px;opacity:.45;pointer-events:none;}",
2161
+ "#mma-host .mma-grid{padding:8px 16px 20px;display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;}",
2162
+ "#mma-host[data-dock='side'] .mma-grid{grid-template-columns:minmax(0,1fr);}",
2163
+ "#mma-host .mma-card,#mma-host .mma-row{text-align:left;border-radius:13px;border:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);color:var(--dsw-alias-fg,#111);cursor:pointer;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background-color .22s ease;}",
2164
+ "#mma-host .mma-card{display:flex;flex-direction:column;align-items:flex-start;gap:0;padding:16px 15px 13px;position:relative;overflow:hidden;}",
2165
+ "#mma-host .mma-row{display:flex;align-items:center;gap:12px;padding:10px 12px;position:relative;overflow:hidden;width:100%;}",
2166
+ "#mma-host .mma-card h3,#mma-host .mma-row .mma-t{font-size:14px;font-weight:650;margin:0;letter-spacing:.1px;position:relative;z-index:1;}",
2167
+ "#mma-host .mma-card p,#mma-host .mma-row small{font-size:12px;color:var(--muted-foreground,inherit);opacity:.85;line-height:1.45;}",
2168
+ "#mma-host .mma-card p{margin:0;position:relative;z-index:1;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}",
2169
+ "#mma-host .mma-row .mma-twrap{flex:1;min-width:0;position:relative;z-index:1;}",
2170
+ "#mma-host .mma-row small{display:block;margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}",
2171
+ "#mma-host .mma-row .mma-right{margin-left:auto;display:flex;align-items:center;gap:7px;flex:0 0 auto;position:relative;z-index:1;}",
2172
+ "#mma-host .mma-chev{color:var(--muted-foreground,inherit);opacity:.5;width:14px;height:14px;}",
2173
+ "#mma-host .mma-meta{display:flex;align-items:center;gap:10px;margin-top:9px;position:relative;z-index:1;}",
2174
+ "#mma-host .mma-ver{font-size:10.5px;color:var(--muted-foreground,inherit);opacity:.8;letter-spacing:.2px;white-space:nowrap;}",
2175
+ "#mma-host .mma-open{display:inline-flex;align-items:center;gap:5px;font-size:11px;font-weight:600;color:var(--dsw-alias-primary,#3b82f6);white-space:nowrap;}",
2176
+ "#mma-host .mma-open i{width:6px;height:6px;border-radius:99px;background:var(--dsw-alias-primary,#3b82f6);}",
2177
+ "#mma-host[data-cardstyle='hero'] .mma-card::before,#mma-host[data-cardstyle='hero'] .mma-row::before{content:'';position:absolute;top:-28px;right:-20px;width:140px;height:120px;background:radial-gradient(62% 62% at 62% 40%,hsl(var(--h,215) 80% 60% / .20),transparent 72%);pointer-events:none;}",
2178
+ "#mma-host[data-cardstyle='hero'] .mma-card:hover,#mma-host[data-cardstyle='hero'] .mma-row:hover{background:linear-gradient(hsl(var(--h,215) 82% 60% / .10),hsl(var(--h,215) 82% 60% / .10)),var(--dsw-alias-surface,#fff);border-color:hsl(var(--h,215) 70% 60% / .5);box-shadow:0 8px 22px var(--dsw-alias-shadow,rgba(0,0,0,.12));transform:translateY(-1px);}",
2179
+ "#mma-host[data-cardstyle='hero'] .mma-mono{font-size:52px;font-weight:800;letter-spacing:2px;line-height:1.05;position:relative;z-index:1;margin-bottom:11px;color:hsl(var(--h,215) 60% 40%);}",
2180
+ "@supports (-webkit-background-clip:text){#mma-host[data-cardstyle='hero'] .mma-mono{background:linear-gradient(135deg,hsl(var(--h,215) 72% 42%),hsl(var(--h,215) 72% 62%));-webkit-background-clip:text;background-clip:text;color:transparent;}}",
2181
+ "#mma-host[data-cardstyle='etch'] .mma-etch{font-size:46px;font-weight:800;letter-spacing:2px;line-height:1.02;color:transparent;-webkit-text-stroke:1.5px hsl(var(--h,215) 65% 45%);margin-bottom:10px;position:relative;z-index:1;}",
2182
+ "#mma-host[data-cardstyle='etch'] .mma-card:hover,#mma-host[data-cardstyle='etch'] .mma-row:hover{background:linear-gradient(hsl(var(--h,215) 80% 55% / .08),hsl(var(--h,215) 80% 55% / .08)),var(--dsw-alias-surface,#fff);border-color:hsl(var(--h,215) 65% 50% / .55);box-shadow:0 8px 22px var(--dsw-alias-shadow,rgba(0,0,0,.12));transform:translateY(-1px);}",
2183
+ "#mma-host[data-cardstyle='etch'] .mma-card:hover .mma-etch,#mma-host[data-cardstyle='etch'] .mma-row:hover .mma-etch{background:linear-gradient(135deg,hsl(var(--h,215) 72% 42%),hsl(var(--h,215) 72% 62%));-webkit-background-clip:text;background-clip:text;color:transparent;-webkit-text-stroke:0;}",
2184
+ "#mma-host[data-cardstyle='stamp'] .mma-stamp{position:absolute;top:13px;right:13px;width:44px;height:44px;border:1.5px solid var(--dsw-alias-fg,#111);border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:800;letter-spacing:1px;color:var(--dsw-alias-fg,#111);background:transparent;transition:background-color .18s ease,color .18s ease,transform .18s ease;}",
2185
+ "#mma-host[data-cardstyle='stamp'] .mma-card:hover .mma-stamp,#mma-host[data-cardstyle='stamp'] .mma-row:hover .mma-stamp{background:var(--dsw-alias-fg,#111);color:var(--dsw-alias-surface,#fff);transform:scale(1.05);}",
2186
+ "#mma-host[data-cardstyle='stamp'] .mma-card:hover,#mma-host[data-cardstyle='stamp'] .mma-row:hover{background:linear-gradient(hsl(var(--h,215) 30% 55% / .07),hsl(var(--h,215) 30% 55% / .07)),var(--dsw-alias-surface,#fff);border-color:var(--dsw-alias-fg,#111);box-shadow:0 8px 22px var(--dsw-alias-shadow,rgba(0,0,0,.12));transform:translateY(-1px);}",
2187
+ "#mma-host[data-cardstyle='stamp'] .mma-card h3,#mma-host[data-cardstyle='stamp'] .mma-card p{padding-right:52px;}",
2188
+ "#mma-host[data-cardstyle='stamp'] .mma-row .mma-stamp{position:static;width:36px;height:36px;font-size:12px;border-radius:8px;flex:0 0 36px;}",
2189
+ "#mma-host .mma-open-dot{width:7px;height:7px;border-radius:99px;background:var(--dsw-alias-primary,#3b82f6);display:inline-block;}",
2190
+ "#mma-host .mma-empty{padding:24px;opacity:.75;line-height:1.6;}",
2191
+ "#mma-host .mma-error{padding:24px;color:#b91c1c;}",
2192
+ ".mma-load{flex:1;min-height:180px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;color:var(--dsw-alias-fg,#111);}",
2193
+ ".mma-load-art{position:relative;width:88px;height:72px;}",
2194
+ ".mma-load-art svg{display:block;width:88px;height:64px;}",
2195
+ ".mma-load-dots{display:flex;gap:5px;justify-content:center;margin-top:2px;}",
2196
+ ".mma-load-dots i{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-primary,#3b82f6);opacity:.35;animation:mma-dot 1s ease-in-out infinite;}",
2197
+ ".mma-load-dots i:nth-child(2){animation-delay:.15s;}",
2198
+ ".mma-load-dots i:nth-child(3){animation-delay:.3s;}",
2199
+ "@keyframes mma-dot{0%,80%,100%{transform:translateY(0);opacity:.3}40%{transform:translateY(-5px);opacity:1}}",
2200
+ ".mma-iframe-wrap{position:relative;flex:1 1 auto;min-height:0;height:100%;display:flex;flex-direction:column;}",
2201
+ ".mma-iframe-wrap .mma-load,#mma-host .mma-frame .mma-load{position:absolute;inset:0;background:var(--dsw-alias-bg,#f7f7f8);z-index:1;}",
2202
+ "#mma-host .mma-modal{position:absolute;inset:0;background:rgba(0,0,0,.35);z-index:5;display:flex;align-items:center;justify-content:center;padding:24px;}",
2203
+ "#mma-host .mma-modal[hidden]{display:none;}",
2204
+ "#mma-host .mma-dialog{width:min(360px,100%);background:var(--dsw-alias-surface,#fff);color:var(--dsw-alias-fg,#111);border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:var(--radius,12px);padding:18px;box-shadow:0 12px 40px var(--dsw-alias-shadow,rgba(0,0,0,.18));}",
2205
+ "#mma-host .mma-dialog h3{margin:0 0 8px;font-size:15px;}",
2206
+ "#mma-host .mma-dialog p{margin:0 0 16px;font-size:13px;opacity:.75;line-height:1.5;}",
2207
+ "#mma-host .mma-dialog-actions{display:flex;justify-content:flex-end;gap:8px;}",
2208
+ "#mma-host .mma-dialog-actions button{height:32px;padding:0 12px;border-radius:8px;border:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);cursor:pointer;}",
2209
+ "#mma-host .mma-dialog-actions .go{background:#dc2626;color:#fff;border-color:#dc2626;}",
2210
+ "#mma-host .mma-settings{position:absolute;inset:0;background:var(--dsw-alias-bg,#f7f7f8);z-index:4;overflow:auto;padding:20px 22px 32px;display:none;}",
2211
+ "#mma-host .mma-settings[data-open='1']{display:block;}",
2212
+ "#mma-host .mma-settings h3{margin:0 0 6px;font-size:16px;}",
2213
+ "#mma-host .mma-settings-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;}",
2214
+ "#mma-host .mma-settings label{display:block;margin-bottom:12px;font-size:12px;opacity:.75;}",
2215
+ "#mma-host .mma-settings input,#mma-host .mma-settings select{display:block;width:100%;margin-top:4px;height:32px;padding:0 10px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:8px;background:var(--dsw-alias-surface,#fff);color:inherit;font-size:13px;box-sizing:border-box;}",
2216
+ "#mma-host .mma-settings-actions{display:flex;flex-direction:column;align-items:flex-end;gap:8px;margin-top:18px;}",
2217
+ "#mma-host .mma-settings-msg{font-size:12px;opacity:.75;line-height:1.4;text-align:right;width:100%;}",
2218
+ "#mma-host .mma-settings-msg.err{color:#dc2626;}",
2219
+ "#mma-host #mma-cfg-save{height:34px;padding:0 18px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:8px;background:var(--dsw-alias-surface,#fff);color:inherit;font-size:14px;font-weight:600;opacity:1;cursor:pointer;}",
2220
+ "#mma-host #mma-cfg-save:hover{background:var(--dsw-alias-muted,#f3f4f6);border-color:var(--dsw-alias-primary,#2563eb);color:var(--dsw-alias-primary,#2563eb);}",
2221
+ "#mma-host .mma-browse{position:absolute;inset:0;background:var(--dsw-alias-bg,#f7f7f8);z-index:3;overflow:auto;padding:16px 18px;display:none;}",
2222
+ "#mma-host .mma-browse[data-open='1']{display:block;}",
2223
+ "#mma-host .mma-browse-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;}",
2224
+ "#mma-host .mma-browse-head--tools{justify-content:flex-start;margin-bottom:8px;}",
2225
+ "#mma-host .mma-browse-head h3{margin:0;font-size:15px;}",
2226
+ "#mma-host .mma-browse-head .sub{margin-left:8px;font-size:12px;opacity:.55;font-weight:400;}",
2227
+ "#mma-host .mma-btns button{border:0;background:transparent;cursor:pointer;color:inherit;opacity:.7;font-size:12px;padding:4px 6px;}",
2228
+ "#mma-host .mma-commit-meta{margin:0 0 12px;}",
2229
+ "#mma-host .mma-commit-msg{margin:0 0 6px;font-size:13px;font-weight:600;line-height:1.45;word-break:break-word;}",
2230
+ "#mma-host .mma-commit-msg--clamp2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}",
2231
+ "#mma-host .mma-commit-msg--clamp3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;}",
2232
+ "#mma-host .mma-commit-msg-toggle{border:0;background:transparent;cursor:pointer;color:inherit;opacity:.65;font-size:12px;padding:0 0 6px;}",
2233
+ "#mma-host .mma-commit-msg-toggle:hover{opacity:1;}",
2234
+ "#mma-host .mma-commit-ids{display:flex;gap:10px;flex-wrap:wrap;font-size:11px;opacity:.75;}",
2235
+ "#mma-host .mma-blist{display:flex;flex-direction:column;gap:4px;}",
2236
+ "#mma-host .mma-bitem{text-align:left;padding:10px 12px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:10px;background:var(--dsw-alias-surface,#fff);cursor:pointer;}",
2237
+ "#mma-host .mma-bitem b,#mma-host .mma-bitem .mma-commit-msg{font-size:13px;display:block;margin-bottom:4px;font-weight:600;}",
2238
+ "#mma-host .mma-bitem .meta{display:flex;gap:10px;font-size:11px;opacity:.65;flex-wrap:wrap;}",
2239
+ "#mma-host .mma-plus{color:#16a34a;font-variant-numeric:tabular-nums;}",
2240
+ "#mma-host .mma-minus{color:#dc2626;font-variant-numeric:tabular-nums;}",
2241
+ "#mma-host .mma-diff-zero{opacity:.35;}",
2242
+ "#mma-host .mma-files{display:flex;flex-direction:column;gap:6px;}",
2243
+ "#mma-host .mma-fitem{display:flex;align-items:center;gap:10px;width:100%;box-sizing:border-box;padding:10px 12px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:10px;background:var(--dsw-alias-surface,#fff);cursor:pointer;font-size:12px;color:inherit;text-align:left;}",
2244
+ "#mma-host .mma-fitem:hover{background:var(--dsw-alias-muted,#f3f4f6);border-color:var(--dsw-alias-border,#d1d5db);}",
2245
+ "#mma-host .mma-fitem[data-open='1']{border-color:var(--dsw-alias-primary,#2563eb);background:var(--dsw-alias-muted,#f3f4f6);}",
2246
+ "#mma-host .mma-fitem .mma-diff{display:inline-flex;gap:6px;flex:0 0 auto;min-width:4.5em;font-family:ui-monospace,monospace;font-size:11px;}",
2247
+ "#mma-host .mma-fitem .p{flex:1;min-width:0;font-family:ui-monospace,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
2248
+ "#mma-host .mma-fitem .mma-chevron{flex:0 0 12px;opacity:.45;transition:transform .15s ease;}",
2249
+ "#mma-host .mma-fitem[data-open='1'] .mma-chevron{transform:rotate(90deg);opacity:.7;}",
2250
+ "#mma-host .mma-preview{margin:0 0 2px;padding:8px 0;background:var(--dsw-alias-surface,#fff);border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:8px;font-size:11px;max-height:220px;overflow:auto;white-space:pre;line-height:1.55;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}",
2251
+ "#mma-host .mma-diff-preview{padding:6px 0;}",
2252
+ "#mma-host .mma-diff-line{display:block;padding:0 12px;}",
2253
+ "#mma-host .mma-diff-line--add{color:#166534;background:rgba(22,163,74,.12);}",
2254
+ "#mma-host .mma-diff-line--del{color:#991b1b;background:rgba(220,38,38,.10);}",
2255
+ "#mma-host .mma-diff-line--ctx{color:inherit;opacity:.85;}",
2256
+ "#mma-host .mma-bempty{padding:20px;opacity:.6;text-align:center;font-size:13px;}",
2257
+ "#mma-host .mma-berr{padding:16px;color:#b91c1c;font-size:13px;}"
2258
+ ];
2259
+ function injectPanelCss() {
2260
+ if (typeof document === "undefined") return;
2261
+ let tag = document.querySelector(`style[data-plugin-css="${PANEL_CSS_TAG}"]`);
2262
+ if (!tag) {
2263
+ tag = document.createElement("style");
2264
+ tag.dataset.plugin = "panel";
2265
+ tag.dataset.pluginCss = PANEL_CSS_TAG;
2266
+ document.head.appendChild(tag);
2267
+ }
2268
+ tag.textContent = CSS.join("\n");
2269
+ }
2270
+ function loadCustomPalettes(host) {
2271
+ if (!host.palettes) return;
2272
+ host.palettes().then((list) => {
2273
+ const custom = {};
2274
+ for (const p of list) {
2275
+ custom[p.id] = { label: p.label, swatch: p.swatch, tokens: p.tokens };
2276
+ }
2277
+ setPanelState({ customPalettes: custom });
2278
+ }).catch(() => {
2279
+ });
2280
+ }
2281
+ function createMiniAppPanel(host, options) {
2282
+ const locale = resolvePanelLocale(options?.locale ?? host.locale);
2283
+ const i18n = createPanelI18n(locale);
2284
+ resetPanelState({
2285
+ tabs: [{ id: "all", title: i18n.t("tabs.all"), kind: "all" }],
2286
+ capabilities: capabilitiesOf(host),
2287
+ locale,
2288
+ emptyText: host.emptyText
2289
+ });
2290
+ let rootEl = null;
2291
+ let root = null;
2292
+ const actions = createPanelActions(host, () => rootEl, i18n);
2293
+ return {
2294
+ actions,
2295
+ open: () => host.openPanel(),
2296
+ close: () => host.closePanel(),
2297
+ mount(el) {
2298
+ rootEl = el;
2299
+ injectPanelCss();
2300
+ const s = getPanelState();
2301
+ applyThemeTo(el, s.theme, s.palette, s.customPalettes);
2302
+ loadCustomPalettes(host);
2303
+ if (!root) root = client.createRoot(el);
2304
+ root.render(
2305
+ /* @__PURE__ */ jsxRuntime.jsx(PanelProvider, { actions, i18n, children: /* @__PURE__ */ jsxRuntime.jsx(MiniAppPanel, {}) })
2306
+ );
2307
+ },
2308
+ unmount() {
2309
+ if (root) {
2310
+ root.unmount();
2311
+ root = null;
2312
+ }
2313
+ rootEl = null;
2314
+ }
2315
+ };
2316
+ }
2317
+
2318
+ // src/host-shell.ts
2319
+ function safeStorage(storage) {
2320
+ if (storage) return storage;
2321
+ try {
2322
+ if (typeof window !== "undefined") return window.localStorage;
2323
+ } catch {
2324
+ }
2325
+ return null;
2326
+ }
2327
+ function readThemePrefs(storage) {
2328
+ const get = (k) => {
2329
+ try {
2330
+ return storage?.getItem(k) ?? null;
2331
+ } catch {
2332
+ return null;
2333
+ }
2334
+ };
2335
+ return { theme: get("mma-theme-mode") || "light", palette: get("mma-palette") || "default" };
2336
+ }
2337
+ function createHostShell(opts) {
2338
+ const storage = safeStorage(opts.storage);
2339
+ const themePrefs = readThemePrefs(storage);
2340
+ const frame = createFrameController({
2341
+ urlOf: (appId) => appFrameUrl(opts.hostUrl, appId, envFor(appId)),
2342
+ envOf: (appId) => envFor(appId)
2343
+ });
2344
+ function envFor(appId) {
2345
+ const s = getPanelState();
2346
+ const app = s.apps.find((a) => a.id === appId);
2347
+ return { theme: app?.theme?.theme || s.theme, palette: app?.theme?.palette || s.palette, dock: s.dock };
2348
+ }
2349
+ const host = createRestPanelHost({
2350
+ hostUrl: opts.hostUrl,
2351
+ storage,
2352
+ cardStyle: opts.cardStyle,
2353
+ locale: opts.locale ?? void 0,
2354
+ emptyText: opts.emptyText,
2355
+ onOpen: () => optOnOpen(),
2356
+ onClose: () => optOnClose(),
2357
+ onHostChange: (next) => opts.onHostChange?.(next),
2358
+ frameController: {
2359
+ url: (appId) => frame.url(appId),
2360
+ // Lazy-bind the frames container (React may not have rendered #mma-frames yet).
2361
+ mount: (appId) => {
2362
+ ensureFrameContainer();
2363
+ frame.mount(appId);
2364
+ },
2365
+ unmount: (appId) => frame.unmount(appId),
2366
+ reload: (appId) => {
2367
+ ensureFrameContainer();
2368
+ frame.reload(appId);
2369
+ },
2370
+ syncEnv: () => frame.postEnvAll()
2371
+ }
2372
+ });
2373
+ let framesBound = false;
2374
+ function ensureFrameContainer() {
2375
+ if (framesBound) return;
2376
+ const el = containerEl?.querySelector("#mma-frames") ?? document.getElementById("mma-frames");
2377
+ if (el) {
2378
+ frame.setContainer(el);
2379
+ framesBound = true;
2380
+ }
2381
+ }
2382
+ let panel = null;
2383
+ let containerEl = null;
2384
+ function optOnOpen() {
2385
+ setPanelState({ visible: true });
2386
+ opts.onOpen?.();
2387
+ }
2388
+ function optOnClose() {
2389
+ setPanelState({ visible: false });
2390
+ opts.onClose?.();
2391
+ }
2392
+ function persistTheme(theme, palette) {
2393
+ setPanelState({ theme, palette });
2394
+ try {
2395
+ storage?.setItem("mma-theme-mode", theme);
2396
+ storage?.setItem("mma-palette", palette);
2397
+ } catch {
2398
+ }
2399
+ if (containerEl) applyThemeTo(containerEl, theme, palette);
2400
+ frame.postEnvAll();
2401
+ }
2402
+ return {
2403
+ host,
2404
+ frames: frame,
2405
+ get panel() {
2406
+ if (!panel) panel = createMiniAppPanel(host);
2407
+ return panel;
2408
+ },
2409
+ mount(el) {
2410
+ containerEl = document.createElement("div");
2411
+ containerEl.id = "mma-host";
2412
+ containerEl.setAttribute("data-ready", "1");
2413
+ containerEl.setAttribute("data-dock", getPanelState().dock);
2414
+ containerEl.setAttribute("data-cardstyle", getPanelState().cardStyle);
2415
+ Object.assign(containerEl.style, {
2416
+ position: "fixed",
2417
+ top: "0",
2418
+ left: "0",
2419
+ right: "0",
2420
+ bottom: "0",
2421
+ zIndex: "40",
2422
+ display: "flex",
2423
+ flexDirection: "column",
2424
+ background: "var(--dsw-alias-bg, #f7f7f8)",
2425
+ color: "var(--dsw-alias-fg, #111)",
2426
+ fontFamily: "ui-sans-serif, system-ui, -apple-system, sans-serif"
2427
+ });
2428
+ const target = el ?? document.body;
2429
+ target.appendChild(containerEl);
2430
+ setPanelState({ theme: themePrefs.theme, palette: themePrefs.palette, visible: true });
2431
+ applyThemeTo(containerEl, themePrefs.theme, themePrefs.palette);
2432
+ this.panel.mount(containerEl);
2433
+ const framesEl = containerEl.querySelector("#mma-frames");
2434
+ if (framesEl) frame.setContainer(framesEl);
2435
+ void this.panel.actions.fetchApps();
2436
+ },
2437
+ unmount() {
2438
+ panel?.unmount();
2439
+ panel = null;
2440
+ frame.unmountAll();
2441
+ containerEl?.parentNode?.removeChild(containerEl);
2442
+ containerEl = null;
2443
+ },
2444
+ openPanel: optOnOpen,
2445
+ closePanel: optOnClose,
2446
+ toggle() {
2447
+ if (getPanelState().visible) optOnClose();
2448
+ else optOnOpen();
2449
+ },
2450
+ persistTheme,
2451
+ setCardStyle(v) {
2452
+ setPanelState({ cardStyle: v });
2453
+ try {
2454
+ storage?.setItem("mma-card-style", v);
2455
+ } catch {
2456
+ }
2457
+ containerEl?.setAttribute("data-cardstyle", v);
2458
+ },
2459
+ setDock(v) {
2460
+ setPanelState({ dock: v });
2461
+ opts.layout?.setDock?.(v);
2462
+ }
2463
+ };
2464
+ }
2465
+
2466
+ // src/index.ts
2467
+ var packageName = "@monkey-mini-app/panel";
2468
+
2469
+ exports.AppList = AppList;
2470
+ exports.Browse = Browse;
2471
+ exports.HostUnreachableError = HostUnreachableError;
2472
+ exports.LOCALE_IDS = LOCALE_IDS;
2473
+ exports.ListRegion = ListRegion;
2474
+ exports.Loading = Loading;
2475
+ exports.MiniAppPanel = MiniAppPanel;
2476
+ exports.Modal = Modal;
2477
+ exports.PALETTES = PALETTES;
2478
+ exports.PANEL_CSS_TAG = PANEL_CSS_TAG;
2479
+ exports.PanelError = PanelError;
2480
+ exports.PanelProvider = PanelProvider;
2481
+ exports.Settings = Settings;
2482
+ exports.Tabs = Tabs;
2483
+ exports.ThemePop = ThemePop;
2484
+ exports.Toolbar = Toolbar;
2485
+ exports.activeAppFrom = activeAppFrom;
2486
+ exports.appBlurb = appBlurb;
2487
+ exports.appFrameUrl = appFrameUrl;
2488
+ exports.applyThemeTo = applyThemeTo;
2489
+ exports.capabilitiesOf = capabilitiesOf;
2490
+ exports.clampMode = clampMode;
2491
+ exports.clampPalette = clampPalette;
2492
+ exports.clampPaletteId = clampPaletteId;
2493
+ exports.createFrameController = createFrameController;
2494
+ exports.createHostShell = createHostShell;
2495
+ exports.createMiniAppPanel = createMiniAppPanel;
2496
+ exports.createPanelActions = createPanelActions;
2497
+ exports.createPanelI18n = createPanelI18n;
2498
+ exports.createRestPanelHost = createRestPanelHost;
2499
+ exports.cssVars = cssVars;
2500
+ exports.defaultHideThemePop = defaultHideThemePop;
2501
+ exports.formToHostConfigBody = formToHostConfigBody;
2502
+ exports.getPanelState = getPanelState;
2503
+ exports.hostConfigToForm = hostConfigToForm;
2504
+ exports.hue = hue;
2505
+ exports.injectPanelCss = injectPanelCss;
2506
+ exports.isHostUnreachable = isHostUnreachable;
2507
+ exports.monoOf = monoOf;
2508
+ exports.packageName = packageName;
2509
+ exports.parseAppsResponse = parseAppsResponse;
2510
+ exports.parseCommitDetail = parseCommitDetail;
2511
+ exports.parseCommitList = parseCommitList;
2512
+ exports.parsePalettes = parsePalettes;
2513
+ exports.parseStorageTables = parseStorageTables;
2514
+ exports.parseThemeCss = parseThemeCss;
2515
+ exports.readJson = readJson;
2516
+ exports.resetPanelState = resetPanelState;
2517
+ exports.resolvePanelLocale = resolvePanelLocale;
2518
+ exports.runnerThemeCss = runnerThemeCss;
2519
+ exports.setPanelState = setPanelState;
2520
+ exports.subscribePanel = subscribePanel;
2521
+ exports.themeLabelFromCss = themeLabelFromCss;
2522
+ exports.tokensOf = tokensOf;
2523
+ exports.usePanelActions = usePanelActions;
2524
+ exports.usePanelI18n = usePanelI18n;
2525
+ exports.usePanelState = usePanelState;