this repo has no description
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>js_top_worker Feature Demo</title>
7 <style>
8 :root {
9 --bg-primary: #1e1e2e;
10 --bg-secondary: #313244;
11 --bg-tertiary: #45475a;
12 --text-primary: #cdd6f4;
13 --text-secondary: #a6adc8;
14 --accent: #89b4fa;
15 --accent-hover: #b4befe;
16 --success: #a6e3a1;
17 --error: #f38ba8;
18 --warning: #fab387;
19 --border: #585b70;
20 }
21
22 * {
23 box-sizing: border-box;
24 margin: 0;
25 padding: 0;
26 }
27
28 body {
29 font-family: 'SF Mono', 'Consolas', 'Monaco', monospace;
30 background: var(--bg-primary);
31 color: var(--text-primary);
32 line-height: 1.6;
33 min-height: 100vh;
34 }
35
36 .container {
37 max-width: 1400px;
38 margin: 0 auto;
39 padding: 20px;
40 }
41
42 header {
43 text-align: center;
44 padding: 30px 0;
45 border-bottom: 1px solid var(--border);
46 margin-bottom: 30px;
47 }
48
49 h1 {
50 font-size: 2rem;
51 color: var(--accent);
52 margin-bottom: 10px;
53 }
54
55 .subtitle {
56 color: var(--text-secondary);
57 font-size: 0.9rem;
58 }
59
60 .status-bar {
61 display: flex;
62 align-items: center;
63 gap: 15px;
64 padding: 10px 15px;
65 background: var(--bg-secondary);
66 border-radius: 8px;
67 margin-bottom: 20px;
68 }
69
70 .status-indicator {
71 width: 10px;
72 height: 10px;
73 border-radius: 50%;
74 background: var(--warning);
75 }
76
77 .status-indicator.ready { background: var(--success); }
78 .status-indicator.error { background: var(--error); }
79
80 .status-text {
81 font-size: 0.85rem;
82 color: var(--text-secondary);
83 }
84
85 .demo-grid {
86 display: grid;
87 grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
88 gap: 20px;
89 }
90
91 .demo-card {
92 background: var(--bg-secondary);
93 border-radius: 12px;
94 overflow: hidden;
95 border: 1px solid var(--border);
96 }
97
98 .card-header {
99 padding: 15px 20px;
100 background: var(--bg-tertiary);
101 border-bottom: 1px solid var(--border);
102 display: flex;
103 justify-content: space-between;
104 align-items: center;
105 }
106
107 .card-title {
108 font-size: 1rem;
109 color: var(--accent);
110 }
111
112 .card-badge {
113 font-size: 0.7rem;
114 padding: 3px 8px;
115 border-radius: 4px;
116 background: var(--bg-primary);
117 color: var(--text-secondary);
118 }
119
120 .card-body {
121 padding: 20px;
122 }
123
124 .code-input {
125 width: 100%;
126 min-height: 100px;
127 padding: 12px;
128 background: var(--bg-primary);
129 border: 1px solid var(--border);
130 border-radius: 8px;
131 color: var(--text-primary);
132 font-family: inherit;
133 font-size: 0.9rem;
134 resize: vertical;
135 margin-bottom: 10px;
136 }
137
138 .code-input:focus {
139 outline: none;
140 border-color: var(--accent);
141 }
142
143 .btn-row {
144 display: flex;
145 gap: 10px;
146 margin-bottom: 15px;
147 }
148
149 .btn {
150 padding: 8px 16px;
151 border: none;
152 border-radius: 6px;
153 cursor: pointer;
154 font-family: inherit;
155 font-size: 0.85rem;
156 transition: all 0.2s;
157 }
158
159 .btn-primary {
160 background: var(--accent);
161 color: var(--bg-primary);
162 }
163
164 .btn-primary:hover {
165 background: var(--accent-hover);
166 }
167
168 .btn-secondary {
169 background: var(--bg-tertiary);
170 color: var(--text-primary);
171 }
172
173 .btn-secondary:hover {
174 background: var(--border);
175 }
176
177 .output-area {
178 background: var(--bg-primary);
179 border: 1px solid var(--border);
180 border-radius: 8px;
181 padding: 12px;
182 min-height: 80px;
183 max-height: 300px;
184 overflow-y: auto;
185 font-size: 0.85rem;
186 }
187
188 .output-line {
189 margin-bottom: 5px;
190 }
191
192 .output-line.stdout { color: var(--text-primary); }
193 .output-line.stderr { color: var(--error); }
194 .output-line.result { color: var(--success); }
195 .output-line.info { color: var(--text-secondary); font-style: italic; }
196
197 .mime-output {
198 background: white;
199 border-radius: 6px;
200 padding: 10px;
201 margin-top: 10px;
202 }
203
204 .completion-list {
205 background: var(--bg-primary);
206 border: 1px solid var(--border);
207 border-radius: 6px;
208 max-height: 200px;
209 overflow-y: auto;
210 }
211
212 .completion-item {
213 padding: 8px 12px;
214 border-bottom: 1px solid var(--border);
215 display: flex;
216 justify-content: space-between;
217 align-items: center;
218 }
219
220 .completion-item:last-child {
221 border-bottom: none;
222 }
223
224 .completion-name {
225 color: var(--accent);
226 }
227
228 .completion-kind {
229 font-size: 0.75rem;
230 color: var(--text-secondary);
231 background: var(--bg-tertiary);
232 padding: 2px 6px;
233 border-radius: 3px;
234 }
235
236 .type-info {
237 padding: 10px;
238 background: var(--bg-primary);
239 border: 1px solid var(--border);
240 border-radius: 6px;
241 color: var(--success);
242 }
243
244 .error-list {
245 background: var(--bg-primary);
246 border: 1px solid var(--border);
247 border-radius: 6px;
248 padding: 10px;
249 }
250
251 .error-item {
252 padding: 8px;
253 margin-bottom: 8px;
254 border-left: 3px solid var(--error);
255 background: rgba(243, 139, 168, 0.1);
256 }
257
258 .error-item.warning {
259 border-left-color: var(--warning);
260 background: rgba(250, 179, 135, 0.1);
261 }
262
263 .env-selector {
264 display: flex;
265 gap: 10px;
266 margin-bottom: 15px;
267 flex-wrap: wrap;
268 }
269
270 .env-btn {
271 padding: 6px 12px;
272 border: 1px solid var(--border);
273 background: var(--bg-primary);
274 color: var(--text-secondary);
275 border-radius: 4px;
276 cursor: pointer;
277 font-family: inherit;
278 font-size: 0.8rem;
279 }
280
281 .env-btn.active {
282 border-color: var(--accent);
283 color: var(--accent);
284 background: rgba(137, 180, 250, 0.1);
285 }
286
287 .log-panel {
288 position: fixed;
289 bottom: 0;
290 left: 0;
291 right: 0;
292 background: var(--bg-secondary);
293 border-top: 1px solid var(--border);
294 max-height: 200px;
295 overflow-y: auto;
296 padding: 10px 20px;
297 font-size: 0.8rem;
298 }
299
300 .log-entry {
301 color: var(--text-secondary);
302 margin-bottom: 3px;
303 }
304
305 .log-entry.error { color: var(--error); }
306 .log-entry.success { color: var(--success); }
307
308 .full-width {
309 grid-column: 1 / -1;
310 }
311
312 .hidden { display: none; }
313
314 pre {
315 white-space: pre-wrap;
316 word-wrap: break-word;
317 }
318 </style>
319</head>
320<body>
321 <div class="container">
322 <header>
323 <h1>js_top_worker Feature Demo</h1>
324 <p class="subtitle">OCaml Toplevel in the Browser via WebWorker</p>
325 </header>
326
327 <div class="status-bar">
328 <div class="status-indicator" id="status-indicator"></div>
329 <span class="status-text" id="status-text">Initializing...</span>
330 </div>
331
332 <div class="demo-grid">
333 <!-- Basic Execution -->
334 <div class="demo-card">
335 <div class="card-header">
336 <span class="card-title">Basic Execution</span>
337 <span class="card-badge">exec</span>
338 </div>
339 <div class="card-body">
340 <textarea class="code-input" id="exec-input">let greet name = Printf.sprintf "Hello, %s!" name;;
341greet "OCaml";;</textarea>
342 <div class="btn-row">
343 <button class="btn btn-primary" onclick="runExec()">Execute</button>
344 <button class="btn btn-secondary" onclick="clearOutput('exec-output')">Clear</button>
345 </div>
346 <div class="output-area" id="exec-output"></div>
347 </div>
348 </div>
349
350 <!-- Multiple Environments -->
351 <div class="demo-card">
352 <div class="card-header">
353 <span class="card-title">Multiple Environments</span>
354 <span class="card-badge">isolation</span>
355 </div>
356 <div class="card-body">
357 <div class="env-selector" id="env-selector">
358 <button class="env-btn active" data-env="">default</button>
359 </div>
360 <div class="btn-row">
361 <button class="btn btn-secondary" onclick="createEnv()">+ New Env</button>
362 <button class="btn btn-secondary" onclick="listEnvs()">List Envs</button>
363 </div>
364 <textarea class="code-input" id="env-input">let env_value = 42;;</textarea>
365 <div class="btn-row">
366 <button class="btn btn-primary" onclick="runInEnv()">Execute in Selected Env</button>
367 </div>
368 <div class="output-area" id="env-output"></div>
369 </div>
370 </div>
371
372 <!-- MIME Output -->
373 <div class="demo-card">
374 <div class="card-header">
375 <span class="card-title">MIME Output</span>
376 <span class="card-badge">rich output</span>
377 </div>
378 <div class="card-body">
379 <textarea class="code-input" id="mime-input">(* SVG output *)
380let svg = {|<svg width="100" height="100">
381 <circle cx="50" cy="50" r="40" fill="#89b4fa"/>
382 <text x="50" y="55" text-anchor="middle" fill="white">OCaml</text>
383</svg>|};;
384Mime_printer.push "image/svg" svg;;</textarea>
385 <div class="btn-row">
386 <button class="btn btn-primary" onclick="runMime()">Execute</button>
387 <button class="btn btn-secondary" onclick="loadMimeExamples()">Examples</button>
388 </div>
389 <div class="output-area" id="mime-output"></div>
390 <div class="mime-output hidden" id="mime-rendered"></div>
391 </div>
392 </div>
393
394 <!-- Autocomplete -->
395 <div class="demo-card">
396 <div class="card-header">
397 <span class="card-title">Autocomplete</span>
398 <span class="card-badge">complete_prefix</span>
399 </div>
400 <div class="card-body">
401 <textarea class="code-input" id="complete-input">List.ma</textarea>
402 <p style="font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 10px;">
403 Enter partial code and click Complete to see suggestions
404 </p>
405 <div class="btn-row">
406 <button class="btn btn-primary" onclick="runComplete()">Complete</button>
407 </div>
408 <div class="completion-list" id="complete-output"></div>
409 </div>
410 </div>
411
412 <!-- Type Information -->
413 <div class="demo-card">
414 <div class="card-header">
415 <span class="card-title">Type Information</span>
416 <span class="card-badge">type_enclosing</span>
417 </div>
418 <div class="card-body">
419 <textarea class="code-input" id="type-input">let f x = List.map (fun y -> y + 1) x</textarea>
420 <p style="font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 10px;">
421 Position (0-indexed): <input type="number" id="type-pos" value="8" style="width: 50px; background: var(--bg-primary); border: 1px solid var(--border); color: var(--text-primary); padding: 4px;">
422 </p>
423 <div class="btn-row">
424 <button class="btn btn-primary" onclick="runTypeEnclosing()">Get Type</button>
425 </div>
426 <div class="type-info" id="type-output">Click "Get Type" to see type information</div>
427 </div>
428 </div>
429
430 <!-- Error Reporting -->
431 <div class="demo-card">
432 <div class="card-header">
433 <span class="card-title">Error Reporting</span>
434 <span class="card-badge">query_errors</span>
435 </div>
436 <div class="card-body">
437 <textarea class="code-input" id="errors-input">let x : string = 42
438let unused = "hello"
439let y = unknown_function ()</textarea>
440 <div class="btn-row">
441 <button class="btn btn-primary" onclick="runQueryErrors()">Check Errors</button>
442 </div>
443 <div class="error-list" id="errors-output">Click "Check Errors" to analyze code</div>
444 </div>
445 </div>
446
447 <!-- Directives -->
448 <div class="demo-card full-width">
449 <div class="card-header">
450 <span class="card-title">Directives</span>
451 <span class="card-badge">#show, #install_printer, etc.</span>
452 </div>
453 <div class="card-body">
454 <div class="btn-row" style="flex-wrap: wrap;">
455 <button class="btn btn-secondary" onclick="runDirective('#show List;;')">show List</button>
456 <button class="btn btn-secondary" onclick="runDirective('#show_type option;;')">show_type option</button>
457 <button class="btn btn-secondary" onclick="runDirective('#help;;')">help</button>
458 <button class="btn btn-secondary" onclick="runDirective('#print_depth 5;;')">print_depth 5</button>
459 <button class="btn btn-secondary" onclick="runDirective('#warnings \"+a\";;')">warnings +a</button>
460 </div>
461 <textarea class="code-input" id="directive-input">#show List.map;;</textarea>
462 <div class="btn-row">
463 <button class="btn btn-primary" onclick="runDirective()">Run Directive</button>
464 </div>
465 <div class="output-area" id="directive-output"></div>
466 </div>
467 </div>
468
469 <!-- Custom Printers -->
470 <div class="demo-card">
471 <div class="card-header">
472 <span class="card-title">Custom Printers</span>
473 <span class="card-badge">#install_printer</span>
474 </div>
475 <div class="card-body">
476 <textarea class="code-input" id="printer-input">type color = Red | Green | Blue;;
477
478let pp_color fmt c =
479 Format.fprintf fmt "[COLOR:%s]"
480 (match c with Red -> "red" | Green -> "green" | Blue -> "blue");;
481
482#install_printer pp_color;;
483
484[Red; Green; Blue];;</textarea>
485 <div class="btn-row">
486 <button class="btn btn-primary" onclick="runPrinter()">Execute</button>
487 </div>
488 <div class="output-area" id="printer-output"></div>
489 </div>
490 </div>
491
492 <!-- Library Loading -->
493 <div class="demo-card">
494 <div class="card-header">
495 <span class="card-title">Library Loading</span>
496 <span class="card-badge">#require</span>
497 </div>
498 <div class="card-body">
499 <p style="font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 10px;">
500 Libraries must be prepared with <code>jtw opam</code> first.
501 </p>
502 <textarea class="code-input" id="require-input">#require "str";;
503Str.split (Str.regexp ",") "a,b,c";;</textarea>
504 <div class="btn-row">
505 <button class="btn btn-primary" onclick="runRequire()">Execute</button>
506 </div>
507 <div class="output-area" id="require-output"></div>
508 </div>
509 </div>
510
511 <!-- Toplevel Script -->
512 <div class="demo-card full-width">
513 <div class="card-header">
514 <span class="card-title">Toplevel Script Execution</span>
515 <span class="card-badge">exec_toplevel</span>
516 </div>
517 <div class="card-body">
518 <p style="font-size: 0.8rem; color: var(--text-secondary); margin-bottom: 10px;">
519 Toplevel scripts use "# " prefix for input lines. Output is indented.
520 </p>
521 <textarea class="code-input" id="toplevel-input" style="min-height: 150px;"># let square x = x * x;;
522# let numbers = [1; 2; 3; 4; 5];;
523# List.map square numbers;;</textarea>
524 <div class="btn-row">
525 <button class="btn btn-primary" onclick="runToplevel()">Execute Script</button>
526 </div>
527 <div class="output-area" id="toplevel-output" style="min-height: 150px;"></div>
528 </div>
529 </div>
530 </div>
531 </div>
532
533 <div class="log-panel" id="log-panel">
534 <div id="log-entries"></div>
535 </div>
536
537 <script src="demo.js"></script>
538</body>
539</html>