From 88185c70e08b7477181b4b331c9a2423dfe8d9d1 Mon Sep 17 00:00:00 2001 From: Bruno Charest Date: Sat, 6 Jun 2026 00:53:40 -0400 Subject: [PATCH] feat: preview uses ObsiGate server-side rendering (Mermaid, highlight, wikilinks) Preview now saves content via API then fetches rendered HTML from GET /api/file/{vault}?path=... instead of client-side marked.parse(). This enables Mermaid diagrams, syntax highlighting, wikilink resolution, and frontmatter cards. Demo mode still uses marked.js fallback. Debounce increased to 500ms. Loading spinner during render. --- frontend/editor-poc.html | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/frontend/editor-poc.html b/frontend/editor-poc.html index bcdbcbb..4d5dc7d 100644 --- a/frontend/editor-poc.html +++ b/frontend/editor-poc.html @@ -604,21 +604,47 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig }); } - // ---- Markdown Preview ---- + // ---- Markdown Preview (server-side rendering via ObsiGate API) ---- var previewTimer = null; + var _previewLoading = false; function schedulePreview() { if (!previewVisible) return; clearTimeout(previewTimer); - previewTimer = setTimeout(renderPreview, 300); + previewTimer = setTimeout(renderPreview, 500); } function renderPreview() { if (!previewVisible) return; - try { - previewContent.innerHTML = marked.parse(val()) || '
Empty document
'; - } catch(e) { - previewContent.innerHTML = '
Preview error
'; + if (_previewLoading) return; + // Demo mode: fallback to client-side marked + if (!fileVault || !filePath) { + try { + previewContent.innerHTML = marked.parse(val()) || '
Empty document
'; + } catch(e) { + previewContent.innerHTML = '
Preview error
'; + } + return; } + // Save first, then fetch server-rendered HTML + _previewLoading = true; + previewContent.innerHTML = '
Rendering...
'; + var content = val(); + fetch('/api/file/' + encodeURIComponent(fileVault) + '/save?path=' + encodeURIComponent(filePath) + '&backup=false', { + method: 'PUT', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ content: content }) + }).then(function(r) { + if (!r.ok) throw new Error('Save failed'); + return fetch('/api/file/' + encodeURIComponent(fileVault) + '?path=' + encodeURIComponent(filePath)); + }).then(function(r) { + if (!r.ok) throw new Error('Render failed'); + return r.json(); + }).then(function(data) { + previewContent.innerHTML = data.html || '
Empty document
'; + _previewLoading = false; + }).catch(function(e) { + previewContent.innerHTML = '
Render error: ' + e.message + '
'; + _previewLoading = false; + }); } function togglePreview() { @@ -627,7 +653,7 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig resizeHandle.style.display = previewVisible ? '' : 'none'; btnPreview.style.color = previewVisible ? 'var(--accent)' : ''; btnPreview.style.background = previewVisible ? 'var(--accent-bg)' : ''; - if (previewVisible) renderPreview(); + if (previewVisible) { renderPreview(); } } // ---- Sync scroll between editor and preview ----