Last active
September 5, 2022 17:23
-
-
Save jordyvandomselaar/204e62e43fd3e2fa75f23cd27bd31d59 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {GetStaticPaths, GetStaticProps} from "next"; | |
import {getPostPathBySlug, getPostSlugs, markdownFileToPost, Post as PostInterface} from "../../services/posts"; | |
import {MDXRemote, MDXRemoteSerializeResult} from 'next-mdx-remote' | |
import {serialize} from 'next-mdx-remote/serialize' | |
import Content from "../../components/Content"; | |
import Layout from "../../components/Layout"; | |
import Footer from "../../components/Footer"; | |
import path from "path"; | |
import Hero from "../../components/Hero"; | |
import Image from "next/image" | |
import Heading from "../../components/Heading"; | |
import Text, {textStyle} from "../../components/Text"; | |
import {css} from "@emotion/react"; | |
import CodeBlock from "../../components/CodeBlock"; | |
import CodeSandbox from "../../components/CodeSandbox"; | |
import Link from "next/link" | |
import Tip from "../../components/Tip"; | |
interface PostProps { | |
data: PostInterface; | |
source: MDXRemoteSerializeResult; | |
} | |
export default function Post({data, source}: PostProps) { | |
const heroPath = "./" + path.join(data.slug, data.hero); | |
// @ts-ignore | |
const allImages = require.context("/content/posts/", true, /\.(jpg|jpeg|png)$/); | |
const heroImage = allImages(heroPath); | |
const components = { | |
h1: (props: any) => <Heading tag="h1" {...props}/>, | |
h2: (props: any) => <Heading tag="h2" {...props}/>, | |
h3: (props: any) => <Heading tag="h3" {...props}/>, | |
h4: (props: any) => <Heading tag="h4" {...props}/>, | |
h5: (props: any) => <Heading tag="h5" {...props}/>, | |
h6: (props: any) => <Heading tag="h6" {...props}/>, | |
p: Text, | |
li: (props: any) => <li {...props} css={[textStyle, css`line-height: 2; | |
::marker { | |
font-weight: bold; | |
font-family: 'Roboto Mono', monospace; | |
}`]}/>, | |
ul: (props: any) => <ul {...props} css={css` | |
padding-left: 1.5rem; | |
margin-top: 0; | |
margin-bottom: 2rem; | |
`}/>, | |
ol: (props: any) => <ol {...props} css={css`margin-top: 0; | |
margin-bottom: 2rem;`}/>, | |
img: ({src, alt}: any) => { | |
throw new Error("Use next/image instead of img"); | |
return null; | |
}, | |
pre: CodeBlock, | |
inlineCode: (props: any) => <code {...props} css={css`background: rgb(230, 230, 230);`}/>, | |
CodeSandbox: CodeSandbox, | |
Tip: Tip, | |
Image: ({src, alt}: any) => { | |
const imagePath = "./" + path.join(data.slug, src); | |
return <div css={css`margin-bottom: 2rem;`}> | |
<Image objectFit="contain" alt={alt} src={allImages(imagePath)}/> | |
</div> | |
; | |
}, | |
} | |
return <Layout> | |
<div> | |
<Hero image={ | |
<Image src={heroImage} alt="hero image" layout="fill" objectFit="cover"/> | |
}> | |
<div> | |
<div> | |
<Link href="/"> | |
<a css={[textStyle, css` | |
text-decoration: none; | |
color: #fff; | |
text-align: center; | |
display: block; | |
font-size: 2rem; | |
padding-bottom: 2rem; | |
&:hover { | |
cursor: pointer; | |
} | |
`]}>« Back to post list</a> | |
</Link> | |
</div> | |
<div css={css`text-align: center; | |
@media screen and (max-width: 800px) { | |
font-size: 10px; | |
};`}> | |
<Heading tag="h1">{data.title}</Heading> | |
</div> | |
</div> | |
</Hero> | |
<Content> | |
<MDXRemote components={components} {...source}/> | |
</Content> | |
</div> | |
<Footer/> | |
</Layout> | |
} | |
export const getStaticProps: GetStaticProps = async ({params}) => { | |
const postPath = getPostPathBySlug((params as { slug: string }).slug); | |
const post = markdownFileToPost(postPath); | |
const mdxSource = await serialize(post.content, { | |
mdxOptions: { | |
remarkPlugins: [], | |
rehypePlugins: [], | |
}, | |
}) | |
return { | |
props: { | |
source: mdxSource, | |
data: post, | |
}, | |
} | |
} | |
export const getStaticPaths: GetStaticPaths = async () => { | |
return { | |
paths: getPostSlugs().map(slug => ({params: {slug}})), | |
fallback: false | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import glob from "glob"; | |
import fs from "fs"; | |
import matter from "gray-matter"; | |
export interface Post { | |
title: string; | |
excerpt: string; | |
slug: string; | |
hero: string; | |
content: string; | |
} | |
export function getPosts(): Post[] { | |
return getPostPaths().map(markdownFileToPost); | |
} | |
export function markdownFileToPost(filePath: string): Post { | |
const source = fs.readFileSync(filePath); | |
const matterData = matter(source) | |
const {title, date, excerpt, hero} = matterData.data; | |
const slug = slugifyPath(filePath); | |
return {title, excerpt, slug, hero, content: matterData.content}; | |
} | |
export function getPostPaths(): string[] { | |
const path = require("path"); | |
return glob.sync(path.join(process.cwd(), "content/posts/**/*.md")); | |
} | |
export function getPostPathBySlug(slug: string): string { | |
const path = require("path"); | |
return path.join(process.cwd(), "content/posts/", slug, "index.md"); | |
} | |
export function getPostSlugs(): string[] { | |
return getPostPaths().map(path => slugifyPath(path)); | |
} | |
function slugifyPath(path: string): string { | |
// Remove everything but the folder name | |
return path.replace(/.+?posts\//, "").replace("\/index.md", ""); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment