/* MarkdownEditor -- shared write/preview editor for the mockups. Mirrors the live Templ component (internal/view/components/markdown_editor.templ). Standalone use -- the mount's Add data-standalone="false" when the mount already sits inside a bordered card (the editor then drops its own border, e.g. the gist file card). Composed use -- other components call CZMarkdownEditor.html({ ... }) to embed the editor markup in their own template (see comment-editor.js). Auto-hydrates every [data-markdown-editor] mount on load. Markup below is a fixed build-time template; the only inputs are data-* attributes / opts. */ (function () { var TOOLBAR = [ ['bold', 'Bold', ''], ['italic', 'Italic', ''], ['code', 'Code', ''], ['link', 'Insert link', ''] ].map(function (b) { return ''; }).join(''); function esc(s) { return String(s).replace(/&/g, '&').replace(/
${TOOLBAR}
`; } /* Replaces a [data-markdown-editor] mount with the rendered editor. */ function hydrate(mount) { var ta = mount.querySelector('textarea'); mount.outerHTML = html({ rows: mount.getAttribute('data-rows'), placeholder: mount.getAttribute('data-placeholder') || '', value: ta ? ta.value : '', standalone: mount.getAttribute('data-standalone') !== 'false' }); } /* write/preview tabs + formatting toolbar -- delegated, so it covers every [data-md-editor] on the page, including ones rendered by comment-editor.js. */ function setMode(ed, mode) { ed.querySelectorAll('[data-md-tab]').forEach(function (t) { var on = t.dataset.mdTab === mode; t.classList.toggle('border-foreground', on); t.classList.toggle('text-foreground', on); t.classList.toggle('font-medium', on); t.classList.toggle('border-transparent', !on); t.classList.toggle('text-muted-foreground', !on); t.setAttribute('aria-selected', on ? 'true' : 'false'); }); ed.querySelector('[data-md-pane="write"]').classList.toggle('hidden', mode !== 'write'); ed.querySelector('[data-md-pane="preview"]').classList.toggle('hidden', mode !== 'preview'); } function wrap(ta, action) { var s = ta.selectionStart, e = ta.selectionEnd, sel = ta.value.slice(s, e); var pairs = { bold: ['**', '**'], italic: ['_', '_'], code: ['`', '`'] }; var out = action === 'link' ? '[' + (sel || 'text') + '](url)' : (pairs[action] || ['', ''])[0] + (sel || 'text') + (pairs[action] || ['', ''])[1]; ta.setRangeText(out, s, e, 'end'); ta.focus(); } document.addEventListener('click', function (e) { var tab = e.target.closest('[data-md-tab]'); if (tab) { setMode(tab.closest('[data-md-editor]'), tab.dataset.mdTab); return; } var act = e.target.closest('[data-md-action]'); if (act) { var ta = act.closest('[data-md-editor]').querySelector('textarea'); if (ta) wrap(ta, act.dataset.mdAction); } }); document.querySelectorAll('[data-markdown-editor]').forEach(hydrate); window.CZMarkdownEditor = { html: html }; })();