|
|
|
import { Metadata } from "next"
|
|
|
|
import { Code } from "bright"
|
|
|
|
import { getPostSlugs, loadPageMetada, loadSinglePage } from "~/utils/post"
|
|
|
|
import MarkdownToJSX from 'markdown-to-jsx'
|
|
|
|
|
|
|
|
import styles from "~/styles/post.module.css"
|
|
|
|
import { ReactElement } from "react"
|
|
|
|
import ScriptLoaderServer from "~/components/ScriptLoader/server"
|
|
|
|
|
|
|
|
export async function generateMetadata({ params: { slug } }: { params: { slug: string } }): Promise<Metadata> {
|
|
|
|
const post = await loadPageMetada(slug)
|
|
|
|
|
|
|
|
return {
|
|
|
|
title: post?.title
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function generateStaticParams(): Promise<{ slug: string }[]> {
|
|
|
|
const slugs = await getPostSlugs()
|
|
|
|
return slugs.map(slug => ({ slug }))
|
|
|
|
}
|
|
|
|
|
|
|
|
export default async function Post({ params: { slug } }: { params: { slug: string } }) {
|
|
|
|
const post = await loadSinglePage(slug)
|
|
|
|
|
|
|
|
if (!post)
|
|
|
|
return null
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<article className={styles.post}>
|
|
|
|
<span>{post.date.toLocaleDateString('en-US', { timeZone: 'UTC' })}</span>
|
|
|
|
<h1>{post.title}</h1>
|
|
|
|
<p className={styles.subtitle}>{post.subtitle}</p>
|
|
|
|
|
|
|
|
<Markdown>{post.body}</Markdown>
|
|
|
|
|
|
|
|
{post.resources?.length && (
|
|
|
|
<>
|
|
|
|
<hr className={styles.postFooter} />
|
|
|
|
<h2 id="resources">Post Resources:</h2>
|
|
|
|
<ul>
|
|
|
|
{post.resources.map(resource => (
|
|
|
|
<li><a target="_blank" href={`/_next/static/scripts/${resource}`}>{resource}</a></li>
|
|
|
|
))}
|
|
|
|
</ul>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</article>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function Markdown({ children }: { children: string }) {
|
|
|
|
const options = {
|
|
|
|
overrides: {
|
|
|
|
pre: {
|
|
|
|
component: CodeBlock,
|
|
|
|
props: {}
|
|
|
|
},
|
|
|
|
ScriptLoader: {
|
|
|
|
component: ScriptLoaderServer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{/* @ts-expect-error Async Server Component */ }
|
|
|
|
return <MarkdownToJSX children={children} options={options} />
|
|
|
|
}
|
|
|
|
|
|
|
|
Code.theme = {
|
|
|
|
dark: "github-dark",
|
|
|
|
light: "github-light",
|
|
|
|
lightSelector: ':root.light'
|
|
|
|
}
|
|
|
|
|
|
|
|
function CodeBlock({ children }: { children: ReactElement }) {
|
|
|
|
// extract props normally passed to pre element
|
|
|
|
const { className: langKey, children: sourceText, ...rest } = children?.props ?? {}
|
|
|
|
const language = langKey?.replace(/^lang-/i, '')
|
|
|
|
|
|
|
|
{/* @ts-expect-error Async Server Component */ }
|
|
|
|
return <Code lang={language} children={sourceText} {...rest} />
|
|
|
|
}
|