// Export dropdown — Markdown / Plain text / Web page / PDF. Client-side, no deps // beyond the bundled marked + DOMPurify. getContent() → { title, md }. import { el } from '../dom.js'; import { marked } from '../vendor/marked.esm.js'; import DOMPurify from '../vendor/purify.es.mjs'; function download(name, text, mime) { const url = URL.createObjectURL(new Blob([text], { type: mime })); const a = el('a', { href: url, download: name }); document.body.appendChild(a); a.click(); a.remove(); setTimeout(() => URL.revokeObjectURL(url), 1000); } function toPlain(md) { return md.replace(/```[\s\S]*?```/g, m => m.replace(/```/g, '')) .replace(/^#{1,6}\s+/gm, '').replace(/\*\*|__|\*|_|`|~~/g, '') .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1').replace(/^>\s?/gm, ''); } function htmlDoc(title, md) { const body = DOMPurify.sanitize(marked.parse(md)); return ` ${title} ${body}`; } export function exportMenu({ getContent, filenameBase }) { const wrap = el('div', { class: 'exp-menu' }); async function run(kind) { wrap.classList.remove('open'); const { title, md } = await getContent(); const base = (filenameBase || title || 'export').replace(/[^\w.-]+/g, '-').replace(/(^-|-$)/g, '') || 'export'; if (kind === 'md') download(base + '.md', md, 'text/markdown'); else if (kind === 'txt') download(base + '.txt', toPlain(md), 'text/plain'); else if (kind === 'html') download(base + '.html', htmlDoc(title, md), 'text/html'); else if (kind === 'pdf') { const w = window.open('', '_blank'); if (!w) return; w.document.write(htmlDoc(title, md)); w.document.close(); w.focus(); setTimeout(() => w.print(), 300); } } const btn = el('button', { class: 'ghost', onclick: (e) => { e.stopPropagation(); wrap.classList.toggle('open'); } }, 'Export ▾'); const list = el('div', { class: 'exp-list' }, el('button', { onclick: () => run('md') }, 'Markdown (.md)'), el('button', { onclick: () => run('txt') }, 'Plain text (.txt)'), el('button', { onclick: () => run('html') }, 'Web page (.html)'), el('button', { onclick: () => run('pdf') }, 'PDF (print)') ); wrap.append(btn, list); document.addEventListener('click', () => wrap.classList.remove('open')); return wrap; }