mosaicmap/components/blocks/TextBlock.tsx
2025-08-11 21:26:46 +08:00

156 lines
7.2 KiB
TypeScript

"use client";
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import rehypePrism from 'rehype-prism-plus';
import type { TextBlock } from "@/types/page";
export default function TextBlockView(props: TextBlock) {
return (
<article className="prose prose-gray max-w-none dark:prose-invert">
<div className="text-gray-700 dark:text-gray-300 leading-relaxed">
<ReactMarkdown
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeKatex, rehypePrism]}
components={{
// 自定义代码块样式
code({ inline, className, children, ...props }: any) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<pre className="bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto">
<code className={className} {...props}>
{children}
</code>
</pre>
) : (
<code className="bg-gray-100 dark:bg-gray-700 px-1 py-0.5 rounded text-sm" {...props}>
{children}
</code>
);
},
// 自定义链接样式
a({ href, children }: any) {
return (
<a
href={href}
className="text-blue-600 dark:text-blue-400 hover:underline transition-colors"
target="_blank"
rel="noopener noreferrer"
>
{children}
</a>
);
},
// 自定义表格样式
table({ children }: any) {
return (
<div className="overflow-x-auto">
<table className="min-w-full border-collapse border border-gray-300 dark:border-gray-600">
{children}
</table>
</div>
);
},
th({ children }: any) {
return (
<th className="border border-gray-300 dark:border-gray-600 px-4 py-2 bg-gray-100 dark:bg-gray-700 font-semibold">
{children}
</th>
);
},
td({ children }: any) {
return (
<td className="border border-gray-300 dark:border-gray-600 px-4 py-2">
{children}
</td>
);
},
// 自定义引用样式
blockquote({ children }: any) {
return (
<blockquote className="border-l-4 border-blue-500 pl-4 py-2 bg-blue-50 dark:bg-blue-900/20 italic">
{children}
</blockquote>
);
},
// 自定义列表样式
ul({ children }: any) {
return (
<ul className="list-disc list-inside space-y-1">
{children}
</ul>
);
},
ol({ children }: any) {
return (
<ol className="list-decimal list-inside space-y-1">
{children}
</ol>
);
},
// 自定义标题样式
h1({ children }: any) {
return (
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4 mt-6">
{children}
</h1>
);
},
h2({ children }: any) {
return (
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-3 mt-5">
{children}
</h2>
);
},
h3({ children }: any) {
return (
<h3 className="text-xl font-bold text-gray-900 dark:text-gray-100 mb-2 mt-4">
{children}
</h3>
);
},
h4({ children }: any) {
return (
<h4 className="text-lg font-bold text-gray-900 dark:text-gray-100 mb-2 mt-3">
{children}
</h4>
);
},
h5({ children }: any) {
return (
<h5 className="text-base font-bold text-gray-900 dark:text-gray-100 mb-1 mt-2">
{children}
</h5>
);
},
h6({ children }: any) {
return (
<h6 className="text-sm font-bold text-gray-900 dark:text-gray-100 mb-1 mt-2">
{children}
</h6>
);
},
// 自定义段落样式
p({ children }: any) {
return (
<p className="mb-4 leading-relaxed">
{children}
</p>
);
},
// 自定义分割线样式
hr() {
return (
<hr className="my-8 border-gray-300 dark:border-gray-600" />
);
}
}}
>
{props.markdown}
</ReactMarkdown>
</div>
</article>
);
}