import { LightAsync as SyntaxHighlighter } from "react-syntax-highlighter"; import { atomOneDark as style } from "react-syntax-highlighter/dist/esm/styles/hljs"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import remarkBreaks from "remark-breaks"; import rehypeKatex from "rehype-katex"; import { parseFile } from "./plugins/file.tsx"; import "@/assets/markdown/all.less"; import { useEffect, useMemo } from "react"; import { useDispatch } from "react-redux"; import { openDialog as openQuotaDialog } from "@/store/quota.ts"; import { openDialog as openSubscriptionDialog } from "@/store/subscription.ts"; import { AppDispatch } from "@/store"; import { Copy } from "lucide-react"; import { copyClipboard } from "@/utils/dom.ts"; import { useToast } from "./ui/use-toast.ts"; import { useTranslation } from "react-i18next"; import { parseProgressbar } from "@/components/plugins/progress.tsx"; type MarkdownProps = { children: string; className?: string; }; function doAction(dispatch: AppDispatch, url: string): boolean { if (url === "/subscribe") { dispatch(openSubscriptionDialog()); return true; } else if (url === "/buy") { dispatch(openQuotaDialog()); return true; } return false; } const LanguageMap: Record = { html: "htmlbars", js: "javascript", ts: "typescript", jsx: "javascript", tsx: "typescript", rs: "rust", }; function MarkdownContent({ children, className }: MarkdownProps) { const dispatch = useDispatch(); const { t } = useTranslation(); const { toast } = useToast(); useEffect(() => { document.querySelectorAll(".file-instance").forEach((el) => { const parent = el.parentElement as HTMLElement; if (!parent.classList.contains("file-block")) parent.classList.add("file-block"); }); }, [children]); return ( { if (doAction(dispatch, url)) e.preventDefault(); }} > {children} ); }, code({ inline, className, children, ...props }) { const match = /language-(\w+)/.exec(className || ""); const language = match ? match[1] : ""; if (language === "file") return parseFile(children.toString()); if (language === "progress") return parseProgressbar(children.toString()); return !inline && match ? (
{ await copyClipboard(children.toString()); toast({ title: t("share.copied"), }); }} />

{language}

) : ( {children} ); }, }} /> ); } function Markdown(props: MarkdownProps) { // memoize the component const { children, className } = props; return useMemo( () => {children}, [props.children, props.className], ); } export default Markdown;