返回 JoyAI-Echo
MarkdownTextRenderer.tsx
根目录 / echo_longvideo / Director_Agent / webui / src / components / MarkdownTextRenderer.tsx
1 import ReactMarkdown from "react-markdown";
2 import rehypeKatex from "rehype-katex";
3 import remarkGfm from "remark-gfm";
4 import remarkMath from "remark-math";
5
6 import { CodeBlock } from "@/components/CodeBlock";
7 import { cn } from "@/lib/utils";
8
9 import "katex/dist/katex.min.css";
10
11 interface MarkdownTextRendererProps {
12 children: string;
13 className?: string;
14 }
15
16 /**
17 * Heavy markdown stack (GFM, math, KaTeX, syntax highlighting) kept in a
18 * separate chunk so the app shell can paint sooner on refresh.
19 */
20 export default function MarkdownTextRenderer({
21 children,
22 className,
23 }: MarkdownTextRendererProps) {
24 return (
25 <div
26 className={cn(
27 "markdown-content prose prose-base max-w-none dark:prose-invert",
28 "prose-headings:mt-4 prose-headings:mb-2 prose-headings:font-semibold prose-headings:tracking-tight",
29 "prose-h1:text-xl prose-h2:text-lg prose-h3:text-base prose-h4:text-sm",
30 "prose-p:my-3.5",
31 "prose-ul:my-2 prose-ol:my-2 prose-li:my-0.5",
32 "prose-blockquote:my-3 prose-blockquote:border-l-2 prose-blockquote:font-normal",
33 "prose-blockquote:not-italic prose-blockquote:text-foreground/80",
34 "prose-a:text-primary prose-a:underline-offset-2 hover:prose-a:opacity-80",
35 "prose-hr:my-6",
36 "prose-pre:my-0 prose-pre:bg-transparent prose-pre:p-0",
37 "prose-code:before:content-none prose-code:after:content-none prose-code:font-normal",
38 "prose-table:my-3 prose-th:text-left prose-th:font-medium",
39 className,
40 )}
41 style={{ lineHeight: "var(--cjk-line-height)" }}
42 >
43 <ReactMarkdown
44 remarkPlugins={[remarkGfm, remarkMath]}
45 rehypePlugins={[rehypeKatex]}
46 components={{
47 code({ className: cls, children: kids, ...props }) {
48 const match = /language-(\w+)/.exec(cls || "");
49 if (!match) {
50 return (
51 <code
52 className={cn(
53 "rounded bg-muted px-1 py-0.5 font-mono text-[0.85em]",
54 cls,
55 )}
56 {...props}
57 >
58 {kids}
59 </code>
60 );
61 }
62 const code = String(kids).replace(/\n$/, "");
63 return <CodeBlock language={match[1]} code={code} className="my-3" />;
64 },
65 pre({ children: markdownChildren }) {
66 return <>{markdownChildren}</>;
67 },
68 a({ href, children: markdownChildren, ...props }) {
69 return (
70 <a
71 href={href}
72 target="_blank"
73 rel="noreferrer noopener"
74 className="text-primary underline underline-offset-2 hover:opacity-80"
75 {...props}
76 >
77 {markdownChildren}
78 </a>
79 );
80 },
81 }}
82 >
83 {children}
84 </ReactMarkdown>
85 </div>
86 );
87 }
88
88 lines Plain Text