dsh-model-arena 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/arena.web.js CHANGED
@@ -87,216 +87,630 @@ var en = {
87
87
  };
88
88
 
89
89
  // src/client/view.tsx
90
+ var import_react2 = require("react");
91
+
92
+ // src/client/ui.tsx
90
93
  var import_react = require("react");
91
94
  var import_jsx_runtime = require("react/jsx-runtime");
92
- var PANEL_PATH = "/api/arena.panel";
93
- var RUN_PATH = "/api/arena.run";
94
- var RATE_PATH = "/api/arena.rate";
95
- var DELETE_PATH = "/api/arena.delete";
96
- var wrap = { display: "flex", flexDirection: "column", gap: 14, maxWidth: 820, fontFamily: "inherit" };
97
- var head = { display: "flex", alignItems: "baseline", gap: 12, flexWrap: "wrap" };
98
- var section = { marginTop: 8 };
99
- var sectionTitle = { fontSize: 13, fontWeight: 600, marginBottom: 6 };
100
- var muted = { fontSize: 12, opacity: 0.75 };
101
- var table = { borderCollapse: "collapse", width: "100%" };
102
- var th = { textAlign: "left", padding: "4px 10px 4px 0", fontWeight: 600, fontSize: 12, opacity: 0.8, borderBottom: "0.5px solid rgba(128,128,128,0.4)" };
103
- var td = { padding: "6px 10px 6px 0", fontSize: 13, borderBottom: "0.5px solid rgba(128,128,128,0.18)" };
104
- var card = { padding: "8px 12px", borderRadius: 6, border: "1px solid rgba(128,128,128,0.2)", background: "rgba(128,128,128,0.04)", fontSize: 13 };
105
- var badge = { display: "inline-block", padding: "1px 6px", borderRadius: 9, fontSize: 11, fontWeight: 600 };
106
- var statRow = { display: "flex", gap: 16, flexWrap: "wrap" };
107
- var statBox = { ...card, flex: 1, minWidth: 100, textAlign: "center" };
108
- var starBtn = { cursor: "pointer", background: "none", border: "none", fontSize: 16, padding: "0 1px" };
109
- var clickRow = { cursor: "pointer" };
110
- var preBlock = { whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: 12, maxHeight: 200, overflow: "auto", padding: 8, borderRadius: 4, background: "rgba(128,128,128,0.06)", border: "1px solid rgba(128,128,128,0.15)" };
111
- var dangerBtn = { fontSize: 11, color: "#e55", background: "none", border: "1px solid #e55", borderRadius: 4, padding: "2px 8px", cursor: "pointer" };
112
- function usePanel() {
113
- const [state, setState] = (0, import_react.useState)({ payload: null, error: null });
95
+ var T = {
96
+ accent: "var(--accent, #4B8BBE)",
97
+ accentHover: "var(--accent-hover, #3a6f9e)",
98
+ error: "var(--error, #e53935)",
99
+ success: "var(--success, #2e7d32)",
100
+ warning: "var(--warning, #ed6c02)",
101
+ bg: "var(--bg-secondary, rgba(128,128,128,0.04))",
102
+ bgHover: "var(--bg-tertiary, rgba(128,128,128,0.08))",
103
+ border: "var(--border, rgba(128,128,128,0.2))",
104
+ text: "var(--text-primary, inherit)",
105
+ muted: "var(--text-secondary, rgba(128,128,128,0.65))",
106
+ surface: "var(--bg-primary, #fff)"
107
+ };
108
+ var injected = false;
109
+ function ensureStyles() {
110
+ if (injected || typeof document === "undefined") return;
111
+ injected = true;
112
+ const el = document.createElement("style");
113
+ el.textContent = `
114
+ @keyframes dsh-fade-in{from{opacity:0}to{opacity:1}}
115
+ @keyframes dsh-slide-up{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
116
+ @keyframes dsh-spin{to{transform:rotate(360deg)}}
117
+ .dsh-modal-overlay{animation:dsh-fade-in .15s ease}
118
+ .dsh-modal-body{animation:dsh-slide-up .2s ease}
119
+ .dsh-toast{animation:dsh-slide-up .2s ease}
120
+ .dsh-spin{animation:dsh-spin .6s linear infinite}
121
+ `;
122
+ document.head.appendChild(el);
123
+ }
124
+ function Modal({
125
+ title,
126
+ onClose,
127
+ children,
128
+ footer,
129
+ width = 520
130
+ }) {
131
+ (0, import_react.useEffect)(() => {
132
+ ensureStyles();
133
+ const handler = (e) => {
134
+ if (e.key === "Escape") onClose();
135
+ };
136
+ document.addEventListener("keydown", handler);
137
+ return () => document.removeEventListener("keydown", handler);
138
+ }, [onClose]);
139
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
140
+ "div",
141
+ {
142
+ className: "dsh-modal-overlay",
143
+ style: {
144
+ position: "fixed",
145
+ inset: 0,
146
+ zIndex: 1e3,
147
+ display: "flex",
148
+ alignItems: "center",
149
+ justifyContent: "center",
150
+ background: "rgba(0,0,0,0.45)",
151
+ backdropFilter: "blur(3px)",
152
+ WebkitBackdropFilter: "blur(3px)"
153
+ },
154
+ onClick: onClose,
155
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
156
+ "div",
157
+ {
158
+ className: "dsh-modal-body",
159
+ style: {
160
+ background: T.surface,
161
+ borderRadius: 14,
162
+ boxShadow: "0 12px 40px rgba(0,0,0,0.25)",
163
+ width: `min(92vw, ${width}px)`,
164
+ maxHeight: "85vh",
165
+ display: "flex",
166
+ flexDirection: "column",
167
+ overflow: "hidden"
168
+ },
169
+ onClick: (e) => e.stopPropagation(),
170
+ children: [
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
172
+ "div",
173
+ {
174
+ style: {
175
+ display: "flex",
176
+ alignItems: "center",
177
+ justifyContent: "space-between",
178
+ padding: "16px 22px",
179
+ borderBottom: `1px solid ${T.border}`
180
+ },
181
+ children: [
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: { margin: 0, fontSize: 15, fontWeight: 600 }, children: title }),
183
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
184
+ "button",
185
+ {
186
+ type: "button",
187
+ onClick: onClose,
188
+ style: {
189
+ background: "none",
190
+ border: "none",
191
+ cursor: "pointer",
192
+ fontSize: 20,
193
+ color: T.muted,
194
+ padding: "0 4px",
195
+ lineHeight: 1,
196
+ borderRadius: 4
197
+ },
198
+ "aria-label": "Close",
199
+ children: "\xD7"
200
+ }
201
+ )
202
+ ]
203
+ }
204
+ ),
205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding: 22, overflow: "auto", flex: 1 }, children }),
206
+ footer !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
207
+ "div",
208
+ {
209
+ style: {
210
+ padding: "14px 22px",
211
+ borderTop: `1px solid ${T.border}`,
212
+ display: "flex",
213
+ justifyContent: "flex-end",
214
+ gap: 10,
215
+ background: T.bg
216
+ },
217
+ children: footer
218
+ }
219
+ )
220
+ ]
221
+ }
222
+ )
223
+ }
224
+ );
225
+ }
226
+ function ConfirmDialog({
227
+ title,
228
+ message,
229
+ confirmLabel,
230
+ cancelLabel = "Cancel",
231
+ onConfirm,
232
+ onClose,
233
+ danger
234
+ }) {
235
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
236
+ Modal,
237
+ {
238
+ title,
239
+ onClose,
240
+ width: 420,
241
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button, { variant: "secondary", onClick: onClose, children: cancelLabel }),
243
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
244
+ Button,
245
+ {
246
+ variant: danger === true ? "danger" : "primary",
247
+ onClick: () => {
248
+ onConfirm();
249
+ onClose();
250
+ },
251
+ children: confirmLabel
252
+ }
253
+ )
254
+ ] }),
255
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: 14, lineHeight: 1.6 }, children: message })
256
+ }
257
+ );
258
+ }
259
+ function Button({
260
+ variant = "secondary",
261
+ size = "md",
262
+ children,
263
+ style,
264
+ ...rest
265
+ }) {
266
+ const base = {
267
+ cursor: "pointer",
268
+ borderRadius: 7,
269
+ fontWeight: 500,
270
+ transition: "all 0.15s ease",
271
+ border: "none",
272
+ display: "inline-flex",
273
+ alignItems: "center",
274
+ gap: 4,
275
+ fontSize: size === "sm" ? 12 : 13,
276
+ padding: size === "sm" ? "5px 12px" : "8px 18px",
277
+ fontFamily: "inherit"
278
+ };
279
+ const variants = {
280
+ primary: { background: T.accent, color: "#fff" },
281
+ secondary: {
282
+ background: T.bg,
283
+ color: T.text,
284
+ border: `1px solid ${T.border}`
285
+ },
286
+ danger: {
287
+ background: "transparent",
288
+ color: T.error,
289
+ border: `1px solid ${T.error}`
290
+ },
291
+ ghost: { background: "transparent", color: T.muted, border: "none" }
292
+ };
293
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: { ...base, ...variants[variant], ...style }, ...rest, children });
294
+ }
295
+ function Card({
296
+ title,
297
+ icon,
298
+ children,
299
+ actions,
300
+ style,
301
+ padding = 14
302
+ }) {
303
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
304
+ "div",
305
+ {
306
+ style: {
307
+ borderRadius: 10,
308
+ border: `1px solid ${T.border}`,
309
+ background: T.bg,
310
+ overflow: "hidden",
311
+ ...style
312
+ },
313
+ children: [
314
+ (title !== void 0 || actions !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
315
+ "div",
316
+ {
317
+ style: {
318
+ display: "flex",
319
+ alignItems: "center",
320
+ justifyContent: "space-between",
321
+ padding: "12px 16px",
322
+ borderBottom: title !== void 0 ? `1px solid ${T.border}` : "none"
323
+ },
324
+ children: [
325
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontSize: 13, fontWeight: 600, display: "flex", alignItems: "center", gap: 6 }, children: [
326
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: icon }),
327
+ title
328
+ ] }),
329
+ actions
330
+ ]
331
+ }
332
+ ),
333
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { padding }, children })
334
+ ]
335
+ }
336
+ );
337
+ }
338
+ function StatCard({
339
+ value,
340
+ label,
341
+ color,
342
+ unit
343
+ }) {
344
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
345
+ "div",
346
+ {
347
+ style: {
348
+ flex: 1,
349
+ minWidth: 90,
350
+ textAlign: "center",
351
+ padding: "14px 10px",
352
+ borderRadius: 10,
353
+ border: `1px solid ${T.border}`,
354
+ background: T.bg
355
+ },
356
+ children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 24, fontWeight: 700, color: color ?? T.text, lineHeight: 1.2 }, children: [
358
+ value,
359
+ unit !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 13, fontWeight: 500, opacity: 0.7, marginLeft: 2 }, children: unit })
360
+ ] }),
361
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 11, color: T.muted, marginTop: 4 }, children: label })
362
+ ]
363
+ }
364
+ );
365
+ }
366
+ function Badge({
367
+ children,
368
+ color = "default"
369
+ }) {
370
+ const colors = {
371
+ default: { bg: "rgba(128,128,128,0.12)", fg: T.muted },
372
+ success: { bg: "rgba(46,125,50,0.12)", fg: T.success },
373
+ error: { bg: "rgba(229,57,53,0.12)", fg: T.error },
374
+ warning: { bg: "rgba(245,124,0,0.12)", fg: T.warning },
375
+ info: { bg: "rgba(75,139,190,0.12)", fg: T.accent }
376
+ };
377
+ const c = colors[color];
378
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
379
+ "span",
380
+ {
381
+ style: {
382
+ display: "inline-block",
383
+ padding: "2px 9px",
384
+ borderRadius: 10,
385
+ fontSize: 11,
386
+ fontWeight: 600,
387
+ background: c.bg,
388
+ color: c.fg
389
+ },
390
+ children
391
+ }
392
+ );
393
+ }
394
+ var ToastContext = (0, import_react.createContext)(
395
+ () => {
396
+ }
397
+ );
398
+ function ToastProvider({ children }) {
399
+ const [toasts, setToasts] = (0, import_react.useState)([]);
400
+ const show = (0, import_react.useCallback)((type, message) => {
401
+ const id = Date.now() + Math.random();
402
+ setToasts((t) => [...t, { id, type, message }]);
403
+ setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3500);
404
+ }, []);
405
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ToastContext.Provider, { value: show, children: [
406
+ children,
407
+ toasts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
408
+ "div",
409
+ {
410
+ style: {
411
+ position: "fixed",
412
+ bottom: 24,
413
+ right: 24,
414
+ zIndex: 2e3,
415
+ display: "flex",
416
+ flexDirection: "column",
417
+ gap: 8
418
+ },
419
+ children: toasts.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
420
+ "div",
421
+ {
422
+ className: "dsh-toast",
423
+ style: {
424
+ padding: "12px 18px",
425
+ borderRadius: 8,
426
+ fontSize: 13,
427
+ fontWeight: 500,
428
+ boxShadow: "0 6px 20px rgba(0,0,0,0.2)",
429
+ color: "#fff",
430
+ background: t.type === "success" ? T.success : t.type === "error" ? T.error : T.accent,
431
+ maxWidth: 360
432
+ },
433
+ children: t.message
434
+ },
435
+ t.id
436
+ ))
437
+ }
438
+ )
439
+ ] });
440
+ }
441
+ function useToast() {
442
+ return (0, import_react.useContext)(ToastContext);
443
+ }
444
+ function Spinner({ size = 16 }) {
445
+ ensureStyles();
446
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
447
+ "span",
448
+ {
449
+ className: "dsh-spin",
450
+ style: {
451
+ display: "inline-block",
452
+ width: size,
453
+ height: size,
454
+ border: `2px solid ${T.border}`,
455
+ borderTopColor: T.accent,
456
+ borderRadius: "50%"
457
+ }
458
+ }
459
+ );
460
+ }
461
+ function EmptyState({
462
+ icon,
463
+ message
464
+ }) {
465
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
466
+ "div",
467
+ {
468
+ style: {
469
+ textAlign: "center",
470
+ padding: "36px 16px",
471
+ color: T.muted
472
+ },
473
+ children: [
474
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 36, marginBottom: 10, opacity: 0.4 }, children: icon }),
475
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 13 }, children: message })
476
+ ]
477
+ }
478
+ );
479
+ }
480
+ function SectionTitle({
481
+ icon,
482
+ children,
483
+ actions
484
+ }) {
485
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
486
+ "div",
487
+ {
488
+ style: {
489
+ display: "flex",
490
+ alignItems: "center",
491
+ justifyContent: "space-between",
492
+ marginTop: 6,
493
+ marginBottom: 8
494
+ },
495
+ children: [
496
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
497
+ "span",
498
+ {
499
+ style: {
500
+ fontSize: 14,
501
+ fontWeight: 600,
502
+ display: "flex",
503
+ alignItems: "center",
504
+ gap: 6
505
+ },
506
+ children: [
507
+ icon !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: icon }),
508
+ children
509
+ ]
510
+ }
511
+ ),
512
+ actions
513
+ ]
514
+ }
515
+ );
516
+ }
517
+ var tableStyles = {
518
+ table: {
519
+ borderCollapse: "collapse",
520
+ width: "100%"
521
+ },
522
+ th: {
523
+ textAlign: "left",
524
+ padding: "8px 12px 8px 0",
525
+ fontWeight: 600,
526
+ fontSize: 12,
527
+ color: T.muted,
528
+ borderBottom: `1px solid ${T.border}`
529
+ },
530
+ td: {
531
+ padding: "8px 12px 8px 0",
532
+ fontSize: 13,
533
+ borderBottom: "1px solid rgba(128,128,128,0.08)"
534
+ },
535
+ clickRow: { cursor: "pointer" }
536
+ };
537
+ function usePanel(path) {
538
+ const [payload, setPayload] = (0, import_react.useState)(null);
539
+ const [error, setError] = (0, import_react.useState)(null);
114
540
  const [tick, setTick] = (0, import_react.useState)(0);
115
541
  const reload = (0, import_react.useCallback)(() => setTick((v) => v + 1), []);
116
542
  (0, import_react.useEffect)(() => {
117
543
  const c = new AbortController();
118
- setState((p) => ({ ...p, error: null }));
119
- fetch(PANEL_PATH, { signal: c.signal }).then(async (r) => {
544
+ setError(null);
545
+ fetch(path, { signal: c.signal }).then(async (r) => {
120
546
  if (!r.ok) throw new Error(String(r.status));
121
547
  return r.json();
122
- }).then((payload) => {
123
- if (!c.signal.aborted) setState({ payload, error: null });
548
+ }).then((p) => {
549
+ if (!c.signal.aborted) setPayload(p);
124
550
  }).catch((e) => {
125
- if (!c.signal.aborted) setState({ payload: null, error: e instanceof Error ? e.message : String(e) });
551
+ if (!c.signal.aborted) setPayload(null), setError(e instanceof Error ? e.message : String(e));
126
552
  });
127
553
  return () => c.abort();
128
- }, [tick]);
129
- return { ...state, reload };
554
+ }, [tick, path]);
555
+ return (0, import_react.useMemo)(() => ({ payload, error, reload }), [payload, error, reload]);
130
556
  }
557
+
558
+ // src/client/view.tsx
559
+ var import_jsx_runtime2 = require("react/jsx-runtime");
560
+ var PANEL_PATH = "/api/arena.panel";
561
+ var RUN_PATH = "/api/arena.run";
562
+ var RATE_PATH = "/api/arena.rate";
563
+ var DELETE_PATH = "/api/arena.delete";
131
564
  function Stars({ rating, onRate }) {
132
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: starBtn, onClick: () => onRate(n), title: `${n}/5`, children: n <= rating ? "\u2605" : "\u2606" }, n)) });
133
- }
134
- function Leaderboard({ entries, t }) {
135
- if (entries.length === 0) return null;
136
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: section, children: [
137
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: sectionTitle, children: [
138
- "\u{1F3C6} ",
139
- t("leaderboard")
140
- ] }),
141
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: table, children: [
142
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
143
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: "#" }),
144
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("model") }),
145
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: "Elo" }),
146
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("wins") }),
147
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("avgRating") }),
148
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("runs") })
149
- ] }) }),
150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: entries.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
151
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: i + 1 }),
152
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: e.model }) }),
153
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: e.elo }),
154
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: e.wins }),
155
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: e.avgRating > 0 ? e.avgRating.toFixed(1) : "\u2014" }),
156
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: e.totalRuns })
157
- ] }, e.model)) })
158
- ] })
159
- ] });
160
- }
161
- function StatsSummary({ stats, t }) {
162
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: statRow, children: [
163
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: statBox, children: [
164
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 20, fontWeight: 700 }, children: stats.totalRuns }),
165
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: muted, children: t("totalRuns") })
166
- ] }),
167
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: statBox, children: [
168
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 20, fontWeight: 700 }, children: stats.uniqueModels }),
169
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: muted, children: t("uniqueModels") })
170
- ] }),
171
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: statBox, children: [
172
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 20, fontWeight: 700 }, children: stats.totalRatings }),
173
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: muted, children: t("totalRatings") })
174
- ] })
175
- ] });
565
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { display: "inline-flex", gap: 1 }, children: [1, 2, 3, 4, 5].map((n) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", style: {
566
+ background: "none",
567
+ border: "none",
568
+ cursor: "pointer",
569
+ fontSize: 18,
570
+ color: n <= rating ? "var(--warning, #ed6c02)" : "rgba(128,128,128,0.3)",
571
+ padding: "0 2px"
572
+ }, onClick: () => onRate(n), title: `${n}/5`, children: "\u2605" }, n)) });
176
573
  }
177
- function RunDetail({ runId, t, onDelete }) {
178
- const [run, setRun] = (0, import_react.useState)(null);
179
- const [loading, setLoading] = (0, import_react.useState)(true);
180
- (0, import_react.useEffect)(() => {
574
+ function RunModal({ runId, t, onClose, onDeleted }) {
575
+ const toast = useToast();
576
+ const [run, setRun] = (0, import_react2.useState)(null);
577
+ const [loading, setLoading] = (0, import_react2.useState)(true);
578
+ const [confirmDel, setConfirmDel] = (0, import_react2.useState)(false);
579
+ (0, import_react2.useCallback)(() => {
181
580
  setLoading(true);
182
- fetch(`${RUN_PATH}?id=${runId}`).then((r) => r.json()).then(setRun).catch(() => setRun(null)).finally(() => setLoading(false));
183
- }, [runId]);
184
- const handleRate = (0, import_react.useCallback)((model, rating) => {
185
- fetch(RATE_PATH, {
186
- method: "POST",
187
- headers: { "Content-Type": "application/json" },
188
- body: JSON.stringify({ runId, model, rating })
189
- }).then((r) => r.json()).then(setRun).catch(() => {
581
+ fetch(`${RUN_PATH}?id=${runId}`).then(async (r) => r.json()).then(setRun).catch(() => setRun(null)).finally(() => setLoading(false));
582
+ }, [runId])();
583
+ const handleRate = (0, import_react2.useCallback)((model, rating) => {
584
+ fetch(RATE_PATH, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ runId, model, rating }) }).then(async (r) => r.json()).then(setRun).catch(() => {
190
585
  });
191
586
  }, [runId]);
192
- const handleDelete = (0, import_react.useCallback)(() => {
193
- if (!confirm(t("confirmDelete"))) return;
194
- fetch(DELETE_PATH, {
195
- method: "POST",
196
- headers: { "Content-Type": "application/json" },
197
- body: JSON.stringify({ runId })
198
- }).then(() => onDelete()).catch(() => {
199
- });
200
- }, [runId, t, onDelete]);
201
- if (loading) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: muted, children: t("loading") });
202
- if (!run) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: muted, children: t("notFound") });
203
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...card, marginTop: 4 }, children: [
204
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
205
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { children: [
206
- t("prompt"),
207
- ": "
208
- ] }),
209
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", style: dangerBtn, onClick: handleDelete, children: t("delete") })
210
- ] }),
211
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: preBlock, children: run.prompt }),
212
- run.reference && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { marginTop: 6 }, children: [
213
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 2 }, children: [
214
- t("reference"),
215
- ":"
216
- ] }),
217
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: preBlock, children: run.reference })
218
- ] }),
219
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 8 }, children: run.results.map((r) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { ...card, marginTop: 6 }, children: [
220
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
221
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: r.model }),
222
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: r.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { ...badge, background: "rgba(255,80,80,0.15)", color: "#e55" }, children: t("error") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { ...badge, background: "rgba(80,200,120,0.15)", color: "#4a4" }, children: [
223
- r.latencyMs,
224
- "ms"
225
- ] }) })
587
+ const handleDelete = (0, import_react2.useCallback)(async () => {
588
+ const r = await fetch(DELETE_PATH, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ runId }) });
589
+ if (r.ok) {
590
+ toast("success", t("deleted"));
591
+ onDeleted();
592
+ onClose();
593
+ }
594
+ }, [runId, t, toast, onDeleted, onClose]);
595
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
596
+ Modal,
597
+ {
598
+ title: `${t("run")} ${runId.slice(0, 8)}\u2026`,
599
+ onClose,
600
+ width: 720,
601
+ footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Button, { variant: "danger", size: "sm", onClick: () => setConfirmDel(true), children: [
602
+ "\u{1F5D1} ",
603
+ t("delete")
226
604
  ] }),
227
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: preBlock, children: r.error ?? r.output }),
228
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 4 }, children: [
229
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: muted, children: [
230
- r.promptTokens + r.completionTokens,
231
- " tokens (",
232
- r.promptTokens,
233
- "\u2191 ",
234
- r.completionTokens,
235
- "\u2193)"
605
+ children: [
606
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: 20 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: 24 }) }) : run === null ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { message: t("notFound") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
607
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: t("prompt"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { style: { whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: 12, margin: 0 }, children: run.prompt }) }),
608
+ run.reference && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { title: t("reference"), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { style: { whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: 12, margin: 0 }, children: run.reference }) }),
609
+ run.results.map((r) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Card, { children: [
610
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
611
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { style: { fontSize: 13 }, children: r.model }),
612
+ r.error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { color: "error", children: t("error") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Badge, { color: "success", children: [
613
+ r.latencyMs,
614
+ "ms"
615
+ ] })
616
+ ] }),
617
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("pre", { style: { whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: 12, margin: 0, padding: 8, borderRadius: 6, background: "rgba(128,128,128,0.06)", maxHeight: 150, overflow: "auto" }, children: r.error ?? r.output }),
618
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 8 }, children: [
619
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { fontSize: 11, opacity: 0.6 }, children: [
620
+ r.promptTokens + r.completionTokens,
621
+ " tokens"
622
+ ] }),
623
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Stars, { rating: r.rating ?? 0, onRate: (n) => handleRate(r.model, n) })
624
+ ] })
625
+ ] }, r.model))
236
626
  ] }),
237
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Stars, { rating: r.rating ?? 0, onRate: (n) => handleRate(r.model, n) })
238
- ] })
239
- ] }, r.model)) })
240
- ] });
627
+ confirmDel && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
628
+ ConfirmDialog,
629
+ {
630
+ title: t("delete"),
631
+ message: t("confirmDelete"),
632
+ confirmLabel: t("delete"),
633
+ danger: true,
634
+ onConfirm: handleDelete,
635
+ onClose: () => setConfirmDel(false)
636
+ }
637
+ )
638
+ ]
639
+ }
640
+ );
241
641
  }
242
- function ArenaPanel({ t }) {
243
- const { payload, error, reload } = usePanel();
244
- const [expandedRun, setExpandedRun] = (0, import_react.useState)(null);
245
- const header = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("header", { style: head, children: [
246
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { style: { fontSize: 14 }, children: [
642
+ function ArenaPanelInner({ t }) {
643
+ const { payload, error, reload } = usePanel(PANEL_PATH);
644
+ const [runModal, setRunModal] = (0, import_react2.useState)(null);
645
+ const header = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("header", { style: { display: "flex", alignItems: "center", gap: 12, marginBottom: 4 }, children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { style: { fontSize: 15 }, children: [
247
647
  "\u2694\uFE0F ",
248
648
  t("title")
249
649
  ] }),
250
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
251
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: reload, style: { fontSize: 12 }, children: t("refresh") })
650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { flex: 1 } }),
651
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { variant: "secondary", size: "sm", onClick: reload, children: t("refresh") })
252
652
  ] });
253
- if (error !== null) {
254
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: wrap, children: [
255
- header,
256
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { role: "alert", style: { margin: 0, fontSize: 13 }, children: [
257
- t("failed"),
258
- ": ",
259
- error
260
- ] }),
261
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", onClick: reload, style: { alignSelf: "flex-start", fontSize: 12 }, children: t("retry") })
262
- ] });
263
- }
264
- if (payload === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: muted, "aria-live": "polite", children: t("loading") });
265
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: wrap, children: [
653
+ if (error !== null) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: 820 }, children: [
266
654
  header,
267
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatsSummary, { stats: payload.stats, t }),
268
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Leaderboard, { entries: payload.leaderboard, t }),
269
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: section, children: [
270
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: sectionTitle, children: [
271
- "\u{1F4CB} ",
272
- t("recentRuns")
273
- ] }),
274
- payload.recentRuns.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontSize: 13, opacity: 0.8 }, children: t("empty") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { style: table, children: [
275
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
276
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("run") }),
277
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("models") }),
278
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("winner") }),
279
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { style: th, children: t("date") })
655
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { role: "alert", style: { margin: 0, fontSize: 13, color: "var(--error, #e53935)" }, children: [
656
+ t("failed"),
657
+ ": ",
658
+ error
659
+ ] }) })
660
+ ] });
661
+ if (payload === null) return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { maxWidth: 820 }, children: [
662
+ header,
663
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: 40 }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Spinner, { size: 28 }) })
664
+ ] });
665
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 14, maxWidth: 820 }, children: [
666
+ header,
667
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", gap: 10, flexWrap: "wrap" }, children: [
668
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.stats.totalRuns, label: t("totalRuns") }),
669
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.stats.uniqueModels, label: t("uniqueModels") }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StatCard, { value: payload.stats.totalRatings, label: t("totalRatings") })
671
+ ] }),
672
+ payload.leaderboard.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
673
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionTitle, { icon: "\u{1F3C6}", children: t("leaderboard") }),
674
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { padding: 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: tableStyles.table, children: [
675
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: "#" }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("model") }),
678
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: "Elo" }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("wins") }),
680
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("avgRating") }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("runs") })
280
682
  ] }) }),
281
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: payload.recentRuns.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
282
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { style: clickRow, onClick: () => setExpandedRun(expandedRun === row.id ? null : row.id), children: [
283
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("td", { style: td, children: [
284
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { style: { fontSize: 11 }, children: row.id }),
285
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { marginLeft: 6, fontSize: 10 }, children: expandedRun === row.id ? "\u25BC" : "\u25B6" })
286
- ] }),
287
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: row.modelCount }),
288
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: row.winner ?? "\u2014" }),
289
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: td, children: new Date(row.timestamp).toLocaleString() })
290
- ] }, row.id),
291
- expandedRun === row.id && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { colSpan: 4, style: { padding: "4px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RunDetail, { runId: row.id, t, onDelete: () => {
292
- setExpandedRun(null);
293
- reload();
294
- } }) }) }, `${row.id}-detail`)
295
- ] })) })
296
- ] })
297
- ] })
683
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: payload.leaderboard.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: i + 1 }),
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: e.model }) }),
686
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: e.elo }),
687
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: e.wins }),
688
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: e.avgRating > 0 ? e.avgRating.toFixed(1) : "\u2014" }),
689
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: e.totalRuns })
690
+ ] }, e.model)) })
691
+ ] }) })
692
+ ] }),
693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionTitle, { icon: "\u{1F4CB}", children: t("recentRuns") }),
694
+ payload.recentRuns.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptyState, { icon: "\u{1F4ED}", message: t("empty") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card, { padding: 0, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("table", { style: tableStyles.table, children: [
695
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { children: [
696
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("run") }),
697
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("models") }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("winner") }),
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { style: tableStyles.th, children: t("date") })
700
+ ] }) }),
701
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("tbody", { children: payload.recentRuns.map((row) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("tr", { style: tableStyles.clickRow, onClick: () => setRunModal(row.id), children: [
702
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { style: { fontSize: 11 }, children: row.id.slice(0, 8) }) }),
703
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: row.modelCount }),
704
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: row.winner ?? "\u2014" }),
705
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { style: tableStyles.td, children: new Date(row.timestamp).toLocaleString() })
706
+ ] }, row.id)) })
707
+ ] }) }),
708
+ runModal !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RunModal, { runId: runModal, t, onClose: () => setRunModal(null), onDeleted: reload })
298
709
  ] });
299
710
  }
711
+ function ArenaPanel({ t }) {
712
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ToastProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ArenaPanelInner, { t }) });
713
+ }
300
714
 
301
715
  // src/client/index.tsx
302
716
  var inject = ["slots", "locale"];