@@ -0,0 +1,106 @@
5+<meta name="viewport" content="width=device-width, initial-scale=1">
6+<title>htmlang Playground</title>
8+ The playground deployed to GitHub Pages (.github/workflows/playground.yml).
9+ It sits next to the wasm-bindgen output of this crate (htmlang_wasm.js and
10+ htmlang_wasm_bg.wasm) and opens with examples/demo.hl, copied as demo.hl.
13+*{box-sizing:border-box;margin:0}
14+body{font-family:system-ui,-apple-system,sans-serif;display:flex;height:100vh;background:#1a1a2e;color:#eee}
15+.panel{flex:1;display:flex;flex-direction:column;min-width:0}
16+.header{padding:12px 16px;background:#16213e;border-bottom:1px solid #0f3460;display:flex;align-items:center;gap:12px}
17+.header h1{font-size:14px;font-weight:600;color:#e94560}
18+.header .tag{font-size:11px;padding:2px 8px;background:#0f3460;border-radius:4px;color:#a8b2d1}
19+.editor-wrap{flex:1;position:relative;overflow:hidden}
20+textarea{width:100%;height:100%;resize:none;border:none;outline:none;padding:16px;font-family:ui-monospace,monospace;font-size:14px;line-height:1.6;background:#1a1a2e;color:#e6e6e6;tab-size:2;position:absolute;top:0;left:0}
21+iframe{flex:1;border:none;background:white}
22+.divider{width:1px;background:#0f3460;cursor:col-resize}
23+.divider:hover{background:#e94560}
24+.toolbar{padding:8px 16px;background:#16213e;border-top:1px solid #0f3460;display:flex;gap:8px;align-items:center}
25+button{padding:6px 16px;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500}
26+.btn-run{background:#e94560;color:white}
27+.btn-run:hover{background:#c81e45}
28+.btn-copy,.btn-share{background:#0f3460;color:#a8b2d1}
29+.status{margin-left:auto;font-size:12px;color:#666}
33+<div class="panel" id="editor-panel">
34+<div class="header"><h1>htmlang</h1><span class="tag">playground</span></div>
35+<div class="editor-wrap">
36+<textarea id="editor" spellcheck="false"></textarea>
39+<button class="btn-run" onclick="compile()">▶ Run (Ctrl+Enter)</button>
40+<button class="btn-copy" onclick="copyOutput()">Copy HTML</button>
41+<button class="btn-share" onclick="share()">Share</button>
42+<span class="status" id="status">Loading…</span>
45+<div class="divider" id="divider"></div>
46+<div class="panel" id="preview-panel">
47+<div class="header"><span class="tag">preview</span></div>
48+<iframe id="preview"></iframe>
50+<script src="htmlang_wasm.js"></script>
52+var editor=document.getElementById('editor');
53+var statusEl=document.getElementById('status');
59+ var start=performance.now();
60+ var html=wasm_bindgen.compile(editor.value);
61+ var ms=(performance.now()-start).toFixed(1);
63+ document.getElementById('preview').srcdoc=html;
64+ statusEl.textContent='Compiled in '+ms+'ms';
66+function copyOutput(){
67+ if(lastOutput)navigator.clipboard.writeText(lastOutput).then(function(){statusEl.textContent='Copied to clipboard!'});
70+ var encoded=btoa(unescape(encodeURIComponent(editor.value)));
71+ history.replaceState(null,'','#'+encoded);
72+ navigator.clipboard.writeText(location.href).then(function(){statusEl.textContent='Share URL copied to clipboard!'});
74+function sourceFromHash(){
75+ if(location.hash.length<=1)return null;
76+ try{return decodeURIComponent(escape(atob(location.hash.slice(1))));}catch(e){return null;}
80+var divider=document.getElementById('divider');
81+var editorPanel=document.getElementById('editor-panel');
83+divider.addEventListener('mousedown',function(){dragging=true;document.body.style.cursor='col-resize';document.body.style.userSelect='none';});
84+document.addEventListener('mousemove',function(e){if(!dragging)return;editorPanel.style.flex='none';editorPanel.style.width=(e.clientX/window.innerWidth)*100+'%';});
85+document.addEventListener('mouseup',function(){if(dragging){dragging=false;document.body.style.cursor='';document.body.style.userSelect='';}});
88+editor.addEventListener('keydown',function(e){
89+ if(e.key==='Enter'&&(e.ctrlKey||e.metaKey)){e.preventDefault();compile();}
90+ if(e.key==='Tab'){e.preventDefault();var s=e.target;var start=s.selectionStart;s.value=s.value.substring(0,start)+' '+s.value.substring(s.selectionEnd);s.selectionStart=s.selectionEnd=start+2;}
93+var shared=sourceFromHash();
95+ wasm_bindgen('htmlang_wasm_bg.wasm'),
96+ shared!==null?Promise.resolve(shared):fetch('demo.hl').then(function(r){return r.ok?r.text():'';})
97+]).then(function(results){
98+ editor.value=results[1];
101+}).catch(function(e){
102+ statusEl.textContent='Failed to load: '+e;