TEXT → HTML | untitled
THEME:
HEADING STYLE:
LISTS:
INLINE:
LIVE
PLAIN TEXT INPUT 0W / 0L
SHORT SOLO LINE→ heading
BLANK LINE→ section break
- / * / + LINE→ bullet
1. 2. 3.→ numbered list
INDENTED→ code block
> LINE→ blockquote
BARE URL→ link
--- / ===→ divider
Ctrl+E→ export
HTML PREVIEW MINIMAL
0 elements 0 chars Ctrl+E export  |  Ctrl+S save .txt  |  Ctrl+O open
\n`; dl(html, title+'.html', 'text/html'); toast('EXPORTED: '+title+'.html ['+t.label+']'); } exportBtn.addEventListener('click', exportHTML); // ── File ops ─────────────────────────────────────────────────────────────── function dl(content, name, mime) { const blob = new Blob([content], {type:mime}); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href=url; a.download=name; a.click(); URL.revokeObjectURL(url); } const fileInput = document.getElementById('file-input'); document.getElementById('btn-open').addEventListener('click', () => fileInput.click()); fileInput.addEventListener('change', e => { const f = e.target.files[0]; if(!f) return; const r = new FileReader(); r.onload = ev => { editor.value = ev.target.result; currentFile = f.name.replace(/\.[^.]+$/,''); fileLbl.textContent = f.name; render(); toast('OPENED: '+f.name); }; r.readAsText(f); fileInput.value=''; }); document.getElementById('btn-save-txt').addEventListener('click', () => { dl(editor.value, (currentFile||'textforge')+'.txt', 'text/plain'); toast('SAVED: '+(currentFile||'textforge')+'.txt'); }); // ── Keyboard ────────────────────────────────────────────────────────────── document.addEventListener('keydown', e => { const ctrl = e.ctrlKey || e.metaKey; if (ctrl && e.key==='e'){ e.preventDefault(); exportHTML(); } if (ctrl && e.key==='s'){ e.preventDefault(); document.getElementById('btn-save-txt').click(); } if (ctrl && e.key==='o'){ e.preventDefault(); fileInput.click(); } }); // ── Toast ───────────────────────────────────────────────────────────────── let toastTimer; function toast(msg){ const el = document.getElementById('toast'); el.textContent=msg; el.classList.add('show'); clearTimeout(toastTimer); toastTimer = setTimeout(()=>el.classList.remove('show'), 2500); } // ── Init ────────────────────────────────────────────────────────────────── try { const saved = localStorage.getItem('tf2_text'); const th = localStorage.getItem('tf2_theme'); const hm = localStorage.getItem('tf2_hmode'); const lm = localStorage.getItem('tf2_lmode'); const im = localStorage.getItem('tf2_imode'); if (th && THEMES[th]) themeSel.value = th; if (hm) headMode.value = hm; if (lm) listMode.value = lm; if (im) inlineMode.value = im; if (saved) editor.value = saved; } catch(e){} applyTheme(themeSel.value); render();