Files
mypage/components/blog/markdown-renderer.tsx
2025-11-13 16:04:17 +02:00

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>
);
}