mirror of
https://github.com/zadam/trilium.git
synced 2026-05-07 03:16:35 +02:00
feat(markdown): use a Mermaid cache to avoid flicker while editing something else
This commit is contained in:
@@ -101,13 +101,55 @@ export async function rewriteMermaidDiagramsInContainer(container: HTMLDivElemen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-container cache of rendered mermaid SVG keyed by diagram source text.
|
||||
* Populated after each successful render; reused on subsequent renders to
|
||||
* avoid flicker when the preview HTML is regenerated (e.g. live markdown
|
||||
* editing). Entries for diagrams no longer present in the container are
|
||||
* evicted on each run so the cache can't grow unbounded.
|
||||
*/
|
||||
const mermaidSvgCache = new WeakMap<HTMLElement, Map<string, string>>();
|
||||
|
||||
export async function applyInlineMermaid(container: HTMLDivElement) {
|
||||
// Initialize mermaid
|
||||
const nodes = Array.from(container.querySelectorAll<HTMLElement>("div.mermaid-diagram"));
|
||||
if (!nodes.length) return;
|
||||
|
||||
let cache = mermaidSvgCache.get(container);
|
||||
if (!cache) {
|
||||
cache = new Map();
|
||||
mermaidSvgCache.set(container, cache);
|
||||
}
|
||||
|
||||
// Paint cached SVGs upfront so unchanged diagrams don't flicker, and collect
|
||||
// only the new/changed diagrams for an actual mermaid render pass.
|
||||
const pendingSources = new Map<HTMLElement, string>();
|
||||
const seen = new Set<string>();
|
||||
for (const node of nodes) {
|
||||
const source = (node.textContent ?? "").trim();
|
||||
seen.add(source);
|
||||
const cached = cache.get(source);
|
||||
if (cached) {
|
||||
node.innerHTML = cached;
|
||||
node.setAttribute("data-processed", "true");
|
||||
} else {
|
||||
pendingSources.set(node, source);
|
||||
}
|
||||
}
|
||||
|
||||
// Evict entries whose source is no longer present.
|
||||
for (const key of [ ...cache.keys() ]) {
|
||||
if (!seen.has(key)) cache.delete(key);
|
||||
}
|
||||
|
||||
if (!pendingSources.size) return;
|
||||
|
||||
const mermaid = (await import("mermaid")).default;
|
||||
mermaid.initialize(getMermaidConfig());
|
||||
const nodes = Array.from(container.querySelectorAll<HTMLElement>("div.mermaid-diagram"));
|
||||
try {
|
||||
await mermaid.run({ nodes });
|
||||
await mermaid.run({ nodes: [ ...pendingSources.keys() ] });
|
||||
for (const [ node, source ] of pendingSources) {
|
||||
cache.set(source, node.innerHTML);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import "@triliumnext/ckeditor5";
|
||||
|
||||
import clsx from "clsx";
|
||||
import { RefObject } from "preact";
|
||||
import { useEffect, useMemo } from "preact/hooks";
|
||||
import { useEffect, useLayoutEffect, useMemo } from "preact/hooks";
|
||||
|
||||
import appContext from "../../../components/app_context";
|
||||
import FNote from "../../../entities/fnote";
|
||||
@@ -76,8 +76,11 @@ export function ReadOnlyTextContent({ html, ntxId, dir, className, contentRef: e
|
||||
document.body.style.setProperty("--code-block-tab-width", codeBlockTabWidth || "4");
|
||||
}, [codeBlockTabWidth]);
|
||||
|
||||
// Apply necessary transforms.
|
||||
useEffect(() => {
|
||||
// Apply necessary transforms. Runs in a layout effect so the synchronous
|
||||
// DOM mutations (mermaid rewrite + cached-SVG repaint, math, etc.) happen
|
||||
// before the browser paints — prevents a flash of raw `<pre>` content
|
||||
// during live preview re-renders.
|
||||
useLayoutEffect(() => {
|
||||
const container = contentRef.current;
|
||||
if (!container) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user