mirror of
https://github.com/usememos/memos.git
synced 2025-02-11 08:50:40 +01:00
feat: add mermaid support in codeblock (#2971)
This commit is contained in:
parent
a86117f613
commit
03d67d5a00
@ -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
|
||||||
|
@ -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
876
web/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -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) {
|
||||||
|
@ -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")}
|
||||||
|
27
web/src/components/MemoContent/MermaidBlock.tsx
Normal file
27
web/src/components/MemoContent/MermaidBlock.tsx
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user