@monkey-mini-app/panel 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/{chunk-X3QW77RD.js → chunk-JAWSEXOV.js} +36 -5
- package/dist/index.cjs +1916 -595
- package/dist/index.d.cts +127 -3
- package/dist/index.d.ts +127 -3
- package/dist/index.js +1451 -169
- package/dist/themes.cjs +41 -4
- package/dist/themes.d.cts +22 -1
- package/dist/themes.d.ts +22 -1
- package/dist/themes.js +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React4 = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var lucideReact = require('lucide-react');
|
|
6
6
|
var client = require('react-dom/client');
|
|
@@ -24,7 +24,7 @@ function _interopNamespace(e) {
|
|
|
24
24
|
return Object.freeze(n);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
|
|
28
28
|
|
|
29
29
|
var __defProp = Object.defineProperty;
|
|
30
30
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -42,292 +42,17 @@ function capabilitiesOf(host) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
// src/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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;
|
|
45
|
+
// src/themes.ts
|
|
46
|
+
var LOCAL_PALETTE_ID = "__local__";
|
|
47
|
+
var GLOBAL_PALETTE_ID = "__global__";
|
|
48
|
+
function effectivePalette(stored, hasLocalTheme, hostPalette) {
|
|
49
|
+
if (stored && stored !== GLOBAL_PALETTE_ID) return stored;
|
|
50
|
+
if (!stored && hasLocalTheme) return LOCAL_PALETTE_ID;
|
|
51
|
+
return hostPalette;
|
|
325
52
|
}
|
|
326
|
-
function
|
|
327
|
-
return
|
|
53
|
+
function selectedPalette(stored, hasLocalTheme) {
|
|
54
|
+
return stored ?? (hasLocalTheme ? LOCAL_PALETTE_ID : GLOBAL_PALETTE_ID);
|
|
328
55
|
}
|
|
329
|
-
|
|
330
|
-
// src/themes.ts
|
|
331
56
|
var PALETTES = [
|
|
332
57
|
{ id: "default", label: "\u9ED8\u8BA4", swatch: "#2563eb" },
|
|
333
58
|
{ id: "tokyo", label: "\u4E1C\u4EAC\u591C", swatch: "#7aa2f7" },
|
|
@@ -692,167 +417,647 @@ var TOKENS = {
|
|
|
692
417
|
}
|
|
693
418
|
}
|
|
694
419
|
};
|
|
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());
|
|
420
|
+
var THEME_VAR_KEYS = [
|
|
421
|
+
"bg",
|
|
422
|
+
"fg",
|
|
423
|
+
"surface",
|
|
424
|
+
"surface-fg",
|
|
425
|
+
"border",
|
|
426
|
+
"muted",
|
|
427
|
+
"muted-fg",
|
|
428
|
+
"primary",
|
|
429
|
+
"primary-fg",
|
|
430
|
+
"secondary",
|
|
431
|
+
"secondary-fg",
|
|
432
|
+
"accent",
|
|
433
|
+
"accent-fg",
|
|
434
|
+
"destructive",
|
|
435
|
+
"destructive-fg",
|
|
436
|
+
"ring",
|
|
437
|
+
"input",
|
|
438
|
+
"radius",
|
|
439
|
+
"shadow"
|
|
440
|
+
];
|
|
441
|
+
function kebabToCamel(k) {
|
|
442
|
+
return k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
443
|
+
}
|
|
444
|
+
function parseThemeCss(css, _id) {
|
|
445
|
+
const out = {};
|
|
446
|
+
const blockRe = /:root\[data-mode="(light|dark)"\]\s*\{([^}]*)\}/g;
|
|
447
|
+
let m;
|
|
448
|
+
while (m = blockRe.exec(String(css || ""))) {
|
|
449
|
+
const mode = m[1];
|
|
450
|
+
const vars = {};
|
|
451
|
+
for (const key of THEME_VAR_KEYS) {
|
|
452
|
+
const vm = new RegExp(`--${key}\\s*:\\s*([^;\\n]+)`).exec(m[2]);
|
|
453
|
+
if (vm) vars[kebabToCamel(key)] = vm[1].trim();
|
|
454
|
+
}
|
|
455
|
+
if (vars.bg && vars.fg && vars.primary) out[mode] = vars;
|
|
456
|
+
}
|
|
457
|
+
if (!out.light || !out.dark) return null;
|
|
458
|
+
const base = {
|
|
459
|
+
surfaceFg: out.light.fg,
|
|
460
|
+
secondary: out.light.muted,
|
|
461
|
+
secondaryFg: out.light.fg,
|
|
462
|
+
destructiveFg: "#ffffff",
|
|
463
|
+
radius: "12px",
|
|
464
|
+
shadow: "rgba(15, 23, 42, 0.1)"
|
|
465
|
+
};
|
|
466
|
+
const fill = (v) => Object.assign({}, base, v);
|
|
467
|
+
return { light: fill(out.light), dark: fill(out.dark) };
|
|
468
|
+
}
|
|
469
|
+
function themeLabelFromCss(css, fallback) {
|
|
470
|
+
const m = /\/\*\s*name\s*:\s*([^*]+)\*\//.exec(String(css || ""));
|
|
471
|
+
return m && m[1].trim() || fallback;
|
|
472
|
+
}
|
|
473
|
+
function clampPalette(value) {
|
|
474
|
+
if (value === "tokyo" || value === "forest" || value === "matcha" || value === "yellow" || value === "zoro" || value === "hokage" || value === "slate" || value === "default") {
|
|
475
|
+
return value;
|
|
476
|
+
}
|
|
477
|
+
if (value === "ocean" || value === "mist") return "tokyo";
|
|
478
|
+
if (value === "violet" || value === "ink") return "matcha";
|
|
479
|
+
if (value === "paper" || value === "noir") return "slate";
|
|
480
|
+
return "default";
|
|
481
|
+
}
|
|
482
|
+
function clampMode(value) {
|
|
483
|
+
return value === "dark" ? "dark" : "light";
|
|
484
|
+
}
|
|
485
|
+
function resolveMode(value) {
|
|
486
|
+
if (value === "system") {
|
|
487
|
+
try {
|
|
488
|
+
if (typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
|
489
|
+
return "dark";
|
|
490
|
+
}
|
|
491
|
+
} catch {
|
|
492
|
+
}
|
|
493
|
+
return "light";
|
|
494
|
+
}
|
|
495
|
+
return clampMode(value);
|
|
496
|
+
}
|
|
497
|
+
function tokensOf(palette, mode) {
|
|
498
|
+
return TOKENS[clampPalette(palette)][clampMode(mode)];
|
|
499
|
+
}
|
|
500
|
+
function cssVars(t) {
|
|
501
|
+
return [
|
|
502
|
+
`--background:${t.bg}`,
|
|
503
|
+
`--foreground:${t.fg}`,
|
|
504
|
+
`--card:${t.surface}`,
|
|
505
|
+
`--card-foreground:${t.surfaceFg}`,
|
|
506
|
+
`--primary:${t.primary}`,
|
|
507
|
+
`--primary-foreground:${t.primaryFg}`,
|
|
508
|
+
`--secondary:${t.secondary}`,
|
|
509
|
+
`--secondary-foreground:${t.secondaryFg}`,
|
|
510
|
+
`--muted:${t.muted}`,
|
|
511
|
+
`--muted-foreground:${t.mutedFg}`,
|
|
512
|
+
`--accent:${t.accent}`,
|
|
513
|
+
`--accent-foreground:${t.accentFg}`,
|
|
514
|
+
`--destructive:${t.destructive}`,
|
|
515
|
+
`--destructive-foreground:${t.destructiveFg}`,
|
|
516
|
+
`--border:${t.border}`,
|
|
517
|
+
`--input:${t.input}`,
|
|
518
|
+
`--ring:${t.ring}`,
|
|
519
|
+
`--radius:${t.radius}`,
|
|
520
|
+
`--shadow:${t.shadow}`,
|
|
521
|
+
`--color-background:var(--background)`,
|
|
522
|
+
`--color-surface:var(--card)`,
|
|
523
|
+
`--color-foreground:var(--foreground)`,
|
|
524
|
+
`--color-primary:var(--primary)`,
|
|
525
|
+
`--color-primary-foreground:var(--primary-foreground)`,
|
|
526
|
+
`--color-muted:var(--muted)`,
|
|
527
|
+
`--color-muted-foreground:var(--muted-foreground)`,
|
|
528
|
+
`--color-border:var(--border)`,
|
|
529
|
+
`--radius-md:var(--radius)`,
|
|
530
|
+
`--space-4:16px`,
|
|
531
|
+
`--font-sans:ui-sans-serif,system-ui,-apple-system,sans-serif`
|
|
532
|
+
].join(";");
|
|
533
|
+
}
|
|
534
|
+
function runnerThemeCss() {
|
|
535
|
+
const blocks = [
|
|
536
|
+
`:root,html[data-theme="light"]:not([data-palette]),html[data-theme="light"][data-palette="default"]{${cssVars(TOKENS.default.light)}}`,
|
|
537
|
+
`html[data-theme="dark"]:not([data-palette]),html[data-theme="dark"][data-palette="default"]{${cssVars(TOKENS.default.dark)}}`
|
|
538
|
+
];
|
|
539
|
+
["tokyo", "forest", "matcha", "yellow", "zoro", "hokage", "slate"].forEach((id) => {
|
|
540
|
+
blocks.push(`html[data-theme="light"][data-palette="${id}"]{${cssVars(TOKENS[id].light)}}`);
|
|
541
|
+
blocks.push(`html[data-theme="dark"][data-palette="${id}"]{${cssVars(TOKENS[id].dark)}}`);
|
|
542
|
+
});
|
|
543
|
+
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}`);
|
|
544
|
+
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}`);
|
|
545
|
+
return blocks.join("\n ");
|
|
546
|
+
}
|
|
547
|
+
function themeCssVars(theme, palette, custom) {
|
|
548
|
+
const mode = clampMode(theme);
|
|
549
|
+
const c = custom && palette ? custom[String(palette)] : void 0;
|
|
550
|
+
const pal = c ? String(palette) : clampPalette(palette);
|
|
551
|
+
const t = c && c.tokens && c.tokens[mode] || tokensOf(pal, mode);
|
|
552
|
+
return {
|
|
553
|
+
"--dsw-alias-bg": t.bg,
|
|
554
|
+
"--dsw-alias-fg": t.fg,
|
|
555
|
+
"--dsw-alias-surface": t.surface,
|
|
556
|
+
"--dsw-alias-border": t.border,
|
|
557
|
+
"--dsw-alias-muted": t.muted,
|
|
558
|
+
"--dsw-alias-primary": t.primary,
|
|
559
|
+
"--dsw-alias-primary-fg": t.primaryFg,
|
|
560
|
+
"--dsw-alias-accent": t.accent,
|
|
561
|
+
"--dsw-alias-shadow": t.shadow,
|
|
562
|
+
"--background": t.bg,
|
|
563
|
+
"--foreground": t.fg,
|
|
564
|
+
"--card": t.surface,
|
|
565
|
+
"--card-foreground": t.surfaceFg,
|
|
566
|
+
"--primary": t.primary,
|
|
567
|
+
"--primary-foreground": t.primaryFg,
|
|
568
|
+
"--secondary": t.secondary,
|
|
569
|
+
"--secondary-foreground": t.secondaryFg,
|
|
570
|
+
"--muted": t.muted,
|
|
571
|
+
"--muted-foreground": t.mutedFg,
|
|
572
|
+
"--accent": t.accent,
|
|
573
|
+
"--accent-foreground": t.accentFg,
|
|
574
|
+
"--border": t.border,
|
|
575
|
+
"--input": t.input,
|
|
576
|
+
"--ring": t.ring,
|
|
577
|
+
"--destructive": t.destructive,
|
|
578
|
+
"--destructive-foreground": t.destructiveFg,
|
|
579
|
+
"--radius": t.radius,
|
|
580
|
+
"--shadow": t.shadow
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
function applyThemeTo(el, theme, palette, custom) {
|
|
584
|
+
const mode = resolveMode(theme);
|
|
585
|
+
const c = custom && palette ? custom[String(palette)] : void 0;
|
|
586
|
+
const pal = c ? String(palette) : clampPalette(palette);
|
|
587
|
+
const t = c && c.tokens && c.tokens[mode] || tokensOf(pal, mode);
|
|
588
|
+
el.setAttribute("data-theme", mode);
|
|
589
|
+
if (theme === "system") el.setAttribute("data-theme-pref", "system");
|
|
590
|
+
else el.removeAttribute("data-theme-pref");
|
|
591
|
+
el.setAttribute("data-palette", pal);
|
|
592
|
+
const map = themeCssVars(mode, palette, custom);
|
|
593
|
+
for (const k of Object.keys(map)) el.style.setProperty(k, map[k]);
|
|
594
|
+
el.style.background = t.bg;
|
|
595
|
+
el.style.color = t.fg;
|
|
596
|
+
return { theme: mode, palette: pal };
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// src/rest.ts
|
|
600
|
+
function isRecord(value) {
|
|
601
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
602
|
+
}
|
|
603
|
+
async function readJson(url, init) {
|
|
604
|
+
let res;
|
|
605
|
+
try {
|
|
606
|
+
res = await fetch(url, init);
|
|
607
|
+
} catch (cause) {
|
|
608
|
+
throw new HostUnreachableError(url, cause);
|
|
609
|
+
}
|
|
610
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
611
|
+
return res.json();
|
|
612
|
+
}
|
|
613
|
+
var HostUnreachableError = class extends Error {
|
|
614
|
+
constructor(url, cause) {
|
|
615
|
+
super(`Cannot reach apps host: ${url}`);
|
|
616
|
+
__publicField(this, "url");
|
|
617
|
+
this.name = "HostUnreachableError";
|
|
618
|
+
this.url = url;
|
|
619
|
+
if (cause !== void 0) {
|
|
620
|
+
Object.defineProperty(this, "cause", { value: cause, configurable: true, writable: true });
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
function isHostUnreachable(e) {
|
|
625
|
+
return e instanceof HostUnreachableError;
|
|
718
626
|
}
|
|
719
|
-
function
|
|
720
|
-
const
|
|
721
|
-
const
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
627
|
+
function appFrameUrl(origin, appId, query) {
|
|
628
|
+
const params = new URLSearchParams();
|
|
629
|
+
for (const key of ["theme", "palette", "dock"]) {
|
|
630
|
+
const value = query[key];
|
|
631
|
+
if (value) params.set(key, value);
|
|
632
|
+
}
|
|
633
|
+
return `${origin}/app/${encodeURIComponent(appId)}?${params.toString()}`;
|
|
634
|
+
}
|
|
635
|
+
function relayViewEval(origin, frames, query) {
|
|
636
|
+
if (!query.requestId || !query.appId) return;
|
|
637
|
+
if (frames.postViewEval(query)) return;
|
|
638
|
+
const body = { appId: query.appId, requestId: query.requestId, view: "not-open" };
|
|
639
|
+
fetch(`${origin.replace(/\/$/, "")}/api/app/${encodeURIComponent(query.appId)}/view/eval`, {
|
|
640
|
+
method: "POST",
|
|
641
|
+
headers: { "content-type": "application/json" },
|
|
642
|
+
body: JSON.stringify(body)
|
|
643
|
+
}).catch(() => {
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
function subscribeHostEvents(origin, handlers) {
|
|
647
|
+
if (typeof EventSource === "undefined") return () => {
|
|
648
|
+
};
|
|
649
|
+
let es = null;
|
|
650
|
+
const listen = (fn) => {
|
|
651
|
+
return (raw) => {
|
|
652
|
+
const e = raw;
|
|
653
|
+
let data;
|
|
654
|
+
try {
|
|
655
|
+
data = JSON.parse(e.data || "{}");
|
|
656
|
+
} catch {
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (!data || typeof data !== "object") return;
|
|
660
|
+
fn(data);
|
|
661
|
+
};
|
|
662
|
+
};
|
|
663
|
+
try {
|
|
664
|
+
es = new EventSource(`${origin.replace(/\/$/, "")}/api/events`);
|
|
665
|
+
es.addEventListener(
|
|
666
|
+
"app:open",
|
|
667
|
+
listen((d) => {
|
|
668
|
+
if (typeof d.appId === "string") handlers.onOpen?.(d.appId, typeof d.title === "string" ? d.title : void 0);
|
|
669
|
+
})
|
|
670
|
+
);
|
|
671
|
+
es.addEventListener(
|
|
672
|
+
"app:reload",
|
|
673
|
+
listen((d) => {
|
|
674
|
+
if (typeof d.appId === "string") handlers.onReload?.(d.appId);
|
|
675
|
+
})
|
|
676
|
+
);
|
|
677
|
+
es.addEventListener(
|
|
678
|
+
"app:eval",
|
|
679
|
+
listen((d) => {
|
|
680
|
+
if (typeof d.requestId !== "string" || typeof d.appId !== "string") return;
|
|
681
|
+
handlers.onEval?.({
|
|
682
|
+
requestId: d.requestId,
|
|
683
|
+
appId: d.appId,
|
|
684
|
+
code: typeof d.code === "string" ? d.code : "",
|
|
685
|
+
maxBytes: typeof d.maxBytes === "number" ? d.maxBytes : 0
|
|
686
|
+
});
|
|
687
|
+
})
|
|
688
|
+
);
|
|
689
|
+
es.addEventListener(
|
|
690
|
+
"app:storage-notice",
|
|
691
|
+
listen((d) => {
|
|
692
|
+
if (typeof d.appId !== "string" || typeof d.table !== "string" || typeof d.prompt !== "string") return;
|
|
693
|
+
const heavyRaw = Array.isArray(d.heavy) ? d.heavy : [];
|
|
694
|
+
const heavy = heavyRaw.flatMap((h) => {
|
|
695
|
+
if (!isRecord(h) || typeof h.key !== "string" || typeof h.bytes !== "number") return [];
|
|
696
|
+
const kind = h.kind === "list" || h.kind === "map" || h.kind === "value" ? h.kind : "value";
|
|
697
|
+
return [{
|
|
698
|
+
key: h.key,
|
|
699
|
+
bytes: h.bytes,
|
|
700
|
+
kind,
|
|
701
|
+
entries: typeof h.entries === "number" ? h.entries : void 0
|
|
702
|
+
}];
|
|
703
|
+
});
|
|
704
|
+
handlers.onStorageNotice?.({
|
|
705
|
+
appId: d.appId,
|
|
706
|
+
table: d.table,
|
|
707
|
+
bytes: typeof d.bytes === "number" ? d.bytes : 0,
|
|
708
|
+
keys: typeof d.keys === "number" ? d.keys : 0,
|
|
709
|
+
heavy,
|
|
710
|
+
prompt: d.prompt
|
|
711
|
+
});
|
|
712
|
+
})
|
|
713
|
+
);
|
|
714
|
+
} catch {
|
|
715
|
+
return () => {
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
return () => {
|
|
719
|
+
try {
|
|
720
|
+
es?.close();
|
|
721
|
+
} catch {
|
|
722
|
+
}
|
|
723
|
+
es = null;
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
function parseLocalPalette(css) {
|
|
727
|
+
if (typeof css !== "string" || !css.trim()) return null;
|
|
728
|
+
const tokens = parseThemeCss(css);
|
|
729
|
+
if (!tokens) return null;
|
|
730
|
+
return {
|
|
731
|
+
label: themeLabelFromCss(css, LOCAL_PALETTE_ID),
|
|
732
|
+
swatch: tokens.dark.primary || tokens.light.primary,
|
|
733
|
+
tokens
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function parseAppTheme(raw) {
|
|
737
|
+
if (raw === null) return null;
|
|
738
|
+
if (!isRecord(raw)) return void 0;
|
|
739
|
+
const theme = typeof raw.theme === "string" ? raw.theme : "";
|
|
740
|
+
const palette = typeof raw.palette === "string" ? raw.palette : "";
|
|
741
|
+
if (!theme && !palette) return null;
|
|
742
|
+
return { theme, palette };
|
|
743
|
+
}
|
|
744
|
+
function parseAbout(raw) {
|
|
745
|
+
const rec = isRecord(raw) ? raw : {};
|
|
746
|
+
const packages = [];
|
|
747
|
+
if (Array.isArray(rec.packages)) {
|
|
748
|
+
for (const p of rec.packages) {
|
|
749
|
+
if (!isRecord(p) || typeof p.name !== "string" || typeof p.version !== "string") continue;
|
|
750
|
+
packages.push({ name: p.name, version: p.version });
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return {
|
|
754
|
+
adapter: typeof rec.adapter === "string" ? rec.adapter : "host",
|
|
755
|
+
env: typeof rec.env === "string" ? rec.env : "unknown",
|
|
756
|
+
packages
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function parseUpdateCheck(raw) {
|
|
760
|
+
const rec = isRecord(raw) ? raw : {};
|
|
761
|
+
return {
|
|
762
|
+
name: typeof rec.name === "string" ? rec.name : "",
|
|
763
|
+
current: typeof rec.current === "string" ? rec.current : "",
|
|
764
|
+
latest: typeof rec.latest === "string" ? rec.latest : null,
|
|
765
|
+
updateAvailable: rec.updateAvailable === true,
|
|
766
|
+
error: typeof rec.error === "string" ? rec.error : void 0
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
function parseAppsResponse(raw) {
|
|
770
|
+
if (!isRecord(raw) || !Array.isArray(raw.apps)) return [];
|
|
771
|
+
const out = [];
|
|
772
|
+
for (const item of raw.apps) {
|
|
773
|
+
if (!isRecord(item) || typeof item.id !== "string") continue;
|
|
774
|
+
out.push({
|
|
775
|
+
id: item.id,
|
|
776
|
+
name: typeof item.name === "string" ? item.name : item.id,
|
|
777
|
+
description: typeof item.description === "string" ? item.description : void 0,
|
|
778
|
+
acronym: typeof item.acronym === "string" ? item.acronym : void 0,
|
|
779
|
+
commits: typeof item.commits === "number" ? item.commits : void 0,
|
|
780
|
+
version: typeof item.version === "string" ? item.version : void 0,
|
|
781
|
+
theme: parseAppTheme(item.theme),
|
|
782
|
+
localPalette: parseLocalPalette(item.localThemeCss)
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
return out;
|
|
786
|
+
}
|
|
787
|
+
function hostConfigToForm(raw, cardStyle) {
|
|
788
|
+
const rec = isRecord(raw) ? raw : {};
|
|
789
|
+
const llm = isRecord(rec.llm) ? rec.llm : null;
|
|
790
|
+
const locale = typeof rec.locale === "string" ? rec.locale : "";
|
|
791
|
+
const chatLanguage = typeof rec.chatLanguage === "string" ? rec.chatLanguage : "";
|
|
792
|
+
return {
|
|
793
|
+
hostPort: rec.hostPort != null ? String(rec.hostPort) : "",
|
|
794
|
+
locale: locale || chatLanguage,
|
|
795
|
+
chatLanguage: chatLanguage || locale,
|
|
796
|
+
theme: typeof rec.theme === "string" ? rec.theme : "",
|
|
797
|
+
palette: typeof rec.palette === "string" ? rec.palette : "",
|
|
798
|
+
cardStyle,
|
|
799
|
+
provider: llm && typeof llm.provider === "string" ? llm.provider : "",
|
|
800
|
+
model: llm && typeof llm.model === "string" ? llm.model : ""
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
function formToHostConfigBody(form) {
|
|
804
|
+
const provider = (form.provider ?? "").trim();
|
|
805
|
+
const model = (form.model ?? "").trim();
|
|
806
|
+
const locale = form.locale || form.chatLanguage;
|
|
807
|
+
const body = { locale, chatLanguage: form.chatLanguage || locale, theme: form.theme, palette: form.palette };
|
|
808
|
+
const port = Number(form.hostPort);
|
|
809
|
+
if (Number.isInteger(port) && port >= 0 && port <= 65535) body.hostPort = port;
|
|
810
|
+
if (provider && model) body.llm = { provider, model };
|
|
811
|
+
else if (!provider && !model) body.llm = null;
|
|
812
|
+
return body;
|
|
813
|
+
}
|
|
814
|
+
function asCommit(raw) {
|
|
815
|
+
if (!isRecord(raw) || typeof raw.id !== "string") return null;
|
|
816
|
+
const files = Array.isArray(raw.files) ? raw.files.flatMap((f) => {
|
|
817
|
+
if (!isRecord(f) || typeof f.path !== "string") return [];
|
|
818
|
+
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 }];
|
|
819
|
+
}) : void 0;
|
|
820
|
+
return { id: raw.id, message: typeof raw.message === "string" ? raw.message : "", time: typeof raw.time === "string" ? raw.time : "", files };
|
|
821
|
+
}
|
|
822
|
+
function parseCommitList(raw) {
|
|
823
|
+
const rec = isRecord(raw) ? raw : {};
|
|
824
|
+
const list = Array.isArray(rec.commits) ? rec.commits : Array.isArray(rec.nodes) ? rec.nodes : [];
|
|
825
|
+
return list.map((c) => asCommit(c)).filter((c) => c !== null);
|
|
826
|
+
}
|
|
827
|
+
function parseCommitDetail(raw, id) {
|
|
828
|
+
const rec = isRecord(raw) ? raw : {};
|
|
829
|
+
const inner = isRecord(rec.commit) ? rec.commit : rec;
|
|
830
|
+
return asCommit(inner) ?? { id, message: "", time: "", files: [] };
|
|
831
|
+
}
|
|
832
|
+
function parseStorageTables(raw) {
|
|
833
|
+
const rec = isRecord(raw) ? raw : {};
|
|
834
|
+
const list = Array.isArray(rec.tables) ? rec.tables : [];
|
|
835
|
+
const out = [];
|
|
836
|
+
for (const row of list) {
|
|
837
|
+
if (!isRecord(row) || typeof row.name !== "string") continue;
|
|
838
|
+
out.push({
|
|
839
|
+
name: row.name,
|
|
840
|
+
size: typeof row.size === "number" ? row.size : void 0,
|
|
841
|
+
updatedAt: typeof row.updatedAt === "string" ? row.updatedAt : void 0,
|
|
842
|
+
keys: typeof row.keys === "number" ? row.keys : void 0
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
return out;
|
|
846
|
+
}
|
|
847
|
+
function parseStorageNotices(raw, appId) {
|
|
848
|
+
const rec = isRecord(raw) ? raw : {};
|
|
849
|
+
const list = Array.isArray(rec.notices) ? rec.notices : [];
|
|
850
|
+
const out = [];
|
|
851
|
+
for (const row of list) {
|
|
852
|
+
if (!isRecord(row) || typeof row.table !== "string" || typeof row.prompt !== "string") continue;
|
|
853
|
+
const heavyRaw = Array.isArray(row.heavy) ? row.heavy : [];
|
|
854
|
+
const heavy = heavyRaw.flatMap((h) => {
|
|
855
|
+
if (!isRecord(h) || typeof h.key !== "string" || typeof h.bytes !== "number") return [];
|
|
856
|
+
const kind = h.kind === "list" || h.kind === "map" || h.kind === "value" ? h.kind : "value";
|
|
857
|
+
return [{
|
|
858
|
+
key: h.key,
|
|
859
|
+
bytes: h.bytes,
|
|
860
|
+
kind,
|
|
861
|
+
entries: typeof h.entries === "number" ? h.entries : void 0
|
|
862
|
+
}];
|
|
863
|
+
});
|
|
864
|
+
out.push({
|
|
865
|
+
appId: typeof row.appId === "string" ? row.appId : appId,
|
|
866
|
+
table: row.table,
|
|
867
|
+
bytes: typeof row.bytes === "number" ? row.bytes : 0,
|
|
868
|
+
keys: typeof row.keys === "number" ? row.keys : 0,
|
|
869
|
+
heavy,
|
|
870
|
+
prompt: row.prompt
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
return out;
|
|
874
|
+
}
|
|
875
|
+
function parsePalettes(raw) {
|
|
876
|
+
const rec = isRecord(raw) ? raw : {};
|
|
877
|
+
const list = Array.isArray(rec.palettes) ? rec.palettes : [];
|
|
878
|
+
const out = [];
|
|
879
|
+
for (const p of list) {
|
|
880
|
+
if (!isRecord(p) || typeof p.id !== "string") continue;
|
|
881
|
+
if (p.custom === false) continue;
|
|
882
|
+
out.push({
|
|
883
|
+
id: p.id,
|
|
884
|
+
label: typeof p.label === "string" ? p.label : p.id,
|
|
885
|
+
swatch: typeof p.swatch === "string" ? p.swatch : "#888",
|
|
886
|
+
tokens: isRecord(p.tokens) ? p.tokens : void 0
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
return out;
|
|
890
|
+
}
|
|
891
|
+
function createRestPanelHost(opts) {
|
|
892
|
+
const storage = opts.storage ?? (typeof window !== "undefined" ? window.localStorage : null);
|
|
893
|
+
function origin() {
|
|
894
|
+
return (opts.getHostUrl ? opts.getHostUrl() : opts.hostUrl).replace(/\/$/, "");
|
|
895
|
+
}
|
|
896
|
+
const host = {
|
|
897
|
+
locale: opts.locale,
|
|
898
|
+
emptyText: opts.emptyText,
|
|
899
|
+
fetchApps: async () => parseAppsResponse(await readJson(`${origin()}/api/apps`)),
|
|
900
|
+
palettes: async () => {
|
|
901
|
+
try {
|
|
902
|
+
return parsePalettes(await readJson(`${origin()}/api/palettes`));
|
|
903
|
+
} catch {
|
|
904
|
+
return [];
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
openPanel: () => opts.onOpen?.(),
|
|
908
|
+
closePanel: () => opts.onClose?.(),
|
|
909
|
+
persistTheme: (theme, palette) => {
|
|
910
|
+
try {
|
|
911
|
+
storage?.setItem("mma-theme-mode", theme);
|
|
912
|
+
storage?.setItem("mma-palette", palette);
|
|
913
|
+
} catch {
|
|
914
|
+
}
|
|
915
|
+
void fetch(`${origin()}/api/host-config`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ theme, palette }) }).catch(() => {
|
|
916
|
+
});
|
|
917
|
+
},
|
|
918
|
+
appTheme: {
|
|
919
|
+
save: async (appId, t) => {
|
|
920
|
+
await fetch(`${origin()}/api/apps/${encodeURIComponent(appId)}/theme`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(t) }).catch(() => {
|
|
921
|
+
});
|
|
922
|
+
},
|
|
923
|
+
clear: async (appId) => {
|
|
924
|
+
await fetch(`${origin()}/api/apps/${encodeURIComponent(appId)}/theme`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ reset: true }) }).catch(() => {
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
config: {
|
|
929
|
+
load: async () => hostConfigToForm(await readJson(`${origin()}/api/host-config`), opts.getCardStyle?.() ?? opts.cardStyle ?? "stamp"),
|
|
930
|
+
save: async (cfg) => {
|
|
931
|
+
const body = formToHostConfigBody(cfg);
|
|
932
|
+
const res = await fetch(`${origin()}/api/host-config`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
|
|
933
|
+
const raw = await res.json().catch(() => ({}));
|
|
934
|
+
if (!res.ok || isRecord(raw) && raw.ok === false) {
|
|
935
|
+
throw new Error(isRecord(raw) && typeof raw.error === "string" ? raw.error : `HTTP ${res.status}`);
|
|
936
|
+
}
|
|
937
|
+
const hostPort = isRecord(raw) ? raw.hostPort : void 0;
|
|
938
|
+
if (typeof hostPort === "number" && Number.isInteger(hostPort) && hostPort > 0) {
|
|
939
|
+
const next = `${new URL(origin()).protocol}//${new URL(origin()).hostname}:${hostPort}`;
|
|
940
|
+
if (next !== origin()) opts.onHostChange?.(next);
|
|
941
|
+
}
|
|
942
|
+
opts.onConfigSaved?.(cfg);
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
about: {
|
|
946
|
+
load: async () => parseAbout(await readJson(`${origin()}/api/about`)),
|
|
947
|
+
checkUpdates: async () => parseUpdateCheck(await readJson(`${origin()}/api/updates`))
|
|
948
|
+
},
|
|
949
|
+
history: {
|
|
950
|
+
list: async (appId) => parseCommitList(await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/history?limit=50`)),
|
|
951
|
+
detail: async (appId, id) => parseCommitDetail(await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/history/${encodeURIComponent(id)}`), id)
|
|
952
|
+
},
|
|
953
|
+
storage: {
|
|
954
|
+
listTables: async (appId) => {
|
|
955
|
+
const raw = await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/storage`);
|
|
956
|
+
return {
|
|
957
|
+
tables: parseStorageTables(raw),
|
|
958
|
+
notices: parseStorageNotices(raw, appId)
|
|
959
|
+
};
|
|
960
|
+
},
|
|
961
|
+
readTable: async (appId, name) => {
|
|
962
|
+
const raw = await readJson(`${origin()}/api/apps/${encodeURIComponent(appId)}/storage/${encodeURIComponent(name)}`);
|
|
963
|
+
return isRecord(raw) && "value" in raw ? raw.value : raw;
|
|
964
|
+
}
|
|
965
|
+
},
|
|
966
|
+
deleteApp: opts.deleteApp ?? (async (appId) => {
|
|
967
|
+
await fetch(`${origin()}/api/app/${encodeURIComponent(appId)}`, { method: "DELETE" }).catch(() => {
|
|
968
|
+
});
|
|
969
|
+
}),
|
|
970
|
+
frame: opts.frameController ?? {
|
|
971
|
+
url: (appId) => `${origin()}/app/${encodeURIComponent(appId)}`,
|
|
972
|
+
mount: () => void 0,
|
|
973
|
+
unmount: () => void 0,
|
|
974
|
+
reload: () => void 0,
|
|
975
|
+
syncEnv: () => void 0
|
|
729
976
|
}
|
|
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
977
|
};
|
|
741
|
-
|
|
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";
|
|
978
|
+
return host;
|
|
759
979
|
}
|
|
760
|
-
|
|
761
|
-
|
|
980
|
+
var none = {
|
|
981
|
+
history: false,
|
|
982
|
+
storage: false,
|
|
983
|
+
config: false,
|
|
984
|
+
appTheme: false,
|
|
985
|
+
customPalettes: false,
|
|
986
|
+
deleteApp: false
|
|
987
|
+
};
|
|
988
|
+
var initial = {
|
|
989
|
+
tabs: [{ id: "all", title: "\u5168\u90E8", kind: "all" }],
|
|
990
|
+
active: "all",
|
|
991
|
+
apps: [],
|
|
992
|
+
error: null,
|
|
993
|
+
loading: false,
|
|
994
|
+
query: "",
|
|
995
|
+
dock: "fill",
|
|
996
|
+
theme: "light",
|
|
997
|
+
palette: "default",
|
|
998
|
+
themeScope: "global",
|
|
999
|
+
customPalettes: {},
|
|
1000
|
+
cardStyle: "stamp",
|
|
1001
|
+
visible: false,
|
|
1002
|
+
pendingDelete: null,
|
|
1003
|
+
themePopOpen: false,
|
|
1004
|
+
settingsOpen: false,
|
|
1005
|
+
cfgMsg: "",
|
|
1006
|
+
cfgVersion: 0,
|
|
1007
|
+
cfg: {},
|
|
1008
|
+
about: null,
|
|
1009
|
+
updateCheck: null,
|
|
1010
|
+
emptyText: void 0,
|
|
1011
|
+
capabilities: none,
|
|
1012
|
+
locale: "zh-CN",
|
|
1013
|
+
browseOpen: false,
|
|
1014
|
+
browseKind: "history",
|
|
1015
|
+
browseAppId: null,
|
|
1016
|
+
browseAppName: "",
|
|
1017
|
+
browseLoading: false,
|
|
1018
|
+
browseError: null,
|
|
1019
|
+
browseList: [],
|
|
1020
|
+
browseDetail: null,
|
|
1021
|
+
browseTable: null,
|
|
1022
|
+
browseTableValue: null,
|
|
1023
|
+
browseOpenFile: null,
|
|
1024
|
+
storageNotice: null
|
|
1025
|
+
};
|
|
1026
|
+
var state = { ...initial, capabilities: { ...none } };
|
|
1027
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
1028
|
+
function getPanelState() {
|
|
1029
|
+
return state;
|
|
762
1030
|
}
|
|
763
|
-
function
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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(";");
|
|
1031
|
+
function setPanelState(patch) {
|
|
1032
|
+
state = { ...state, ...patch };
|
|
1033
|
+
for (const fn of listeners) fn();
|
|
1034
|
+
return state;
|
|
796
1035
|
}
|
|
797
|
-
function
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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 ");
|
|
1036
|
+
function subscribePanel(listener) {
|
|
1037
|
+
listeners.add(listener);
|
|
1038
|
+
return () => {
|
|
1039
|
+
listeners.delete(listener);
|
|
1040
|
+
};
|
|
809
1041
|
}
|
|
810
|
-
function
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
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
|
|
1042
|
+
function resetPanelState(seed) {
|
|
1043
|
+
state = {
|
|
1044
|
+
...initial,
|
|
1045
|
+
capabilities: { ...none },
|
|
1046
|
+
customPalettes: {},
|
|
1047
|
+
cfg: {},
|
|
1048
|
+
tabs: [{ id: "all", title: "\u5168\u90E8", kind: "all" }],
|
|
1049
|
+
...seed || {}
|
|
846
1050
|
};
|
|
847
|
-
for (const
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
1051
|
+
for (const fn of listeners) fn();
|
|
1052
|
+
return state;
|
|
1053
|
+
}
|
|
1054
|
+
function usePanelState() {
|
|
1055
|
+
return React4.useSyncExternalStore(subscribePanel, getPanelState);
|
|
851
1056
|
}
|
|
852
1057
|
|
|
853
1058
|
// src/actions.ts
|
|
854
1059
|
function activeAppFrom(state2) {
|
|
855
|
-
const tab = state2.tabs.find((t) => t.kind === "app" && t.id === state2.active)
|
|
1060
|
+
const tab = state2.tabs.find((t) => t.kind === "app" && t.id === state2.active);
|
|
856
1061
|
return tab?.app ?? null;
|
|
857
1062
|
}
|
|
858
1063
|
function errorMessage(err) {
|
|
@@ -869,6 +1074,17 @@ function pushAppTab(app) {
|
|
|
869
1074
|
function asCustomPalettes(value) {
|
|
870
1075
|
return value;
|
|
871
1076
|
}
|
|
1077
|
+
function loadCustomPalettes(host) {
|
|
1078
|
+
if (!host.palettes) return;
|
|
1079
|
+
host.palettes().then((list) => {
|
|
1080
|
+
const custom = {};
|
|
1081
|
+
for (const p of list) {
|
|
1082
|
+
custom[p.id] = { label: p.label, swatch: p.swatch, tokens: p.tokens };
|
|
1083
|
+
}
|
|
1084
|
+
setPanelState({ customPalettes: custom });
|
|
1085
|
+
}).catch(() => {
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
872
1088
|
function createPanelActions(host, getRootEl, i18n) {
|
|
873
1089
|
setPanelState({ capabilities: capabilitiesOf(host), locale: i18n.locale, emptyText: host.emptyText });
|
|
874
1090
|
return {
|
|
@@ -883,14 +1099,18 @@ function createPanelActions(host, getRootEl, i18n) {
|
|
|
883
1099
|
const tab = s.tabs.find((t) => t.id === id);
|
|
884
1100
|
setPanelState({
|
|
885
1101
|
tabs: s.tabs.filter((t) => t.id !== id),
|
|
886
|
-
active: s.active === id ? "all" : s.active
|
|
1102
|
+
active: s.active === id ? "all" : s.active,
|
|
1103
|
+
...s.active === id ? { themeScope: "global" } : {}
|
|
887
1104
|
});
|
|
888
1105
|
if (tab?.app) host.frame.unmount(tab.app.id);
|
|
889
1106
|
},
|
|
890
1107
|
switchTab: (id) => {
|
|
891
|
-
setPanelState({ active: id });
|
|
892
1108
|
const s = getPanelState();
|
|
893
1109
|
const tab = s.tabs.find((t) => t.id === id && t.kind === "app");
|
|
1110
|
+
setPanelState({
|
|
1111
|
+
active: id,
|
|
1112
|
+
...!tab?.app ? { themeScope: "global" } : {}
|
|
1113
|
+
});
|
|
894
1114
|
if (tab?.app) host.frame.mount(tab.app.id);
|
|
895
1115
|
},
|
|
896
1116
|
setDock: (next) => {
|
|
@@ -901,31 +1121,38 @@ function createPanelActions(host, getRootEl, i18n) {
|
|
|
901
1121
|
}
|
|
902
1122
|
},
|
|
903
1123
|
setQuery: (q) => setPanelState({ query: q }),
|
|
904
|
-
toggleThemePop: () =>
|
|
1124
|
+
toggleThemePop: () => {
|
|
1125
|
+
const next = !getPanelState().themePopOpen;
|
|
1126
|
+
setPanelState({ themePopOpen: next });
|
|
1127
|
+
if (next) loadCustomPalettes(host);
|
|
1128
|
+
},
|
|
905
1129
|
setAppearance: (next, scope) => {
|
|
906
1130
|
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
1131
|
if (scope === "app") {
|
|
915
|
-
const app = activeAppFrom(
|
|
1132
|
+
const app = activeAppFrom(s);
|
|
916
1133
|
if (app && host.appTheme) {
|
|
917
|
-
const
|
|
1134
|
+
const base = app.theme ?? { theme: s.theme, palette: s.palette };
|
|
1135
|
+
const nextTheme = {
|
|
1136
|
+
theme: next.theme ? String(next.theme) : base.theme,
|
|
1137
|
+
palette: next.palette ? String(next.palette) : base.palette
|
|
1138
|
+
};
|
|
918
1139
|
host.appTheme.save(app.id, nextTheme).catch(() => {
|
|
919
1140
|
});
|
|
920
1141
|
const cur = getPanelState();
|
|
1142
|
+
const patchApp = (a) => a.id === app.id ? { ...a, theme: nextTheme } : a;
|
|
921
1143
|
setPanelState({
|
|
922
|
-
apps: cur.apps.some((a) => a.id === app.id) ? cur.apps.map(
|
|
923
|
-
tabs: cur.tabs.map(
|
|
924
|
-
(t) => t.app?.id === app.id ? { ...t, app: { ...t.app, theme: nextTheme } } : t
|
|
925
|
-
)
|
|
1144
|
+
apps: cur.apps.some((a) => a.id === app.id) ? cur.apps.map(patchApp) : [...cur.apps, { ...app, theme: nextTheme }],
|
|
1145
|
+
tabs: cur.tabs.map((t) => t.app?.id === app.id ? { ...t, app: { ...t.app, theme: nextTheme } } : t)
|
|
926
1146
|
});
|
|
927
1147
|
}
|
|
928
1148
|
} else {
|
|
1149
|
+
const theme = next.theme ? String(next.theme) : s.theme;
|
|
1150
|
+
const palette = next.palette ? String(next.palette) : s.palette;
|
|
1151
|
+
setPanelState({ theme, palette });
|
|
1152
|
+
const root = getRootEl();
|
|
1153
|
+
if (root) {
|
|
1154
|
+
applyThemeTo(root, theme, palette, asCustomPalettes(s.customPalettes));
|
|
1155
|
+
}
|
|
929
1156
|
host.persistTheme?.(theme, palette);
|
|
930
1157
|
}
|
|
931
1158
|
host.frame.syncEnv?.();
|
|
@@ -948,23 +1175,71 @@ function createPanelActions(host, getRootEl, i18n) {
|
|
|
948
1175
|
},
|
|
949
1176
|
getActiveApp: () => activeAppFrom(getPanelState()),
|
|
950
1177
|
toggleSettings: (open) => {
|
|
951
|
-
setPanelState({
|
|
1178
|
+
setPanelState({
|
|
1179
|
+
settingsOpen: open,
|
|
1180
|
+
cfgMsg: open ? "" : getPanelState().cfgMsg,
|
|
1181
|
+
updateCheck: open ? null : getPanelState().updateCheck
|
|
1182
|
+
});
|
|
952
1183
|
if (open && host.config) {
|
|
953
1184
|
host.config.load().then((cfg) => {
|
|
954
1185
|
setPanelState({ cfg, cfgVersion: getPanelState().cfgVersion + 1 });
|
|
955
1186
|
}).catch(() => {
|
|
956
1187
|
});
|
|
957
1188
|
}
|
|
1189
|
+
if (open && host.about) {
|
|
1190
|
+
host.about.load().then((about) => setPanelState({ about })).catch(() => setPanelState({ about: null }));
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
getCfg: () => getPanelState().cfg,
|
|
1194
|
+
checkUpdates: () => {
|
|
1195
|
+
if (!host.about) return;
|
|
1196
|
+
setPanelState({
|
|
1197
|
+
updateCheck: {
|
|
1198
|
+
name: "",
|
|
1199
|
+
current: "",
|
|
1200
|
+
latest: null,
|
|
1201
|
+
updateAvailable: false,
|
|
1202
|
+
status: "loading"
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
host.about.checkUpdates().then((check) => setPanelState({ updateCheck: { ...check, status: "done" } })).catch(
|
|
1206
|
+
(err) => setPanelState({
|
|
1207
|
+
updateCheck: {
|
|
1208
|
+
name: "",
|
|
1209
|
+
current: "",
|
|
1210
|
+
latest: null,
|
|
1211
|
+
updateAvailable: false,
|
|
1212
|
+
status: "done",
|
|
1213
|
+
error: errorMessage(err)
|
|
1214
|
+
}
|
|
1215
|
+
})
|
|
1216
|
+
);
|
|
958
1217
|
},
|
|
959
|
-
getCfg: () => getPanelState().cfg,
|
|
960
1218
|
saveHostConfig: (form) => {
|
|
961
1219
|
if (!host.config) return;
|
|
962
1220
|
host.config.save(form).then(() => {
|
|
1221
|
+
const style = form.cardStyle || getPanelState().cardStyle;
|
|
1222
|
+
const theme = form.theme || getPanelState().theme;
|
|
1223
|
+
const palette = form.palette || getPanelState().palette;
|
|
963
1224
|
setPanelState({
|
|
964
1225
|
cfg: { ...form },
|
|
965
1226
|
cfgMsg: i18n.t("config.saved"),
|
|
966
|
-
cfgVersion: getPanelState().cfgVersion + 1
|
|
1227
|
+
cfgVersion: getPanelState().cfgVersion + 1,
|
|
1228
|
+
cardStyle: style,
|
|
1229
|
+
theme,
|
|
1230
|
+
palette
|
|
967
1231
|
});
|
|
1232
|
+
const root = getRootEl();
|
|
1233
|
+
if (root) {
|
|
1234
|
+
applyThemeTo(root, theme, palette, asCustomPalettes(getPanelState().customPalettes));
|
|
1235
|
+
root.setAttribute("data-cardstyle", style);
|
|
1236
|
+
}
|
|
1237
|
+
host.persistTheme?.(theme, palette);
|
|
1238
|
+
host.frame.syncEnv?.();
|
|
1239
|
+
try {
|
|
1240
|
+
localStorage.setItem("mma-card-style", style);
|
|
1241
|
+
} catch {
|
|
1242
|
+
}
|
|
968
1243
|
}).catch((e) => {
|
|
969
1244
|
setPanelState({ cfgMsg: i18n.t("config.error", { message: errorMessage(e) }) });
|
|
970
1245
|
});
|
|
@@ -998,11 +1273,22 @@ function createPanelActions(host, getRootEl, i18n) {
|
|
|
998
1273
|
setPanelState({ browseList: list, browseLoading: false });
|
|
999
1274
|
}).catch((e) => setPanelState({ browseError: errorMessage(e), browseLoading: false }));
|
|
1000
1275
|
} else if (host.storage) {
|
|
1001
|
-
host.storage.listTables(app.id).then((
|
|
1002
|
-
|
|
1276
|
+
host.storage.listTables(app.id).then(({ tables, notices }) => {
|
|
1277
|
+
const notice = notices[0] ?? null;
|
|
1278
|
+
setPanelState({
|
|
1279
|
+
browseList: tables,
|
|
1280
|
+
browseLoading: false,
|
|
1281
|
+
...notice ? { storageNotice: notice } : {}
|
|
1282
|
+
});
|
|
1003
1283
|
}).catch((e) => setPanelState({ browseError: errorMessage(e), browseLoading: false }));
|
|
1004
1284
|
}
|
|
1005
1285
|
},
|
|
1286
|
+
dismissStorageNotice: () => {
|
|
1287
|
+
setPanelState({ storageNotice: null });
|
|
1288
|
+
},
|
|
1289
|
+
applyStorageNotice: (notice) => {
|
|
1290
|
+
setPanelState({ storageNotice: notice });
|
|
1291
|
+
},
|
|
1006
1292
|
loadCommitDetail: (id) => {
|
|
1007
1293
|
const s = getPanelState();
|
|
1008
1294
|
if (!host.history || !s.browseAppId) return;
|
|
@@ -1061,7 +1347,14 @@ function createPanelActions(host, getRootEl, i18n) {
|
|
|
1061
1347
|
});
|
|
1062
1348
|
});
|
|
1063
1349
|
},
|
|
1064
|
-
setCardStyle: (v) =>
|
|
1350
|
+
setCardStyle: (v) => {
|
|
1351
|
+
setPanelState({ cardStyle: v });
|
|
1352
|
+
getRootEl()?.setAttribute("data-cardstyle", v);
|
|
1353
|
+
try {
|
|
1354
|
+
localStorage.setItem("mma-card-style", v);
|
|
1355
|
+
} catch {
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1065
1358
|
};
|
|
1066
1359
|
}
|
|
1067
1360
|
function defaultHideThemePop() {
|
|
@@ -1072,8 +1365,8 @@ function defaultHideThemePop() {
|
|
|
1072
1365
|
function clampPaletteId(v) {
|
|
1073
1366
|
return clampPalette(v);
|
|
1074
1367
|
}
|
|
1075
|
-
var PanelActionsContext =
|
|
1076
|
-
var PanelI18nContext =
|
|
1368
|
+
var PanelActionsContext = React4__namespace.createContext(null);
|
|
1369
|
+
var PanelI18nContext = React4__namespace.createContext(null);
|
|
1077
1370
|
function PanelProvider({
|
|
1078
1371
|
actions,
|
|
1079
1372
|
i18n,
|
|
@@ -1082,12 +1375,12 @@ function PanelProvider({
|
|
|
1082
1375
|
return /* @__PURE__ */ jsxRuntime.jsx(PanelI18nContext.Provider, { value: i18n, children: /* @__PURE__ */ jsxRuntime.jsx(PanelActionsContext.Provider, { value: actions, children }) });
|
|
1083
1376
|
}
|
|
1084
1377
|
function usePanelActions() {
|
|
1085
|
-
const ctx =
|
|
1378
|
+
const ctx = React4__namespace.useContext(PanelActionsContext);
|
|
1086
1379
|
if (!ctx) throw new Error("usePanelActions must be used inside <PanelProvider>");
|
|
1087
1380
|
return ctx;
|
|
1088
1381
|
}
|
|
1089
1382
|
function usePanelI18n() {
|
|
1090
|
-
const ctx =
|
|
1383
|
+
const ctx = React4__namespace.useContext(PanelI18nContext);
|
|
1091
1384
|
if (!ctx) throw new Error("usePanelI18n must be used inside <PanelProvider>");
|
|
1092
1385
|
return ctx;
|
|
1093
1386
|
}
|
|
@@ -1147,6 +1440,7 @@ function AppCard({ app }) {
|
|
|
1147
1440
|
{
|
|
1148
1441
|
type: "button",
|
|
1149
1442
|
className: "mma-card",
|
|
1443
|
+
"data-app-id": app.id,
|
|
1150
1444
|
style: { "--h": hue(app.id) },
|
|
1151
1445
|
onClick: () => actions.openAppTab(app),
|
|
1152
1446
|
children: [
|
|
@@ -1175,6 +1469,7 @@ function AppRow({ app }) {
|
|
|
1175
1469
|
{
|
|
1176
1470
|
type: "button",
|
|
1177
1471
|
className: "mma-row",
|
|
1472
|
+
"data-app-id": app.id,
|
|
1178
1473
|
style: { "--h": hue(app.id) },
|
|
1179
1474
|
onClick: () => actions.openAppTab(app),
|
|
1180
1475
|
children: [
|
|
@@ -1282,26 +1577,60 @@ function CommitItem({ c }) {
|
|
|
1282
1577
|
] })
|
|
1283
1578
|
] });
|
|
1284
1579
|
}
|
|
1580
|
+
function humanBytes(n, t) {
|
|
1581
|
+
if (n < 1024) return `${n} B`;
|
|
1582
|
+
if (n < 1024 * 1024) return t("browse.sizeKb", { value: (n / 1024).toFixed(1) });
|
|
1583
|
+
return t("browse.sizeMb", { value: (n / (1024 * 1024)).toFixed(1) });
|
|
1584
|
+
}
|
|
1285
1585
|
function StorageItem({ table }) {
|
|
1286
1586
|
const actions = usePanelActions();
|
|
1587
|
+
const { t } = usePanelI18n();
|
|
1287
1588
|
return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "mma-bitem", onClick: () => actions.loadTable(table.name), children: [
|
|
1288
1589
|
/* @__PURE__ */ jsxRuntime.jsx("b", { children: table.name }),
|
|
1289
1590
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "meta", children: [
|
|
1290
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1291
|
-
|
|
1292
|
-
" B"
|
|
1293
|
-
] }),
|
|
1591
|
+
typeof table.keys === "number" ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("browse.entries", { count: table.keys }) }) : null,
|
|
1592
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: humanBytes(table.size || 0, t) }),
|
|
1294
1593
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: table.updatedAt || "" })
|
|
1295
1594
|
] })
|
|
1296
1595
|
] });
|
|
1297
1596
|
}
|
|
1597
|
+
function StorageNoticeBanner() {
|
|
1598
|
+
const s = usePanelState();
|
|
1599
|
+
const actions = usePanelActions();
|
|
1600
|
+
const { t } = usePanelI18n();
|
|
1601
|
+
const notice = s.storageNotice;
|
|
1602
|
+
const [copied, setCopied] = React4__namespace.useState(false);
|
|
1603
|
+
if (!notice) return null;
|
|
1604
|
+
if (s.browseAppId && notice.appId !== s.browseAppId) return null;
|
|
1605
|
+
const top = notice.heavy[0];
|
|
1606
|
+
const summary = top ? t("browse.noticeTop", { key: top.key, size: humanBytes(top.bytes, t) }) : "";
|
|
1607
|
+
const copyPrompt = async () => {
|
|
1608
|
+
try {
|
|
1609
|
+
await navigator.clipboard.writeText(notice.prompt);
|
|
1610
|
+
setCopied(true);
|
|
1611
|
+
window.setTimeout(() => setCopied(false), 1500);
|
|
1612
|
+
} catch {
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-storage-notice", role: "status", children: [
|
|
1616
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-storage-notice-body", children: [
|
|
1617
|
+
/* @__PURE__ */ jsxRuntime.jsx("b", { children: t("browse.noticeTitle", { table: notice.table, size: humanBytes(notice.bytes, t) }) }),
|
|
1618
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: t("browse.noticeBody") }),
|
|
1619
|
+
summary ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mma-storage-notice-top", children: summary }) : null
|
|
1620
|
+
] }),
|
|
1621
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-storage-notice-actions", children: [
|
|
1622
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-storage-notice-copy", onClick: () => void copyPrompt(), children: copied ? t("browse.noticeCopied") : t("browse.noticeCopy") }),
|
|
1623
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => actions.dismissStorageNotice(), children: t("browse.noticeDismiss") })
|
|
1624
|
+
] })
|
|
1625
|
+
] });
|
|
1626
|
+
}
|
|
1298
1627
|
function CommitDetail() {
|
|
1299
1628
|
const s = usePanelState();
|
|
1300
1629
|
const actions = usePanelActions();
|
|
1301
1630
|
const { t } = usePanelI18n();
|
|
1302
|
-
const [msgExpanded, setMsgExpanded] =
|
|
1631
|
+
const [msgExpanded, setMsgExpanded] = React4__namespace.useState(false);
|
|
1303
1632
|
const d = s.browseDetail;
|
|
1304
|
-
|
|
1633
|
+
React4__namespace.useEffect(() => {
|
|
1305
1634
|
setMsgExpanded(false);
|
|
1306
1635
|
}, [d?.id]);
|
|
1307
1636
|
if (!d) return null;
|
|
@@ -1389,7 +1718,10 @@ function Browse() {
|
|
|
1389
1718
|
) })
|
|
1390
1719
|
] });
|
|
1391
1720
|
}
|
|
1392
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-browse", id: "mma-browse", "data-open": "1", children: /* @__PURE__ */ jsxRuntime.
|
|
1721
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-browse", id: "mma-browse", "data-open": "1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-browse-body", id: "mma-browse-body", children: [
|
|
1722
|
+
s.browseKind === "storage" ? /* @__PURE__ */ jsxRuntime.jsx(StorageNoticeBanner, {}) : null,
|
|
1723
|
+
content
|
|
1724
|
+
] }) });
|
|
1393
1725
|
}
|
|
1394
1726
|
function Modal() {
|
|
1395
1727
|
const s = usePanelState();
|
|
@@ -1406,66 +1738,676 @@ function Modal() {
|
|
|
1406
1738
|
] })
|
|
1407
1739
|
] }) });
|
|
1408
1740
|
}
|
|
1741
|
+
function OptionCardGrid({
|
|
1742
|
+
options,
|
|
1743
|
+
value,
|
|
1744
|
+
onChange,
|
|
1745
|
+
columns = 3,
|
|
1746
|
+
"aria-label": ariaLabel,
|
|
1747
|
+
className,
|
|
1748
|
+
trailing
|
|
1749
|
+
}) {
|
|
1750
|
+
const refs = React4__namespace.useRef([]);
|
|
1751
|
+
const values = options.map((o) => o.value);
|
|
1752
|
+
const focusAt = (index) => {
|
|
1753
|
+
const el = refs.current[index];
|
|
1754
|
+
el?.focus();
|
|
1755
|
+
};
|
|
1756
|
+
const onKeyDown = (e, index) => {
|
|
1757
|
+
const enabled = options.map((o, i) => ({ o, i })).filter((x) => !x.o.disabled);
|
|
1758
|
+
if (!enabled.length) return;
|
|
1759
|
+
const pos = enabled.findIndex((x) => x.i === index);
|
|
1760
|
+
if (pos < 0) return;
|
|
1761
|
+
let nextPos = pos;
|
|
1762
|
+
if (e.key === "ArrowRight" || e.key === "ArrowDown") {
|
|
1763
|
+
e.preventDefault();
|
|
1764
|
+
nextPos = (pos + 1) % enabled.length;
|
|
1765
|
+
} else if (e.key === "ArrowLeft" || e.key === "ArrowUp") {
|
|
1766
|
+
e.preventDefault();
|
|
1767
|
+
nextPos = (pos - 1 + enabled.length) % enabled.length;
|
|
1768
|
+
} else if (e.key === "Home") {
|
|
1769
|
+
e.preventDefault();
|
|
1770
|
+
nextPos = 0;
|
|
1771
|
+
} else if (e.key === "End") {
|
|
1772
|
+
e.preventDefault();
|
|
1773
|
+
nextPos = enabled.length - 1;
|
|
1774
|
+
} else {
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
const next = enabled[nextPos];
|
|
1778
|
+
if (!next) return;
|
|
1779
|
+
focusAt(next.i);
|
|
1780
|
+
if (!next.o.disabled) onChange(next.o.value);
|
|
1781
|
+
};
|
|
1782
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1783
|
+
"div",
|
|
1784
|
+
{
|
|
1785
|
+
className: `mma-optgrid mma-optgrid--${columns}${className ? ` ${className}` : ""}`,
|
|
1786
|
+
role: "radiogroup",
|
|
1787
|
+
"aria-label": ariaLabel,
|
|
1788
|
+
children: [
|
|
1789
|
+
options.map((opt, index) => {
|
|
1790
|
+
const checked = value === opt.value;
|
|
1791
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1792
|
+
"button",
|
|
1793
|
+
{
|
|
1794
|
+
type: "button",
|
|
1795
|
+
role: "radio",
|
|
1796
|
+
"aria-checked": checked,
|
|
1797
|
+
"aria-label": opt.hint ? `${opt.label}. ${opt.hint}` : opt.label,
|
|
1798
|
+
disabled: opt.disabled,
|
|
1799
|
+
tabIndex: checked || !value && index === 0 ? 0 : -1,
|
|
1800
|
+
className: "mma-optcard",
|
|
1801
|
+
"data-on": checked ? "1" : "0",
|
|
1802
|
+
ref: (el) => {
|
|
1803
|
+
refs.current[index] = el;
|
|
1804
|
+
},
|
|
1805
|
+
onClick: () => {
|
|
1806
|
+
if (!opt.disabled) onChange(opt.value);
|
|
1807
|
+
},
|
|
1808
|
+
onKeyDown: (e) => onKeyDown(e, index),
|
|
1809
|
+
children: [
|
|
1810
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-optcard-preview", "aria-hidden": "true", children: opt.preview }),
|
|
1811
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-optcard-label", children: opt.label }),
|
|
1812
|
+
checked ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-optcard-check", "aria-hidden": "true", children: "\u2713" }) : null
|
|
1813
|
+
]
|
|
1814
|
+
},
|
|
1815
|
+
opt.value
|
|
1816
|
+
);
|
|
1817
|
+
}),
|
|
1818
|
+
trailing ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1819
|
+
"button",
|
|
1820
|
+
{
|
|
1821
|
+
type: "button",
|
|
1822
|
+
className: "mma-optcard mma-optcard--ghost",
|
|
1823
|
+
disabled: trailing.disabled !== false,
|
|
1824
|
+
title: trailing.hint,
|
|
1825
|
+
onClick: () => trailing.onClick?.(),
|
|
1826
|
+
children: [
|
|
1827
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-optcard-preview mma-optcard-preview--plus", "aria-hidden": "true", children: "+" }),
|
|
1828
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-optcard-label", children: trailing.label })
|
|
1829
|
+
]
|
|
1830
|
+
}
|
|
1831
|
+
) : null,
|
|
1832
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { hidden: true, children: values.join(",") })
|
|
1833
|
+
]
|
|
1834
|
+
}
|
|
1835
|
+
);
|
|
1836
|
+
}
|
|
1837
|
+
var SECTIONS = ["appearance", "network", "model", "about"];
|
|
1838
|
+
var DEFAULTS = {
|
|
1839
|
+
hostPort: "17880",
|
|
1840
|
+
provider: "",
|
|
1841
|
+
model: "",
|
|
1842
|
+
locale: "zh-CN",
|
|
1843
|
+
theme: "light",
|
|
1844
|
+
palette: "default",
|
|
1845
|
+
cardStyle: "stamp"
|
|
1846
|
+
};
|
|
1847
|
+
function shortPkg(name) {
|
|
1848
|
+
return name.replace(/^@monkey-mini-app\//, "");
|
|
1849
|
+
}
|
|
1850
|
+
function validatePort(raw) {
|
|
1851
|
+
const trimmed = raw.trim();
|
|
1852
|
+
if (!trimmed) return "empty";
|
|
1853
|
+
if (!/^\d+$/.test(trimmed)) return "nan";
|
|
1854
|
+
const n = Number(trimmed);
|
|
1855
|
+
if (!Number.isInteger(n) || n < 1024 || n > 65535) return "range";
|
|
1856
|
+
return null;
|
|
1857
|
+
}
|
|
1858
|
+
function ThemePreview({ mode }) {
|
|
1859
|
+
if (mode === "system") {
|
|
1860
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-preview-theme mma-preview-theme--system", children: [
|
|
1861
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-preview-theme-half mma-preview-theme-half--light" }),
|
|
1862
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-preview-theme-half mma-preview-theme-half--dark" })
|
|
1863
|
+
] });
|
|
1864
|
+
}
|
|
1865
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: `mma-preview-theme mma-preview-theme--${mode}`, children: [
|
|
1866
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-preview-bar" }),
|
|
1867
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-preview-bar" })
|
|
1868
|
+
] });
|
|
1869
|
+
}
|
|
1870
|
+
function PalettePreview({ id, mode }) {
|
|
1871
|
+
const t = tokensOf(id, mode);
|
|
1872
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-preview-swatches", children: [
|
|
1873
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { background: t.primary } }),
|
|
1874
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { background: t.secondary } }),
|
|
1875
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { background: t.bg } })
|
|
1876
|
+
] });
|
|
1877
|
+
}
|
|
1878
|
+
function CardStylePreview({ style }) {
|
|
1879
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `mma-preview-cardstyle mma-preview-cardstyle--${style}` });
|
|
1880
|
+
}
|
|
1409
1881
|
function Settings() {
|
|
1410
1882
|
const s = usePanelState();
|
|
1411
1883
|
const actions = usePanelActions();
|
|
1412
1884
|
const { t } = usePanelI18n();
|
|
1413
|
-
const [form, setForm] =
|
|
1414
|
-
|
|
1885
|
+
const [form, setForm] = React4__namespace.useState({});
|
|
1886
|
+
const [snapshot, setSnapshot] = React4__namespace.useState(null);
|
|
1887
|
+
const [section, setSection] = React4__namespace.useState("appearance");
|
|
1888
|
+
const [portTouched, setPortTouched] = React4__namespace.useState(false);
|
|
1889
|
+
const [confirm, setConfirm] = React4__namespace.useState(null);
|
|
1890
|
+
const [lastSavedAt, setLastSavedAt] = React4__namespace.useState(null);
|
|
1891
|
+
const rootRef = React4__namespace.useRef(null);
|
|
1892
|
+
const contentRef = React4__namespace.useRef(null);
|
|
1893
|
+
const sectionRefs = React4__namespace.useRef({});
|
|
1894
|
+
const dirtyCountRef = React4__namespace.useRef(0);
|
|
1895
|
+
const confirmRef = React4__namespace.useRef(confirm);
|
|
1896
|
+
confirmRef.current = confirm;
|
|
1897
|
+
const [wide, setWide] = React4__namespace.useState(false);
|
|
1898
|
+
React4__namespace.useEffect(() => {
|
|
1899
|
+
if (!s.settingsOpen) return;
|
|
1900
|
+
const next = s.cfg && Object.keys(s.cfg).length ? { ...s.cfg } : { ...actions.getCfg() };
|
|
1901
|
+
const snap = {
|
|
1902
|
+
hostPort: next.hostPort || "",
|
|
1903
|
+
provider: next.provider || "",
|
|
1904
|
+
model: next.model || "",
|
|
1905
|
+
theme: next.theme || s.theme || "light",
|
|
1906
|
+
palette: next.palette || s.palette || "default",
|
|
1907
|
+
cardStyle: next.cardStyle || s.cardStyle || "stamp",
|
|
1908
|
+
locale: next.locale || next.chatLanguage || "zh-CN"
|
|
1909
|
+
};
|
|
1910
|
+
setForm({ ...next, ...snap, chatLanguage: snap.locale });
|
|
1911
|
+
setSnapshot(snap);
|
|
1912
|
+
setPortTouched(false);
|
|
1913
|
+
setConfirm(null);
|
|
1914
|
+
setSection("appearance");
|
|
1915
|
+
}, [s.settingsOpen, s.cfgVersion, s.cfg, actions, s.theme, s.palette, s.cardStyle]);
|
|
1916
|
+
React4__namespace.useEffect(() => {
|
|
1415
1917
|
if (!s.settingsOpen) return;
|
|
1416
|
-
|
|
1417
|
-
|
|
1918
|
+
const host = rootRef.current?.closest("#mma-host") ?? rootRef.current;
|
|
1919
|
+
if (!host || typeof ResizeObserver === "undefined") return;
|
|
1920
|
+
const ro = new ResizeObserver((entries) => {
|
|
1921
|
+
const w = entries[0]?.contentRect.width ?? 0;
|
|
1922
|
+
setWide(w >= 720);
|
|
1923
|
+
});
|
|
1924
|
+
ro.observe(host);
|
|
1925
|
+
return () => ro.disconnect();
|
|
1926
|
+
}, [s.settingsOpen]);
|
|
1927
|
+
React4__namespace.useEffect(() => {
|
|
1928
|
+
if (!s.settingsOpen) return;
|
|
1929
|
+
const root = contentRef.current;
|
|
1930
|
+
if (!root) return;
|
|
1931
|
+
const nodes = SECTIONS.map((id) => sectionRefs.current[id]).filter(Boolean);
|
|
1932
|
+
if (!nodes.length) return;
|
|
1933
|
+
const obs = new IntersectionObserver(
|
|
1934
|
+
(entries) => {
|
|
1935
|
+
const visible = entries.filter((e) => e.isIntersecting).sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
|
1936
|
+
const id = visible?.target.getAttribute("data-section");
|
|
1937
|
+
if (id) setSection(id);
|
|
1938
|
+
},
|
|
1939
|
+
{ root, threshold: [0.25, 0.5, 0.75], rootMargin: "-20% 0px -55% 0px" }
|
|
1940
|
+
);
|
|
1941
|
+
for (const n of nodes) obs.observe(n);
|
|
1942
|
+
return () => obs.disconnect();
|
|
1943
|
+
}, [s.settingsOpen, form]);
|
|
1944
|
+
React4__namespace.useEffect(() => {
|
|
1945
|
+
if (!s.settingsOpen) return;
|
|
1946
|
+
const onKey = (e) => {
|
|
1947
|
+
if (e.key !== "Escape") return;
|
|
1948
|
+
e.preventDefault();
|
|
1949
|
+
if (confirmRef.current) {
|
|
1950
|
+
setConfirm(null);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (dirtyCountRef.current > 0) setConfirm("close");
|
|
1954
|
+
else actions.toggleSettings(false);
|
|
1955
|
+
};
|
|
1956
|
+
window.addEventListener("keydown", onKey);
|
|
1957
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1958
|
+
}, [s.settingsOpen, actions]);
|
|
1418
1959
|
if (!s.capabilities.config) return null;
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
] })
|
|
1468
|
-
|
|
1960
|
+
const themeMode = form.theme === "system" || form.theme === "dark" || form.theme === "light" ? form.theme : s.theme === "system" || s.theme === "dark" || s.theme === "light" ? s.theme : "light";
|
|
1961
|
+
const resolvedMode = resolveMode(themeMode === "system" ? "system" : themeMode);
|
|
1962
|
+
const palette = form.palette || s.palette || "default";
|
|
1963
|
+
const cardStyle = form.cardStyle || s.cardStyle || "stamp";
|
|
1964
|
+
const locale = form.locale || form.chatLanguage || "zh-CN";
|
|
1965
|
+
const dirty = {
|
|
1966
|
+
hostPort: form.hostPort || "",
|
|
1967
|
+
provider: form.provider || "",
|
|
1968
|
+
model: form.model || "",
|
|
1969
|
+
theme: themeMode,
|
|
1970
|
+
palette,
|
|
1971
|
+
cardStyle,
|
|
1972
|
+
locale
|
|
1973
|
+
};
|
|
1974
|
+
const dirtyKeys = ["hostPort", "provider", "model", "theme", "palette", "cardStyle", "locale"].filter((k) => snapshot != null && dirty[k] !== snapshot[k]);
|
|
1975
|
+
const dirtyCount = dirtyKeys.length;
|
|
1976
|
+
dirtyCountRef.current = dirtyCount;
|
|
1977
|
+
const portDirty = snapshot != null && dirty.hostPort !== snapshot.hostPort;
|
|
1978
|
+
const portErrorKey = portTouched || portDirty ? validatePort(form.hostPort || "") : null;
|
|
1979
|
+
const portError = portErrorKey === "empty" ? t("settings.portEmpty") : portErrorKey === "nan" ? t("settings.portNan") : portErrorKey === "range" ? t("settings.portRange") : null;
|
|
1980
|
+
const canSave = dirtyCount > 0 && !portError;
|
|
1981
|
+
const hostUrl = `http://127.0.0.1:${(form.hostPort || "").trim() || "\u2014"}`;
|
|
1982
|
+
const paletteLabel = t(`palette.${clampPalette(palette)}`);
|
|
1983
|
+
const versionLabel = s.about?.packages?.[0]?.version ?? s.about?.packages?.find((p) => p.name.includes("dsh"))?.version ?? "\u2014";
|
|
1984
|
+
const patch = (partial) => setForm((prev) => ({ ...prev, ...partial }));
|
|
1985
|
+
const paintPreview = (next) => {
|
|
1986
|
+
const host = document.getElementById("mma-host");
|
|
1987
|
+
if (!host) return;
|
|
1988
|
+
const theme = next.theme ?? themeMode;
|
|
1989
|
+
const pal = next.palette ?? palette;
|
|
1990
|
+
const style = next.cardStyle ?? cardStyle;
|
|
1991
|
+
applyThemeTo(host, theme, pal, s.customPalettes);
|
|
1992
|
+
host.setAttribute("data-cardstyle", style);
|
|
1993
|
+
};
|
|
1994
|
+
const previewAppearance = (partial) => {
|
|
1995
|
+
const nextTheme = partial.theme ?? themeMode;
|
|
1996
|
+
const nextPalette = partial.palette ?? palette;
|
|
1997
|
+
const nextCard = partial.cardStyle ?? cardStyle;
|
|
1998
|
+
paintPreview({ theme: nextTheme, palette: nextPalette, cardStyle: nextCard });
|
|
1999
|
+
patch({
|
|
2000
|
+
...partial.theme != null ? { theme: partial.theme } : {},
|
|
2001
|
+
...partial.palette != null ? { palette: partial.palette } : {},
|
|
2002
|
+
...partial.cardStyle != null ? { cardStyle: partial.cardStyle } : {},
|
|
2003
|
+
...partial.locale != null ? { locale: partial.locale, chatLanguage: partial.locale } : {}
|
|
2004
|
+
});
|
|
2005
|
+
};
|
|
2006
|
+
const scrollTo = (id) => {
|
|
2007
|
+
setSection(id);
|
|
2008
|
+
sectionRefs.current[id]?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
2009
|
+
};
|
|
2010
|
+
const discard = () => {
|
|
2011
|
+
if (!snapshot) return;
|
|
2012
|
+
patch({ ...snapshot, chatLanguage: snapshot.locale });
|
|
2013
|
+
paintPreview({
|
|
2014
|
+
theme: snapshot.theme,
|
|
2015
|
+
palette: snapshot.palette,
|
|
2016
|
+
cardStyle: snapshot.cardStyle
|
|
2017
|
+
});
|
|
2018
|
+
setPortTouched(false);
|
|
2019
|
+
};
|
|
2020
|
+
const requestClose = () => {
|
|
2021
|
+
if (dirtyCount > 0) setConfirm("close");
|
|
2022
|
+
else actions.toggleSettings(false);
|
|
2023
|
+
};
|
|
2024
|
+
const restoreDefaults = () => {
|
|
2025
|
+
previewAppearance({
|
|
2026
|
+
theme: DEFAULTS.theme,
|
|
2027
|
+
palette: DEFAULTS.palette,
|
|
2028
|
+
cardStyle: DEFAULTS.cardStyle,
|
|
2029
|
+
locale: DEFAULTS.locale
|
|
2030
|
+
});
|
|
2031
|
+
patch({
|
|
2032
|
+
hostPort: DEFAULTS.hostPort,
|
|
2033
|
+
provider: DEFAULTS.provider,
|
|
2034
|
+
model: DEFAULTS.model,
|
|
2035
|
+
locale: DEFAULTS.locale,
|
|
2036
|
+
chatLanguage: DEFAULTS.locale,
|
|
2037
|
+
theme: DEFAULTS.theme,
|
|
2038
|
+
palette: DEFAULTS.palette,
|
|
2039
|
+
cardStyle: DEFAULTS.cardStyle
|
|
2040
|
+
});
|
|
2041
|
+
setPortTouched(true);
|
|
2042
|
+
setConfirm(null);
|
|
2043
|
+
};
|
|
2044
|
+
const save = () => {
|
|
2045
|
+
if (!canSave) return;
|
|
2046
|
+
const committed = { ...dirty };
|
|
2047
|
+
actions.saveHostConfig({
|
|
2048
|
+
...form,
|
|
2049
|
+
theme: committed.theme,
|
|
2050
|
+
palette: committed.palette,
|
|
2051
|
+
cardStyle: committed.cardStyle,
|
|
2052
|
+
locale: committed.locale,
|
|
2053
|
+
chatLanguage: committed.locale
|
|
2054
|
+
});
|
|
2055
|
+
actions.setAppearance(
|
|
2056
|
+
{ theme: committed.theme, palette: committed.palette },
|
|
2057
|
+
"global"
|
|
2058
|
+
);
|
|
2059
|
+
actions.setCardStyle(committed.cardStyle);
|
|
2060
|
+
setSnapshot(committed);
|
|
2061
|
+
const now = /* @__PURE__ */ new Date();
|
|
2062
|
+
setLastSavedAt(
|
|
2063
|
+
`${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`
|
|
2064
|
+
);
|
|
2065
|
+
};
|
|
2066
|
+
const copyUrl = async () => {
|
|
2067
|
+
try {
|
|
2068
|
+
await navigator.clipboard.writeText(hostUrl);
|
|
2069
|
+
} catch {
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
const sectionLabel = (id) => id === "appearance" ? t("settings.sectionAppearance") : id === "network" ? t("settings.sectionNetwork") : id === "model" ? t("settings.sectionModel") : t("settings.sectionAbout");
|
|
2073
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2074
|
+
"div",
|
|
2075
|
+
{
|
|
2076
|
+
ref: rootRef,
|
|
2077
|
+
className: "mma-settings",
|
|
2078
|
+
id: "mma-settings",
|
|
2079
|
+
"data-open": s.settingsOpen ? "1" : "0",
|
|
2080
|
+
"data-wide": wide ? "1" : "0",
|
|
2081
|
+
children: [
|
|
2082
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "mma-settings-head", children: [
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-head-left", children: [
|
|
2084
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-head-icon", "aria-hidden": "true", children: "\u2699" }),
|
|
2085
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: t("settings.title") })
|
|
2086
|
+
] }),
|
|
2087
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-head-right", children: [
|
|
2088
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-settings-meta", children: [
|
|
2089
|
+
versionLabel,
|
|
2090
|
+
" \xB7 ",
|
|
2091
|
+
paletteLabel
|
|
2092
|
+
] }),
|
|
2093
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2094
|
+
"button",
|
|
2095
|
+
{
|
|
2096
|
+
type: "button",
|
|
2097
|
+
className: "mma-iconbtn",
|
|
2098
|
+
id: "mma-cfg-close",
|
|
2099
|
+
"aria-label": t("settings.close"),
|
|
2100
|
+
onClick: requestClose,
|
|
2101
|
+
children: "\u2715"
|
|
2102
|
+
}
|
|
2103
|
+
)
|
|
2104
|
+
] })
|
|
2105
|
+
] }),
|
|
2106
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-body", children: [
|
|
2107
|
+
/* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "mma-settings-rail", role: "tablist", "aria-label": t("settings.sectionsAria"), children: [
|
|
2108
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-settings-rail-title", children: t("settings.sectionNav") }),
|
|
2109
|
+
SECTIONS.map((id) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2110
|
+
"button",
|
|
2111
|
+
{
|
|
2112
|
+
type: "button",
|
|
2113
|
+
role: "tab",
|
|
2114
|
+
"aria-current": section === id ? "page" : void 0,
|
|
2115
|
+
"data-on": section === id ? "1" : "0",
|
|
2116
|
+
className: "mma-settings-rail-item",
|
|
2117
|
+
onClick: () => scrollTo(id),
|
|
2118
|
+
children: sectionLabel(id)
|
|
2119
|
+
},
|
|
2120
|
+
id
|
|
2121
|
+
))
|
|
2122
|
+
] }),
|
|
2123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-content", ref: contentRef, children: [
|
|
2124
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2125
|
+
"section",
|
|
2126
|
+
{
|
|
2127
|
+
className: "mma-settings-section",
|
|
2128
|
+
"data-section": "appearance",
|
|
2129
|
+
ref: (el) => {
|
|
2130
|
+
sectionRefs.current.appearance = el;
|
|
2131
|
+
},
|
|
2132
|
+
children: [
|
|
2133
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { children: t("settings.sectionAppearance") }),
|
|
2134
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field", children: [
|
|
2135
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mma-settings-label", htmlFor: "mma-cfg-lang-seg", children: t("settings.language") }),
|
|
2136
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-seg", id: "mma-cfg-lang-seg", role: "group", "aria-label": t("settings.language"), children: [
|
|
2137
|
+
["zh-CN", t("settings.langZh")],
|
|
2138
|
+
["en", t("settings.langEn")]
|
|
2139
|
+
].map(([id, label]) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2140
|
+
"button",
|
|
2141
|
+
{
|
|
2142
|
+
type: "button",
|
|
2143
|
+
"data-on": locale === id ? "1" : "0",
|
|
2144
|
+
onClick: () => previewAppearance({ locale: id }),
|
|
2145
|
+
children: label
|
|
2146
|
+
},
|
|
2147
|
+
id
|
|
2148
|
+
)) })
|
|
2149
|
+
] }),
|
|
2150
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field", children: [
|
|
2151
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-label", children: t("settings.theme") }),
|
|
2152
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2153
|
+
OptionCardGrid,
|
|
2154
|
+
{
|
|
2155
|
+
"aria-label": t("settings.theme"),
|
|
2156
|
+
columns: 3,
|
|
2157
|
+
value: themeMode,
|
|
2158
|
+
onChange: (v) => previewAppearance({ theme: v }),
|
|
2159
|
+
options: ["system", "light", "dark"].map((mode) => ({
|
|
2160
|
+
value: mode,
|
|
2161
|
+
label: t(`theme.${mode}`),
|
|
2162
|
+
preview: /* @__PURE__ */ jsxRuntime.jsx(ThemePreview, { mode })
|
|
2163
|
+
}))
|
|
2164
|
+
}
|
|
2165
|
+
)
|
|
2166
|
+
] }),
|
|
2167
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field", children: [
|
|
2168
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-label", children: t("settings.palette") }),
|
|
2169
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2170
|
+
OptionCardGrid,
|
|
2171
|
+
{
|
|
2172
|
+
"aria-label": t("settings.palette"),
|
|
2173
|
+
columns: 4,
|
|
2174
|
+
value: palette,
|
|
2175
|
+
onChange: (v) => previewAppearance({ palette: v }),
|
|
2176
|
+
options: PALETTES.map((p) => ({
|
|
2177
|
+
value: p.id,
|
|
2178
|
+
label: t(`palette.${p.id}`),
|
|
2179
|
+
preview: /* @__PURE__ */ jsxRuntime.jsx(PalettePreview, { id: p.id, mode: resolvedMode })
|
|
2180
|
+
}))
|
|
2181
|
+
}
|
|
2182
|
+
)
|
|
2183
|
+
] }),
|
|
2184
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field", children: [
|
|
2185
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-label", children: t("settings.cardStyle") }),
|
|
2186
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2187
|
+
OptionCardGrid,
|
|
2188
|
+
{
|
|
2189
|
+
"aria-label": t("settings.cardStyle"),
|
|
2190
|
+
columns: 3,
|
|
2191
|
+
value: cardStyle,
|
|
2192
|
+
onChange: (v) => previewAppearance({ cardStyle: v }),
|
|
2193
|
+
options: [
|
|
2194
|
+
["stamp", t("settings.cardStamp")],
|
|
2195
|
+
["etch", t("settings.cardEtch")],
|
|
2196
|
+
["hero", t("settings.cardHero")],
|
|
2197
|
+
["list", t("settings.cardList")]
|
|
2198
|
+
].map(([value, label]) => ({
|
|
2199
|
+
value,
|
|
2200
|
+
label,
|
|
2201
|
+
preview: /* @__PURE__ */ jsxRuntime.jsx(CardStylePreview, { style: value })
|
|
2202
|
+
}))
|
|
2203
|
+
}
|
|
2204
|
+
)
|
|
2205
|
+
] }),
|
|
2206
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mma-settings-hint", children: t("settings.appearanceHint") })
|
|
2207
|
+
]
|
|
2208
|
+
}
|
|
2209
|
+
),
|
|
2210
|
+
/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "mma-settings-rule" }),
|
|
2211
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2212
|
+
"section",
|
|
2213
|
+
{
|
|
2214
|
+
className: "mma-settings-section",
|
|
2215
|
+
"data-section": "network",
|
|
2216
|
+
ref: (el) => {
|
|
2217
|
+
sectionRefs.current.network = el;
|
|
2218
|
+
},
|
|
2219
|
+
children: [
|
|
2220
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { children: t("settings.sectionNetwork") }),
|
|
2221
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `mma-settings-field mma-settings-field--row${portError ? " is-error" : ""}`, children: [
|
|
2222
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mma-settings-label", htmlFor: "mma-cfg-port", children: t("settings.hostPort") }),
|
|
2223
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-control", children: [
|
|
2224
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-port-row", children: [
|
|
2225
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-port-addon", "aria-hidden": "true", children: ":" }),
|
|
2226
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2227
|
+
"input",
|
|
2228
|
+
{
|
|
2229
|
+
id: "mma-cfg-port",
|
|
2230
|
+
type: "text",
|
|
2231
|
+
inputMode: "numeric",
|
|
2232
|
+
autoComplete: "off",
|
|
2233
|
+
value: form.hostPort || "",
|
|
2234
|
+
"aria-invalid": !!portError,
|
|
2235
|
+
"aria-describedby": "mma-cfg-port-hint",
|
|
2236
|
+
onChange: (e) => {
|
|
2237
|
+
setPortTouched(true);
|
|
2238
|
+
patch({ hostPort: e.target.value });
|
|
2239
|
+
},
|
|
2240
|
+
onBlur: () => setPortTouched(true)
|
|
2241
|
+
}
|
|
2242
|
+
),
|
|
2243
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "mma-port-url", children: hostUrl }),
|
|
2244
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-ghostbtn", onClick: () => void copyUrl(), children: t("settings.copyUrl") }),
|
|
2245
|
+
/* @__PURE__ */ jsxRuntime.jsx("a", { className: "mma-ghostbtn", href: hostUrl, target: "_blank", rel: "noreferrer", children: t("settings.openUrl") })
|
|
2246
|
+
] }),
|
|
2247
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mma-settings-hint", id: "mma-cfg-port-hint", role: portError ? "alert" : void 0, children: portError ?? t("settings.portHint") })
|
|
2248
|
+
] })
|
|
2249
|
+
] })
|
|
2250
|
+
]
|
|
2251
|
+
}
|
|
2252
|
+
),
|
|
2253
|
+
/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "mma-settings-rule" }),
|
|
2254
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2255
|
+
"section",
|
|
2256
|
+
{
|
|
2257
|
+
className: "mma-settings-section",
|
|
2258
|
+
"data-section": "model",
|
|
2259
|
+
ref: (el) => {
|
|
2260
|
+
sectionRefs.current.model = el;
|
|
2261
|
+
},
|
|
2262
|
+
children: [
|
|
2263
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { children: t("settings.sectionModel") }),
|
|
2264
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field mma-settings-field--row", children: [
|
|
2265
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mma-settings-label", htmlFor: "mma-cfg-provider", children: t("settings.llmProvider") }),
|
|
2266
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-control mma-settings-control--model", children: [
|
|
2267
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2268
|
+
"input",
|
|
2269
|
+
{
|
|
2270
|
+
id: "mma-cfg-provider",
|
|
2271
|
+
list: "mma-cfg-provider-list",
|
|
2272
|
+
placeholder: t("settings.providerPlaceholder"),
|
|
2273
|
+
value: form.provider || "",
|
|
2274
|
+
onChange: (e) => patch({ provider: e.target.value, model: "" })
|
|
2275
|
+
}
|
|
2276
|
+
),
|
|
2277
|
+
/* @__PURE__ */ jsxRuntime.jsxs("datalist", { id: "mma-cfg-provider-list", children: [
|
|
2278
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "openai" }),
|
|
2279
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "anthropic" }),
|
|
2280
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "deepseek" })
|
|
2281
|
+
] })
|
|
2282
|
+
] })
|
|
2283
|
+
] }),
|
|
2284
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-field mma-settings-field--row", children: [
|
|
2285
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "mma-settings-label", htmlFor: "mma-cfg-model", children: t("settings.llmModel") }),
|
|
2286
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-settings-control mma-settings-control--model", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-model-row", children: [
|
|
2287
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2288
|
+
"input",
|
|
2289
|
+
{
|
|
2290
|
+
id: "mma-cfg-model",
|
|
2291
|
+
placeholder: form.provider ? t("settings.modelPlaceholder") : t("settings.modelNeedsProvider"),
|
|
2292
|
+
value: form.model || "",
|
|
2293
|
+
disabled: !form.provider,
|
|
2294
|
+
onChange: (e) => patch({ model: e.target.value })
|
|
2295
|
+
}
|
|
2296
|
+
),
|
|
2297
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-status-pill", "data-state": "idle", children: t("settings.llmProbeIdle") })
|
|
2298
|
+
] }) })
|
|
2299
|
+
] })
|
|
2300
|
+
]
|
|
2301
|
+
}
|
|
2302
|
+
),
|
|
2303
|
+
/* @__PURE__ */ jsxRuntime.jsx("hr", { className: "mma-settings-rule" }),
|
|
2304
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2305
|
+
"section",
|
|
2306
|
+
{
|
|
2307
|
+
className: "mma-settings-section",
|
|
2308
|
+
"data-section": "about",
|
|
2309
|
+
ref: (el) => {
|
|
2310
|
+
sectionRefs.current.about = el;
|
|
2311
|
+
},
|
|
2312
|
+
children: [
|
|
2313
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { children: t("settings.sectionAbout") }),
|
|
2314
|
+
s.about ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2315
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-about-meta", children: [
|
|
2316
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-label", children: t("settings.env") }),
|
|
2317
|
+
/* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
|
|
2318
|
+
s.about.adapter,
|
|
2319
|
+
" \xB7 ",
|
|
2320
|
+
s.about.env
|
|
2321
|
+
] })
|
|
2322
|
+
] }),
|
|
2323
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mma-about-pkgs", children: s.about.packages.map((pkg) => /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
2324
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { title: pkg.name, children: shortPkg(pkg.name) }),
|
|
2325
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: pkg.version })
|
|
2326
|
+
] }, pkg.name)) }),
|
|
2327
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-about-actions", children: [
|
|
2328
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2329
|
+
"button",
|
|
2330
|
+
{
|
|
2331
|
+
type: "button",
|
|
2332
|
+
className: "mma-ghostbtn",
|
|
2333
|
+
id: "mma-cfg-check-update",
|
|
2334
|
+
disabled: s.updateCheck?.status === "loading",
|
|
2335
|
+
onClick: () => actions.checkUpdates(),
|
|
2336
|
+
children: s.updateCheck?.status === "loading" ? t("settings.checkingUpdate") : t("settings.checkUpdate")
|
|
2337
|
+
}
|
|
2338
|
+
),
|
|
2339
|
+
s.updateCheck?.status === "done" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-hint", children: s.updateCheck.error ? t("settings.updateError", { message: s.updateCheck.error }) : s.updateCheck.updateAvailable ? t("settings.updateAvailable", {
|
|
2340
|
+
latest: s.updateCheck.latest ?? "",
|
|
2341
|
+
current: s.updateCheck.current
|
|
2342
|
+
}) : t("settings.upToDate", {
|
|
2343
|
+
version: s.updateCheck.latest ?? s.updateCheck.current
|
|
2344
|
+
}) }) : null
|
|
2345
|
+
] })
|
|
2346
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mma-settings-hint", children: t("settings.aboutLoading") })
|
|
2347
|
+
]
|
|
2348
|
+
}
|
|
2349
|
+
)
|
|
2350
|
+
] })
|
|
2351
|
+
] }),
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsxs("footer", { className: "mma-settings-foot", children: [
|
|
2353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-foot-left", "aria-live": "polite", children: [
|
|
2354
|
+
lastSavedAt ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "mma-settings-hint", children: [
|
|
2355
|
+
t("settings.lastSaved", { time: lastSavedAt }),
|
|
2356
|
+
dirtyCount > 0 ? " \xB7 " : ""
|
|
2357
|
+
] }) : null,
|
|
2358
|
+
dirtyCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-dirty", children: t("settings.dirtyCount", { count: dirtyCount }) }) : null
|
|
2359
|
+
] }),
|
|
2360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-settings-foot-right", children: [
|
|
2361
|
+
dirtyCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-ghostbtn", onClick: discard, children: t("settings.discard") }) : null,
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "mma-ghostbtn", onClick: () => setConfirm("restore"), children: t("settings.restore") }),
|
|
2363
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2364
|
+
"button",
|
|
2365
|
+
{
|
|
2366
|
+
type: "button",
|
|
2367
|
+
className: "mma-primarybtn",
|
|
2368
|
+
id: "mma-cfg-save",
|
|
2369
|
+
disabled: !canSave,
|
|
2370
|
+
onClick: save,
|
|
2371
|
+
children: t("settings.save")
|
|
2372
|
+
}
|
|
2373
|
+
)
|
|
2374
|
+
] }),
|
|
2375
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mma-settings-msg", id: "mma-cfg-msg", children: s.cfgMsg })
|
|
2376
|
+
] }),
|
|
2377
|
+
confirm ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-settings-confirm", role: "presentation", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2378
|
+
"div",
|
|
2379
|
+
{
|
|
2380
|
+
className: "mma-dialog",
|
|
2381
|
+
role: "dialog",
|
|
2382
|
+
"aria-modal": "true",
|
|
2383
|
+
"aria-labelledby": "mma-settings-confirm-title",
|
|
2384
|
+
children: [
|
|
2385
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { id: "mma-settings-confirm-title", children: confirm === "close" ? t("settings.confirmCloseTitle") : t("settings.confirmRestoreTitle") }),
|
|
2386
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: confirm === "close" ? t("settings.confirmCloseBody") : t("settings.confirmRestoreBody") }),
|
|
2387
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-dialog-actions", children: [
|
|
2388
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setConfirm(null), children: t("modal.cancel") }),
|
|
2389
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2390
|
+
"button",
|
|
2391
|
+
{
|
|
2392
|
+
type: "button",
|
|
2393
|
+
className: "go",
|
|
2394
|
+
onClick: () => {
|
|
2395
|
+
if (confirm === "close") {
|
|
2396
|
+
discard();
|
|
2397
|
+
actions.toggleSettings(false);
|
|
2398
|
+
} else restoreDefaults();
|
|
2399
|
+
setConfirm(null);
|
|
2400
|
+
},
|
|
2401
|
+
children: confirm === "close" ? t("settings.confirmDiscard") : t("settings.confirmRestoreAction")
|
|
2402
|
+
}
|
|
2403
|
+
)
|
|
2404
|
+
] })
|
|
2405
|
+
]
|
|
2406
|
+
}
|
|
2407
|
+
) }) : null
|
|
2408
|
+
]
|
|
2409
|
+
}
|
|
2410
|
+
);
|
|
1469
2411
|
}
|
|
1470
2412
|
function Tabs() {
|
|
1471
2413
|
const s = usePanelState();
|
|
@@ -1508,8 +2450,11 @@ function ThemePop() {
|
|
|
1508
2450
|
const actions = usePanelActions();
|
|
1509
2451
|
const { t } = usePanelI18n();
|
|
1510
2452
|
const app = actions.getActiveApp();
|
|
1511
|
-
const
|
|
2453
|
+
const appScope = Boolean(app) && s.themeScope === "app";
|
|
2454
|
+
const viewTheme = appScope ? app?.theme?.theme ?? s.theme : s.theme;
|
|
2455
|
+
const viewPalette = appScope ? selectedPalette(app?.theme?.palette, Boolean(app?.localPalette)) : s.palette;
|
|
1512
2456
|
const customs = s.customPalettes || {};
|
|
2457
|
+
const canApp = Boolean(app && s.capabilities.appTheme);
|
|
1513
2458
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1514
2459
|
s.themePopOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1515
2460
|
"div",
|
|
@@ -1533,18 +2478,61 @@ function ThemePop() {
|
|
|
1533
2478
|
onClick: (e) => e.stopPropagation(),
|
|
1534
2479
|
onPointerDown: (e) => e.stopPropagation(),
|
|
1535
2480
|
children: [
|
|
1536
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-
|
|
2481
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-lab", children: t("theme.apply") }),
|
|
2482
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-pop-seg", children: [
|
|
2483
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2484
|
+
"button",
|
|
2485
|
+
{
|
|
2486
|
+
type: "button",
|
|
2487
|
+
"data-scope": "global",
|
|
2488
|
+
"data-on": s.themeScope === "global" ? "1" : "0",
|
|
2489
|
+
onClick: () => actions.setThemeScope("global"),
|
|
2490
|
+
children: t("theme.global")
|
|
2491
|
+
}
|
|
2492
|
+
),
|
|
2493
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2494
|
+
"button",
|
|
2495
|
+
{
|
|
2496
|
+
type: "button",
|
|
2497
|
+
"data-scope": "app",
|
|
2498
|
+
id: "mma-scope-app",
|
|
2499
|
+
title: app ? t("theme.saveTo", { name: app.name }) : t("theme.openAppFirst"),
|
|
2500
|
+
"data-on": appScope ? "1" : "0",
|
|
2501
|
+
disabled: !canApp,
|
|
2502
|
+
onClick: () => actions.setThemeScope("app"),
|
|
2503
|
+
children: app ? app.name : t("theme.currentApp")
|
|
2504
|
+
}
|
|
2505
|
+
)
|
|
2506
|
+
] }),
|
|
2507
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-lab", children: t("theme.appearance") }),
|
|
2508
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-seg", children: ["system", "light", "dark"].map((mode) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1537
2509
|
"button",
|
|
1538
2510
|
{
|
|
1539
2511
|
type: "button",
|
|
1540
2512
|
"data-mode": mode,
|
|
1541
|
-
"data-on":
|
|
2513
|
+
"data-on": viewTheme === mode ? "1" : "0",
|
|
1542
2514
|
onClick: () => actions.setAppearance({ theme: mode }, s.themeScope),
|
|
1543
2515
|
children: t(`theme.${mode}`)
|
|
1544
2516
|
},
|
|
1545
2517
|
mode
|
|
1546
2518
|
)) }),
|
|
2519
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mma-pop-lab", children: t("theme.palettes") }),
|
|
1547
2520
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mma-pop-list", children: [
|
|
2521
|
+
appScope ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2522
|
+
"button",
|
|
2523
|
+
{
|
|
2524
|
+
type: "button",
|
|
2525
|
+
className: "mma-swatch",
|
|
2526
|
+
id: "mma-follow-global",
|
|
2527
|
+
"data-on": viewPalette === GLOBAL_PALETTE_ID ? "1" : "0",
|
|
2528
|
+
role: "menuitem",
|
|
2529
|
+
onClick: () => actions.setAppearance({ palette: GLOBAL_PALETTE_ID }, "app"),
|
|
2530
|
+
children: [
|
|
2531
|
+
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: "linear-gradient(135deg,#888,#ddd)" } }),
|
|
2532
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t("theme.followGlobal") })
|
|
2533
|
+
]
|
|
2534
|
+
}
|
|
2535
|
+
) : null,
|
|
1548
2536
|
PALETTES.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1549
2537
|
"button",
|
|
1550
2538
|
{
|
|
@@ -1552,11 +2540,12 @@ function ThemePop() {
|
|
|
1552
2540
|
className: "mma-swatch",
|
|
1553
2541
|
"data-palette": p.id,
|
|
1554
2542
|
role: "menuitem",
|
|
1555
|
-
"data-on":
|
|
2543
|
+
"data-on": viewPalette === p.id ? "1" : "0",
|
|
1556
2544
|
onClick: () => actions.setAppearance({ palette: p.id }, s.themeScope),
|
|
1557
2545
|
children: [
|
|
1558
2546
|
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: p.swatch } }),
|
|
1559
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t(`palette.${p.id}`) })
|
|
2547
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: t(`palette.${p.id}`) }),
|
|
2548
|
+
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-custom-badge", children: t("theme.chipSystem") })
|
|
1560
2549
|
]
|
|
1561
2550
|
},
|
|
1562
2551
|
p.id
|
|
@@ -1569,7 +2558,7 @@ function ThemePop() {
|
|
|
1569
2558
|
"data-palette": id,
|
|
1570
2559
|
"data-custom": "1",
|
|
1571
2560
|
role: "menuitem",
|
|
1572
|
-
"data-on":
|
|
2561
|
+
"data-on": viewPalette === id ? "1" : "0",
|
|
1573
2562
|
onClick: () => actions.setAppearance({ palette: id }, s.themeScope),
|
|
1574
2563
|
children: [
|
|
1575
2564
|
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: customs[id].swatch || "#888" } }),
|
|
@@ -1578,34 +2567,34 @@ function ThemePop() {
|
|
|
1578
2567
|
]
|
|
1579
2568
|
},
|
|
1580
2569
|
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(
|
|
2570
|
+
)),
|
|
2571
|
+
appScope && app?.localPalette ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1595
2572
|
"button",
|
|
1596
2573
|
{
|
|
1597
2574
|
type: "button",
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
"data-on":
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
2575
|
+
className: "mma-swatch",
|
|
2576
|
+
"data-palette": LOCAL_PALETTE_ID,
|
|
2577
|
+
role: "menuitem",
|
|
2578
|
+
"data-on": viewPalette === LOCAL_PALETTE_ID ? "1" : "0",
|
|
2579
|
+
onClick: () => actions.setAppearance({ palette: LOCAL_PALETTE_ID }, "app"),
|
|
2580
|
+
children: [
|
|
2581
|
+
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-dot", style: { background: app.localPalette.swatch } }),
|
|
2582
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: app.localPalette.label }),
|
|
2583
|
+
/* @__PURE__ */ jsxRuntime.jsx("i", { className: "mma-custom-badge", children: t("theme.chipApp") })
|
|
2584
|
+
]
|
|
1605
2585
|
}
|
|
1606
|
-
)
|
|
2586
|
+
) : null
|
|
1607
2587
|
] }),
|
|
1608
|
-
|
|
2588
|
+
appScope && app?.theme ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2589
|
+
"button",
|
|
2590
|
+
{
|
|
2591
|
+
type: "button",
|
|
2592
|
+
className: "mma-textbtn",
|
|
2593
|
+
id: "mma-reset-app-theme",
|
|
2594
|
+
onClick: () => actions.clearAppTheme(),
|
|
2595
|
+
children: t("theme.resetApp")
|
|
2596
|
+
}
|
|
2597
|
+
) : null
|
|
1609
2598
|
]
|
|
1610
2599
|
}
|
|
1611
2600
|
)
|
|
@@ -1788,6 +2777,13 @@ function createFrameController(opts) {
|
|
|
1788
2777
|
const { container: initial2, urlOf, envOf } = opts;
|
|
1789
2778
|
let container = initial2 ?? null;
|
|
1790
2779
|
const map = /* @__PURE__ */ new Map();
|
|
2780
|
+
function targetOrigin(appId, rec) {
|
|
2781
|
+
try {
|
|
2782
|
+
return new URL(rec?.iframe.src || urlOf(appId)).origin;
|
|
2783
|
+
} catch {
|
|
2784
|
+
return "";
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
1791
2787
|
return {
|
|
1792
2788
|
map,
|
|
1793
2789
|
url: (appId) => urlOf(appId),
|
|
@@ -1799,8 +2795,13 @@ function createFrameController(opts) {
|
|
|
1799
2795
|
const w = rec?.iframe.contentWindow;
|
|
1800
2796
|
if (!w) return;
|
|
1801
2797
|
const env = envOf(appId);
|
|
2798
|
+
const target = targetOrigin(appId, rec);
|
|
2799
|
+
if (!target) return;
|
|
1802
2800
|
try {
|
|
1803
|
-
w.postMessage(
|
|
2801
|
+
w.postMessage(
|
|
2802
|
+
{ type: "mma-set-env", theme: env.theme, palette: env.palette, dock: env.dock, vars: env.vars },
|
|
2803
|
+
target
|
|
2804
|
+
);
|
|
1804
2805
|
} catch {
|
|
1805
2806
|
}
|
|
1806
2807
|
},
|
|
@@ -1814,7 +2815,7 @@ function createFrameController(opts) {
|
|
|
1814
2815
|
const wrap = document.createElement("div");
|
|
1815
2816
|
wrap.className = "mma-frame";
|
|
1816
2817
|
wrap.setAttribute("data-app", appId);
|
|
1817
|
-
wrap.innerHTML = `${loadingMarkup()}<iframe title="${escapeHtml(title || appId)}"></iframe>`;
|
|
2818
|
+
wrap.innerHTML = `${loadingMarkup()}<iframe title="${escapeHtml(title || appId)}" allow="clipboard-write"></iframe>`;
|
|
1818
2819
|
if (!container) return;
|
|
1819
2820
|
container.appendChild(wrap);
|
|
1820
2821
|
const iframe = wrap.querySelector("iframe");
|
|
@@ -1844,6 +2845,27 @@ function createFrameController(opts) {
|
|
|
1844
2845
|
if (!rec) return;
|
|
1845
2846
|
if (!rec.wrap.querySelector(".mma-load")) rec.wrap.insertAdjacentHTML("afterbegin", loadingMarkup());
|
|
1846
2847
|
rec.iframe.src = `${urlOf(appId)}&_=${Date.now()}`;
|
|
2848
|
+
},
|
|
2849
|
+
postViewEval(query) {
|
|
2850
|
+
const rec = map.get(query.appId);
|
|
2851
|
+
const w = rec?.iframe.contentWindow;
|
|
2852
|
+
const target = rec ? targetOrigin(query.appId, rec) : "";
|
|
2853
|
+
if (!w || !target) return false;
|
|
2854
|
+
try {
|
|
2855
|
+
w.postMessage(
|
|
2856
|
+
{
|
|
2857
|
+
type: "mma-view-eval",
|
|
2858
|
+
requestId: query.requestId,
|
|
2859
|
+
appId: query.appId,
|
|
2860
|
+
code: query.code ?? "",
|
|
2861
|
+
maxBytes: query.maxBytes ?? 0
|
|
2862
|
+
},
|
|
2863
|
+
target
|
|
2864
|
+
);
|
|
2865
|
+
return true;
|
|
2866
|
+
} catch {
|
|
2867
|
+
return false;
|
|
2868
|
+
}
|
|
1847
2869
|
}
|
|
1848
2870
|
};
|
|
1849
2871
|
}
|
|
@@ -1867,6 +2889,7 @@ var en_default = {
|
|
|
1867
2889
|
close: "Close"
|
|
1868
2890
|
},
|
|
1869
2891
|
theme: {
|
|
2892
|
+
system: "System",
|
|
1870
2893
|
light: "Light",
|
|
1871
2894
|
dark: "Dark",
|
|
1872
2895
|
custom: "Custom",
|
|
@@ -1874,7 +2897,13 @@ var en_default = {
|
|
|
1874
2897
|
currentApp: "Current app",
|
|
1875
2898
|
openAppFirst: "Open an app first",
|
|
1876
2899
|
saveTo: 'Save to "{{name}}"',
|
|
1877
|
-
followGlobal: "Follow global
|
|
2900
|
+
followGlobal: "Follow global",
|
|
2901
|
+
apply: "Apply to",
|
|
2902
|
+
appearance: "Appearance",
|
|
2903
|
+
palettes: "Palette",
|
|
2904
|
+
chipSystem: "System",
|
|
2905
|
+
chipApp: "This app",
|
|
2906
|
+
resetApp: "Restore this app default"
|
|
1878
2907
|
},
|
|
1879
2908
|
palette: {
|
|
1880
2909
|
default: "Default",
|
|
@@ -1900,20 +2929,59 @@ var en_default = {
|
|
|
1900
2929
|
},
|
|
1901
2930
|
settings: {
|
|
1902
2931
|
title: "Settings",
|
|
2932
|
+
close: "Close settings",
|
|
2933
|
+
sectionNav: "Sections",
|
|
2934
|
+
sectionsAria: "Settings sections",
|
|
2935
|
+
sectionAppearance: "Appearance",
|
|
2936
|
+
sectionNetwork: "Network",
|
|
2937
|
+
sectionModel: "Model",
|
|
2938
|
+
sectionAbout: "About",
|
|
2939
|
+
sectionHost: "Host",
|
|
1903
2940
|
hostPort: "Host port",
|
|
1904
2941
|
language: "Language",
|
|
1905
2942
|
langZh: "Chinese",
|
|
1906
2943
|
langEn: "English",
|
|
1907
2944
|
theme: "Theme",
|
|
1908
2945
|
palette: "Palette",
|
|
2946
|
+
dock: "Dock",
|
|
2947
|
+
dockFill: "Fill",
|
|
2948
|
+
dockSide: "Side",
|
|
1909
2949
|
cardStyle: "Card style",
|
|
1910
2950
|
cardStamp: "Stamp",
|
|
1911
2951
|
cardEtch: "Etch",
|
|
1912
2952
|
cardHero: "Hero",
|
|
1913
2953
|
cardList: "List",
|
|
2954
|
+
appearanceHint: "Preview only. Click Save to persist; closing discards unsaved changes.",
|
|
2955
|
+
portHint: "Range 1024\u201365535. Restart the app after changing.",
|
|
2956
|
+
portEmpty: "Enter a port.",
|
|
2957
|
+
portNan: "Port must be a number.",
|
|
2958
|
+
portRange: "Port must be between 1024 and 65535.",
|
|
2959
|
+
copyUrl: "Copy",
|
|
2960
|
+
openUrl: "Open",
|
|
1914
2961
|
llmProvider: "LLM Provider",
|
|
1915
2962
|
llmModel: "LLM model",
|
|
1916
|
-
|
|
2963
|
+
providerPlaceholder: "Select a provider",
|
|
2964
|
+
modelPlaceholder: "Enter a model",
|
|
2965
|
+
modelNeedsProvider: "Select a provider first",
|
|
2966
|
+
llmProbeIdle: "Probe not wired",
|
|
2967
|
+
save: "Save",
|
|
2968
|
+
discard: "Discard",
|
|
2969
|
+
restore: "Restore defaults",
|
|
2970
|
+
lastSaved: "Saved {{time}}",
|
|
2971
|
+
dirtyCount: "{{count}} unsaved",
|
|
2972
|
+
confirmCloseTitle: "Discard unsaved changes?",
|
|
2973
|
+
confirmCloseBody: "Unsaved appearance, network, and model changes will be discarded and restored.",
|
|
2974
|
+
confirmDiscard: "Discard",
|
|
2975
|
+
confirmRestoreTitle: "Restore defaults?",
|
|
2976
|
+
confirmRestoreBody: "Resets appearance, port, and model fields (port/model still need Save).",
|
|
2977
|
+
confirmRestoreAction: "Restore",
|
|
2978
|
+
env: "Environment",
|
|
2979
|
+
aboutLoading: "Loading version info\u2026",
|
|
2980
|
+
checkUpdate: "Check for updates",
|
|
2981
|
+
checkingUpdate: "Checking\u2026",
|
|
2982
|
+
upToDate: "Up to date ({{version}})",
|
|
2983
|
+
updateAvailable: "Update available: {{latest}} (current {{current}})",
|
|
2984
|
+
updateError: "Check failed: {{message}}"
|
|
1917
2985
|
},
|
|
1918
2986
|
modal: {
|
|
1919
2987
|
title: "Delete mini app",
|
|
@@ -1932,7 +3000,16 @@ var en_default = {
|
|
|
1932
3000
|
noCommits: "No commits yet",
|
|
1933
3001
|
noStorage: "No storage files",
|
|
1934
3002
|
expandMsg: "Show more",
|
|
1935
|
-
collapseMsg: "Show less"
|
|
3003
|
+
collapseMsg: "Show less",
|
|
3004
|
+
entries: "{{count}} entries",
|
|
3005
|
+
sizeKb: "{{value}} KB",
|
|
3006
|
+
sizeMb: "{{value}} MB",
|
|
3007
|
+
noticeTitle: '"{{table}}" is already {{size}}',
|
|
3008
|
+
noticeBody: "The bigger this file gets, the slower every save becomes. Move anything that keeps growing into its own table \u2014 copy the prompt below and paste it to an AI to do the split for you.",
|
|
3009
|
+
noticeTop: 'The heaviest piece right now is "{{key}}" (about {{size}}).',
|
|
3010
|
+
noticeCopy: "Copy split prompt",
|
|
3011
|
+
noticeCopied: "Copied",
|
|
3012
|
+
noticeDismiss: "Got it"
|
|
1936
3013
|
},
|
|
1937
3014
|
load: {
|
|
1938
3015
|
label: "Loading"
|
|
@@ -1962,6 +3039,7 @@ var zh_CN_default = {
|
|
|
1962
3039
|
close: "\u5173\u95ED"
|
|
1963
3040
|
},
|
|
1964
3041
|
theme: {
|
|
3042
|
+
system: "\u8DDF\u968F\u7CFB\u7EDF",
|
|
1965
3043
|
light: "\u6D45\u8272",
|
|
1966
3044
|
dark: "\u6DF1\u8272",
|
|
1967
3045
|
custom: "\u81EA\u5B9A\u4E49",
|
|
@@ -1969,7 +3047,13 @@ var zh_CN_default = {
|
|
|
1969
3047
|
currentApp: "\u5F53\u524D\u5C0F\u7A0B\u5E8F",
|
|
1970
3048
|
openAppFirst: "\u6253\u5F00\u5C0F\u7A0B\u5E8F\u540E\u53EF\u7528",
|
|
1971
3049
|
saveTo: "\u4FDD\u5B58\u5230\u300C{{name}}\u300D",
|
|
1972
|
-
followGlobal: "\u8DDF\u968F\u5168\u5C40
|
|
3050
|
+
followGlobal: "\u8DDF\u968F\u5168\u5C40",
|
|
3051
|
+
apply: "\u5E94\u7528\u5230",
|
|
3052
|
+
appearance: "\u5916\u89C2",
|
|
3053
|
+
palettes: "\u8272\u677F",
|
|
3054
|
+
chipSystem: "\u7CFB\u7EDF",
|
|
3055
|
+
chipApp: "\u672C\u5E94\u7528",
|
|
3056
|
+
resetApp: "\u6062\u590D\u8BE5\u5E94\u7528\u9ED8\u8BA4"
|
|
1973
3057
|
},
|
|
1974
3058
|
palette: {
|
|
1975
3059
|
default: "\u9ED8\u8BA4",
|
|
@@ -1995,20 +3079,59 @@ var zh_CN_default = {
|
|
|
1995
3079
|
},
|
|
1996
3080
|
settings: {
|
|
1997
3081
|
title: "\u8BBE\u7F6E",
|
|
3082
|
+
close: "\u5173\u95ED\u8BBE\u7F6E",
|
|
3083
|
+
sectionNav: "\u5206\u7EC4",
|
|
3084
|
+
sectionsAria: "\u8BBE\u7F6E\u5206\u7EC4",
|
|
3085
|
+
sectionAppearance: "\u5916\u89C2",
|
|
3086
|
+
sectionNetwork: "\u7F51\u7EDC",
|
|
3087
|
+
sectionModel: "\u6A21\u578B",
|
|
3088
|
+
sectionAbout: "\u5173\u4E8E",
|
|
3089
|
+
sectionHost: "\u5BBF\u4E3B",
|
|
1998
3090
|
hostPort: "Host \u7AEF\u53E3",
|
|
1999
3091
|
language: "\u754C\u9762\u8BED\u8A00",
|
|
2000
3092
|
langZh: "\u4E2D\u6587",
|
|
2001
3093
|
langEn: "English",
|
|
2002
3094
|
theme: "\u4E3B\u9898",
|
|
2003
3095
|
palette: "\u8C03\u8272\u677F",
|
|
3096
|
+
dock: "\u505C\u9760",
|
|
3097
|
+
dockFill: "\u94FA\u6EE1",
|
|
3098
|
+
dockSide: "\u4FA7\u680F",
|
|
2004
3099
|
cardStyle: "\u5361\u7247\u6837\u5F0F",
|
|
2005
3100
|
cardStamp: "\u5370\u7AE0",
|
|
2006
3101
|
cardEtch: "\u8680\u523B",
|
|
2007
3102
|
cardHero: "\u6D77\u62A5",
|
|
2008
3103
|
cardList: "\u5217\u8868",
|
|
3104
|
+
appearanceHint: "\u4EC5\u9884\u89C8\uFF0C\u70B9\u4FDD\u5B58\u540E\u624D\u4F1A\u5199\u5165\uFF1B\u5173\u95ED\u672A\u4FDD\u5B58\u5C06\u6062\u590D\u539F\u6837\u3002",
|
|
3105
|
+
portHint: "\u8303\u56F4 1024\u201365535\uFF0C\u4FEE\u6539\u540E\u9700\u91CD\u542F\u5E94\u7528\u3002",
|
|
3106
|
+
portEmpty: "\u8BF7\u8F93\u5165\u7AEF\u53E3\u3002",
|
|
3107
|
+
portNan: "\u7AEF\u53E3\u5FC5\u987B\u662F\u6570\u5B57\u3002",
|
|
3108
|
+
portRange: "\u7AEF\u53E3\u9700\u5728 1024\u201365535 \u4E4B\u95F4\u3002",
|
|
3109
|
+
copyUrl: "\u590D\u5236",
|
|
3110
|
+
openUrl: "\u6253\u5F00",
|
|
2009
3111
|
llmProvider: "LLM Provider",
|
|
2010
3112
|
llmModel: "LLM \u6A21\u578B",
|
|
2011
|
-
|
|
3113
|
+
providerPlaceholder: "\u9009\u62E9 Provider",
|
|
3114
|
+
modelPlaceholder: "\u8F93\u5165\u6A21\u578B\u540D",
|
|
3115
|
+
modelNeedsProvider: "\u5148\u9009\u62E9 Provider",
|
|
3116
|
+
llmProbeIdle: "\u672A\u63A5\u5165\u68C0\u6D4B",
|
|
3117
|
+
save: "\u4FDD\u5B58",
|
|
3118
|
+
discard: "\u653E\u5F03\u4FEE\u6539",
|
|
3119
|
+
restore: "\u6062\u590D\u9ED8\u8BA4",
|
|
3120
|
+
lastSaved: "\u4E0A\u6B21\u4FDD\u5B58 {{time}}",
|
|
3121
|
+
dirtyCount: "{{count}} \u9879\u672A\u4FDD\u5B58",
|
|
3122
|
+
confirmCloseTitle: "\u653E\u5F03\u672A\u4FDD\u5B58\u7684\u4FEE\u6539\uFF1F",
|
|
3123
|
+
confirmCloseBody: "\u5173\u95ED\u540E\uFF0C\u672A\u4FDD\u5B58\u7684\u5916\u89C2 / \u7F51\u7EDC / \u6A21\u578B\u6539\u52A8\u90FD\u4F1A\u4E22\u5F03\u5E76\u6062\u590D\u539F\u6837\u3002",
|
|
3124
|
+
confirmDiscard: "\u653E\u5F03",
|
|
3125
|
+
confirmRestoreTitle: "\u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E\uFF1F",
|
|
3126
|
+
confirmRestoreBody: "\u5C06\u91CD\u7F6E\u5916\u89C2\u3001\u7AEF\u53E3\u4E0E\u6A21\u578B\u5B57\u6BB5\u4E3A\u9ED8\u8BA4\u503C\uFF08\u4ECD\u9700\u4FDD\u5B58\u7AEF\u53E3/\u6A21\u578B\uFF09\u3002",
|
|
3127
|
+
confirmRestoreAction: "\u6062\u590D",
|
|
3128
|
+
env: "\u73AF\u5883",
|
|
3129
|
+
aboutLoading: "\u6B63\u5728\u8BFB\u53D6\u7248\u672C\u4FE1\u606F\u2026",
|
|
3130
|
+
checkUpdate: "\u68C0\u67E5\u66F4\u65B0",
|
|
3131
|
+
checkingUpdate: "\u68C0\u67E5\u4E2D\u2026",
|
|
3132
|
+
upToDate: "\u5DF2\u662F\u6700\u65B0\uFF08{{version}}\uFF09",
|
|
3133
|
+
updateAvailable: "\u6709\u65B0\u7248\u672C {{latest}}\uFF08\u5F53\u524D {{current}}\uFF09",
|
|
3134
|
+
updateError: "\u68C0\u67E5\u5931\u8D25\uFF1A{{message}}"
|
|
2012
3135
|
},
|
|
2013
3136
|
modal: {
|
|
2014
3137
|
title: "\u5220\u9664\u5C0F\u7A0B\u5E8F",
|
|
@@ -2027,7 +3150,16 @@ var zh_CN_default = {
|
|
|
2027
3150
|
noCommits: "\u6682\u65E0\u63D0\u4EA4\u8BB0\u5F55",
|
|
2028
3151
|
noStorage: "\u6682\u65E0\u5B58\u50A8\u6587\u4EF6",
|
|
2029
3152
|
expandMsg: "\u5C55\u5F00\u5168\u6587",
|
|
2030
|
-
collapseMsg: "\u6536\u8D77"
|
|
3153
|
+
collapseMsg: "\u6536\u8D77",
|
|
3154
|
+
entries: "{{count}} \u6761",
|
|
3155
|
+
sizeKb: "{{value}} KB",
|
|
3156
|
+
sizeMb: "{{value}} MB",
|
|
3157
|
+
noticeTitle: "\u300C{{table}}\u300D\u5DF2\u7ECF\u6709 {{size}} \u4E86",
|
|
3158
|
+
noticeBody: "\u8FD9\u4E2A\u6587\u4EF6\u8D8A\u5927\uFF0C\u6BCF\u6B21\u4FDD\u5B58\u90FD\u4F1A\u8D8A\u6162\u3002\u5EFA\u8BAE\u628A\u4F1A\u4E0D\u65AD\u53D8\u591A\u7684\u6570\u636E\u62C6\u5230\u5355\u72EC\u7684\u8868\u91CC\u2014\u2014\u4F60\u53EF\u4EE5\u628A\u4E0B\u9762\u7684\u63D0\u793A\u8BCD\u590D\u5236\u7ED9 AI\uFF0C\u8BA9\u5B83\u5E2E\u4F60\u6539\u3002",
|
|
3159
|
+
noticeTop: "\u773C\u4E0B\u6700\u5927\u7684\u4E00\u5757\u662F\u300C{{key}}\u300D\uFF08\u7EA6 {{size}}\uFF09\u3002",
|
|
3160
|
+
noticeCopy: "\u590D\u5236\u62C6\u5206\u63D0\u793A\u8BCD",
|
|
3161
|
+
noticeCopied: "\u5DF2\u590D\u5236",
|
|
3162
|
+
noticeDismiss: "\u77E5\u9053\u4E86"
|
|
2031
3163
|
},
|
|
2032
3164
|
load: {
|
|
2033
3165
|
label: "\u52A0\u8F7D\u4E2D"
|
|
@@ -2107,7 +3239,7 @@ function resolvePanelLocale(value) {
|
|
|
2107
3239
|
// src/styles.ts
|
|
2108
3240
|
var PANEL_CSS_TAG = "panel";
|
|
2109
3241
|
var CSS = [
|
|
2110
|
-
"#mma-host{color:var(--dsw-alias-fg,#111);background:var(--dsw-alias-bg,#f7f7f8);overflow:hidden;}",
|
|
3242
|
+
"#mma-host{color:var(--dsw-alias-fg,#111);background:var(--dsw-alias-bg,#f7f7f8);overflow:hidden;container-type:inline-size;container-name:mma-host;}",
|
|
2111
3243
|
"#mma-host button,#mma-host input,#mma-host select{color:inherit;font:inherit;}",
|
|
2112
3244
|
"#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
3245
|
"#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;}",
|
|
@@ -2123,12 +3255,18 @@ var CSS = [
|
|
|
2123
3255
|
"#mma-host .mma-toolbar .mma-ico{display:block;}",
|
|
2124
3256
|
"#mma-host .mma-theme-wrap{position:relative;flex:0 0 auto;}",
|
|
2125
3257
|
"#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:
|
|
3258
|
+
"#mma-host .mma-pop{display:none;position:absolute;right:0;top:40px;z-index:8;width:260px;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
3259
|
"#mma-host .mma-pop[data-open='1']{display:block;}",
|
|
2128
3260
|
"#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
3261
|
"#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
3262
|
"#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-
|
|
3263
|
+
"#mma-host .mma-pop-seg button:disabled{opacity:.45;cursor:not-allowed;}",
|
|
3264
|
+
"#mma-host .mma-pop-lab{font-size:10px;letter-spacing:.12em;text-transform:uppercase;opacity:.55;margin:10px 2px 6px;}",
|
|
3265
|
+
"#mma-host .mma-pop-lab:first-child{margin-top:0;}",
|
|
3266
|
+
"#mma-host .mma-pop-list{margin:0;display:flex;flex-direction:column;gap:6px!important;max-height:280px;overflow-y:auto;padding:4px 0;scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--dsw-alias-fg,#111) 35%,transparent) transparent;}",
|
|
3267
|
+
"#mma-host .mma-pop-list::-webkit-scrollbar{width:8px;}",
|
|
3268
|
+
"#mma-host .mma-pop-list::-webkit-scrollbar-track{background:transparent;}",
|
|
3269
|
+
"#mma-host .mma-pop-list::-webkit-scrollbar-thumb{background:color-mix(in srgb,var(--dsw-alias-fg,#111) 35%,transparent);border-radius:99px;}",
|
|
2132
3270
|
"#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
3271
|
"#mma-host .mma-swatch:hover{background:var(--dsw-alias-accent,var(--dsw-alias-muted,#f3f4f6));}",
|
|
2134
3272
|
"#mma-host .mma-swatch[data-on='1']{background:var(--dsw-alias-accent,var(--dsw-alias-muted,#f3f4f6));font-weight:600;}",
|
|
@@ -2207,17 +3345,106 @@ var CSS = [
|
|
|
2207
3345
|
"#mma-host .mma-dialog-actions{display:flex;justify-content:flex-end;gap:8px;}",
|
|
2208
3346
|
"#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
3347
|
"#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);
|
|
2211
|
-
"#mma-host .mma-settings[data-open='1']{display:
|
|
2212
|
-
"#mma-host .mma-settings
|
|
2213
|
-
"#mma-host .mma-settings-head{display:flex;align-items:center;
|
|
2214
|
-
"#mma-host .mma-settings
|
|
2215
|
-
"#mma-host .mma-settings
|
|
2216
|
-
"#mma-host .mma-settings-
|
|
2217
|
-
"#mma-host .mma-settings-
|
|
2218
|
-
"#mma-host .mma-settings-
|
|
2219
|
-
"#mma-host
|
|
2220
|
-
"#mma-host
|
|
3348
|
+
"#mma-host .mma-settings{position:absolute;inset:0;z-index:4;display:none;flex-direction:column;background:var(--dsw-alias-bg,#f7f7f8);color:inherit;overflow:hidden;}",
|
|
3349
|
+
"#mma-host .mma-settings[data-open='1']{display:flex;}",
|
|
3350
|
+
"#mma-host .mma-settings-head{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border-bottom:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);}",
|
|
3351
|
+
"#mma-host .mma-settings-head-left{display:flex;align-items:center;gap:8px;min-width:0;}",
|
|
3352
|
+
"#mma-host .mma-settings-head-icon{opacity:.7;font-size:14px;}",
|
|
3353
|
+
"#mma-host .mma-settings-head h3{margin:0;font-size:15px;font-weight:650;letter-spacing:-.01em;}",
|
|
3354
|
+
"#mma-host .mma-settings-head-right{display:flex;align-items:center;gap:8px;}",
|
|
3355
|
+
"#mma-host .mma-settings-meta{font-size:11px;opacity:.55;white-space:nowrap;}",
|
|
3356
|
+
"#mma-host .mma-settings-body{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;}",
|
|
3357
|
+
"#mma-host .mma-settings-rail{flex:0 0 auto;display:flex;gap:4px;padding:8px 10px;border-bottom:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);overflow-x:auto;}",
|
|
3358
|
+
"#mma-host .mma-settings-rail-title{display:none;}",
|
|
3359
|
+
"#mma-host .mma-settings-rail-item{flex:0 0 auto;height:30px;padding:0 10px;border:0;border-radius:8px;background:transparent;color:inherit;opacity:.7;font-size:12.5px;cursor:pointer;}",
|
|
3360
|
+
"#mma-host .mma-settings-rail-item:hover{background:var(--dsw-alias-muted,#f3f4f6);opacity:1;}",
|
|
3361
|
+
"#mma-host .mma-settings-rail-item[data-on='1']{background:var(--dsw-alias-muted,#f3f4f6);opacity:1;font-weight:600;color:var(--dsw-alias-primary,#2563eb);box-shadow:inset 0 -2px 0 var(--dsw-alias-primary,#2563eb);}",
|
|
3362
|
+
"#mma-host .mma-settings-content{flex:1 1 auto;min-height:0;overflow:auto;padding:18px 16px 24px;scroll-behavior:smooth;}",
|
|
3363
|
+
"#mma-host .mma-settings-section{scroll-margin-top:12px;}",
|
|
3364
|
+
"#mma-host .mma-settings-section h4{margin:0 0 14px;font-size:12.5px;font-weight:600;letter-spacing:.5px;text-transform:uppercase;opacity:.55;}",
|
|
3365
|
+
"#mma-host .mma-settings-field{display:flex;flex-direction:column;gap:8px;margin-bottom:20px;}",
|
|
3366
|
+
"#mma-host .mma-settings-label{font-size:12.5px;opacity:.75;}",
|
|
3367
|
+
"#mma-host .mma-settings-control{min-width:0;}",
|
|
3368
|
+
"#mma-host .mma-settings-control--model{max-width:520px;}",
|
|
3369
|
+
"#mma-host .mma-settings input{display:block;width:100%;height:34px;padding:0 10px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:9px;background:var(--dsw-alias-surface,#fff);color:inherit;font-size:13px;box-sizing:border-box;}",
|
|
3370
|
+
"#mma-host .mma-settings input:focus{outline:none;border-color:var(--dsw-alias-primary,#2563eb);box-shadow:0 0 0 2px color-mix(in srgb, var(--dsw-alias-primary,#2563eb) 20%, transparent);}",
|
|
3371
|
+
"#mma-host .mma-settings input:disabled{opacity:.55;}",
|
|
3372
|
+
"#mma-host .mma-settings-field.is-error input{border-color:var(--dsw-alias-destructive,#dc2626);}",
|
|
3373
|
+
"#mma-host .mma-seg{display:flex;gap:4px;padding:3px;border-radius:10px;background:var(--dsw-alias-muted,#f3f4f6);max-width:280px;}",
|
|
3374
|
+
"#mma-host .mma-seg button{flex:1;height:30px;padding:0 8px;border:0;border-radius:8px;background:transparent;cursor:pointer;font-size:12.5px;color:inherit;}",
|
|
3375
|
+
"#mma-host .mma-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);}",
|
|
3376
|
+
"#mma-host .mma-optgrid{display:grid;gap:10px;}",
|
|
3377
|
+
"#mma-host .mma-optgrid--2{grid-template-columns:repeat(2,minmax(0,1fr));}",
|
|
3378
|
+
"#mma-host .mma-optgrid--3{grid-template-columns:repeat(2,minmax(0,1fr));}",
|
|
3379
|
+
"#mma-host .mma-optgrid--4{grid-template-columns:repeat(2,minmax(0,1fr));}",
|
|
3380
|
+
"#mma-host .mma-optcard{position:relative;display:flex;flex-direction:column;gap:8px;padding:10px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:10px;background:var(--dsw-alias-surface,#fff);color:inherit;cursor:pointer;text-align:left;}",
|
|
3381
|
+
"#mma-host .mma-optcard:hover{border-color:color-mix(in srgb, var(--dsw-alias-fg,#111) 28%, var(--dsw-alias-border,#e5e7eb));}",
|
|
3382
|
+
"#mma-host .mma-optcard:focus-visible{outline:2px solid var(--dsw-alias-primary,#2563eb);outline-offset:2px;}",
|
|
3383
|
+
"#mma-host .mma-optcard[data-on='1']{border-color:var(--dsw-alias-primary,#2563eb);background:color-mix(in srgb, var(--dsw-alias-primary,#2563eb) 8%, var(--dsw-alias-surface,#fff));}",
|
|
3384
|
+
"#mma-host .mma-optcard:disabled,.mma-optcard--ghost{opacity:.55;cursor:default;border-style:dashed;}",
|
|
3385
|
+
"#mma-host .mma-optcard-preview{display:block;height:42px;border-radius:8px;overflow:hidden;background:var(--dsw-alias-muted,#f3f4f6);}",
|
|
3386
|
+
"#mma-host .mma-optcard-preview--plus{display:flex;align-items:center;justify-content:center;font-size:20px;opacity:.7;}",
|
|
3387
|
+
"#mma-host .mma-optcard-label{font-size:12px;line-height:1.2;}",
|
|
3388
|
+
"#mma-host .mma-optcard-check{position:absolute;top:8px;right:8px;width:18px;height:18px;border-radius:999px;background:var(--dsw-alias-primary,#2563eb);color:var(--dsw-alias-primary-fg,#fff);font-size:11px;display:flex;align-items:center;justify-content:center;}",
|
|
3389
|
+
"#mma-host .mma-preview-theme{display:flex;flex-direction:column;justify-content:center;gap:6px;height:100%;padding:8px;box-sizing:border-box;}",
|
|
3390
|
+
"#mma-host .mma-preview-theme--light{background:var(--dsw-alias-bg,#f7f7f8);}",
|
|
3391
|
+
"#mma-host .mma-preview-theme--dark{background:color-mix(in srgb, var(--dsw-alias-fg,#111) 88%, transparent);}",
|
|
3392
|
+
"#mma-host .mma-preview-theme--system{display:flex;flex-direction:row;padding:0;}",
|
|
3393
|
+
"#mma-host .mma-preview-theme-half{flex:1;height:100%;display:flex;flex-direction:column;justify-content:center;gap:6px;padding:8px;box-sizing:border-box;}",
|
|
3394
|
+
"#mma-host .mma-preview-theme-half--light{background:var(--dsw-alias-bg,#f7f7f8);}",
|
|
3395
|
+
"#mma-host .mma-preview-theme-half--dark{background:color-mix(in srgb, var(--dsw-alias-fg,#111) 88%, transparent);}",
|
|
3396
|
+
"#mma-host .mma-preview-bar{display:block;height:4px;border-radius:999px;background:color-mix(in srgb, var(--dsw-alias-fg,#111) 25%, transparent);}",
|
|
3397
|
+
"#mma-host .mma-preview-theme--dark .mma-preview-bar,#mma-host .mma-preview-theme-half--dark .mma-preview-bar{background:color-mix(in srgb, #fff 45%, transparent);}",
|
|
3398
|
+
"#mma-host .mma-preview-swatches{display:flex;align-items:center;justify-content:center;gap:8px;height:100%;}",
|
|
3399
|
+
"#mma-host .mma-preview-swatches > span{width:14px;height:14px;border-radius:999px;border:1px solid color-mix(in srgb, var(--dsw-alias-fg,#111) 12%, transparent);}",
|
|
3400
|
+
"#mma-host .mma-preview-cardstyle{display:block;height:100%;margin:8px;border-radius:6px;border:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);box-sizing:border-box;}",
|
|
3401
|
+
"#mma-host .mma-preview-cardstyle--stamp{box-shadow:inset 0 0 0 1px var(--dsw-alias-border,#e5e7eb);position:relative;}",
|
|
3402
|
+
"#mma-host .mma-preview-cardstyle--stamp::after{content:'';position:absolute;top:4px;right:4px;width:18px;height:8px;border-radius:3px;background:var(--dsw-alias-muted,#f3f4f6);}",
|
|
3403
|
+
"#mma-host .mma-preview-cardstyle--etch{background:transparent;}",
|
|
3404
|
+
"#mma-host .mma-preview-cardstyle--hero{box-shadow:3px 3px 0 var(--dsw-alias-border,#e5e7eb);}",
|
|
3405
|
+
"#mma-host .mma-preview-cardstyle--list{border:0;border-bottom:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:0;margin:14px 8px;}",
|
|
3406
|
+
"#mma-host .mma-port-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}",
|
|
3407
|
+
"#mma-host .mma-port-addon{display:inline-flex;align-items:center;justify-content:center;height:34px;padding:0 8px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-right:0;border-radius:9px 0 0 9px;background:var(--dsw-alias-muted,#f3f4f6);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;}",
|
|
3408
|
+
"#mma-host .mma-port-row input{width:120px;border-radius:0 9px 9px 0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}",
|
|
3409
|
+
"#mma-host .mma-port-url{font-size:11px;opacity:.65;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;}",
|
|
3410
|
+
"#mma-host .mma-model-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;}",
|
|
3411
|
+
"#mma-host .mma-model-row input{flex:1 1 180px;min-width:0;}",
|
|
3412
|
+
"#mma-host .mma-status-pill{display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 10px;border-radius:20px;border:1px solid var(--dsw-alias-border,#e5e7eb);font-size:11px;opacity:.75;white-space:nowrap;}",
|
|
3413
|
+
"#mma-host .mma-ghostbtn{height:30px;padding:0 10px;border:1px solid var(--dsw-alias-border,#e5e7eb);border-radius:8px;background:var(--dsw-alias-surface,#fff);color:inherit;font-size:12px;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;}",
|
|
3414
|
+
"#mma-host .mma-ghostbtn:hover{background:var(--dsw-alias-muted,#f3f4f6);}",
|
|
3415
|
+
"#mma-host .mma-ghostbtn:disabled{opacity:.55;cursor:default;}",
|
|
3416
|
+
"#mma-host .mma-primarybtn{height:34px;padding:0 16px;border:0;border-radius:8px;background:var(--dsw-alias-primary,#2563eb);color:var(--dsw-alias-primary-fg,#fff);font-size:13px;font-weight:600;cursor:pointer;}",
|
|
3417
|
+
"#mma-host .mma-primarybtn:disabled{opacity:.45;cursor:default;}",
|
|
3418
|
+
"#mma-host .mma-settings-hint{margin:0;font-size:11.5px;opacity:.6;line-height:1.45;}",
|
|
3419
|
+
"#mma-host .mma-settings-field.is-error .mma-settings-hint{color:var(--dsw-alias-destructive,#dc2626);opacity:1;}",
|
|
3420
|
+
"#mma-host .mma-settings-rule{border:0;border-top:1px solid var(--dsw-alias-border,#e5e7eb);margin:20px 0;}",
|
|
3421
|
+
"#mma-host .mma-about-meta{margin-bottom:10px;display:flex;flex-direction:column;gap:6px;}",
|
|
3422
|
+
"#mma-host .mma-about-meta code{display:inline-block;width:fit-content;font-size:12px;padding:3px 8px;border-radius:6px;background:var(--dsw-alias-muted,#f3f4f6);}",
|
|
3423
|
+
"#mma-host .mma-about-pkgs{list-style:none;margin:0 0 12px;padding:0;display:flex;flex-direction:column;gap:6px;}",
|
|
3424
|
+
"#mma-host .mma-about-pkgs li{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;padding:8px 10px;border-radius:9px;background:var(--dsw-alias-surface,#fff);border:1px solid var(--dsw-alias-border,#e5e7eb);}",
|
|
3425
|
+
"#mma-host .mma-about-pkgs li span{opacity:.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}",
|
|
3426
|
+
"#mma-host .mma-about-pkgs li code{font-size:11px;font-variant-numeric:tabular-nums;opacity:.9;}",
|
|
3427
|
+
"#mma-host .mma-about-actions{display:flex;flex-direction:column;align-items:flex-start;gap:8px;}",
|
|
3428
|
+
"#mma-host .mma-settings-foot{flex:0 0 auto;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px;padding:10px 14px;border-top:1px solid var(--dsw-alias-border,#e5e7eb);background:var(--dsw-alias-surface,#fff);}",
|
|
3429
|
+
"#mma-host .mma-settings-foot-left{display:flex;flex-wrap:wrap;align-items:center;gap:4px;min-width:0;}",
|
|
3430
|
+
"#mma-host .mma-settings-foot-right{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-left:auto;}",
|
|
3431
|
+
"#mma-host .mma-settings-dirty{font-size:11.5px;color:var(--dsw-alias-primary,#2563eb);}",
|
|
3432
|
+
"#mma-host .mma-settings-msg{flex-basis:100%;font-size:12px;opacity:.75;line-height:1.4;}",
|
|
3433
|
+
"#mma-host .mma-settings-msg.err{color:var(--dsw-alias-destructive,#dc2626);}",
|
|
3434
|
+
"#mma-host .mma-settings-confirm{position:absolute;inset:0;z-index:5;display:flex;align-items:center;justify-content:center;padding:16px;background:color-mix(in srgb, var(--dsw-alias-fg,#111) 35%, transparent);}",
|
|
3435
|
+
/* Wide layout: data-wide from ResizeObserver (reliable on fixed #mma-host) + container query fallback. */
|
|
3436
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-body{flex-direction:row;}",
|
|
3437
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-rail{flex:0 0 148px;flex-direction:column;align-items:stretch;gap:2px;border-bottom:0;border-right:1px solid var(--dsw-alias-border,#e5e7eb);padding:14px 10px;overflow:visible;}",
|
|
3438
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-rail-title{display:block;font-size:10px;letter-spacing:.08em;text-transform:uppercase;opacity:.45;margin:0 8px 8px;}",
|
|
3439
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-rail-item{width:100%;justify-content:flex-start;text-align:left;box-shadow:none;border-radius:8px;position:relative;}",
|
|
3440
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-rail-item[data-on='1']{box-shadow:none;background:var(--dsw-alias-muted,#f3f4f6);}",
|
|
3441
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-rail-item[data-on='1']::before{content:'';position:absolute;left:0;top:6px;bottom:6px;width:2px;border-radius:2px;background:var(--dsw-alias-primary,#2563eb);}",
|
|
3442
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-content{padding:22px 26px 28px;}",
|
|
3443
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-optgrid--3{grid-template-columns:repeat(3,minmax(0,1fr));}",
|
|
3444
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-optgrid--4{grid-template-columns:repeat(4,minmax(0,1fr));}",
|
|
3445
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-field--row{flex-direction:row;align-items:flex-start;gap:16px;}",
|
|
3446
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-field--row > .mma-settings-label{flex:0 0 112px;padding-top:8px;}",
|
|
3447
|
+
"#mma-host .mma-settings[data-wide='1'] .mma-settings-field--row > .mma-settings-control{flex:1 1 auto;}",
|
|
2221
3448
|
"#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
3449
|
"#mma-host .mma-browse[data-open='1']{display:block;}",
|
|
2223
3450
|
"#mma-host .mma-browse-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:12px;}",
|
|
@@ -2254,7 +3481,15 @@ var CSS = [
|
|
|
2254
3481
|
"#mma-host .mma-diff-line--del{color:#991b1b;background:rgba(220,38,38,.10);}",
|
|
2255
3482
|
"#mma-host .mma-diff-line--ctx{color:inherit;opacity:.85;}",
|
|
2256
3483
|
"#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;}"
|
|
3484
|
+
"#mma-host .mma-berr{padding:16px;color:#b91c1c;font-size:13px;}",
|
|
3485
|
+
"#mma-host .mma-storage-notice{display:flex;gap:12px;align-items:flex-start;justify-content:space-between;padding:12px 14px;margin:0 0 12px;border-radius:10px;background:color-mix(in srgb, var(--dsw-alias-warning, #f59e0b) 14%, var(--dsw-alias-bg, #f7f7f8));border:1px solid color-mix(in srgb, var(--dsw-alias-warning, #f59e0b) 35%, transparent);}",
|
|
3486
|
+
"#mma-host .mma-storage-notice-body{min-width:0;flex:1;}",
|
|
3487
|
+
"#mma-host .mma-storage-notice-body b{display:block;font-size:13px;margin:0 0 4px;}",
|
|
3488
|
+
"#mma-host .mma-storage-notice-body p{margin:0;font-size:12px;line-height:1.45;opacity:.85;}",
|
|
3489
|
+
"#mma-host .mma-storage-notice-top{margin-top:6px !important;}",
|
|
3490
|
+
"#mma-host .mma-storage-notice-actions{display:flex;flex-direction:column;gap:6px;flex-shrink:0;}",
|
|
3491
|
+
"#mma-host .mma-storage-notice-actions button{font-size:12px;padding:6px 10px;border-radius:8px;border:1px solid color-mix(in srgb, currentColor 18%, transparent);background:var(--dsw-alias-bg, #fff);cursor:pointer;}",
|
|
3492
|
+
"#mma-host .mma-storage-notice-copy{font-weight:600;}"
|
|
2258
3493
|
];
|
|
2259
3494
|
function injectPanelCss() {
|
|
2260
3495
|
if (typeof document === "undefined") return;
|
|
@@ -2267,25 +3502,20 @@ function injectPanelCss() {
|
|
|
2267
3502
|
}
|
|
2268
3503
|
tag.textContent = CSS.join("\n");
|
|
2269
3504
|
}
|
|
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
3505
|
function createMiniAppPanel(host, options) {
|
|
2282
3506
|
const locale = resolvePanelLocale(options?.locale ?? host.locale);
|
|
2283
3507
|
const i18n = createPanelI18n(locale);
|
|
3508
|
+
const prev = getPanelState();
|
|
2284
3509
|
resetPanelState({
|
|
2285
3510
|
tabs: [{ id: "all", title: i18n.t("tabs.all"), kind: "all" }],
|
|
2286
3511
|
capabilities: capabilitiesOf(host),
|
|
2287
3512
|
locale,
|
|
2288
|
-
emptyText: host.emptyText
|
|
3513
|
+
emptyText: host.emptyText,
|
|
3514
|
+
theme: prev.theme,
|
|
3515
|
+
palette: prev.palette,
|
|
3516
|
+
dock: prev.dock,
|
|
3517
|
+
cardStyle: prev.cardStyle,
|
|
3518
|
+
visible: prev.visible
|
|
2289
3519
|
});
|
|
2290
3520
|
let rootEl = null;
|
|
2291
3521
|
let root = null;
|
|
@@ -2332,29 +3562,98 @@ function readThemePrefs(storage) {
|
|
|
2332
3562
|
return null;
|
|
2333
3563
|
}
|
|
2334
3564
|
};
|
|
2335
|
-
return {
|
|
3565
|
+
return {
|
|
3566
|
+
theme: (() => {
|
|
3567
|
+
const m = get("mma-theme-mode");
|
|
3568
|
+
return m === "system" || m === "dark" || m === "light" ? m : "light";
|
|
3569
|
+
})(),
|
|
3570
|
+
palette: get("mma-palette") || "default",
|
|
3571
|
+
cardStyle: get("mma-card-style") || "stamp"
|
|
3572
|
+
};
|
|
2336
3573
|
}
|
|
2337
3574
|
function createHostShell(opts) {
|
|
2338
3575
|
const storage = safeStorage(opts.storage);
|
|
2339
3576
|
const themePrefs = readThemePrefs(storage);
|
|
3577
|
+
let currentOrigin = opts.hostUrl.replace(/\/$/, "");
|
|
2340
3578
|
const frame = createFrameController({
|
|
2341
|
-
urlOf: (appId) => appFrameUrl(
|
|
3579
|
+
urlOf: (appId) => appFrameUrl(currentOrigin, appId, envFor(appId)),
|
|
2342
3580
|
envOf: (appId) => envFor(appId)
|
|
2343
3581
|
});
|
|
3582
|
+
let unsubEvents = null;
|
|
3583
|
+
function bindHostEvents() {
|
|
3584
|
+
unsubEvents?.();
|
|
3585
|
+
unsubEvents = subscribeHostEvents(currentOrigin, {
|
|
3586
|
+
// `mini_app_open` asked to show an app. Without this the panel opens on the list and
|
|
3587
|
+
// the agent's follow-up (`mini_app_errors`, `mini_app_view_eval`) waits on a view that
|
|
3588
|
+
// was never mounted — the dsh client already does this in its own stream handler.
|
|
3589
|
+
onOpen: (appId, title) => {
|
|
3590
|
+
optOnOpen();
|
|
3591
|
+
void host.fetchApps().then((apps) => {
|
|
3592
|
+
const app = apps.find((a) => a.id === appId);
|
|
3593
|
+
if (app) panelRef()?.actions.openAppTab(app);
|
|
3594
|
+
else if (title) console.warn(`[mma] opened app ${appId} is not registered on this host`);
|
|
3595
|
+
});
|
|
3596
|
+
},
|
|
3597
|
+
onReload: (appId) => {
|
|
3598
|
+
if (frame.map.has(appId)) frame.reload(appId);
|
|
3599
|
+
},
|
|
3600
|
+
onEval: (query) => relayViewEval(currentOrigin, frame, query),
|
|
3601
|
+
onStorageNotice: (notice) => {
|
|
3602
|
+
setPanelState({ storageNotice: notice });
|
|
3603
|
+
}
|
|
3604
|
+
});
|
|
3605
|
+
}
|
|
2344
3606
|
function envFor(appId) {
|
|
2345
3607
|
const s = getPanelState();
|
|
2346
3608
|
const app = s.apps.find((a) => a.id === appId);
|
|
2347
|
-
|
|
3609
|
+
const theme = app?.theme?.theme || s.theme;
|
|
3610
|
+
const palette = effectivePalette(app?.theme?.palette, Boolean(app?.localPalette), s.palette);
|
|
3611
|
+
const custom = { ...s.customPalettes };
|
|
3612
|
+
if (app?.localPalette) {
|
|
3613
|
+
custom[LOCAL_PALETTE_ID] = {
|
|
3614
|
+
label: app.localPalette.label,
|
|
3615
|
+
swatch: app.localPalette.swatch,
|
|
3616
|
+
tokens: app.localPalette.tokens
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3619
|
+
return {
|
|
3620
|
+
theme,
|
|
3621
|
+
palette,
|
|
3622
|
+
dock: s.dock,
|
|
3623
|
+
vars: themeCssVars(resolveMode(theme), palette, custom)
|
|
3624
|
+
};
|
|
3625
|
+
}
|
|
3626
|
+
async function migrateOrigin(next) {
|
|
3627
|
+
const origin = next.replace(/\/$/, "");
|
|
3628
|
+
for (let i = 0; i < 30; i++) {
|
|
3629
|
+
try {
|
|
3630
|
+
const res = await fetch(`${origin}/health`);
|
|
3631
|
+
if (res.ok) break;
|
|
3632
|
+
} catch {
|
|
3633
|
+
}
|
|
3634
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
3635
|
+
}
|
|
3636
|
+
currentOrigin = origin;
|
|
3637
|
+
try {
|
|
3638
|
+
storage?.setItem("mma-host-url", origin);
|
|
3639
|
+
} catch {
|
|
3640
|
+
}
|
|
3641
|
+
opts.onHostChange?.(origin);
|
|
3642
|
+
bindHostEvents();
|
|
3643
|
+
for (const id of [...frame.map.keys()]) frame.reload(id);
|
|
2348
3644
|
}
|
|
2349
3645
|
const host = createRestPanelHost({
|
|
2350
3646
|
hostUrl: opts.hostUrl,
|
|
3647
|
+
getHostUrl: () => currentOrigin,
|
|
2351
3648
|
storage,
|
|
2352
3649
|
cardStyle: opts.cardStyle,
|
|
2353
3650
|
locale: opts.locale ?? void 0,
|
|
2354
3651
|
emptyText: opts.emptyText,
|
|
2355
3652
|
onOpen: () => optOnOpen(),
|
|
2356
3653
|
onClose: () => optOnClose(),
|
|
2357
|
-
onHostChange: (next) =>
|
|
3654
|
+
onHostChange: (next) => {
|
|
3655
|
+
void migrateOrigin(next);
|
|
3656
|
+
},
|
|
2358
3657
|
frameController: {
|
|
2359
3658
|
url: (appId) => frame.url(appId),
|
|
2360
3659
|
// Lazy-bind the frames container (React may not have rendered #mma-frames yet).
|
|
@@ -2381,6 +3680,10 @@ function createHostShell(opts) {
|
|
|
2381
3680
|
}
|
|
2382
3681
|
let panel = null;
|
|
2383
3682
|
let containerEl = null;
|
|
3683
|
+
function panelRef() {
|
|
3684
|
+
if (!panel) panel = createMiniAppPanel(host);
|
|
3685
|
+
return panel;
|
|
3686
|
+
}
|
|
2384
3687
|
function optOnOpen() {
|
|
2385
3688
|
setPanelState({ visible: true });
|
|
2386
3689
|
opts.onOpen?.();
|
|
@@ -2403,15 +3706,15 @@ function createHostShell(opts) {
|
|
|
2403
3706
|
host,
|
|
2404
3707
|
frames: frame,
|
|
2405
3708
|
get panel() {
|
|
2406
|
-
|
|
2407
|
-
return panel;
|
|
3709
|
+
return panelRef();
|
|
2408
3710
|
},
|
|
2409
3711
|
mount(el) {
|
|
2410
3712
|
containerEl = document.createElement("div");
|
|
2411
3713
|
containerEl.id = "mma-host";
|
|
2412
3714
|
containerEl.setAttribute("data-ready", "1");
|
|
2413
3715
|
containerEl.setAttribute("data-dock", getPanelState().dock);
|
|
2414
|
-
containerEl.setAttribute("data-cardstyle",
|
|
3716
|
+
containerEl.setAttribute("data-cardstyle", themePrefs.cardStyle);
|
|
3717
|
+
bindHostEvents();
|
|
2415
3718
|
Object.assign(containerEl.style, {
|
|
2416
3719
|
position: "fixed",
|
|
2417
3720
|
top: "0",
|
|
@@ -2427,14 +3730,24 @@ function createHostShell(opts) {
|
|
|
2427
3730
|
});
|
|
2428
3731
|
const target = el ?? document.body;
|
|
2429
3732
|
target.appendChild(containerEl);
|
|
2430
|
-
|
|
2431
|
-
|
|
3733
|
+
const cardStyle = themePrefs.cardStyle;
|
|
3734
|
+
setPanelState({
|
|
3735
|
+
theme: themePrefs.theme,
|
|
3736
|
+
palette: themePrefs.palette,
|
|
3737
|
+
cardStyle,
|
|
3738
|
+
visible: true
|
|
3739
|
+
});
|
|
2432
3740
|
this.panel.mount(containerEl);
|
|
3741
|
+
applyThemeTo(containerEl, themePrefs.theme, themePrefs.palette);
|
|
3742
|
+
setPanelState({ theme: themePrefs.theme, palette: themePrefs.palette, cardStyle });
|
|
3743
|
+
containerEl.setAttribute("data-cardstyle", cardStyle);
|
|
2433
3744
|
const framesEl = containerEl.querySelector("#mma-frames");
|
|
2434
3745
|
if (framesEl) frame.setContainer(framesEl);
|
|
2435
3746
|
void this.panel.actions.fetchApps();
|
|
2436
3747
|
},
|
|
2437
3748
|
unmount() {
|
|
3749
|
+
unsubEvents?.();
|
|
3750
|
+
unsubEvents = null;
|
|
2438
3751
|
panel?.unmount();
|
|
2439
3752
|
panel = null;
|
|
2440
3753
|
frame.unmountAll();
|
|
@@ -2468,8 +3781,10 @@ var packageName = "@monkey-mini-app/panel";
|
|
|
2468
3781
|
|
|
2469
3782
|
exports.AppList = AppList;
|
|
2470
3783
|
exports.Browse = Browse;
|
|
3784
|
+
exports.GLOBAL_PALETTE_ID = GLOBAL_PALETTE_ID;
|
|
2471
3785
|
exports.HostUnreachableError = HostUnreachableError;
|
|
2472
3786
|
exports.LOCALE_IDS = LOCALE_IDS;
|
|
3787
|
+
exports.LOCAL_PALETTE_ID = LOCAL_PALETTE_ID;
|
|
2473
3788
|
exports.ListRegion = ListRegion;
|
|
2474
3789
|
exports.Loading = Loading;
|
|
2475
3790
|
exports.MiniAppPanel = MiniAppPanel;
|
|
@@ -2498,6 +3813,7 @@ exports.createPanelI18n = createPanelI18n;
|
|
|
2498
3813
|
exports.createRestPanelHost = createRestPanelHost;
|
|
2499
3814
|
exports.cssVars = cssVars;
|
|
2500
3815
|
exports.defaultHideThemePop = defaultHideThemePop;
|
|
3816
|
+
exports.effectivePalette = effectivePalette;
|
|
2501
3817
|
exports.formToHostConfigBody = formToHostConfigBody;
|
|
2502
3818
|
exports.getPanelState = getPanelState;
|
|
2503
3819
|
exports.hostConfigToForm = hostConfigToForm;
|
|
@@ -2513,11 +3829,16 @@ exports.parsePalettes = parsePalettes;
|
|
|
2513
3829
|
exports.parseStorageTables = parseStorageTables;
|
|
2514
3830
|
exports.parseThemeCss = parseThemeCss;
|
|
2515
3831
|
exports.readJson = readJson;
|
|
3832
|
+
exports.relayViewEval = relayViewEval;
|
|
2516
3833
|
exports.resetPanelState = resetPanelState;
|
|
3834
|
+
exports.resolveMode = resolveMode;
|
|
2517
3835
|
exports.resolvePanelLocale = resolvePanelLocale;
|
|
2518
3836
|
exports.runnerThemeCss = runnerThemeCss;
|
|
3837
|
+
exports.selectedPalette = selectedPalette;
|
|
2519
3838
|
exports.setPanelState = setPanelState;
|
|
3839
|
+
exports.subscribeHostEvents = subscribeHostEvents;
|
|
2520
3840
|
exports.subscribePanel = subscribePanel;
|
|
3841
|
+
exports.themeCssVars = themeCssVars;
|
|
2521
3842
|
exports.themeLabelFromCss = themeLabelFromCss;
|
|
2522
3843
|
exports.tokensOf = tokensOf;
|
|
2523
3844
|
exports.usePanelActions = usePanelActions;
|