// Single-pane Markdown view with an Edit/Done toggle. Returns the pane plus its // controls (toggle + save) so the page can place them in the header. Edit is the // accent (orange) action; Save appears only in edit mode. import { marked } from '../vendor/marked.esm.js'; import DOMPurify from '../vendor/purify.es.mjs'; import { el } from '../dom.js'; marked.setOptions({ gfm: true, breaks: true }); export function markdownEditor({ initial = '', save }) { let editing = false; const ta = el('textarea', { style: { width: '100%', minHeight: '460px', resize: 'vertical', fontFamily: 'var(--font-mono)', fontSize: '13px', lineHeight: '1.5' } }); ta.value = initial; const preview = el('div', { class: 'md-preview' }); const rerender = () => { preview.innerHTML = DOMPurify.sanitize(marked.parse(ta.value)); }; rerender(); const pane = el('div', {}, preview); const stamp = el('span', { class: 'muted', style: { fontSize: '11px' } }, ''); const saveBtn = el('button', { class: 'ghost', style: { display: 'none' }, onclick: async () => { saveBtn.disabled = true; try { const updated = await save(ta.value); stamp.textContent = updated?.updated_at ? 'Saved ' + new Date(updated.updated_at).toLocaleTimeString() : 'Saved'; } catch (e) { stamp.textContent = 'Save failed: ' + e.message; } finally { saveBtn.disabled = false; } } }, 'Save'); const toggle = el('button', { class: 'primary', onclick: () => { editing = !editing; if (editing) { pane.replaceChild(ta, preview); ta.focus(); toggle.textContent = 'Done'; saveBtn.style.display = ''; } else { rerender(); pane.replaceChild(preview, ta); toggle.textContent = 'Edit'; saveBtn.style.display = 'none'; } } }, 'Edit'); return { pane, controls: el('span', { class: 'ed-controls' }, toggle, saveBtn, stamp), setValue: (md) => { ta.value = md; if (!editing) rerender(); }, value: () => ta.value }; }