mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-30 03:32:26 +08:00
refactor(client): use webpack for mermaid
This commit is contained in:
parent
f4d5b9fc29
commit
28c51cb38a
@ -76,7 +76,6 @@ try {
|
|||||||
"node_modules/dayjs/",
|
"node_modules/dayjs/",
|
||||||
"node_modules/boxicons/css/",
|
"node_modules/boxicons/css/",
|
||||||
"node_modules/boxicons/fonts/",
|
"node_modules/boxicons/fonts/",
|
||||||
"node_modules/mermaid/dist/",
|
|
||||||
"node_modules/jquery/dist/",
|
"node_modules/jquery/dist/",
|
||||||
"node_modules/jquery-hotkeys/",
|
"node_modules/jquery-hotkeys/",
|
||||||
"node_modules/split.js/dist/",
|
"node_modules/split.js/dist/",
|
||||||
|
@ -16,7 +16,6 @@ import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons
|
|||||||
import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js";
|
import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js";
|
||||||
import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
|
import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js";
|
||||||
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
|
import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js";
|
||||||
import MermaidWidget from "../widgets/mermaid.js";
|
|
||||||
import NoteListWidget from "../widgets/note_list.js";
|
import NoteListWidget from "../widgets/note_list.js";
|
||||||
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
import GlobalMenuWidget from "../widgets/buttons/global_menu.js";
|
||||||
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
import LauncherContainer from "../widgets/containers/launcher_container.js";
|
||||||
@ -165,7 +164,6 @@ export default class MobileLayout {
|
|||||||
.child(new BacklinksWidget())
|
.child(new BacklinksWidget())
|
||||||
.child(new HideFloatingButtonsButton())
|
.child(new HideFloatingButtonsButton())
|
||||||
)
|
)
|
||||||
.child(new MermaidWidget())
|
|
||||||
.child(new PromotedAttributesWidget())
|
.child(new PromotedAttributesWidget())
|
||||||
.child(
|
.child(
|
||||||
new ScrollingContainer()
|
new ScrollingContainer()
|
||||||
|
@ -15,6 +15,7 @@ import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
|
|||||||
import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
|
import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js";
|
||||||
import renderDoc from "./doc_renderer.js";
|
import renderDoc from "./doc_renderer.js";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
|
import type { Mermaid } from "mermaid";
|
||||||
|
|
||||||
let idCounter = 1;
|
let idCounter = 1;
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent:
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>) {
|
async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery<HTMLElement>) {
|
||||||
await libraryLoader.requireLibrary(libraryLoader.MERMAID);
|
const mermaid = (await import("mermaid")).default;
|
||||||
|
|
||||||
const blob = await note.getBlob();
|
const blob = await note.getBlob();
|
||||||
const content = blob?.content || "";
|
const content = blob?.content || "";
|
||||||
@ -236,10 +237,10 @@ async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery
|
|||||||
const documentStyle = window.getComputedStyle(document.documentElement);
|
const documentStyle = window.getComputedStyle(document.documentElement);
|
||||||
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
|
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
|
||||||
|
|
||||||
mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim(), securityLevel: "antiscript" });
|
mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim() as "default", securityLevel: "antiscript" });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await loadElkIfNeeded(content);
|
await loadElkIfNeeded(mermaid, content);
|
||||||
const { svg } = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content);
|
const { svg } = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content);
|
||||||
|
|
||||||
$renderedContent.append($(postprocessMermaidSvg(svg)));
|
$renderedContent.append($(postprocessMermaidSvg(svg)));
|
||||||
|
@ -55,10 +55,6 @@ const WHEEL_ZOOM: Library = {
|
|||||||
js: ["node_modules/vanilla-js-wheel-zoom/dist/wheel-zoom.min.js"]
|
js: ["node_modules/vanilla-js-wheel-zoom/dist/wheel-zoom.min.js"]
|
||||||
};
|
};
|
||||||
|
|
||||||
const MERMAID: Library = {
|
|
||||||
js: ["node_modules/mermaid/dist/mermaid.min.js"]
|
|
||||||
};
|
|
||||||
|
|
||||||
const MARKJS: Library = {
|
const MARKJS: Library = {
|
||||||
js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"]
|
js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"]
|
||||||
};
|
};
|
||||||
@ -181,7 +177,6 @@ export default {
|
|||||||
CALENDAR_WIDGET,
|
CALENDAR_WIDGET,
|
||||||
KATEX,
|
KATEX,
|
||||||
WHEEL_ZOOM,
|
WHEEL_ZOOM,
|
||||||
MERMAID,
|
|
||||||
MARKJS,
|
MARKJS,
|
||||||
HIGHLIGHT_JS,
|
HIGHLIGHT_JS,
|
||||||
LEAFLET
|
LEAFLET
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import type { Mermaid } from "mermaid";
|
||||||
|
|
||||||
let elkLoaded = false;
|
let elkLoaded = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -9,7 +11,7 @@ let elkLoaded = false;
|
|||||||
*
|
*
|
||||||
* @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter.
|
* @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter.
|
||||||
*/
|
*/
|
||||||
export async function loadElkIfNeeded(mermaidContent: string) {
|
export async function loadElkIfNeeded(mermaid: Mermaid, mermaidContent: string) {
|
||||||
if (elkLoaded) {
|
if (elkLoaded) {
|
||||||
// Exit immediately since the ELK library is already loaded.
|
// Exit immediately since the ELK library is already loaded.
|
||||||
return;
|
return;
|
||||||
@ -18,7 +20,7 @@ export async function loadElkIfNeeded(mermaidContent: string) {
|
|||||||
const parsedContent = await mermaid.parse(mermaidContent, {
|
const parsedContent = await mermaid.parse(mermaidContent, {
|
||||||
suppressErrors: true
|
suppressErrors: true
|
||||||
});
|
});
|
||||||
if (parsedContent?.config?.layout === "elk") {
|
if (parsedContent && parsedContent.config?.layout === "elk") {
|
||||||
elkLoaded = true;
|
elkLoaded = true;
|
||||||
mermaid.registerLayoutLoaders((await import("@mermaid-js/layout-elk")).default);
|
mermaid.registerLayoutLoaders((await import("@mermaid-js/layout-elk")).default);
|
||||||
}
|
}
|
||||||
|
42
src/public/app/types.d.ts
vendored
42
src/public/app/types.d.ts
vendored
@ -8,6 +8,7 @@ import library_loader, { Library } from "./services/library_loader.ts";
|
|||||||
import type { init } from "i18next";
|
import type { init } from "i18next";
|
||||||
import type { lint } from "./services/eslint.ts";
|
import type { lint } from "./services/eslint.ts";
|
||||||
import type { RelationType } from "./widgets/type_widgets/relation_map.ts";
|
import type { RelationType } from "./widgets/type_widgets/relation_map.ts";
|
||||||
|
import type { Mermaid } from "mermaid";
|
||||||
|
|
||||||
interface ElectronProcess {
|
interface ElectronProcess {
|
||||||
type: string;
|
type: string;
|
||||||
@ -138,45 +139,6 @@ declare global {
|
|||||||
zoomOnClick: boolean
|
zoomOnClick: boolean
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
interface MermaidApi {
|
|
||||||
initialize(opts: {
|
|
||||||
startOnLoad: boolean,
|
|
||||||
theme: string,
|
|
||||||
securityLevel: "antiscript"
|
|
||||||
}): void;
|
|
||||||
render(selector: string, data: string);
|
|
||||||
}
|
|
||||||
interface MermaidLoader {
|
|
||||||
|
|
||||||
}
|
|
||||||
interface MermaidChartConfig {
|
|
||||||
useMaxWidth: boolean;
|
|
||||||
}
|
|
||||||
interface MermaidConfig {
|
|
||||||
theme: string;
|
|
||||||
securityLevel: "antiscript",
|
|
||||||
flow: MermaidChartConfig;
|
|
||||||
sequence: MermaidChartConfig;
|
|
||||||
gantt: MermaidChartConfig;
|
|
||||||
class: MermaidChartConfig;
|
|
||||||
state: MermaidChartConfig;
|
|
||||||
pie: MermaidChartConfig;
|
|
||||||
journey: MermaidChartConfig;
|
|
||||||
git: MermaidChartConfig;
|
|
||||||
}
|
|
||||||
var mermaid: {
|
|
||||||
mermaidAPI: MermaidApi;
|
|
||||||
registerLayoutLoaders(loader: MermaidLoader);
|
|
||||||
init(config: MermaidConfig, el: HTMLElement | JQuery<HTMLElement>);
|
|
||||||
parse(content: string, opts: {
|
|
||||||
suppressErrors: true
|
|
||||||
}): Promise<{
|
|
||||||
config: {
|
|
||||||
layout: string;
|
|
||||||
}
|
|
||||||
}>
|
|
||||||
};
|
|
||||||
|
|
||||||
interface CKCodeBlockLanguage {
|
interface CKCodeBlockLanguage {
|
||||||
language: string;
|
language: string;
|
||||||
label: string;
|
label: string;
|
||||||
@ -207,7 +169,7 @@ declare global {
|
|||||||
enablePreview: boolean
|
enablePreview: boolean
|
||||||
},
|
},
|
||||||
mermaid: {
|
mermaid: {
|
||||||
lazyLoad: () => Promise<void>,
|
lazyLoad: () => Promise<Mermaid>,
|
||||||
config: MermaidConfig
|
config: MermaidConfig
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,7 @@ import AbstractSplitTypeWidget from "./abstract_split_type_widget.js";
|
|||||||
* This adds the following functionality:
|
* This adds the following functionality:
|
||||||
*
|
*
|
||||||
* - Automatic handling of the preview when content or the note changes.
|
* - Automatic handling of the preview when content or the note changes.
|
||||||
|
* - Built-in pan and zoom functionality with automatic re-centering.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTypeWidget {
|
export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTypeWidget {
|
||||||
|
@ -13,10 +13,10 @@ import dialogService from "../../services/dialog.js";
|
|||||||
import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js";
|
import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js";
|
||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import toast from "../../services/toast.js";
|
import toast from "../../services/toast.js";
|
||||||
import { getMermaidConfig } from "../mermaid.js";
|
|
||||||
import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js";
|
import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js";
|
||||||
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
|
import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
|
import { getMermaidConfig } from "./mermaid.js";
|
||||||
|
|
||||||
const ENABLE_INSPECTOR = false;
|
const ENABLE_INSPECTOR = false;
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
enablePreview: true // Enable preview view
|
enablePreview: true // Enable preview view
|
||||||
},
|
},
|
||||||
mermaid: {
|
mermaid: {
|
||||||
lazyLoad: async () => await libraryLoader.requireLibrary(libraryLoader.MERMAID),
|
lazyLoad: async () => (await import("mermaid")).default, // FIXME
|
||||||
config: getMermaidConfig()
|
config: getMermaidConfig()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import type { MermaidConfig } from "mermaid";
|
||||||
import library_loader from "../../services/library_loader.js";
|
import library_loader from "../../services/library_loader.js";
|
||||||
import { loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js";
|
import { loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js";
|
||||||
import AbstractSvgSplitTypeWidget from "./abstract_svg_split_type_widget.js";
|
import AbstractSvgSplitTypeWidget from "./abstract_svg_split_type_widget.js";
|
||||||
@ -11,8 +12,8 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async renderSvg(content: string) {
|
async renderSvg(content: string) {
|
||||||
await library_loader.requireLibrary(library_loader.MERMAID);
|
const mermaid = (await import("mermaid")).default;
|
||||||
await loadElkIfNeeded(content);
|
await loadElkIfNeeded(mermaid, content);
|
||||||
|
|
||||||
mermaid.mermaidAPI.initialize({
|
mermaid.mermaidAPI.initialize({
|
||||||
startOnLoad: false,
|
startOnLoad: false,
|
||||||
@ -28,19 +29,18 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget {
|
|||||||
|
|
||||||
export function getMermaidConfig(): MermaidConfig {
|
export function getMermaidConfig(): MermaidConfig {
|
||||||
const documentStyle = window.getComputedStyle(document.documentElement);
|
const documentStyle = window.getComputedStyle(document.documentElement);
|
||||||
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
|
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme") as "default";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
theme: mermaidTheme.trim(),
|
theme: mermaidTheme.trim() as "default",
|
||||||
securityLevel: "antiscript",
|
securityLevel: "antiscript",
|
||||||
// TODO: Are all these options correct?
|
flowchart: { useMaxWidth: false },
|
||||||
flow: { useMaxWidth: false },
|
|
||||||
sequence: { useMaxWidth: false },
|
sequence: { useMaxWidth: false },
|
||||||
gantt: { useMaxWidth: false },
|
gantt: { useMaxWidth: false },
|
||||||
class: { useMaxWidth: false },
|
class: { useMaxWidth: false },
|
||||||
state: { useMaxWidth: false },
|
state: { useMaxWidth: false },
|
||||||
pie: { useMaxWidth: true },
|
pie: { useMaxWidth: true },
|
||||||
journey: { useMaxWidth: false },
|
journey: { useMaxWidth: false },
|
||||||
git: { useMaxWidth: false }
|
gitGraph: { useMaxWidth: false }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
||||||
import libraryLoader from "../../services/library_loader.js";
|
import libraryLoader from "../../services/library_loader.js";
|
||||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
|
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
|
||||||
import { getMermaidConfig } from "../mermaid.js";
|
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import type { EventData } from "../../components/app_context.js";
|
import type { EventData } from "../../components/app_context.js";
|
||||||
import { getLocaleById } from "../../services/i18n.js";
|
import { getLocaleById } from "../../services/i18n.js";
|
||||||
|
import { getMermaidConfig } from "./mermaid.js";
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="note-detail-readonly-text note-detail-printable">
|
<div class="note-detail-readonly-text note-detail-printable">
|
||||||
@ -141,8 +141,8 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Initialize mermaid
|
// Initialize mermaid
|
||||||
await libraryLoader.requireLibrary(libraryLoader.MERMAID);
|
const mermaid = (await import("mermaid")).default;
|
||||||
mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram"));
|
mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram")[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) {
|
async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) {
|
||||||
|
@ -64,8 +64,6 @@ async function register(app: express.Application) {
|
|||||||
app.use(`/${assetPath}/node_modules/boxicons/css/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/css/")));
|
app.use(`/${assetPath}/node_modules/boxicons/css/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/css/")));
|
||||||
app.use(`/${assetPath}/node_modules/boxicons/fonts/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/fonts/")));
|
app.use(`/${assetPath}/node_modules/boxicons/fonts/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/fonts/")));
|
||||||
|
|
||||||
app.use(`/${assetPath}/node_modules/mermaid/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/mermaid/dist/")));
|
|
||||||
|
|
||||||
app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery/dist/")));
|
app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery/dist/")));
|
||||||
|
|
||||||
app.use(`/${assetPath}/node_modules/jquery-hotkeys/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery-hotkeys/")));
|
app.use(`/${assetPath}/node_modules/jquery-hotkeys/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery-hotkeys/")));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user