Something went wrong. Try again.
Monorepo for the nibling.run platform
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>@nibling/kernel — VFS harness</title> <link rel="stylesheet" href="/demo/demo.css"> <link rel="stylesheet" href="/demo/harness.css"></head><body> <!-- VS Code-style shell: activity bar | explorer sidebar | editor (tabs + gutter) over an OUTPUT panel, with a status bar across the bottom. All styling lives in harness.css (demo.css stays shared with the other demo pages). Every control is id-anchored so tests and humans target the same things. No window.prompt/confirm/alert anywhere: creation and rename run through the inline row, recursive directory deletion through the inline confirm row. --> <div id="app"> <nav id="activity-bar" aria-label="Activity bar"> <button id="btn-view-explorer" class="activity-btn active" aria-label="Explorer" title="Explorer (toggle sidebar)" aria-pressed="true"> <span class="icon-files" aria-hidden="true"></span> </button> <button id="btn-view-output" class="activity-btn active" aria-label="Output" title="Output (toggle panel)" aria-pressed="true"> <span class="icon-output" aria-hidden="true"></span> </button> </nav>
<section id="sidebar" aria-label="Explorer"> <header id="sidebar-title">EXPLORER</header> <div id="section-title">NODE</div>
<!-- Inline create/rename row (no window.prompt). Lives in the sidebar, right above the tree it acts on. --> <div id="inline-row" hidden> <label id="inline-label" for="inline-input"></label> <input id="inline-input" autocomplete="off" spellcheck="false"> <button id="inline-ok">Create</button> <button id="inline-cancel">Cancel</button> </div> <!-- Inline confirm for recursive directory deletes (no window.confirm). --> <div id="confirm-row" hidden> <span id="confirm-text"></span> <button id="confirm-yes">Delete</button> <button id="confirm-no">Cancel</button> </div>
<!-- Live tree of the VFS root. Refreshes on runtime.onFsChanged (the host coalesces ~25 ms). Folders collapse via their twisty; expansion state survives re-renders. Right-click a row for the context menu. --> <div id="tree" role="tree" aria-label="VFS files"></div> </section>
<section id="main"> <!-- One tab per open file. The actions at the right act on the ACTIVE tab: Save writes its buffer, Delete removes its file (dirs are deleted from the tree's context menu instead). --> <div id="tab-bar"> <div id="tabs" role="tablist" aria-label="Open editors"></div> <div id="tab-actions"> <button id="btn-save" class="icon-btn" aria-label="Save" title="Save (active tab)" disabled> <span class="icon-save" aria-hidden="true"></span> </button> <button id="btn-editor-delete" class="icon-btn" aria-label="Delete" title="Delete (active file)" disabled> <span class="icon-trash" aria-hidden="true"></span> </button> </div> </div>
<!-- Every operation outcome lands here: errors with their Node code, never silent, never alert(). Single element, tests read it directly. --> <div id="status" aria-live="polite" hidden></div>
<div id="editor"> <!-- Binary / read-error notice, shown as a banner above the editor. --> <div id="file-note" hidden></div> <!-- Gutter tracks the textarea: line count re-renders on input, vertical scroll is mirrored with a transform. The highlight mirror (microlighter) sits in the textarea's grid cell behind it — same font/padding/white-space, scroll synced; the textarea text goes transparent while a language is active. --> <div id="editor-body" hidden> <div id="gutter" aria-hidden="true"><div id="gutter-inner"></div></div> <pre id="hl-wrap" hidden><code id="hl-mirror"></code></pre> <textarea id="content" spellcheck="false" wrap="off"></textarea> </div> <div id="editor-empty"> <p id="empty-title">no editor open</p> <p class="hint">Right-click a file in the Explorer to open, create, rename or delete it. Folders collapse via their twisty.</p> </div> </div>
<!-- Bottom panel: run a guest entry against the same VFS the editor writes to. stdout and stderr are styled separately; the exit code appears when the process exits. Toggleable from the activity bar. --> <section id="output" aria-label="Output panel"> <div id="output-header"> <span id="output-label">OUTPUT</span> <input id="entry" value="/app/main.cjs" autocomplete="off" spellcheck="false" aria-label="Guest entry"> <button id="btn-run">Run</button> <span id="exit-badge">exit <span id="exit">—</span></span> </div> <div id="output-log"> <pre id="stdout"></pre> <pre id="stderr"></pre> </div> </section> </section>
<!-- Full-width status bar: boot state left; last exit code, the selected path and the encoding right. --> <footer id="statusbar"> <div id="sb-left"> <span id="sb-brand">nib 0.0.1</span> <span id="sb-boot">booting…</span> </div> <div id="sb-right"> <span id="sb-exit">—</span> <span id="sb-selected"></span> <span id="sb-encoding">UTF-8</span> </div> </footer> </div>
<!-- Tree context menu: positioned at the cursor (viewport-clamped), dismissed by click-away and Escape. --> <div id="context-menu" role="menu" hidden> <button id="ctx-new-file" role="menuitem">New File</button> <button id="ctx-new-folder" role="menuitem">New Folder</button> <button id="ctx-rename" role="menuitem">Rename</button> <button id="ctx-delete" role="menuitem">Delete</button> <div class="menu-sep" role="separator"></div> <button id="ctx-copy-path" role="menuitem">Copy Path</button> </div>
<!-- Import maps are document-scoped: they wire the PAGE's bare modifiers. Guest node:* resolution inside the worker goes through the builtin registry. --> <script type="importmap"> { "imports": { "@nibling/kernel": "/dist/runtime/host.js" } } </script> <script type="module" src="/demo/harness.js"></script></body></html>