mirror of https://github.com/almqv/wych.dev
parent
ff4a3ec032
commit
a64e2a8a44
@ -0,0 +1,15 @@ |
|||||||
|
--- |
||||||
|
title: "Example Essay with Math" |
||||||
|
createdAt: "2024-03-20" |
||||||
|
updatedAt: "2024-03-20" |
||||||
|
--- |
||||||
|
|
||||||
|
# Example Essay with Math |
||||||
|
|
||||||
|
This is an example of an essay with both inline math $E = mc^2$ and block math: |
||||||
|
|
||||||
|
$$ |
||||||
|
\frac{-b \pm \sqrt{b^2 - 4ac}}{2a} |
||||||
|
$$ |
||||||
|
|
||||||
|
You can write normal markdown and **MDX** content here. |
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,74 @@ |
|||||||
import { notFound } from "next/navigation"; |
import { notFound } from "next/navigation"; |
||||||
|
import { MDXRemote } from 'next-mdx-remote/rsc'; |
||||||
|
import fs from 'fs/promises'; |
||||||
|
import path from 'path'; |
||||||
|
import matter from 'gray-matter'; |
||||||
|
import remarkMath from 'remark-math'; |
||||||
|
import rehypeKatex from 'rehype-katex'; |
||||||
|
|
||||||
type Log = { |
// Update the type to match our MDX frontmatter
|
||||||
|
type Post = { |
||||||
title: string; |
title: string; |
||||||
createdAt: Date; |
createdAt: string; |
||||||
updatedAt: Date; |
updatedAt: string; |
||||||
content: React.ReactNode; |
content: string; |
||||||
}; |
}; |
||||||
|
|
||||||
const Page = async () => { |
async function getPost(slug: string[]): Promise<Post | null> { |
||||||
const post = undefined; |
// Handle only essays/[name] route
|
||||||
|
if (slug[0] !== 'essays' || slug.length !== 2) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
const postName = slug[1]; |
||||||
|
const postsDirectory = path.join(process.cwd(), 'content/essays'); |
||||||
|
|
||||||
|
try { |
||||||
|
const fullPath = path.join(postsDirectory, `${postName}.mdx`); |
||||||
|
const fileContents = await fs.readFile(fullPath, 'utf8'); |
||||||
|
|
||||||
|
const { data, content } = matter(fileContents); |
||||||
|
|
||||||
|
return { |
||||||
|
title: data.title, |
||||||
|
createdAt: data.createdAt, |
||||||
|
updatedAt: data.updatedAt, |
||||||
|
content: content, |
||||||
|
}; |
||||||
|
} catch (error) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const Page = async ({ params }: { params: { dir: string[] } }) => { |
||||||
|
const post = await getPost(params.dir); |
||||||
|
|
||||||
if (!post) { |
if (!post) { |
||||||
return notFound(); |
return notFound(); |
||||||
} |
} |
||||||
|
|
||||||
return <h1>WIP</h1>; |
return ( |
||||||
|
<article className="prose prose-lg max-w-prose mx-auto py-8"> |
||||||
|
<h1>{post.title}</h1> |
||||||
|
<div className="text-sm text-gray-500"> |
||||||
|
<time>Created: {new Date(post.createdAt).toLocaleDateString()}</time> |
||||||
|
{post.updatedAt && ( |
||||||
|
<time className="ml-4"> |
||||||
|
Updated: {new Date(post.updatedAt).toLocaleDateString()} |
||||||
|
</time> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
<MDXRemote
|
||||||
|
source={post.content} |
||||||
|
options={{ |
||||||
|
mdxOptions: { |
||||||
|
remarkPlugins: [remarkMath], |
||||||
|
rehypePlugins: [rehypeKatex], |
||||||
|
} |
||||||
|
}} |
||||||
|
/> |
||||||
|
</article> |
||||||
|
); |
||||||
}; |
}; |
||||||
|
|
||||||
export default Page; |
export default Page; |
||||||
|
@ -0,0 +1,60 @@ |
|||||||
|
import fs from 'fs/promises'; |
||||||
|
import path from 'path'; |
||||||
|
import matter from 'gray-matter'; |
||||||
|
import Link from 'next/link'; |
||||||
|
|
||||||
|
type PostMeta = { |
||||||
|
title: string; |
||||||
|
createdAt: string; |
||||||
|
slug: string; |
||||||
|
}; |
||||||
|
|
||||||
|
async function getPosts(): Promise<PostMeta[]> { |
||||||
|
const postsDirectory = path.join(process.cwd(), 'content/essays'); |
||||||
|
const files = await fs.readdir(postsDirectory); |
||||||
|
|
||||||
|
const posts = await Promise.all( |
||||||
|
files |
||||||
|
.filter(file => file.endsWith('.mdx')) |
||||||
|
.map(async (file) => { |
||||||
|
const fullPath = path.join(postsDirectory, file); |
||||||
|
const fileContents = await fs.readFile(fullPath, 'utf8'); |
||||||
|
const { data } = matter(fileContents); |
||||||
|
|
||||||
|
return { |
||||||
|
title: data.title, |
||||||
|
createdAt: data.createdAt, |
||||||
|
slug: file.replace(/\.mdx$/, ''), |
||||||
|
}; |
||||||
|
}) |
||||||
|
); |
||||||
|
|
||||||
|
return posts.sort((a, b) =>
|
||||||
|
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default async function PostsPage() { |
||||||
|
const posts = await getPosts(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="max-w-prose mx-auto py-8"> |
||||||
|
<h1 className="text-3xl font-bold mb-8">Essays</h1> |
||||||
|
<ul className="space-y-4"> |
||||||
|
{posts.map((post) => ( |
||||||
|
<li key={post.slug}> |
||||||
|
<Link
|
||||||
|
href={`/essays/${post.slug}`} |
||||||
|
className="block hover:bg-gray-50 p-4 rounded-lg transition" |
||||||
|
> |
||||||
|
<h2 className="text-xl font-semibold">{post.title}</h2> |
||||||
|
<time className="text-sm text-gray-500"> |
||||||
|
{new Date(post.createdAt).toLocaleDateString()} |
||||||
|
</time> |
||||||
|
</Link> |
||||||
|
</li> |
||||||
|
))} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}
|
Loading…
Reference in new issue