this repo has no description
at main 539 lines 16 kB view raw
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>