103 lines
2.8 KiB
TypeScript
103 lines
2.8 KiB
TypeScript
'use client';
|
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
import remarkGfm from 'remark-gfm';
|
|
import Image from 'next/image';
|
|
import Link from 'next/link';
|
|
import { CodeBlock } from './code-block';
|
|
|
|
interface MarkdownRendererProps {
|
|
content: string;
|
|
}
|
|
|
|
export default function MarkdownRenderer({ content }: MarkdownRendererProps) {
|
|
return (
|
|
<ReactMarkdown
|
|
remarkPlugins={[remarkGfm]}
|
|
components={{
|
|
h1: ({ children }) => {
|
|
const text = String(children);
|
|
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
return <h1 id={id}>{children}</h1>;
|
|
},
|
|
h2: ({ children }) => {
|
|
const text = String(children);
|
|
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
return <h2 id={id}>{children}</h2>;
|
|
},
|
|
h3: ({ children }) => {
|
|
const text = String(children);
|
|
const id = text.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/(^-|-$)/g, '');
|
|
return <h3 id={id}>{children}</h3>;
|
|
},
|
|
code: ({ inline, className, children, ...props }: any) => {
|
|
const match = /language-(\w+)/.exec(className || '');
|
|
if (!inline && match) {
|
|
return (
|
|
<CodeBlock
|
|
code={String(children).replace(/\n$/, '')}
|
|
language={match[1]}
|
|
/>
|
|
);
|
|
}
|
|
return (
|
|
<code {...props}>
|
|
{children}
|
|
</code>
|
|
);
|
|
},
|
|
img: ({ src, alt }) => {
|
|
if (!src || typeof src !== 'string') return null;
|
|
const isExternal = src.startsWith('http://') || src.startsWith('https://');
|
|
|
|
if (isExternal) {
|
|
return (
|
|
<img
|
|
src={src}
|
|
alt={alt || ''}
|
|
className="w-full h-auto"
|
|
/>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="relative w-full h-auto">
|
|
<Image
|
|
src={src}
|
|
alt={alt || ''}
|
|
width={800}
|
|
height={600}
|
|
style={{ width: '100%', height: 'auto' }}
|
|
/>
|
|
</div>
|
|
);
|
|
},
|
|
a: ({ href, children }) => {
|
|
if (!href) return <>{children}</>;
|
|
const isExternal = href.startsWith('http://') || href.startsWith('https://');
|
|
|
|
if (isExternal) {
|
|
return (
|
|
<a
|
|
href={href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
{children}
|
|
</a>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Link href={href}>
|
|
{children}
|
|
</Link>
|
|
);
|
|
},
|
|
}}
|
|
>
|
|
{content}
|
|
</ReactMarkdown>
|
|
);
|
|
}
|