v1.0.0
viewing older
Initial release
2026-08-20
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Markdown Editor — demo</title>
<style>
html,body{margin:0;height:100%;background:#0a0e14;color:#e7ecf3;font:14px/1.6 -apple-system,Inter,sans-serif}
.bar{height:42px;background:#0f141c;border-bottom:1px solid #1f2937;display:flex;align-items:center;padding:0 16px;gap:10px;font:500 13px ui-monospace,monospace}
.bar b{color:#00ff95}
.bar .stat{color:#8b95a7;margin-left:auto}
.grid{display:grid;grid-template-columns:1fr 1fr;height:calc(100% - 42px)}
.pane{padding:18px 22px;overflow:auto;border-right:1px solid #1f2937;position:relative}
.pane:last-child{border-right:none}
.pane::before{content:attr(data-label);position:absolute;top:6px;right:14px;font:600 10px ui-monospace,monospace;letter-spacing:.15em;color:#5c6577}
textarea{width:100%;height:100%;background:transparent;color:#e7ecf3;border:none;outline:none;resize:none;font:500 14px/1.7 ui-monospace,monospace;tab-size:2}
.preview h1{font-size:28px;margin:0 0 12px;color:#fff}
.preview h2{font-size:22px;margin:20px 0 10px;color:#fff}
.preview h3{font-size:18px;margin:18px 0 8px}
.preview p{margin:0 0 12px}
.preview code{background:#151c28;padding:2px 6px;border-radius:4px;font:500 13px ui-monospace,monospace;color:#00ff95}
.preview pre{background:#0f141c;border:1px solid #1f2937;border-radius:8px;padding:14px;overflow:auto;margin:12px 0}
.preview pre code{background:transparent;color:#e7ecf3;padding:0}
.preview blockquote{border-left:3px solid #00ff95;padding-left:14px;color:#8b95a7;margin:12px 0}
.preview ul, .preview ol{padding-left:22px}
.preview a{color:#00d2ff;text-decoration:none;border-bottom:1px solid rgba(0,210,255,.3)}
.preview strong{color:#fff}
</style>
</head>
<body>
<div class="bar">
<b>Markdown Editor</b> · live preview
<span class="stat" id="stat">0 words · 0 chars</span>
</div>
<div class="grid">
<div class="pane" data-label="EDITOR">
<textarea id="src" spellcheck="false"></textarea>
</div>
<div class="pane" data-label="PREVIEW">
<div class="preview" id="out"></div>
</div>
</div>
<script>
const SAMPLE = `# Welcome to **Markdown Live**
A tiny editor with **zero dependencies**. Type on the left, see the result on the right.
## Features
- **Bold**, *italic*, ~~strike~~
- Inline \`code\` and code blocks
- Lists, quotes, links
- Auto word count
\`\`\`js
function fib(n) {
return n < 2 ? n : fib(n-1) + fib(n-2);
}
console.log(fib(10));
\`\`\`
> "Simplicity is the ultimate sophistication." — Leonardo da Vinci
### Links & emphasis
Check out [Hacker News](https://news.ycombinator.com) for tech news.
`;
const src = document.getElementById('src'), out = document.getElementById('out'), stat = document.getElementById('stat');
src.value = SAMPLE;
function esc(s) { return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); }
function md(s) {
s = s.replace(/```(\w*)\n([\s\S]*?)```/g, (_, l, c) => `<pre><code>${esc(c.trim())}</code></pre>`);
s = s.replace(/^### (.+)$/gm, '<h3>$1</h3>');
s = s.replace(/^## (.+)$/gm, '<h2>$1</h2>');
s = s.replace(/^# (.+)$/gm, '<h1>$1</h1>');
s = s.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
s = s.replace(/\*(.+?)\*/g, '<em>$1</em>');
s = s.replace(/~~(.+?)~~/g, '<del>$1</del>');
s = s.replace(/`([^`]+)`/g, '<code>$1</code>');
s = s.replace(/^> (.+)$/gm, '<blockquote>$1</blockquote>');
s = s.replace(/^\* (.+)$/gm, '<li>$1</li>');
s = s.replace(/(<li>.+<\/li>\n?)+/g, m => '<ul>' + m + '</ul>');
s = s.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener">$1</a>');
s = s.split(/\n\n+/).map(b => /^<(h\d|ul|pre|blockquote)/.test(b) ? b : `<p>${b}</p>`).join('\n');
return s;
}
function upd() {
out.innerHTML = md(src.value);
const t = src.value.trim();
stat.textContent = `${t ? t.split(/\s+/).length : 0} words · ${t.length} chars`;
}
src.addEventListener('input', upd);
upd();
</script>
</body>
</html>