89 lines
2.6 KiB
TypeScript
89 lines
2.6 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>
|
|
)
|
|
}
|