/** * mist-detail.ts — Mist detail page module. * * Responsibilities: * 1. Copy artifact content to clipboard (toolbar button). * 2. Copy embed snippets (iframe / script) from sidebar. * 3. Copy-button visual feedback (check icon for 2s). */ // ── SVG icons ───────────────────────────────────────────────────────────────── const COPY_ICON = ``; const CHECK_ICON = ``; // ── Generic clipboard helper ────────────────────────────────────────────────── async function copyText(text: string): Promise { try { await navigator.clipboard.writeText(text); return true; } catch { return false; } } function flashButton(btn: HTMLElement, originalHtml: string): void { btn.innerHTML = `${CHECK_ICON} Copied`; btn.classList.add('is-copied'); setTimeout(() => { btn.innerHTML = originalHtml; btn.classList.remove('is-copied'); }, 2000); } // ── Copy artifact content ───────────────────────────────────────────────────── function bindCopyContent(): void { const btn = document.querySelector('[data-action="copy-content"]'); if (!btn) return; const originalHtml = btn.innerHTML; btn.addEventListener('click', async () => { const code = document.getElementById('artifact-content'); const text = (code?.textContent ?? '').trimEnd(); const ok = await copyText(text); if (ok) flashButton(btn, originalHtml); }); } // ── Copy embed snippets ─────────────────────────────────────────────────────── function bindCopyEmbeds(): void { document.querySelectorAll('[data-action="copy-embed"]').forEach(snippet => { const copyBtn = snippet.querySelector('.ms-embed-copy'); const codeEl = snippet.querySelector('.ms-embed-code'); if (!copyBtn || !codeEl) return; const originalHtml = copyBtn.innerHTML; const doCopy = async () => { // Decode HTML entities in the code element's text content const text = codeEl.textContent ?? ''; const ok = await copyText(text); if (ok) flashButton(copyBtn, originalHtml); }; copyBtn.addEventListener('click', (e) => { e.stopPropagation(); void doCopy(); }); snippet.addEventListener('click', () => { void doCopy(); }); }); } // ── Markdown heading anchors ────────────────────────────────────────────────── function initMarkdownAnchors(): void { const container = document.querySelector('.blob2-markdown'); if (!container) return; container.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(heading => { const slug = heading.id; if (!slug) return; const anchor = document.createElement('a'); anchor.href = '#' + slug; anchor.className = 'blob2-md-anchor'; anchor.textContent = '#'; anchor.setAttribute('aria-hidden', 'true'); heading.appendChild(anchor); }); } // ── Entry point ─────────────────────────────────────────────────────────────── export function initMistDetail(_data?: Record): void { bindCopyContent(); bindCopyEmbeds(); initMarkdownAnchors(); }