@webmcp-auto-ui/ui 2.5.27 → 2.5.29
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/package.json +18 -5
- package/src/agent/LLMSelector.svelte +11 -3
- package/src/agent/ModelCacheManager.svelte +359 -0
- package/src/index.ts +42 -30
- package/src/theme/scale.ts +128 -0
- package/src/widgets/WidgetRenderer.svelte +144 -107
- package/src/widgets/export-widget.ts +28 -1
- package/src/widgets/helpers/safe-image.ts +78 -0
- package/src/widgets/notebook/.gitkeep +0 -0
- package/src/widgets/notebook/chart-renderer.ts +63 -0
- package/src/widgets/notebook/executors/.gitkeep +1 -0
- package/src/widgets/notebook/executors/index.ts +4 -0
- package/src/widgets/notebook/executors/js-worker.ts +269 -0
- package/src/widgets/notebook/executors/sql.ts +206 -0
- package/src/widgets/notebook/import-modals.ts +560 -0
- package/src/widgets/notebook/left-pane.ts +256 -0
- package/src/widgets/notebook/notebook.ts +930 -0
- package/src/widgets/notebook/prose.ts +615 -0
- package/src/widgets/notebook/recipe-browser.ts +350 -0
- package/src/widgets/notebook/recipes/notebook.md +124 -0
- package/src/widgets/notebook/resource-extractor.ts +162 -0
- package/src/widgets/notebook/share-handlers.ts +222 -0
- package/src/widgets/notebook/shared.ts +1633 -0
- package/src/widgets/rich/cards.ts +181 -0
- package/src/widgets/rich/carousel.ts +319 -0
- package/src/widgets/rich/chart-rich.ts +386 -0
- package/src/widgets/rich/d3.ts +503 -0
- package/src/widgets/rich/data-table.ts +342 -0
- package/src/widgets/rich/gallery.ts +350 -0
- package/src/widgets/rich/grid-data.ts +173 -0
- package/src/widgets/rich/hemicycle.ts +313 -0
- package/src/widgets/rich/js-sandbox.ts +122 -0
- package/src/widgets/rich/json-viewer.ts +202 -0
- package/src/widgets/rich/log.ts +143 -0
- package/src/widgets/rich/map.ts +218 -0
- package/src/widgets/rich/profile.ts +256 -0
- package/src/widgets/rich/sankey.ts +257 -0
- package/src/widgets/rich/stat-card.ts +125 -0
- package/src/widgets/rich/timeline.ts +179 -0
- package/src/widgets/rich/trombinoscope.ts +246 -0
- package/src/widgets/simple/actions.ts +89 -0
- package/src/widgets/simple/alert.ts +100 -0
- package/src/widgets/simple/chart.ts +189 -0
- package/src/widgets/simple/code.ts +79 -0
- package/src/widgets/simple/kv.ts +68 -0
- package/src/widgets/simple/list.ts +89 -0
- package/src/widgets/simple/stat.ts +58 -0
- package/src/widgets/simple/tags.ts +125 -0
- package/src/widgets/simple/text.ts +198 -0
- package/src/widgets/SafeImage.svelte +0 -76
- package/src/widgets/rich/Cards.svelte +0 -39
- package/src/widgets/rich/Carousel.svelte +0 -88
- package/src/widgets/rich/Chart.svelte +0 -142
- package/src/widgets/rich/D3Widget.svelte +0 -378
- package/src/widgets/rich/DataTable.svelte +0 -62
- package/src/widgets/rich/Gallery.svelte +0 -94
- package/src/widgets/rich/GridData.svelte +0 -44
- package/src/widgets/rich/Hemicycle.svelte +0 -78
- package/src/widgets/rich/JsSandbox.svelte +0 -51
- package/src/widgets/rich/JsonViewer.svelte +0 -42
- package/src/widgets/rich/LogViewer.svelte +0 -24
- package/src/widgets/rich/MapView.svelte +0 -140
- package/src/widgets/rich/ProfileCard.svelte +0 -59
- package/src/widgets/rich/Sankey.svelte +0 -56
- package/src/widgets/rich/StatCard.svelte +0 -35
- package/src/widgets/rich/Timeline.svelte +0 -43
- package/src/widgets/rich/Trombinoscope.svelte +0 -48
- package/src/widgets/simple/ActionsBlock.svelte +0 -15
- package/src/widgets/simple/AlertBlock.svelte +0 -11
- package/src/widgets/simple/ChartBlock.svelte +0 -21
- package/src/widgets/simple/CodeBlock.svelte +0 -11
- package/src/widgets/simple/KVBlock.svelte +0 -16
- package/src/widgets/simple/ListBlock.svelte +0 -17
- package/src/widgets/simple/StatBlock.svelte +0 -14
- package/src/widgets/simple/TagsBlock.svelte +0 -15
- package/src/widgets/simple/TextBlock.svelte +0 -122
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Share handlers — real implementations for notebook share modal.
|
|
4
|
+
// 4 formats: JSON, Markdown, Hyperskill link (+ short), PNG snapshot.
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
import { encode, buildShortUrl } from '@webmcp-auto-ui/sdk';
|
|
8
|
+
import type { NotebookState, NotebookCell } from './shared.js';
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// JSON export
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
export async function shareAsJson(state: NotebookState): Promise<void> {
|
|
15
|
+
const minimal = minify(state);
|
|
16
|
+
const blob = new Blob([JSON.stringify(minimal, null, 2)], { type: 'application/json' });
|
|
17
|
+
triggerDownload(blob, sanitizeFilename(state.title || 'notebook') + '.json');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Markdown export
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
export async function shareAsMarkdown(state: NotebookState): Promise<void> {
|
|
25
|
+
const md = serializeToMarkdown(state);
|
|
26
|
+
const blob = new Blob([md], { type: 'text/markdown' });
|
|
27
|
+
triggerDownload(blob, sanitizeFilename(state.title || 'notebook') + '.md');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function serializeToMarkdown(state: NotebookState): string {
|
|
31
|
+
const parts: string[] = [];
|
|
32
|
+
if (state.title) parts.push(`# ${state.title}`, '');
|
|
33
|
+
for (const cell of state.cells) {
|
|
34
|
+
if (cell.type === 'md') {
|
|
35
|
+
parts.push(stripHtml(cell.content).trim(), '');
|
|
36
|
+
} else {
|
|
37
|
+
const lang = cell.type === 'sql' ? 'sql' : 'js';
|
|
38
|
+
const varname = cell.varname ? ` // → ${cell.varname}` : '';
|
|
39
|
+
parts.push('```' + lang + varname, cell.content.trim(), '```', '');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return parts.join('\n').trim() + '\n';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function stripHtml(s: string): string {
|
|
46
|
+
if (typeof document === 'undefined') return s;
|
|
47
|
+
const d = document.createElement('div');
|
|
48
|
+
d.innerHTML = s;
|
|
49
|
+
return d.textContent || '';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Hyperskill link (+ short URL)
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
export interface HyperskillShareResult {
|
|
57
|
+
fullUrl: string;
|
|
58
|
+
shortUrl: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function shareAsHyperskill(state: NotebookState): Promise<HyperskillShareResult> {
|
|
62
|
+
const origin = typeof window !== 'undefined' ? window.location.href.split('?')[0] : 'https://example.com';
|
|
63
|
+
const payload = JSON.stringify(minify(state));
|
|
64
|
+
const fullUrl = await encode(origin, payload);
|
|
65
|
+
const shortUrl = await buildShortUrl(origin, payload);
|
|
66
|
+
try {
|
|
67
|
+
await navigator.clipboard?.writeText(fullUrl);
|
|
68
|
+
} catch {
|
|
69
|
+
/* clipboard API can fail silently (focus, permission) */
|
|
70
|
+
}
|
|
71
|
+
return { fullUrl, shortUrl };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
// PNG snapshot — uses __exportPng widget hook (commit ded48c9) if present,
|
|
76
|
+
// falls back to a library-free DOM → SVG → PNG pipeline.
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
export async function shareAsPng(state: NotebookState, container: HTMLElement): Promise<void> {
|
|
80
|
+
// Preferred: widget-level hook
|
|
81
|
+
const hook = (container as any).__exportPng as (() => Promise<Blob>) | undefined;
|
|
82
|
+
if (typeof hook === 'function') {
|
|
83
|
+
try {
|
|
84
|
+
const blob = await hook();
|
|
85
|
+
triggerDownload(blob, sanitizeFilename(state.title || 'notebook') + '.png');
|
|
86
|
+
return;
|
|
87
|
+
} catch {
|
|
88
|
+
/* fall through to fallback */
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Fallback: SVG foreignObject → canvas → PNG
|
|
92
|
+
const blob = await domToPngBlob(container);
|
|
93
|
+
triggerDownload(blob, sanitizeFilename(state.title || 'notebook') + '.png');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function domToPngBlob(el: HTMLElement): Promise<Blob> {
|
|
97
|
+
const rect = el.getBoundingClientRect();
|
|
98
|
+
const w = Math.max(1, Math.ceil(rect.width));
|
|
99
|
+
const h = Math.max(1, Math.ceil(rect.height));
|
|
100
|
+
const serialized = new XMLSerializer().serializeToString(el);
|
|
101
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}">
|
|
102
|
+
<foreignObject width="100%" height="100%">
|
|
103
|
+
<div xmlns="http://www.w3.org/1999/xhtml">${serialized}</div>
|
|
104
|
+
</foreignObject>
|
|
105
|
+
</svg>`;
|
|
106
|
+
const svgBlob = new Blob([svg], { type: 'image/svg+xml;charset=utf-8' });
|
|
107
|
+
const url = URL.createObjectURL(svgBlob);
|
|
108
|
+
const img = new Image();
|
|
109
|
+
await new Promise<void>((resolve, reject) => {
|
|
110
|
+
img.onload = () => resolve();
|
|
111
|
+
img.onerror = (e) => reject(e);
|
|
112
|
+
img.src = url;
|
|
113
|
+
});
|
|
114
|
+
const canvas = document.createElement('canvas');
|
|
115
|
+
canvas.width = w;
|
|
116
|
+
canvas.height = h;
|
|
117
|
+
const ctx = canvas.getContext('2d')!;
|
|
118
|
+
ctx.fillStyle = 'white';
|
|
119
|
+
ctx.fillRect(0, 0, w, h);
|
|
120
|
+
ctx.drawImage(img, 0, 0);
|
|
121
|
+
URL.revokeObjectURL(url);
|
|
122
|
+
return new Promise<Blob>((resolve, reject) => {
|
|
123
|
+
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob failed'))), 'image/png');
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---------------------------------------------------------------------------
|
|
128
|
+
// Dispatcher used by shared.ts::openShareModal callback
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
|
|
131
|
+
export type ShareKind = 'hyperskill' | 'json' | 'markdown' | 'png';
|
|
132
|
+
|
|
133
|
+
export interface ShareResultInfo {
|
|
134
|
+
fmt: string;
|
|
135
|
+
kind: ShareKind | string;
|
|
136
|
+
message: string;
|
|
137
|
+
url?: string;
|
|
138
|
+
shortUrl?: string;
|
|
139
|
+
fullUrl?: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface ShareDispatchOptions {
|
|
143
|
+
container?: HTMLElement;
|
|
144
|
+
onResult?: (info: ShareResultInfo) => void;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function dispatchShare(
|
|
148
|
+
fmt: string,
|
|
149
|
+
state: NotebookState,
|
|
150
|
+
opts: ShareDispatchOptions = {},
|
|
151
|
+
): Promise<void> {
|
|
152
|
+
try {
|
|
153
|
+
if (fmt === 'json') {
|
|
154
|
+
await shareAsJson(state);
|
|
155
|
+
opts.onResult?.({ fmt, kind: 'json', message: 'JSON downloaded' });
|
|
156
|
+
} else if (fmt === 'md' || fmt === 'markdown') {
|
|
157
|
+
await shareAsMarkdown(state);
|
|
158
|
+
opts.onResult?.({ fmt, kind: 'markdown', message: 'Markdown downloaded' });
|
|
159
|
+
} else if (fmt === 'hyperskill' || fmt === 'hs') {
|
|
160
|
+
const { fullUrl, shortUrl } = await shareAsHyperskill(state);
|
|
161
|
+
opts.onResult?.({
|
|
162
|
+
fmt,
|
|
163
|
+
kind: 'hyperskill',
|
|
164
|
+
message: 'URL copied',
|
|
165
|
+
url: shortUrl || fullUrl,
|
|
166
|
+
shortUrl,
|
|
167
|
+
fullUrl,
|
|
168
|
+
});
|
|
169
|
+
} else if (fmt === 'png') {
|
|
170
|
+
if (!opts.container) throw new Error('png export requires container');
|
|
171
|
+
await shareAsPng(state, opts.container);
|
|
172
|
+
opts.onResult?.({ fmt, kind: 'png', message: 'PNG downloaded' });
|
|
173
|
+
} else {
|
|
174
|
+
throw new Error(`Unknown share format: ${fmt}`);
|
|
175
|
+
}
|
|
176
|
+
} catch (err: any) {
|
|
177
|
+
opts.onResult?.({ fmt, kind: fmt, message: 'Error: ' + String(err?.message ?? err) });
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// Helpers
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Strip non-serializable / transient fields from state for share/encode.
|
|
188
|
+
*/
|
|
189
|
+
function minify(state: NotebookState): Record<string, unknown> {
|
|
190
|
+
return {
|
|
191
|
+
id: state.id,
|
|
192
|
+
title: state.title,
|
|
193
|
+
mode: state.mode,
|
|
194
|
+
kicker: state.kicker,
|
|
195
|
+
cells: state.cells.map((c: NotebookCell) => ({
|
|
196
|
+
id: c.id,
|
|
197
|
+
type: c.type,
|
|
198
|
+
content: c.content,
|
|
199
|
+
name: c.name,
|
|
200
|
+
varname: c.varname,
|
|
201
|
+
hideSource: c.hideSource,
|
|
202
|
+
hideResult: c.hideResult,
|
|
203
|
+
comment: c.comment ?? undefined,
|
|
204
|
+
// intentionally skip lastResult, runState, lastMs — transient
|
|
205
|
+
})),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function triggerDownload(blob: Blob, filename: string): void {
|
|
210
|
+
const url = URL.createObjectURL(blob);
|
|
211
|
+
const a = document.createElement('a');
|
|
212
|
+
a.href = url;
|
|
213
|
+
a.download = filename;
|
|
214
|
+
document.body.appendChild(a);
|
|
215
|
+
a.click();
|
|
216
|
+
document.body.removeChild(a);
|
|
217
|
+
URL.revokeObjectURL(url);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function sanitizeFilename(name: string): string {
|
|
221
|
+
return name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9._-]/g, '') || 'notebook';
|
|
222
|
+
}
|