From abfc2fea3e02aa4fa68d8bdc7085f0dedeec3b8a Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Thu, 20 Nov 2025 14:26:04 +0200 Subject: [PATCH] feat(print): render inline mermaid --- apps/client/src/print.tsx | 7 ++++- apps/client/src/services/content_renderer.ts | 31 ++++++++++++++++++- .../type_widgets/text/ReadOnlyText.tsx | 23 ++------------ 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/apps/client/src/print.tsx b/apps/client/src/print.tsx index 5db1ebe75..a9dec12c4 100644 --- a/apps/client/src/print.tsx +++ b/apps/client/src/print.tsx @@ -2,7 +2,7 @@ import FNote from "./entities/fnote"; import { render } from "preact"; import { CustomNoteList, useNoteViewType } from "./widgets/collections/NoteList"; import { useCallback, useLayoutEffect, useRef } from "preact/hooks"; -import content_renderer from "./services/content_renderer"; +import content_renderer, { applyInlineMermaid } from "./services/content_renderer"; interface RendererProps { note: FNote; @@ -71,6 +71,11 @@ function SingleNoteRenderer({ note, onReady }: RendererProps) { }) ); + // Initialize mermaid. + if (note.type === "text") { + await applyInlineMermaid(container); + } + // Check custom CSS. await loadCustomCss(note); } diff --git a/apps/client/src/services/content_renderer.ts b/apps/client/src/services/content_renderer.ts index e891b96d7..f7658d669 100644 --- a/apps/client/src/services/content_renderer.ts +++ b/apps/client/src/services/content_renderer.ts @@ -10,7 +10,7 @@ import FNote from "../entities/fnote.js"; import FAttachment from "../entities/fattachment.js"; import imageContextMenuService from "../menus/image_context_menu.js"; import { applySingleBlockSyntaxHighlight, formatCodeBlocks } from "./syntax_highlight.js"; -import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js"; +import { getMermaidConfig, loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js"; import renderDoc from "./doc_renderer.js"; import { t } from "../services/i18n.js"; import WheelZoom from 'vanilla-js-wheel-zoom'; @@ -136,6 +136,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery to
in order not to apply a codeblock style to it. */ +export async function rewriteMermaidDiagramsInContainer(container: HTMLDivElement) { + const mermaidBlocks = container.querySelectorAll('pre:has(code[class="language-mermaid"])'); + if (!mermaidBlocks.length) return; + const nodes: HTMLElement[] = []; + + for (const mermaidBlock of mermaidBlocks) { + const div = document.createElement("div"); + div.classList.add("mermaid-diagram"); + div.innerHTML = mermaidBlock.querySelector("code")?.innerHTML ?? ""; + mermaidBlock.replaceWith(div); + nodes.push(div); + } +} + +export async function applyInlineMermaid(container: HTMLDivElement) { + // Initialize mermaid + const mermaid = (await import("mermaid")).default; + mermaid.initialize(getMermaidConfig()); + const nodes = Array.from(container.querySelectorAll("div.mermaid-diagram")); + console.log("Got nodes", nodes); + try { + await mermaid.run({ nodes }); + } catch (e) { + console.log(e); + } +} + export default { getRenderedContent }; diff --git a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx index caa0302b8..0a17868c5 100644 --- a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx +++ b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx @@ -10,13 +10,13 @@ import RawHtml from "../../react/RawHtml"; import "@triliumnext/ckeditor5"; import FNote from "../../../entities/fnote"; import { getLocaleById } from "../../../services/i18n"; -import { getMermaidConfig } from "../../../services/mermaid"; import { loadIncludedNote, refreshIncludedNote, setupImageOpening } from "./utils"; import { renderMathInElement } from "../../../services/math"; import { formatCodeBlocks } from "../../../services/syntax_highlight"; import TouchBar, { TouchBarButton, TouchBarSpacer } from "../../react/TouchBar"; import appContext from "../../../components/app_context"; import { applyReferenceLinks } from "./read_only_helper"; +import { applyInlineMermaid, rewriteMermaidDiagramsInContainer } from "../../../services/content_renderer"; export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetProps) { const blob = useNoteBlob(note); @@ -29,6 +29,7 @@ export default function ReadOnlyText({ note, noteContext, ntxId }: TypeWidgetPro const container = contentRef.current; if (!container) return; + rewriteMermaidDiagramsInContainer(container); applyInlineMermaid(container); applyIncludedNotes(container); applyMath(container); @@ -87,26 +88,6 @@ function useNoteLanguage(note: FNote) { return { isRtl }; } -async function applyInlineMermaid(container: HTMLDivElement) { - const mermaidBlocks = container.querySelectorAll('pre:has(code[class="language-mermaid"])'); - if (!mermaidBlocks.length) return; - const nodes: HTMLElement[] = []; - - // Rewrite the code block from
 to 
in order not to apply a codeblock style to it. - for (const mermaidBlock of mermaidBlocks) { - const div = document.createElement("div"); - div.classList.add("mermaid-diagram"); - div.innerHTML = mermaidBlock.querySelector("code")?.innerHTML ?? ""; - mermaidBlock.replaceWith(div); - nodes.push(div); - } - - // Initialize mermaid - const mermaid = (await import("mermaid")).default; - mermaid.initialize(getMermaidConfig()); - mermaid.run({ nodes }); -} - function applyIncludedNotes(container: HTMLDivElement) { const includedNotes = container.querySelectorAll("section.include-note"); for (const includedNote of includedNotes) {