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 +596 -182
- package/lib/arena.web.js.map +4 -4
- package/lib/client/ui.d.ts +124 -0
- package/lib/client/ui.js +388 -0
- package/lib/client/view.d.ts +3 -17
- package/lib/client/view.js +39 -99
- package/package.json +1 -1
package/lib/arena.web.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/client/index.tsx", "../src/client/locales.ts", "../src/client/view.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Browser half of dsh-model-arena: its page inside Settings.\n *\n * Two services are injected by their runtime identity, not by the packages that provide\n * them: the settings shell is `slots`, the dictionary registry is `locale`. The label and\n * every string inside the component are translated through this plugin's own namespace,\n * which is why the page follows the UI language instead of the plugin author's.\n *\n * @module client\n */\n\nimport type { ComponentType } from 'react'\n\nimport { NS, en, zh } from './locales.js'\nimport { ArenaPanel } from './view.js'\n\nexport const inject = ['slots', 'locale']\n\ninterface SlotsService {\n inject(name: string, register: () => void): void\n register(\n options: { name: string; id: string; order: number; label: () => string; locale: string },\n component: ComponentType<{ t: (key: string, params?: Record<string, unknown>) => string }>,\n ): unknown\n}\n\ninterface ClientContext {\n slots: SlotsService\n locale: {\n register(ns: string, dicts: { zh: unknown; en: unknown }): () => void\n bind(ns: string): (key: string, params?: Record<string, unknown>) => string\n }\n effect(callback: () => unknown, label?: string): unknown\n}\n\nexport function apply(ctx: ClientContext): void {\n // `zh` is the key-set source of truth, matching the official client plugins.\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-arena: dictionaries')\n\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n {\n name: 'settings.section',\n id: 'model-arena',\n order: 42,\n label: () => ctx.locale.bind(NS)('nav'),\n locale: NS,\n },\n ArenaPanel,\n ))\n}\n", "/**\n * Dictionaries for the Model Arena page.\n *\n * `zh` is the key-set source of truth, as in the official client plugins, and `en` is\n * typed against it: a key translated in one language but not the other fails the build\n * instead of silently rendering the raw key.\n *\n * @module client/locales\n */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelArena'\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'nav': '\u6A21\u578B\u7ADE\u6280\u573A',\n 'title': '\u6A21\u578B\u7ADE\u6280\u573A',\n 'run': '\u8FD0\u884C',\n 'models': '\u6A21\u578B\u6570',\n 'model': '\u6A21\u578B',\n 'date': '\u65F6\u95F4',\n 'prompt': '\u63D0\u793A\u8BCD',\n 'empty': '\u8FD8\u6CA1\u6709\u8FD0\u884C\u8BB0\u5F55\u3002\u7528\u540C\u4E00\u4E2A\u63D0\u793A\u8BCD\u8DD1\u591A\u4E2A\u6A21\u578B\u540E\uFF0C\u7ED3\u679C\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002',\n 'refresh': '\u5237\u65B0',\n 'loading': '\u6B63\u5728\u52A0\u8F7D\u2026',\n 'failed': '\u52A0\u8F7D\u5931\u8D25',\n 'retry': '\u91CD\u8BD5',\n 'leaderboard': 'Elo \u6392\u884C\u699C',\n 'wins': '\u80DC',\n 'avgRating': '\u5E73\u5747\u8BC4\u5206',\n 'runs': '\u6B21\u6570',\n 'totalRuns': '\u603B\u8FD0\u884C\u6570',\n 'uniqueModels': '\u6A21\u578B\u79CD\u7C7B',\n 'totalRatings': '\u603B\u8BC4\u5206\u6570',\n 'recentRuns': '\u6700\u8FD1\u8FD0\u884C',\n 'winner': '\u80DC\u51FA',\n 'reference': '\u53C2\u8003\u7B54\u6848',\n 'error': '\u9519\u8BEF',\n 'delete': '\u5220\u9664',\n 'confirmDelete': '\u786E\u5B9A\u5220\u9664\u8FD9\u6761\u8FD0\u884C\u8BB0\u5F55\uFF1F',\n 'notFound': '\u672A\u627E\u5230\u8FD0\u884C\u8BB0\u5F55',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: typeof zh = {\n 'nav': 'Model Arena',\n 'title': 'Model Arena',\n 'run': 'Run',\n 'models': 'Models',\n 'model': 'Model',\n 'date': 'Date',\n 'prompt': 'Prompt',\n 'empty': 'No runs yet. Run one prompt through several models and the comparison appears here.',\n 'refresh': 'Refresh',\n 'loading': 'Loading\u2026',\n 'failed': 'Failed to load',\n 'retry': 'Retry',\n 'leaderboard': 'Elo Leaderboard',\n 'wins': 'Wins',\n 'avgRating': 'Avg Rating',\n 'runs': 'Runs',\n 'totalRuns': 'Total Runs',\n 'uniqueModels': 'Models',\n 'totalRatings': 'Ratings',\n 'recentRuns': 'Recent Runs',\n 'winner': 'Winner',\n 'reference': 'Reference',\n 'error': 'Error',\n 'delete': 'Delete',\n 'confirmDelete': 'Delete this run?',\n 'notFound': 'Run not found',\n}\n", "/**\n * Pure rendering half of the modelArena page.\n *\n * Separate from `index.tsx` so a static render can assert in Node what the page draws \u2014\n * the shipped bundle is a loader factory only a browser can run. Every user-visible\n * string comes from the `t` seat the renderer binds from this plugin's namespace, so the\n * page follows the UI language; no copy is hardcoded here.\n *\n * @module client/view\n */\n\nimport { useCallback, useEffect, useState } from 'react'\nimport type { CSSProperties } from 'react'\n\nimport type { PanelPayload, LeaderboardEntry, ArenaStats, RunSummary, ArenaRun } from '../types.js'\n\nexport type Translate = (key: string, params?: Record<string, unknown>) => string\n\nexport interface PanelProps {\n t: Translate\n}\n\nconst PANEL_PATH = '/api/arena.panel'\nconst RUN_PATH = '/api/arena.run'\nconst RATE_PATH = '/api/arena.rate'\nconst DELETE_PATH = '/api/arena.delete'\n\n// --- Styles ---\nconst wrap: CSSProperties = { display: 'flex', flexDirection: 'column', gap: 14, maxWidth: 820, fontFamily: 'inherit' }\nconst head: CSSProperties = { display: 'flex', alignItems: 'baseline', gap: 12, flexWrap: 'wrap' }\nconst section: CSSProperties = { marginTop: 8 }\nconst sectionTitle: CSSProperties = { fontSize: 13, fontWeight: 600, marginBottom: 6 }\nconst muted: CSSProperties = { fontSize: 12, opacity: 0.75 }\nconst table: CSSProperties = { borderCollapse: 'collapse', width: '100%' }\nconst th: CSSProperties = { textAlign: 'left', padding: '4px 10px 4px 0', fontWeight: 600, fontSize: 12, opacity: 0.8, borderBottom: '0.5px solid rgba(128,128,128,0.4)' }\nconst td: CSSProperties = { padding: '6px 10px 6px 0', fontSize: 13, borderBottom: '0.5px solid rgba(128,128,128,0.18)' }\nconst card: CSSProperties = { padding: '8px 12px', borderRadius: 6, border: '1px solid rgba(128,128,128,0.2)', background: 'rgba(128,128,128,0.04)', fontSize: 13 }\nconst badge: CSSProperties = { display: 'inline-block', padding: '1px 6px', borderRadius: 9, fontSize: 11, fontWeight: 600 }\nconst statRow: CSSProperties = { display: 'flex', gap: 16, flexWrap: 'wrap' }\nconst statBox: CSSProperties = { ...card, flex: 1, minWidth: 100, textAlign: 'center' as const }\nconst starBtn: CSSProperties = { cursor: 'pointer', background: 'none', border: 'none', fontSize: 16, padding: '0 1px' }\nconst clickRow: CSSProperties = { cursor: 'pointer' }\nconst preBlock: CSSProperties = { 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)' }\nconst dangerBtn: CSSProperties = { fontSize: 11, color: '#e55', background: 'none', border: '1px solid #e55', borderRadius: 4, padding: '2px 8px', cursor: 'pointer' }\n\ninterface PanelState {\n payload: PanelPayload | null\n error: string | null\n}\n\nexport function usePanel(): PanelState & { reload: () => void } {\n const [state, setState] = useState<PanelState>({ payload: null, error: null })\n const [tick, setTick] = useState(0)\n const reload = useCallback(() => setTick((v) => v + 1), [])\n useEffect(() => {\n const c = new AbortController()\n setState((p) => ({ ...p, error: null }))\n fetch(PANEL_PATH, { signal: c.signal })\n .then(async (r) => {\n if (!r.ok) throw new Error(String(r.status))\n return r.json() as Promise<PanelPayload>\n })\n .then((payload) => { if (!c.signal.aborted) setState({ payload, error: null }) })\n .catch((e: unknown) => { if (!c.signal.aborted) setState({ payload: null, error: e instanceof Error ? e.message : String(e) }) })\n return () => c.abort()\n }, [tick])\n return { ...state, reload }\n}\n\n// --- Stars ---\nfunction Stars({ rating, onRate }: { rating: number; onRate: (n: number) => void }) {\n return (\n <span>\n {[1, 2, 3, 4, 5].map((n) => (\n <button key={n} type=\"button\" style={starBtn} onClick={() => onRate(n)} title={`${n}/5`}>\n {n <= rating ? '\u2605' : '\u2606'}\n </button>\n ))}\n </span>\n )\n}\n\n// --- Leaderboard ---\nfunction Leaderboard({ entries, t }: { entries: LeaderboardEntry[]; t: Translate }) {\n if (entries.length === 0) return null\n return (\n <div style={section}>\n <div style={sectionTitle}>\uD83C\uDFC6 {t('leaderboard')}</div>\n <table style={table}>\n <thead>\n <tr>\n <th style={th}>#</th>\n <th style={th}>{t('model')}</th>\n <th style={th}>Elo</th>\n <th style={th}>{t('wins')}</th>\n <th style={th}>{t('avgRating')}</th>\n <th style={th}>{t('runs')}</th>\n </tr>\n </thead>\n <tbody>\n {entries.map((e, i) => (\n <tr key={e.model}>\n <td style={td}>{i + 1}</td>\n <td style={td}><strong>{e.model}</strong></td>\n <td style={td}>{e.elo}</td>\n <td style={td}>{e.wins}</td>\n <td style={td}>{e.avgRating > 0 ? e.avgRating.toFixed(1) : '\u2014'}</td>\n <td style={td}>{e.totalRuns}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n )\n}\n\n// --- Stats summary ---\nfunction StatsSummary({ stats, t }: { stats: ArenaStats; t: Translate }) {\n return (\n <div style={statRow}>\n <div style={statBox}><div style={{ fontSize: 20, fontWeight: 700 }}>{stats.totalRuns}</div><div style={muted}>{t('totalRuns')}</div></div>\n <div style={statBox}><div style={{ fontSize: 20, fontWeight: 700 }}>{stats.uniqueModels}</div><div style={muted}>{t('uniqueModels')}</div></div>\n <div style={statBox}><div style={{ fontSize: 20, fontWeight: 700 }}>{stats.totalRatings}</div><div style={muted}>{t('totalRatings')}</div></div>\n </div>\n )\n}\n\n// --- Run detail expansion ---\nfunction RunDetail({ runId, t, onDelete }: { runId: string; t: Translate; onDelete: () => void }) {\n const [run, setRun] = useState<ArenaRun | null>(null)\n const [loading, setLoading] = useState(true)\n useEffect(() => {\n setLoading(true)\n fetch(`${RUN_PATH}?id=${runId}`)\n .then((r) => r.json() as Promise<ArenaRun>)\n .then(setRun)\n .catch(() => setRun(null))\n .finally(() => setLoading(false))\n }, [runId])\n\n const handleRate = useCallback((model: string, rating: number) => {\n fetch(RATE_PATH, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ runId, model, rating }),\n })\n .then((r) => r.json() as Promise<ArenaRun>)\n .then(setRun)\n .catch(() => {})\n }, [runId])\n\n const handleDelete = useCallback(() => {\n if (!confirm(t('confirmDelete'))) return\n fetch(DELETE_PATH, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ runId }),\n }).then(() => onDelete()).catch(() => {})\n }, [runId, t, onDelete])\n\n if (loading) return <p style={muted}>{t('loading')}</p>\n if (!run) return <p style={muted}>{t('notFound')}</p>\n return (\n <div style={{ ...card, marginTop: 4 }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>\n <strong>{t('prompt')}: </strong>\n <button type=\"button\" style={dangerBtn} onClick={handleDelete}>{t('delete')}</button>\n </div>\n <div style={preBlock}>{run.prompt}</div>\n {run.reference && (\n <div style={{ marginTop: 6 }}>\n <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 2 }}>{t('reference')}:</div>\n <div style={preBlock}>{run.reference}</div>\n </div>\n )}\n <div style={{ marginTop: 8 }}>\n {run.results.map((r) => (\n <div key={r.model} style={{ ...card, marginTop: 6 }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <strong>{r.model}</strong>\n <span>\n {r.error ? (\n <span style={{ ...badge, background: 'rgba(255,80,80,0.15)', color: '#e55' }}>{t('error')}</span>\n ) : (\n <span style={{ ...badge, background: 'rgba(80,200,120,0.15)', color: '#4a4' }}>{r.latencyMs}ms</span>\n )}\n </span>\n </div>\n <div style={preBlock}>{r.error ?? r.output}</div>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 4 }}>\n <span style={muted}>{r.promptTokens + r.completionTokens} tokens ({r.promptTokens}\u2191 {r.completionTokens}\u2193)</span>\n <Stars rating={r.rating ?? 0} onRate={(n) => handleRate(r.model, n)} />\n </div>\n </div>\n ))}\n </div>\n </div>\n )\n}\n\n// --- Main Panel ---\nexport function ArenaPanel({ t }: PanelProps) {\n const { payload, error, reload } = usePanel()\n const [expandedRun, setExpandedRun] = useState<string | null>(null)\n\n const header = (\n <header style={head}>\n <strong style={{ fontSize: 14 }}>\u2694\uFE0F {t('title')}</strong>\n <span style={{ flex: 1 }} />\n <button type=\"button\" onClick={reload} style={{ fontSize: 12 }}>{t('refresh')}</button>\n </header>\n )\n if (error !== null) {\n return (\n <div style={wrap}>\n {header}\n <p role=\"alert\" style={{ margin: 0, fontSize: 13 }}>{t('failed')}: {error}</p>\n <button type=\"button\" onClick={reload} style={{ alignSelf: 'flex-start', fontSize: 12 }}>{t('retry')}</button>\n </div>\n )\n }\n if (payload === null) return <p style={muted} aria-live=\"polite\">{t('loading')}</p>\n return (\n <div style={wrap}>\n {header}\n\n {/* Stats */}\n <StatsSummary stats={payload.stats} t={t} />\n\n {/* Leaderboard */}\n <Leaderboard entries={payload.leaderboard} t={t} />\n\n {/* Recent runs */}\n <div style={section}>\n <div style={sectionTitle}>\uD83D\uDCCB {t('recentRuns')}</div>\n {payload.recentRuns.length === 0 ? (\n <p style={{ margin: 0, fontSize: 13, opacity: 0.8 }}>{t('empty')}</p>\n ) : (\n <table style={table}>\n <thead>\n <tr><th style={th}>{t('run')}</th><th style={th}>{t('models')}</th><th style={th}>{t('winner')}</th><th style={th}>{t('date')}</th></tr>\n </thead>\n <tbody>\n {payload.recentRuns.map((row) => (\n <>\n <tr key={row.id} style={clickRow} onClick={() => setExpandedRun(expandedRun === row.id ? null : row.id)}>\n <td style={td}>\n <code style={{ fontSize: 11 }}>{row.id}</code>\n <span style={{ marginLeft: 6, fontSize: 10 }}>{expandedRun === row.id ? '\u25BC' : '\u25B6'}</span>\n </td>\n <td style={td}>{row.modelCount}</td>\n <td style={td}>{row.winner ?? '\u2014'}</td>\n <td style={td}>{new Date(row.timestamp).toLocaleString()}</td>\n </tr>\n {expandedRun === row.id && (\n <tr key={`${row.id}-detail`}>\n <td colSpan={4} style={{ padding: '4px 0' }}>\n <RunDetail runId={row.id} t={t} onDelete={() => { setExpandedRun(null); reload() }} />\n </td>\n </tr>\n )}\n </>\n ))}\n </tbody>\n </table>\n )}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
3
|
+
"sources": ["../src/client/index.tsx", "../src/client/locales.ts", "../src/client/view.tsx", "../src/client/ui.tsx"],
|
|
4
|
+
"sourcesContent": ["/**\n * Browser half of dsh-model-arena: its page inside Settings.\n *\n * Two services are injected by their runtime identity, not by the packages that provide\n * them: the settings shell is `slots`, the dictionary registry is `locale`. The label and\n * every string inside the component are translated through this plugin's own namespace,\n * which is why the page follows the UI language instead of the plugin author's.\n *\n * @module client\n */\n\nimport type { ComponentType } from 'react'\n\nimport { NS, en, zh } from './locales.js'\nimport { ArenaPanel } from './view.js'\n\nexport const inject = ['slots', 'locale']\n\ninterface SlotsService {\n inject(name: string, register: () => void): void\n register(\n options: { name: string; id: string; order: number; label: () => string; locale: string },\n component: ComponentType<{ t: (key: string, params?: Record<string, unknown>) => string }>,\n ): unknown\n}\n\ninterface ClientContext {\n slots: SlotsService\n locale: {\n register(ns: string, dicts: { zh: unknown; en: unknown }): () => void\n bind(ns: string): (key: string, params?: Record<string, unknown>) => string\n }\n effect(callback: () => unknown, label?: string): unknown\n}\n\nexport function apply(ctx: ClientContext): void {\n // `zh` is the key-set source of truth, matching the official client plugins.\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-model-arena: dictionaries')\n\n ctx.slots.inject('settings.section', () => ctx.slots.register(\n {\n name: 'settings.section',\n id: 'model-arena',\n order: 42,\n label: () => ctx.locale.bind(NS)('nav'),\n locale: NS,\n },\n ArenaPanel,\n ))\n}\n", "/**\n * Dictionaries for the Model Arena page.\n *\n * `zh` is the key-set source of truth, as in the official client plugins, and `en` is\n * typed against it: a key translated in one language but not the other fails the build\n * instead of silently rendering the raw key.\n *\n * @module client/locales\n */\n\n/** Dictionary namespace owned by this plugin. */\nexport const NS = 'modelArena'\n\n/** Simplified Chinese dictionary (the key-set source of truth). */\nexport const zh = {\n 'nav': '\u6A21\u578B\u7ADE\u6280\u573A',\n 'title': '\u6A21\u578B\u7ADE\u6280\u573A',\n 'run': '\u8FD0\u884C',\n 'models': '\u6A21\u578B\u6570',\n 'model': '\u6A21\u578B',\n 'date': '\u65F6\u95F4',\n 'prompt': '\u63D0\u793A\u8BCD',\n 'empty': '\u8FD8\u6CA1\u6709\u8FD0\u884C\u8BB0\u5F55\u3002\u7528\u540C\u4E00\u4E2A\u63D0\u793A\u8BCD\u8DD1\u591A\u4E2A\u6A21\u578B\u540E\uFF0C\u7ED3\u679C\u4F1A\u663E\u793A\u5728\u8FD9\u91CC\u3002',\n 'refresh': '\u5237\u65B0',\n 'loading': '\u6B63\u5728\u52A0\u8F7D\u2026',\n 'failed': '\u52A0\u8F7D\u5931\u8D25',\n 'retry': '\u91CD\u8BD5',\n 'leaderboard': 'Elo \u6392\u884C\u699C',\n 'wins': '\u80DC',\n 'avgRating': '\u5E73\u5747\u8BC4\u5206',\n 'runs': '\u6B21\u6570',\n 'totalRuns': '\u603B\u8FD0\u884C\u6570',\n 'uniqueModels': '\u6A21\u578B\u79CD\u7C7B',\n 'totalRatings': '\u603B\u8BC4\u5206\u6570',\n 'recentRuns': '\u6700\u8FD1\u8FD0\u884C',\n 'winner': '\u80DC\u51FA',\n 'reference': '\u53C2\u8003\u7B54\u6848',\n 'error': '\u9519\u8BEF',\n 'delete': '\u5220\u9664',\n 'confirmDelete': '\u786E\u5B9A\u5220\u9664\u8FD9\u6761\u8FD0\u884C\u8BB0\u5F55\uFF1F',\n 'notFound': '\u672A\u627E\u5230\u8FD0\u884C\u8BB0\u5F55',\n}\n\n/** English dictionary, checked complete against the zh key set. */\nexport const en: typeof zh = {\n 'nav': 'Model Arena',\n 'title': 'Model Arena',\n 'run': 'Run',\n 'models': 'Models',\n 'model': 'Model',\n 'date': 'Date',\n 'prompt': 'Prompt',\n 'empty': 'No runs yet. Run one prompt through several models and the comparison appears here.',\n 'refresh': 'Refresh',\n 'loading': 'Loading\u2026',\n 'failed': 'Failed to load',\n 'retry': 'Retry',\n 'leaderboard': 'Elo Leaderboard',\n 'wins': 'Wins',\n 'avgRating': 'Avg Rating',\n 'runs': 'Runs',\n 'totalRuns': 'Total Runs',\n 'uniqueModels': 'Models',\n 'totalRatings': 'Ratings',\n 'recentRuns': 'Recent Runs',\n 'winner': 'Winner',\n 'reference': 'Reference',\n 'error': 'Error',\n 'delete': 'Delete',\n 'confirmDelete': 'Delete this run?',\n 'notFound': 'Run not found',\n}\n", "/**\n * Pure rendering half of the modelArena page. Uses shared UI kit.\n * @module client/view\n */\n\nimport { useCallback, useState } from 'react'\nimport type { ReactNode } from 'react'\n\nimport type { PanelPayload, ArenaRun } from '../types.js'\nimport {\n Badge, Button, Card, ConfirmDialog, EmptyState, Modal, SectionTitle,\n Spinner, StatCard, ToastProvider, tableStyles, usePanel, useToast,\n} from './ui.js'\n\nexport type Translate = (key: string, params?: Record<string, unknown>) => string\nexport interface PanelProps { t: Translate }\n\nconst PANEL_PATH = '/api/arena.panel'\nconst RUN_PATH = '/api/arena.run'\nconst RATE_PATH = '/api/arena.rate'\nconst DELETE_PATH = '/api/arena.delete'\n\nfunction Stars({ rating, onRate }: { rating: number; onRate: (n: number) => void }): ReactNode {\n return (\n <span style={{ display: 'inline-flex', gap: 1 }}>\n {[1, 2, 3, 4, 5].map((n) => (\n <button key={n} type=\"button\" style={{\n background: 'none', border: 'none', cursor: 'pointer', fontSize: 18,\n color: n <= rating ? 'var(--warning, #ed6c02)' : 'rgba(128,128,128,0.3)',\n padding: '0 2px',\n }} onClick={() => onRate(n)} title={`${n}/5`}>\u2605</button>\n ))}\n </span>\n )\n}\n\nfunction RunModal({ runId, t, onClose, onDeleted }: {\n runId: string; t: Translate; onClose: () => void; onDeleted: () => void\n}): ReactNode {\n const toast = useToast()\n const [run, setRun] = useState<ArenaRun | null>(null)\n const [loading, setLoading] = useState(true)\n const [confirmDel, setConfirmDel] = useState(false)\n\n useCallback(() => {\n setLoading(true)\n fetch(`${RUN_PATH}?id=${runId}`).then(async (r) => r.json() as Promise<ArenaRun>)\n .then(setRun).catch(() => setRun(null)).finally(() => setLoading(false))\n }, [runId])()\n\n const handleRate = useCallback((model: string, rating: number) => {\n fetch(RATE_PATH, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ runId, model, rating }) })\n .then(async (r) => r.json() as Promise<ArenaRun>).then(setRun).catch(() => {})\n }, [runId])\n\n const handleDelete = useCallback(async () => {\n const r = await fetch(DELETE_PATH, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ runId }) })\n if (r.ok) { toast('success', t('deleted')); onDeleted(); onClose() }\n }, [runId, t, toast, onDeleted, onClose])\n\n return (\n <Modal title={`${t('run')} ${runId.slice(0, 8)}\u2026`} onClose={onClose} width={720}\n footer={<Button variant=\"danger\" size=\"sm\" onClick={() => setConfirmDel(true)}>\uD83D\uDDD1 {t('delete')}</Button>}>\n {loading ? <div style={{ display: 'flex', justifyContent: 'center', padding: 20 }}><Spinner size={24} /></div>\n : run === null ? <EmptyState message={t('notFound')} />\n : (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>\n <Card title={t('prompt')}><pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', fontSize: 12, margin: 0 }}>{run.prompt}</pre></Card>\n {run.reference && <Card title={t('reference')}><pre style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word', fontSize: 12, margin: 0 }}>{run.reference}</pre></Card>}\n {run.results.map((r) => (\n <Card key={r.model}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>\n <strong style={{ fontSize: 13 }}>{r.model}</strong>\n {r.error ? <Badge color=\"error\">{t('error')}</Badge> : <Badge color=\"success\">{r.latencyMs}ms</Badge>}\n </div>\n <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' }}>{r.error ?? r.output}</pre>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 8 }}>\n <span style={{ fontSize: 11, opacity: 0.6 }}>{r.promptTokens + r.completionTokens} tokens</span>\n <Stars rating={r.rating ?? 0} onRate={(n) => handleRate(r.model, n)} />\n </div>\n </Card>\n ))}\n </div>\n )}\n {confirmDel && <ConfirmDialog title={t('delete')} message={t('confirmDelete')} confirmLabel={t('delete')}\n danger onConfirm={handleDelete} onClose={() => setConfirmDel(false)} />}\n </Modal>\n )\n}\n\nfunction ArenaPanelInner({ t }: PanelProps): ReactNode {\n const { payload, error, reload } = usePanel<PanelPayload>(PANEL_PATH)\n const [runModal, setRunModal] = useState<string | null>(null)\n\n const header = (\n <header style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 4 }}>\n <strong style={{ fontSize: 15 }}>\u2694\uFE0F {t('title')}</strong>\n <span style={{ flex: 1 }} />\n <Button variant=\"secondary\" size=\"sm\" onClick={reload}>{t('refresh')}</Button>\n </header>\n )\n\n if (error !== null) return <div style={{ maxWidth: 820 }}>{header}<Card><p role=\"alert\" style={{ margin: 0, fontSize: 13, color: 'var(--error, #e53935)' }}>{t('failed')}: {error}</p></Card></div>\n if (payload === null) return <div style={{ maxWidth: 820 }}>{header}<div style={{ display: 'flex', justifyContent: 'center', padding: 40 }}><Spinner size={28} /></div></div>\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 14, maxWidth: 820 }}>\n {header}\n\n <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>\n <StatCard value={payload.stats.totalRuns} label={t('totalRuns')} />\n <StatCard value={payload.stats.uniqueModels} label={t('uniqueModels')} />\n <StatCard value={payload.stats.totalRatings} label={t('totalRatings')} />\n </div>\n\n {payload.leaderboard.length > 0 && (\n <>\n <SectionTitle icon=\"\uD83C\uDFC6\">{t('leaderboard')}</SectionTitle>\n <Card padding={0}>\n <table style={tableStyles.table}>\n <thead><tr><th style={tableStyles.th}>#</th><th style={tableStyles.th}>{t('model')}</th><th style={tableStyles.th}>Elo</th><th style={tableStyles.th}>{t('wins')}</th><th style={tableStyles.th}>{t('avgRating')}</th><th style={tableStyles.th}>{t('runs')}</th></tr></thead>\n <tbody>\n {payload.leaderboard.map((e, i) => (\n <tr key={e.model}><td style={tableStyles.td}>{i + 1}</td><td style={tableStyles.td}><strong>{e.model}</strong></td>\n <td style={tableStyles.td}>{e.elo}</td><td style={tableStyles.td}>{e.wins}</td>\n <td style={tableStyles.td}>{e.avgRating > 0 ? e.avgRating.toFixed(1) : '\u2014'}</td><td style={tableStyles.td}>{e.totalRuns}</td></tr>\n ))}\n </tbody>\n </table>\n </Card>\n </>\n )}\n\n <SectionTitle icon=\"\uD83D\uDCCB\">{t('recentRuns')}</SectionTitle>\n {payload.recentRuns.length === 0 ? <EmptyState icon=\"\uD83D\uDCED\" message={t('empty')} /> : (\n <Card padding={0}>\n <table style={tableStyles.table}>\n <thead><tr><th style={tableStyles.th}>{t('run')}</th><th style={tableStyles.th}>{t('models')}</th><th style={tableStyles.th}>{t('winner')}</th><th style={tableStyles.th}>{t('date')}</th></tr></thead>\n <tbody>\n {payload.recentRuns.map((row) => (\n <tr key={row.id} style={tableStyles.clickRow} onClick={() => setRunModal(row.id)}>\n <td style={tableStyles.td}><code style={{ fontSize: 11 }}>{row.id.slice(0, 8)}</code></td>\n <td style={tableStyles.td}>{row.modelCount}</td>\n <td style={tableStyles.td}>{row.winner ?? '\u2014'}</td>\n <td style={tableStyles.td}>{new Date(row.timestamp).toLocaleString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </Card>\n )}\n\n {runModal !== null && <RunModal runId={runModal} t={t} onClose={() => setRunModal(null)} onDeleted={reload} />}\n </div>\n )\n}\n\nexport function ArenaPanel({ t }: PanelProps): ReactNode {\n return <ToastProvider><ArenaPanelInner t={t} /></ToastProvider>\n}\n", "/**\n * Shared UI component kit for dsh plugin panels.\n *\n * Self-contained: imports nothing but React. All styling is inline + CSS custom\n * properties so the components follow the host theme. A single <style> tag injects\n * keyframes the first time any component mounts.\n *\n * @module client/ui\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from 'react'\nimport type {\n ButtonHTMLAttributes,\n CSSProperties,\n InputHTMLAttributes,\n ReactNode,\n SelectHTMLAttributes,\n} from 'react'\n\n// \u2500\u2500\u2500 Theme tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nconst T = {\n accent: 'var(--accent, #4B8BBE)',\n accentHover: 'var(--accent-hover, #3a6f9e)',\n error: 'var(--error, #e53935)',\n success: 'var(--success, #2e7d32)',\n warning: 'var(--warning, #ed6c02)',\n bg: 'var(--bg-secondary, rgba(128,128,128,0.04))',\n bgHover: 'var(--bg-tertiary, rgba(128,128,128,0.08))',\n border: 'var(--border, rgba(128,128,128,0.2))',\n text: 'var(--text-primary, inherit)',\n muted: 'var(--text-secondary, rgba(128,128,128,0.65))',\n surface: 'var(--bg-primary, #fff)',\n}\n\n// \u2500\u2500\u2500 Style injection (once) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nlet injected = false\nfunction ensureStyles(): void {\n if (injected || typeof document === 'undefined') return\n injected = true\n const el = document.createElement('style')\n el.textContent = `\n@keyframes dsh-fade-in{from{opacity:0}to{opacity:1}}\n@keyframes dsh-slide-up{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}\n@keyframes dsh-spin{to{transform:rotate(360deg)}}\n.dsh-modal-overlay{animation:dsh-fade-in .15s ease}\n.dsh-modal-body{animation:dsh-slide-up .2s ease}\n.dsh-toast{animation:dsh-slide-up .2s ease}\n.dsh-spin{animation:dsh-spin .6s linear infinite}\n `\n document.head.appendChild(el)\n}\n\n// \u2500\u2500\u2500 Modal \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Modal({\n title,\n onClose,\n children,\n footer,\n width = 520,\n}: {\n title: string\n onClose: () => void\n children: ReactNode\n footer?: ReactNode\n width?: number\n}): ReactNode {\n useEffect(() => {\n ensureStyles()\n const handler = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') onClose()\n }\n document.addEventListener('keydown', handler)\n return () => document.removeEventListener('keydown', handler)\n }, [onClose])\n\n return (\n <div\n className=\"dsh-modal-overlay\"\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 1000,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.45)',\n backdropFilter: 'blur(3px)',\n WebkitBackdropFilter: 'blur(3px)',\n }}\n onClick={onClose}\n >\n <div\n className=\"dsh-modal-body\"\n style={{\n background: T.surface,\n borderRadius: 14,\n boxShadow: '0 12px 40px rgba(0,0,0,0.25)',\n width: `min(92vw, ${width}px)`,\n maxHeight: '85vh',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n }}\n onClick={(e) => e.stopPropagation()}\n >\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '16px 22px',\n borderBottom: `1px solid ${T.border}`,\n }}\n >\n <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>{title}</h3>\n <button\n type=\"button\"\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n fontSize: 20,\n color: T.muted,\n padding: '0 4px',\n lineHeight: 1,\n borderRadius: 4,\n }}\n aria-label=\"Close\"\n >\n \u00D7\n </button>\n </div>\n <div style={{ padding: 22, overflow: 'auto', flex: 1 }}>{children}</div>\n {footer !== undefined && (\n <div\n style={{\n padding: '14px 22px',\n borderTop: `1px solid ${T.border}`,\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 10,\n background: T.bg,\n }}\n >\n {footer}\n </div>\n )}\n </div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 ConfirmDialog \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function ConfirmDialog({\n title,\n message,\n confirmLabel,\n cancelLabel = 'Cancel',\n onConfirm,\n onClose,\n danger,\n}: {\n title: string\n message: string\n confirmLabel: string\n cancelLabel?: string\n onConfirm: () => void\n onClose: () => void\n danger?: boolean\n}): ReactNode {\n return (\n <Modal\n title={title}\n onClose={onClose}\n width={420}\n footer={\n <>\n <Button variant=\"secondary\" onClick={onClose}>\n {cancelLabel}\n </Button>\n <Button\n variant={danger === true ? 'danger' : 'primary'}\n onClick={() => {\n onConfirm()\n onClose()\n }}\n >\n {confirmLabel}\n </Button>\n </>\n }\n >\n <p style={{ margin: 0, fontSize: 14, lineHeight: 1.6 }}>{message}</p>\n </Modal>\n )\n}\n\n// \u2500\u2500\u2500 Button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Button({\n variant = 'secondary',\n size = 'md',\n children,\n style,\n ...rest\n}: {\n variant?: 'primary' | 'secondary' | 'danger' | 'ghost'\n size?: 'sm' | 'md'\n children: ReactNode\n style?: CSSProperties\n} & ButtonHTMLAttributes<HTMLButtonElement>): ReactNode {\n const base: CSSProperties = {\n cursor: 'pointer',\n borderRadius: 7,\n fontWeight: 500,\n transition: 'all 0.15s ease',\n border: 'none',\n display: 'inline-flex',\n alignItems: 'center',\n gap: 4,\n fontSize: size === 'sm' ? 12 : 13,\n padding: size === 'sm' ? '5px 12px' : '8px 18px',\n fontFamily: 'inherit',\n }\n const variants: Record<string, CSSProperties> = {\n primary: { background: T.accent, color: '#fff' },\n secondary: {\n background: T.bg,\n color: T.text,\n border: `1px solid ${T.border}`,\n },\n danger: {\n background: 'transparent',\n color: T.error,\n border: `1px solid ${T.error}`,\n },\n ghost: { background: 'transparent', color: T.muted, border: 'none' },\n }\n return (\n <button type=\"button\" style={{ ...base, ...variants[variant], ...style }} {...rest}>\n {children}\n </button>\n )\n}\n\n// \u2500\u2500\u2500 Card \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Card({\n title,\n icon,\n children,\n actions,\n style,\n padding = 14,\n}: {\n title?: string\n icon?: string\n children: ReactNode\n actions?: ReactNode\n style?: CSSProperties\n padding?: number\n}): ReactNode {\n return (\n <div\n style={{\n borderRadius: 10,\n border: `1px solid ${T.border}`,\n background: T.bg,\n overflow: 'hidden',\n ...style,\n }}\n >\n {(title !== undefined || actions !== undefined) && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: '12px 16px',\n borderBottom: title !== undefined ? `1px solid ${T.border}` : 'none',\n }}\n >\n <span style={{ fontSize: 13, fontWeight: 600, display: 'flex', alignItems: 'center', gap: 6 }}>\n {icon !== undefined && <span>{icon}</span>}\n {title}\n </span>\n {actions}\n </div>\n )}\n <div style={{ padding }}>{children}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 StatCard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function StatCard({\n value,\n label,\n color,\n unit,\n}: {\n value: string | number\n label: string\n color?: string\n unit?: string\n}): ReactNode {\n return (\n <div\n style={{\n flex: 1,\n minWidth: 90,\n textAlign: 'center',\n padding: '14px 10px',\n borderRadius: 10,\n border: `1px solid ${T.border}`,\n background: T.bg,\n }}\n >\n <div style={{ fontSize: 24, fontWeight: 700, color: color ?? T.text, lineHeight: 1.2 }}>\n {value}\n {unit !== undefined && (\n <span style={{ fontSize: 13, fontWeight: 500, opacity: 0.7, marginLeft: 2 }}>{unit}</span>\n )}\n </div>\n <div style={{ fontSize: 11, color: T.muted, marginTop: 4 }}>{label}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Badge({\n children,\n color = 'default',\n}: {\n children: ReactNode\n color?: 'default' | 'success' | 'error' | 'warning' | 'info'\n}): ReactNode {\n const colors: Record<string, { bg: string; fg: string }> = {\n default: { bg: 'rgba(128,128,128,0.12)', fg: T.muted },\n success: { bg: 'rgba(46,125,50,0.12)', fg: T.success },\n error: { bg: 'rgba(229,57,53,0.12)', fg: T.error },\n warning: { bg: 'rgba(245,124,0,0.12)', fg: T.warning },\n info: { bg: 'rgba(75,139,190,0.12)', fg: T.accent },\n }\n const c = colors[color]\n return (\n <span\n style={{\n display: 'inline-block',\n padding: '2px 9px',\n borderRadius: 10,\n fontSize: 11,\n fontWeight: 600,\n background: c.bg,\n color: c.fg,\n }}\n >\n {children}\n </span>\n )\n}\n\n// \u2500\u2500\u2500 Input \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Input({\n style,\n ...rest\n}: { style?: CSSProperties } & InputHTMLAttributes<HTMLInputElement>): ReactNode {\n return (\n <input\n {...rest}\n style={{\n fontSize: 13,\n padding: '8px 12px',\n borderRadius: 7,\n border: `1px solid ${T.border}`,\n background: T.surface,\n color: T.text,\n width: '100%',\n boxSizing: 'border-box',\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'border-color 0.15s',\n ...style,\n }}\n />\n )\n}\n\n// \u2500\u2500\u2500 Select \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Select({\n style,\n children,\n ...rest\n}: {\n style?: CSSProperties\n children: ReactNode\n} & SelectHTMLAttributes<HTMLSelectElement>): ReactNode {\n return (\n <select\n {...rest}\n style={{\n fontSize: 13,\n padding: '8px 12px',\n borderRadius: 7,\n border: `1px solid ${T.border}`,\n background: T.surface,\n color: T.text,\n cursor: 'pointer',\n fontFamily: 'inherit',\n outline: 'none',\n ...style,\n }}\n >\n {children}\n </select>\n )\n}\n\n// \u2500\u2500\u2500 Textarea \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Textarea({\n style,\n ...rest\n}: { style?: CSSProperties } & React.TextareaHTMLAttributes<HTMLTextAreaElement>): ReactNode {\n return (\n <textarea\n {...rest}\n style={{\n fontSize: 13,\n padding: '8px 12px',\n borderRadius: 7,\n border: `1px solid ${T.border}`,\n background: T.surface,\n color: T.text,\n width: '100%',\n boxSizing: 'border-box',\n fontFamily: 'inherit',\n outline: 'none',\n resize: 'vertical',\n lineHeight: 1.5,\n ...style,\n }}\n />\n )\n}\n\n// \u2500\u2500\u2500 Toast \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ninterface ToastItem {\n id: number\n type: 'success' | 'error' | 'info'\n message: string\n}\n\nconst ToastContext = createContext<(type: ToastItem['type'], message: string) => void>(\n () => {},\n)\n\nexport function ToastProvider({ children }: { children: ReactNode }): ReactNode {\n const [toasts, setToasts] = useState<ToastItem[]>([])\n const show = useCallback((type: ToastItem['type'], message: string) => {\n const id = Date.now() + Math.random()\n setToasts((t) => [...t, { id, type, message }])\n setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 3500)\n }, [])\n return (\n <ToastContext.Provider value={show}>\n {children}\n {toasts.length > 0 && (\n <div\n style={{\n position: 'fixed',\n bottom: 24,\n right: 24,\n zIndex: 2000,\n display: 'flex',\n flexDirection: 'column',\n gap: 8,\n }}\n >\n {toasts.map((t) => (\n <div\n key={t.id}\n className=\"dsh-toast\"\n style={{\n padding: '12px 18px',\n borderRadius: 8,\n fontSize: 13,\n fontWeight: 500,\n boxShadow: '0 6px 20px rgba(0,0,0,0.2)',\n color: '#fff',\n background:\n t.type === 'success'\n ? T.success\n : t.type === 'error'\n ? T.error\n : T.accent,\n maxWidth: 360,\n }}\n >\n {t.message}\n </div>\n ))}\n </div>\n )}\n </ToastContext.Provider>\n )\n}\n\nexport function useToast(): (type: ToastItem['type'], message: string) => void {\n return useContext(ToastContext)\n}\n\n// \u2500\u2500\u2500 Spinner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Spinner({ size = 16 }: { size?: number }): ReactNode {\n ensureStyles()\n return (\n <span\n className=\"dsh-spin\"\n style={{\n display: 'inline-block',\n width: size,\n height: size,\n border: `2px solid ${T.border}`,\n borderTopColor: T.accent,\n borderRadius: '50%',\n }}\n />\n )\n}\n\n// \u2500\u2500\u2500 EmptyState \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function EmptyState({\n icon,\n message,\n}: {\n icon?: string\n message: string\n}): ReactNode {\n return (\n <div\n style={{\n textAlign: 'center',\n padding: '36px 16px',\n color: T.muted,\n }}\n >\n {icon !== undefined && (\n <div style={{ fontSize: 36, marginBottom: 10, opacity: 0.4 }}>{icon}</div>\n )}\n <div style={{ fontSize: 13 }}>{message}</div>\n </div>\n )\n}\n\n// \u2500\u2500\u2500 SectionTitle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function SectionTitle({\n icon,\n children,\n actions,\n}: {\n icon?: string\n children: ReactNode\n actions?: ReactNode\n}): ReactNode {\n return (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginTop: 6,\n marginBottom: 8,\n }}\n >\n <span\n style={{\n fontSize: 14,\n fontWeight: 600,\n display: 'flex',\n alignItems: 'center',\n gap: 6,\n }}\n >\n {icon !== undefined && <span>{icon}</span>}\n {children}\n </span>\n {actions}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Table helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport const tableStyles = {\n table: {\n borderCollapse: 'collapse' as const,\n width: '100%' as const,\n },\n th: {\n textAlign: 'left' as const,\n padding: '8px 12px 8px 0',\n fontWeight: 600 as const,\n fontSize: 12 as const,\n color: T.muted,\n borderBottom: `1px solid ${T.border}`,\n },\n td: {\n padding: '8px 12px 8px 0',\n fontSize: 13 as const,\n borderBottom: '1px solid rgba(128,128,128,0.08)',\n },\n clickRow: { cursor: 'pointer' as const },\n}\n\n// \u2500\u2500\u2500 CodeBlock \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function CodeBlock({\n children,\n maxHeight = 200,\n style,\n}: {\n children: string\n maxHeight?: number\n style?: CSSProperties\n}): ReactNode {\n return (\n <pre\n style={{\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-word',\n fontSize: 12,\n maxHeight,\n overflow: 'auto',\n padding: 10,\n borderRadius: 7,\n background: 'rgba(128,128,128,0.06)',\n border: `1px solid ${T.border}`,\n margin: 0,\n ...style,\n }}\n >\n {children}\n </pre>\n )\n}\n\n// \u2500\u2500\u2500 ProgressBar \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function ProgressBar({\n pct,\n color,\n height = 18,\n}: {\n pct: number\n color?: string\n height?: number\n}): ReactNode {\n return (\n <div\n style={{\n width: '100%',\n height,\n background: 'rgba(128,128,128,0.12)',\n borderRadius: 5,\n overflow: 'hidden',\n position: 'relative',\n }}\n >\n <div\n style={{\n width: `${Math.min(pct, 100)}%`,\n height: '100%',\n background: color ?? T.accent,\n borderRadius: 5,\n transition: 'width 0.3s ease',\n }}\n />\n </div>\n )\n}\n\n// \u2500\u2500\u2500 Field label \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function Field({\n label,\n children,\n hint,\n}: {\n label: string\n children: ReactNode\n hint?: string\n}): ReactNode {\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>\n <label style={{ fontSize: 12, fontWeight: 600, color: T.text }}>{label}</label>\n {children}\n {hint !== undefined && (\n <span style={{ fontSize: 11, color: T.muted }}>{hint}</span>\n )}\n </div>\n )\n}\n\n// \u2500\u2500\u2500 usePanel hook (shared fetch logic) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nexport function usePanel<P>(path: string): {\n payload: P | null\n error: string | null\n reload: () => void\n} {\n const [payload, setPayload] = useState<P | null>(null)\n const [error, setError] = useState<string | null>(null)\n const [tick, setTick] = useState(0)\n const reload = useCallback(() => setTick((v) => v + 1), [])\n\n useEffect(() => {\n const c = new AbortController()\n setError(null)\n fetch(path, { signal: c.signal })\n .then(async (r) => {\n if (!r.ok) throw new Error(String(r.status))\n return r.json() as Promise<P>\n })\n .then((p) => {\n if (!c.signal.aborted) setPayload(p)\n })\n .catch((e: unknown) => {\n if (!c.signal.aborted) setPayload(null), setError(e instanceof Error ? e.message : String(e))\n })\n return () => c.abort()\n }, [tick, path])\n\n return useMemo(() => ({ payload, error, reload }), [payload, error, reload])\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_react", "import_jsx_runtime"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared UI component kit for dsh plugin panels.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained: imports nothing but React. All styling is inline + CSS custom
|
|
5
|
+
* properties so the components follow the host theme. A single <style> tag injects
|
|
6
|
+
* keyframes the first time any component mounts.
|
|
7
|
+
*
|
|
8
|
+
* @module client/ui
|
|
9
|
+
*/
|
|
10
|
+
import type { ButtonHTMLAttributes, CSSProperties, InputHTMLAttributes, ReactNode, SelectHTMLAttributes } from 'react';
|
|
11
|
+
export declare function Modal({ title, onClose, children, footer, width, }: {
|
|
12
|
+
title: string;
|
|
13
|
+
onClose: () => void;
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
footer?: ReactNode;
|
|
16
|
+
width?: number;
|
|
17
|
+
}): ReactNode;
|
|
18
|
+
export declare function ConfirmDialog({ title, message, confirmLabel, cancelLabel, onConfirm, onClose, danger, }: {
|
|
19
|
+
title: string;
|
|
20
|
+
message: string;
|
|
21
|
+
confirmLabel: string;
|
|
22
|
+
cancelLabel?: string;
|
|
23
|
+
onConfirm: () => void;
|
|
24
|
+
onClose: () => void;
|
|
25
|
+
danger?: boolean;
|
|
26
|
+
}): ReactNode;
|
|
27
|
+
export declare function Button({ variant, size, children, style, ...rest }: {
|
|
28
|
+
variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
|
|
29
|
+
size?: 'sm' | 'md';
|
|
30
|
+
children: ReactNode;
|
|
31
|
+
style?: CSSProperties;
|
|
32
|
+
} & ButtonHTMLAttributes<HTMLButtonElement>): ReactNode;
|
|
33
|
+
export declare function Card({ title, icon, children, actions, style, padding, }: {
|
|
34
|
+
title?: string;
|
|
35
|
+
icon?: string;
|
|
36
|
+
children: ReactNode;
|
|
37
|
+
actions?: ReactNode;
|
|
38
|
+
style?: CSSProperties;
|
|
39
|
+
padding?: number;
|
|
40
|
+
}): ReactNode;
|
|
41
|
+
export declare function StatCard({ value, label, color, unit, }: {
|
|
42
|
+
value: string | number;
|
|
43
|
+
label: string;
|
|
44
|
+
color?: string;
|
|
45
|
+
unit?: string;
|
|
46
|
+
}): ReactNode;
|
|
47
|
+
export declare function Badge({ children, color, }: {
|
|
48
|
+
children: ReactNode;
|
|
49
|
+
color?: 'default' | 'success' | 'error' | 'warning' | 'info';
|
|
50
|
+
}): ReactNode;
|
|
51
|
+
export declare function Input({ style, ...rest }: {
|
|
52
|
+
style?: CSSProperties;
|
|
53
|
+
} & InputHTMLAttributes<HTMLInputElement>): ReactNode;
|
|
54
|
+
export declare function Select({ style, children, ...rest }: {
|
|
55
|
+
style?: CSSProperties;
|
|
56
|
+
children: ReactNode;
|
|
57
|
+
} & SelectHTMLAttributes<HTMLSelectElement>): ReactNode;
|
|
58
|
+
export declare function Textarea({ style, ...rest }: {
|
|
59
|
+
style?: CSSProperties;
|
|
60
|
+
} & React.TextareaHTMLAttributes<HTMLTextAreaElement>): ReactNode;
|
|
61
|
+
interface ToastItem {
|
|
62
|
+
id: number;
|
|
63
|
+
type: 'success' | 'error' | 'info';
|
|
64
|
+
message: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function ToastProvider({ children }: {
|
|
67
|
+
children: ReactNode;
|
|
68
|
+
}): ReactNode;
|
|
69
|
+
export declare function useToast(): (type: ToastItem['type'], message: string) => void;
|
|
70
|
+
export declare function Spinner({ size }: {
|
|
71
|
+
size?: number;
|
|
72
|
+
}): ReactNode;
|
|
73
|
+
export declare function EmptyState({ icon, message, }: {
|
|
74
|
+
icon?: string;
|
|
75
|
+
message: string;
|
|
76
|
+
}): ReactNode;
|
|
77
|
+
export declare function SectionTitle({ icon, children, actions, }: {
|
|
78
|
+
icon?: string;
|
|
79
|
+
children: ReactNode;
|
|
80
|
+
actions?: ReactNode;
|
|
81
|
+
}): ReactNode;
|
|
82
|
+
export declare const tableStyles: {
|
|
83
|
+
table: {
|
|
84
|
+
borderCollapse: "collapse";
|
|
85
|
+
width: "100%";
|
|
86
|
+
};
|
|
87
|
+
th: {
|
|
88
|
+
textAlign: "left";
|
|
89
|
+
padding: string;
|
|
90
|
+
fontWeight: 600;
|
|
91
|
+
fontSize: 12;
|
|
92
|
+
color: string;
|
|
93
|
+
borderBottom: string;
|
|
94
|
+
};
|
|
95
|
+
td: {
|
|
96
|
+
padding: string;
|
|
97
|
+
fontSize: 13;
|
|
98
|
+
borderBottom: string;
|
|
99
|
+
};
|
|
100
|
+
clickRow: {
|
|
101
|
+
cursor: "pointer";
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
export declare function CodeBlock({ children, maxHeight, style, }: {
|
|
105
|
+
children: string;
|
|
106
|
+
maxHeight?: number;
|
|
107
|
+
style?: CSSProperties;
|
|
108
|
+
}): ReactNode;
|
|
109
|
+
export declare function ProgressBar({ pct, color, height, }: {
|
|
110
|
+
pct: number;
|
|
111
|
+
color?: string;
|
|
112
|
+
height?: number;
|
|
113
|
+
}): ReactNode;
|
|
114
|
+
export declare function Field({ label, children, hint, }: {
|
|
115
|
+
label: string;
|
|
116
|
+
children: ReactNode;
|
|
117
|
+
hint?: string;
|
|
118
|
+
}): ReactNode;
|
|
119
|
+
export declare function usePanel<P>(path: string): {
|
|
120
|
+
payload: P | null;
|
|
121
|
+
error: string | null;
|
|
122
|
+
reload: () => void;
|
|
123
|
+
};
|
|
124
|
+
export {};
|