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.
This commit is contained in:
@@ -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()) || '<div class="preview-loading">Empty document</div>';
|
||||
} catch(e) {
|
||||
previewContent.innerHTML = '<div class="preview-loading">Preview error</div>';
|
||||
if (_previewLoading) return;
|
||||
// Demo mode: fallback to client-side marked
|
||||
if (!fileVault || !filePath) {
|
||||
try {
|
||||
previewContent.innerHTML = marked.parse(val()) || '<div class="preview-loading">Empty document</div>';
|
||||
} catch(e) {
|
||||
previewContent.innerHTML = '<div class="preview-loading">Preview error</div>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Save first, then fetch server-rendered HTML
|
||||
_previewLoading = true;
|
||||
previewContent.innerHTML = '<div class="preview-loading"><span class="spin"></span> Rendering...</div>';
|
||||
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 || '<div class="preview-loading">Empty document</div>';
|
||||
_previewLoading = false;
|
||||
}).catch(function(e) {
|
||||
previewContent.innerHTML = '<div class="preview-loading">Render error: ' + e.message + '</div>';
|
||||
_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 ----
|
||||
|
||||
Reference in New Issue
Block a user