import ReactMarkdown from "react-markdown"; import "katex/dist/katex.min.css"; import RemarkMath from "remark-math"; import RemarkBreaks from "remark-breaks"; import RehypeKatex from "rehype-katex"; import RemarkGfm from "remark-gfm"; import RehypeHighlight from "rehype-highlight"; import { useRef, useState, RefObject, useEffect, useMemo } from "react"; import { copyToClipboard } from "../utils"; import mermaid from "mermaid"; import LoadingIcon from "../icons/three-dots.svg"; import React from "react"; import { useDebouncedCallback } from "use-debounce"; import { showImageModal } from "./ui-lib"; export function Mermaid(props: { code: string }) { const ref = useRef(null); const [hasError, setHasError] = useState(false); useEffect(() => { if (props.code && ref.current) { mermaid .run({ nodes: [ref.current], suppressErrors: true, }) .catch((e) => { setHasError(true); console.error("[Mermaid] ", e.message); }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [props.code]); function viewSvgInNewWindow() { const svg = ref.current?.querySelector("svg"); if (!svg) return; const text = new XMLSerializer().serializeToString(svg); const blob = new Blob([text], { type: "image/svg+xml" }); showImageModal(URL.createObjectURL(blob)); } if (hasError) { return null; } return (
viewSvgInNewWindow()} > {props.code}
); } export function PreCode(props: { children: any }) { const ref = useRef(null); const refText = ref.current?.innerText; const [mermaidCode, setMermaidCode] = useState(""); const renderMermaid = useDebouncedCallback(() => { if (!ref.current) return; const mermaidDom = ref.current.querySelector("code.language-mermaid"); if (mermaidDom) { setMermaidCode((mermaidDom as HTMLElement).innerText); } }, 600); useEffect(() => { setTimeout(renderMermaid, 1); // eslint-disable-next-line react-hooks/exhaustive-deps }, [refText]); return ( <> {mermaidCode.length > 0 && ( )}
         {
            if (ref.current) {
              const code = ref.current.innerText;
              copyToClipboard(code);
            }
          }}
        >
        {props.children}
      
); } function escapeDollarNumber(text: string) { let escapedText = ""; for (let i = 0; i < text.length; i += 1) { let char = text[i]; const nextChar = text[i + 1] || " "; if (char === "$" && nextChar >= "0" && nextChar <= "9") { char = "\\$"; } escapedText += char; } return escapedText; } function _MarkDownContent(props: { content: string }) { const escapedContent = useMemo( () => escapeDollarNumber(props.content), [props.content], ); return (

, a: (aProps) => { const href = aProps.href || ""; const isInternal = /^\/#/i.test(href); const target = isInternal ? "_self" : aProps.target ?? "_blank"; return ; }, }} > {escapedContent} ); } export const MarkdownContent = React.memo(_MarkDownContent); export function Markdown( props: { content: string; loading?: boolean; fontSize?: number; parentRef?: RefObject; defaultShow?: boolean; } & React.DOMAttributes, ) { const mdRef = useRef(null); return (

{props.loading ? ( ) : ( )}
); }