From ab71dd4aebe8d0925f441413a4714d9f7a8275e8 Mon Sep 17 00:00:00 2001 From: chyzman Date: Fri, 28 Aug 2026 23:17:02 -0400 Subject: [PATCH] mermaid and I tried to theme it --- package.json | 3 +- packages/assets/styles/classes.scss | 12 ++++ packages/ui/package.json | 1 + .../ui/src/components/base/MarkdownBody.vue | 2 + .../base/markdown/MarkdownMermaid.vue | 29 ++++++++++ packages/utils/markdown/parse.ts | 3 +- packages/utils/markdown/security.ts | 1 + patches/beautiful-mermaid@1.1.3.patch | 56 +++++++++++++++++++ patches/comark@0.6.2.patch | 4 +- pnpm-lock.yaml | 45 +++++++++++---- 10 files changed, 142 insertions(+), 14 deletions(-) create mode 100644 packages/ui/src/components/base/markdown/MarkdownMermaid.vue create mode 100644 patches/beautiful-mermaid@1.1.3.patch diff --git a/package.json b/package.json index 1b77452d1c..2477232ed9 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,8 @@ "pnpm": { "patchedDependencies": { "readable-stream@2.3.8": "patches/readable-stream@2.3.8.patch", - "comark@0.6.2": "patches/comark@0.6.2.patch" + "comark@0.6.2": "patches/comark@0.6.2.patch", + "beautiful-mermaid@1.1.3": "patches/beautiful-mermaid@1.1.3.patch" }, "peerDependencyRules": { "allowedVersions": { diff --git a/packages/assets/styles/classes.scss b/packages/assets/styles/classes.scss index 69c4615458..ab32774ee1 100644 --- a/packages/assets/styles/classes.scss +++ b/packages/assets/styles/classes.scss @@ -953,6 +953,18 @@ a:not(.no-click-animation), } } + .mermaid { + @apply bg-surface-2 rounded-xl p-4 border border-solid border-surface-5; + margin-top: 1rem; + overflow-x: auto; + + svg { + width: 100%; + max-width: 32rem; + height: auto; + } + } + code { @apply bg-surface-3 rounded-md p-4 border border-solid border-surface-5; padding: 0.2em 0.4em; diff --git a/packages/ui/package.json b/packages/ui/package.json index a1b22d3675..809ad59018 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -74,6 +74,7 @@ "@xterm/xterm": "^6.0.0", "ace-builds": "^1.43.5", "apexcharts": "^4.0.0", + "beautiful-mermaid": "^1.1.3", "comark": "^0.6.2", "dayjs": "^1.11.10", "dompurify": "^3.1.7", diff --git a/packages/ui/src/components/base/MarkdownBody.vue b/packages/ui/src/components/base/MarkdownBody.vue index 18cecec1fa..669a2ba36d 100644 --- a/packages/ui/src/components/base/MarkdownBody.vue +++ b/packages/ui/src/components/base/MarkdownBody.vue @@ -35,6 +35,7 @@ import { computed } from 'vue' import MarkdownAlert, { alertMarkerTypes } from './markdown/MarkdownAlert.vue' import MarkdownCollectionEmbed from './markdown/MarkdownCollectionEmbed.vue' import MarkdownHighlightedPre from './markdown/MarkdownHighlightedPre.vue' +import MarkdownMermaid from './markdown/MarkdownMermaid.vue' import MarkdownOrganizationEmbed from './markdown/MarkdownOrganizationEmbed.vue' import MarkdownProjectEmbed from './markdown/MarkdownProjectEmbed.vue' import MarkdownTaskCheckbox from './markdown/MarkdownTaskCheckbox.vue' @@ -84,6 +85,7 @@ const components = computed(() => organization: MarkdownOrganizationEmbed, collection: MarkdownCollectionEmbed, input: MarkdownTaskCheckbox, + mermaid: MarkdownMermaid, ...(props.highlight ? { pre: MarkdownHighlightedPre } : {}), }, ) diff --git a/packages/ui/src/components/base/markdown/MarkdownMermaid.vue b/packages/ui/src/components/base/markdown/MarkdownMermaid.vue new file mode 100644 index 0000000000..a348499408 --- /dev/null +++ b/packages/ui/src/components/base/markdown/MarkdownMermaid.vue @@ -0,0 +1,29 @@ + + + diff --git a/packages/utils/markdown/parse.ts b/packages/utils/markdown/parse.ts index 6e8693a11f..c307504252 100644 --- a/packages/utils/markdown/parse.ts +++ b/packages/utils/markdown/parse.ts @@ -11,6 +11,7 @@ import components from 'comark/plugins/components' import emoji from 'comark/plugins/emoji' import footnotes from 'comark/plugins/footnotes' import html from 'comark/plugins/html' +import mermaid from 'comark/plugins/mermaid' import punctuation from 'comark/plugins/punctuation' import taskList from 'comark/plugins/task-list' import { visitAsync } from 'comark/utils' @@ -48,7 +49,7 @@ export const modrinthPlugins: ComarkPlugin[] = [ modrinthHtmlBlock(), // json-render() // math(), // needs dep - // mermaid(), // needs dep + mermaid(), punctuation(), // rangi() // needs dep + we have highlight.js + if we do want to switch I'd say shiki is better modrinthEmbedSyntax(), diff --git a/packages/utils/markdown/security.ts b/packages/utils/markdown/security.ts index f757399c22..748a947fbd 100644 --- a/packages/utils/markdown/security.ts +++ b/packages/utils/markdown/security.ts @@ -93,6 +93,7 @@ export const attributeAllowlist: Record = { li: ['class'], map: ['name'], mark: [], + mermaid: ['content', 'theme', 'theme-dark', 'class'], nav: [], ol: [], organization: ['id'], diff --git a/patches/beautiful-mermaid@1.1.3.patch b/patches/beautiful-mermaid@1.1.3.patch new file mode 100644 index 0000000000..8f464a4444 --- /dev/null +++ b/patches/beautiful-mermaid@1.1.3.patch @@ -0,0 +1,56 @@ +diff --git a/dist/index.js b/dist/index.js +index e7e087bcb6f29d0d8f36cd558e0183bc0f162fcb..500c550c2723be4e84775afbb680dc1e06351451 100644 +--- a/dist/index.js ++++ b/dist/index.js +@@ -6985,14 +6985,18 @@ function markerSuffix(color) { + function renderGroup(group, font) { + const headerHeight = FONT_SIZES.groupHeader + 16; + const parts = []; ++ const clipId = `group-clip-${group.id.replace(/[^a-zA-Z0-9_-]/g, "_")}`; ++ parts.push( ++ `` ++ ); + parts.push( + `` + ); + parts.push( +- ` ` ++ ` ` + ); + parts.push( +- ` ` ++ ` ` + ); + parts.push( + " " + renderMultilineText( +@@ -7134,10 +7138,10 @@ function renderNodeShape(node) { + } + } + function renderRect(x, y, w, h, fill, stroke, sw) { +- return ``; ++ return ``; + } + function renderRoundedRect(x, y, w, h, fill, stroke, sw) { +- return ``; ++ return ``; + } + function renderStadium(x, y, w, h, fill, stroke, sw) { + const r2 = h / 2; +@@ -7168,7 +7172,7 @@ function renderDiamond(x, y, w, h, fill, stroke, sw) { + } + function renderSubroutine(x, y, w, h, fill, stroke, sw) { + const inset = 8; +- return ` ++ return ` + + `; + } +@@ -7645,7 +7649,7 @@ function renderActor(actor) { + } else { + const boxX = x - width / 2; + parts.push( +- ` ` ++ ` ` + ); + parts.push( + " " + renderMultilineText( diff --git a/patches/comark@0.6.2.patch b/patches/comark@0.6.2.patch index f8053d6cb6..4cc3ed7bb8 100644 --- a/patches/comark@0.6.2.patch +++ b/patches/comark@0.6.2.patch @@ -1,8 +1,8 @@ diff --git a/dist/internal/parse/token-processor.js b/dist/internal/parse/token-processor.js -index 440841f8d9252067681f09df935dd0287fff2cf0..71c44f24a932a1f900329800f28029206aa5a13f 100644 +index 440841f8d9252067681f09df935dd0287fff2cf0..e71c6f763d8520c53d7f7d8a1e9bcdc5e29f0526 100644 --- a/dist/internal/parse/token-processor.js +++ b/dist/internal/parse/token-processor.js -@@ -483,6 +483,20 @@ function processBlockChildren(tokens, startIndex, closeType, inlineOnly, inHeadi +@@ -483,6 +483,16 @@ function processBlockChildren(tokens, startIndex, closeType, inlineOnly, inHeadi } i++; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ce89af57f..3137a64ff9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,8 +5,11 @@ settings: excludeLinksFromLockfile: false patchedDependencies: + beautiful-mermaid@1.1.3: + hash: 51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47 + path: patches/beautiful-mermaid@1.1.3.patch comark@0.6.2: - hash: 4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c + hash: c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8 path: patches/comark@0.6.2.patch readable-stream@2.3.8: hash: 3045f7adf989b4e668a4a13819b7285b0de186b79bbf22408acaf2a41c6eaa86 @@ -654,7 +657,7 @@ importers: version: 6.39.12 '@comark/vue': specifier: ^0.6.2 - version: 0.6.2(vue@3.5.27(typescript@5.9.3)) + version: 0.6.2(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47))(vue@3.5.27(typescript@5.9.3)) '@intercom/messenger-js-sdk': specifier: ^0.0.14 version: 0.0.14 @@ -709,9 +712,12 @@ importers: apexcharts: specifier: ^4.0.0 version: 4.7.0 + beautiful-mermaid: + specifier: ^1.1.3 + version: 1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47) comark: specifier: ^0.6.2 - version: 0.6.2(patch_hash=4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c) + version: 0.6.2(patch_hash=c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8)(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)) dayjs: specifier: ^1.11.10 version: 1.11.19 @@ -856,13 +862,13 @@ importers: version: 6.39.12 '@comark/html': specifier: ^0.6.2 - version: 0.6.2 + version: 0.6.2(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)) '@types/three': specifier: ^0.172.0 version: 0.172.0 comark: specifier: ^0.6.2 - version: 0.6.2(patch_hash=4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c) + version: 0.6.2(patch_hash=c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8)(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)) dayjs: specifier: ^1.11.10 version: 1.11.19 @@ -5571,6 +5577,9 @@ packages: bcp-47@2.1.0: resolution: {integrity: sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==} + beautiful-mermaid@1.1.3: + resolution: {integrity: sha512-TItrtrAyHp1vwFfFVYauWGrquouk/6SS21Aq3RsxindSYZODcN4xYrPZD6BiZRU+o5mKJzDPz9MUSMvELdylyg==} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -6242,6 +6251,9 @@ packages: electron-to-chromium@1.5.286: resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} + elkjs@0.11.1: + resolution: {integrity: sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==} + emmet@2.4.11: resolution: {integrity: sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ==} @@ -11308,16 +11320,20 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@comark/html@0.6.2': + '@comark/html@0.6.2(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47))': dependencies: - comark: 0.6.2(patch_hash=4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c) + comark: 0.6.2(patch_hash=c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8)(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)) + optionalDependencies: + beautiful-mermaid: 1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47) transitivePeerDependencies: - rangi - '@comark/vue@0.6.2(vue@3.5.27(typescript@5.9.3))': + '@comark/vue@0.6.2(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47))(vue@3.5.27(typescript@5.9.3))': dependencies: - comark: 0.6.2(patch_hash=4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c) + comark: 0.6.2(patch_hash=c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8)(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)) vue: 3.5.27(typescript@5.9.3) + optionalDependencies: + beautiful-mermaid: 1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47) transitivePeerDependencies: - rangi @@ -15692,6 +15708,11 @@ snapshots: is-alphanumerical: 2.0.1 is-decimal: 2.0.1 + beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47): + dependencies: + elkjs: 0.11.1 + entities: 7.0.1 + binary-extensions@2.3.0: {} bindings@1.5.0: @@ -15951,12 +15972,14 @@ snapshots: colord@2.9.3: {} - comark@0.6.2(patch_hash=4e73fba3ed127a788219ec2e7a413966f48fc7695802a1b0f2694ef2686d475c): + comark@0.6.2(patch_hash=c8af805d46dd2a152fda357d551ed56a0a876f61520b78ad6fe250b82afd17f8)(beautiful-mermaid@1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47)): dependencies: entities: 8.0.0 htmlparser2: 12.0.0 js-yaml: 5.3.0 markdown-exit: 1.1.0-beta.2 + optionalDependencies: + beautiful-mermaid: 1.1.3(patch_hash=51834efb99f2945be29ce3a3cbc45a3b9ff4cde6ca80ba6d2c22e85d9b9cbd47) combined-stream@1.0.8: dependencies: @@ -16323,6 +16346,8 @@ snapshots: electron-to-chromium@1.5.286: {} + elkjs@0.11.1: {} + emmet@2.4.11: dependencies: '@emmetio/abbreviation': 2.3.3