mirror of
https://github.com/theoludwig/theoludwig.git
synced 2024-12-08 00:44:30 +01:00
112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
|
import Image from 'next/image'
|
||
|
import Link from 'next/link'
|
||
|
import { cookies } from 'next/headers'
|
||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||
|
import { faLink } from '@fortawesome/free-solid-svg-icons'
|
||
|
import { MDXRemote } from 'next-mdx-remote/rsc'
|
||
|
import { nodeTypes } from '@mdx-js/mdx'
|
||
|
import rehypeRaw from 'rehype-raw'
|
||
|
import remarkGfm from 'remark-gfm'
|
||
|
import rehypeSlug from 'rehype-slug'
|
||
|
import remarkMath from 'remark-math'
|
||
|
import rehypeKatex from 'rehype-katex'
|
||
|
import { getHighlighter } from 'shiki'
|
||
|
|
||
|
import 'katex/dist/katex.min.css'
|
||
|
|
||
|
import { getTheme } from '@/theme/theme.server'
|
||
|
import { remarkSyntaxHighlightingPlugin } from '@/blog/remarkSyntaxHighlightingPlugin'
|
||
|
import { BlogPostComments } from '@/blog/BlogPostComments'
|
||
|
|
||
|
const Heading = (
|
||
|
props: React.DetailedHTMLProps<
|
||
|
React.HTMLAttributes<HTMLHeadingElement>,
|
||
|
HTMLHeadingElement
|
||
|
>
|
||
|
): JSX.Element => {
|
||
|
const { children, id = '' } = props
|
||
|
return (
|
||
|
<h2 {...props} className='group'>
|
||
|
<Link
|
||
|
href={`#${id}`}
|
||
|
className='invisible !text-black group-hover:visible dark:!text-white'
|
||
|
>
|
||
|
<FontAwesomeIcon className='mr-2 inline h-4 w-4' icon={faLink} />
|
||
|
</Link>
|
||
|
{children}
|
||
|
</h2>
|
||
|
)
|
||
|
}
|
||
|
|
||
|
export interface BlogPostContentProps {
|
||
|
content: string
|
||
|
}
|
||
|
|
||
|
export const BlogPostContent = async (
|
||
|
props: BlogPostContentProps
|
||
|
): Promise<JSX.Element> => {
|
||
|
const { content } = props
|
||
|
|
||
|
const cookiesStore = cookies()
|
||
|
const theme = getTheme()
|
||
|
|
||
|
const highlighter = await getHighlighter({
|
||
|
theme: `${theme}-plus`
|
||
|
})
|
||
|
|
||
|
return (
|
||
|
<div className='prose mb-10'>
|
||
|
<div className='px-8'>
|
||
|
<MDXRemote
|
||
|
source={content}
|
||
|
options={{
|
||
|
mdxOptions: {
|
||
|
remarkPlugins: [
|
||
|
remarkGfm,
|
||
|
[remarkSyntaxHighlightingPlugin, { highlighter }],
|
||
|
remarkMath
|
||
|
],
|
||
|
rehypePlugins: [
|
||
|
rehypeSlug,
|
||
|
[rehypeRaw, { passThrough: nodeTypes }],
|
||
|
rehypeKatex
|
||
|
]
|
||
|
}
|
||
|
}}
|
||
|
components={{
|
||
|
h1: Heading,
|
||
|
h2: Heading,
|
||
|
h3: Heading,
|
||
|
h4: Heading,
|
||
|
h5: Heading,
|
||
|
h6: Heading,
|
||
|
img: (properties) => {
|
||
|
const { src = '', alt = 'Blog Image' } = properties
|
||
|
const source = src.replace('../../public/', '/')
|
||
|
return (
|
||
|
<span className='flex flex-col items-center justify-center'>
|
||
|
<Image
|
||
|
src={source}
|
||
|
alt={alt}
|
||
|
width={1000}
|
||
|
height={1000}
|
||
|
className='h-auto w-auto'
|
||
|
/>
|
||
|
</span>
|
||
|
)
|
||
|
},
|
||
|
a: (props) => {
|
||
|
const { href = '' } = props
|
||
|
if (href.startsWith('#')) {
|
||
|
return <a {...props} />
|
||
|
}
|
||
|
return <a target='_blank' rel='noopener noreferrer' {...props} />
|
||
|
}
|
||
|
}}
|
||
|
/>
|
||
|
<BlogPostComments cookiesStore={cookiesStore.toString()} />
|
||
|
</div>
|
||
|
</div>
|
||
|
)
|
||
|
}
|