feat: add mermaid support in codeblock (#2971)

This commit is contained in:
Kristián 2024-02-19 08:10:58 +01:00 committed by GitHub
parent a86117f613
commit 03d67d5a00
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 911 additions and 7 deletions

View File

@ -62,6 +62,7 @@ services:
- pnpm-store:/work/web/.pnpm-store - pnpm-store:/work/web/.pnpm-store
- ../proto:/work/proto - ../proto:/work/proto
- ../web:/work/web - ../web:/work/web
- ../web/node_modules:/work/web/node_modules
healthcheck: healthcheck:
test: ["CMD", "wget", "-qO", "-", "http://localhost:3001"] test: ["CMD", "wget", "-qO", "-", "http://localhost:3001"]
interval: 10s interval: 10s

View File

@ -23,6 +23,7 @@
"katex": "^0.16.9", "katex": "^0.16.9",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"lucide-react": "^0.309.0", "lucide-react": "^0.309.0",
"mermaid": "^10.8.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1", "react-hot-toast": "^2.4.1",
@ -38,6 +39,8 @@
"devDependencies": { "devDependencies": {
"@bufbuild/buf": "^1.29.0", "@bufbuild/buf": "^1.29.0",
"@trivago/prettier-plugin-sort-imports": "^4.3.0", "@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/d3": "^7.4.3",
"@types/dompurify": "^3.0.5",
"@types/katex": "^0.16.7", "@types/katex": "^0.16.7",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/node": "^20.11.16", "@types/node": "^20.11.16",

876
web/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import { useColorScheme } from "@mui/joy"; import { useColorScheme } from "@mui/joy";
import mermaid from "mermaid";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Outlet } from "react-router-dom"; import { Outlet } from "react-router-dom";
@ -18,6 +19,8 @@ const App = () => {
const { appearance, locale, systemStatus } = globalStore.state; const { appearance, locale, systemStatus } = globalStore.state;
const userSetting = userStore.userSetting; const userSetting = userStore.userSetting;
mermaid.initialize({ startOnLoad: false, theme: mode });
// Redirect to sign up page if no host. // Redirect to sign up page if no host.
useEffect(() => { useEffect(() => {
if (!systemStatus.host) { if (!systemStatus.host) {

View File

@ -3,8 +3,11 @@ import copy from "copy-to-clipboard";
import hljs from "highlight.js"; import hljs from "highlight.js";
import toast from "react-hot-toast"; import toast from "react-hot-toast";
import Icon from "../Icon"; import Icon from "../Icon";
import MermaidBlock from "./MermaidBlock";
import { BaseProps } from "./types"; import { BaseProps } from "./types";
const MERMAID_LANGUAGE = "mermaid";
interface Props extends BaseProps { interface Props extends BaseProps {
language: string; language: string;
content: string; content: string;
@ -19,6 +22,10 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
return <div className="w-full overflow-auto !my-2" dangerouslySetInnerHTML={{ __html: content }} />; return <div className="w-full overflow-auto !my-2" dangerouslySetInnerHTML={{ __html: content }} />;
} }
if (formatedLanguage === MERMAID_LANGUAGE) {
return <MermaidBlock content={content} />;
}
try { try {
const temp = hljs.highlight(content, { const temp = hljs.highlight(content, {
language: formatedLanguage, language: formatedLanguage,
@ -39,6 +46,7 @@ const CodeBlock: React.FC<Props> = ({ language, content }: Props) => {
<span className="text-sm font-mono">{formatedLanguage}</span> <span className="text-sm font-mono">{formatedLanguage}</span>
<Icon.Copy className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} /> <Icon.Copy className="w-4 h-auto cursor-pointer hover:opacity-80" onClick={handleCopyButtonClick} />
</div> </div>
<pre className="w-full p-2 bg-amber-50 dark:bg-zinc-700 whitespace-pre-wrap relative"> <pre className="w-full p-2 bg-amber-50 dark:bg-zinc-700 whitespace-pre-wrap relative">
<code <code
className={classNames(`language-${formatedLanguage}`, "block text-sm leading-5")} className={classNames(`language-${formatedLanguage}`, "block text-sm leading-5")}

View File

@ -0,0 +1,27 @@
import mermaid from "mermaid";
import { useEffect, useRef } from "react";
interface Props {
content: string;
}
const MermaidBlock: React.FC<Props> = ({ content }: Props) => {
const mermaidDockBlock = useRef<null>(null);
useEffect(() => {
if (!mermaidDockBlock.current) {
return;
}
// Render mermaid when mounted
mermaid.run({
nodes: [mermaidDockBlock.current],
});
});
return (
<pre ref={mermaidDockBlock} className="w-full p-2 whitespace-pre-wrap relative" dangerouslySetInnerHTML={{ __html: content }}></pre>
);
};
export default MermaidBlock;