Add next-mdx-remote
5
assets/sandpack/hello-world/main.js
Normal file
@ -0,0 +1,5 @@
|
||||
const main = `export default function App() {
|
||||
return <h1>Hello world</h1>
|
||||
}`;
|
||||
|
||||
export default main;
|
9
components/mdx/components.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import RUASandpack from 'components/RUA/RUASandpack';
|
||||
import Anchor from 'components/mdx/Anchor';
|
||||
|
||||
const components = {
|
||||
RUASandpack,
|
||||
a: Anchor,
|
||||
};
|
||||
|
||||
export default components;
|
9
data/mdxData.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import main from 'assets/sandpack/hello-world/main';
|
||||
|
||||
const data = {
|
||||
sandpack: {
|
||||
'hello-world': main,
|
||||
},
|
||||
};
|
||||
|
||||
export default data;
|
22
data/posts/hello-world.mdx
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
title: Hello world
|
||||
date: '2022-04-06'
|
||||
tags: ['Hello world']
|
||||
---
|
||||
|
||||
## Hello
|
||||
|
||||
This is my first post!
|
||||
|
||||
```ts
|
||||
console.log('Hello world');
|
||||
```
|
||||
|
||||
## Say hello to world
|
||||
|
||||
<RUASandpack
|
||||
template="react"
|
||||
files={{
|
||||
'/App.js': sandpack['hello-world'],
|
||||
}}
|
||||
/>
|
35
lib/posts.ts
@ -1,17 +1,19 @@
|
||||
import fs from 'fs';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import matter from 'gray-matter';
|
||||
import { MyMatters, Post } from 'types';
|
||||
import { sortByDate } from 'lib/utils';
|
||||
|
||||
const dataPath = 'data/posts';
|
||||
|
||||
/**
|
||||
* Read post meta info with gray-matter.
|
||||
* @param filename
|
||||
* @returns
|
||||
*/
|
||||
const readFileMeta = (filename: string) => {
|
||||
const markdownWithMeta = fs.readFileSync(
|
||||
path.join('pages/p', filename),
|
||||
const readFileMeta = async (filename: string) => {
|
||||
const markdownWithMeta = await fs.readFile(
|
||||
path.join(dataPath, filename),
|
||||
'utf-8'
|
||||
);
|
||||
const slug = filename.replace(/\.mdx$/, '');
|
||||
@ -27,8 +29,25 @@ const readFileMeta = (filename: string) => {
|
||||
* @returns
|
||||
*/
|
||||
export const postLists = async (): Promise<Post[]> => {
|
||||
const files = fs.readdirSync(path.join('pages/p'));
|
||||
const posts = files.map(readFileMeta).sort(sortByDate);
|
||||
|
||||
return posts;
|
||||
const files = await fs.readdir(path.join(dataPath));
|
||||
return (await Promise.all(files.map(readFileMeta))).sort(sortByDate);
|
||||
};
|
||||
|
||||
const readFilePath = async (filename: string) => {
|
||||
const slug = filename.replace(/\.mdx$/, '');
|
||||
return {
|
||||
params: {
|
||||
slug,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const allPostsPath = async () => {
|
||||
const files = await fs.readdir(path.join(dataPath));
|
||||
return await Promise.all(files.map(readFilePath));
|
||||
};
|
||||
|
||||
export const readSinglePost = async (slug: string) => {
|
||||
const filename = path.join(`${dataPath}/${slug}.mdx`);
|
||||
return await fs.readFile(filename, { encoding: 'utf-8' });
|
||||
};
|
||||
|
@ -24,6 +24,7 @@
|
||||
"dayjs": "^1.11.4",
|
||||
"next": "12.2.4",
|
||||
"next-compose-plugins": "^2.2.1",
|
||||
"next-mdx-remote": "^4.1.0",
|
||||
"next-themes": "^0.2.0",
|
||||
"octokit": "^2.0.4",
|
||||
"react": "^18.2.0",
|
||||
|
@ -40,9 +40,9 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
|
||||
enableSystem
|
||||
defaultTheme="system"
|
||||
>
|
||||
<MDXProvider components={components}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
</MDXProvider>
|
||||
{/* <MDXProvider components={components}> */}
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
{/* </MDXProvider> */}
|
||||
</ThemeProvider>
|
||||
|
||||
{loading && <VercelLoading />}
|
||||
|
74
pages/p/[slug].tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import { allPostsPath, readSinglePost } from 'lib/posts';
|
||||
import { GetStaticPaths, GetStaticProps, InferGetStaticPropsType } from 'next';
|
||||
import { serialize } from 'next-mdx-remote/serialize';
|
||||
import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote';
|
||||
import components from 'components/mdx/components';
|
||||
import data from 'data/mdxData';
|
||||
import rehypePrism from '@mapbox/rehype-prism';
|
||||
import remarkGfm from 'remark-gfm';
|
||||
import rehypeSlug from 'rehype-slug';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { MyMatters } from 'types';
|
||||
|
||||
const Footer = dynamic(() => import('components/Footer'));
|
||||
const HeadBar = dynamic(() => import('components/NavBar'));
|
||||
const PostComment = dynamic(() => import('components/post/PostComment'));
|
||||
|
||||
const Slug = ({
|
||||
mdxSource,
|
||||
}: InferGetStaticPropsType<typeof getStaticProps>) => {
|
||||
return (
|
||||
<>
|
||||
<HeadBar />
|
||||
|
||||
<main id="article" className="relative max-w-4xl px-4 mx-auto my-10">
|
||||
<h1>{mdxSource.frontmatter?.title}</h1>
|
||||
<time>{mdxSource.frontmatter?.date}</time>
|
||||
|
||||
<article id="post-content">
|
||||
<MDXRemote {...mdxSource} components={components} />
|
||||
<PostComment />
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const getStaticPaths: GetStaticPaths = async () => {
|
||||
return {
|
||||
paths: await allPostsPath(),
|
||||
fallback: false,
|
||||
};
|
||||
};
|
||||
|
||||
export const getStaticProps: GetStaticProps<{
|
||||
mdxSource: MDXRemoteSerializeResult;
|
||||
}> = async ({ params }) => {
|
||||
const slug = params?.slug?.toString();
|
||||
if (!slug)
|
||||
return {
|
||||
notFound: true,
|
||||
};
|
||||
|
||||
const post = await readSinglePost(slug);
|
||||
const mdxSource = await serialize(post, {
|
||||
mdxOptions: {
|
||||
remarkPlugins: [remarkGfm],
|
||||
rehypePlugins: [
|
||||
[rehypePrism, { alias: { vue: 'xml' }, ignoreMissing: true }],
|
||||
rehypeSlug,
|
||||
],
|
||||
},
|
||||
parseFrontmatter: true,
|
||||
scope: data,
|
||||
});
|
||||
return {
|
||||
props: {
|
||||
mdxSource,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default Slug;
|
@ -1,43 +0,0 @@
|
||||
---
|
||||
title: Hello world
|
||||
date: '2022-04-06'
|
||||
tags: ['Hello world']
|
||||
---
|
||||
|
||||
import Layout from 'layouts/MDXLayout';
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
export const RUASandpack = dynamic(() => import('components/RUA/RUASandpack'));
|
||||
|
||||
export const meta = {
|
||||
title: 'Hello world',
|
||||
date: '2022-04-06',
|
||||
tags: ['Hello world'],
|
||||
};
|
||||
|
||||
export default ({ children }) => (
|
||||
<Layout {...meta} showTOC={false}>
|
||||
{children}
|
||||
</Layout>
|
||||
);
|
||||
|
||||
## Hello
|
||||
|
||||
This is my first post!
|
||||
|
||||
```ts
|
||||
console.log('Hello world');
|
||||
```
|
||||
|
||||
## Say hello to world
|
||||
|
||||
export const main = `export default function App() {
|
||||
return <h1>Hello world</h1>
|
||||
}`;
|
||||
|
||||
<RUASandpack
|
||||
template="react"
|
||||
files={{
|
||||
'/App.js': main,
|
||||
}}
|
||||
/>
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 144 KiB |
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 343 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 348 B |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
44
yarn.lock
@ -1281,6 +1281,14 @@
|
||||
unist-util-visit "^4.0.0"
|
||||
vfile "^5.0.0"
|
||||
|
||||
"@mdx-js/react@^2.0.0":
|
||||
version "2.1.3"
|
||||
resolved "https://registry.npmmirror.com/@mdx-js/react/-/react-2.1.3.tgz#4b28a774295ed1398cf6be1b8ddef69d6a30e78d"
|
||||
integrity sha512-11n4lTvvRyxq3OYbWJwEYM+7q6PE0GxKbk0AwYIIQmrRkxDeljIsjDQkKOgdr/orgRRbYy5zi+iERdnwe01CHQ==
|
||||
dependencies:
|
||||
"@types/mdx" "^2.0.0"
|
||||
"@types/react" ">=16"
|
||||
|
||||
"@mdx-js/react@^2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmmirror.com/@mdx-js/react/-/react-2.1.2.tgz#02972f170cd3ad9113ce448245c5f636bb3e750d"
|
||||
@ -1903,6 +1911,11 @@
|
||||
jest-matcher-utils "^28.0.0"
|
||||
pretty-format "^28.0.0"
|
||||
|
||||
"@types/js-yaml@^4.0.0":
|
||||
version "4.0.5"
|
||||
resolved "https://registry.npmmirror.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138"
|
||||
integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==
|
||||
|
||||
"@types/jsdom@^16.2.4":
|
||||
version "16.2.14"
|
||||
resolved "https://registry.npmmirror.com/@types/jsdom/-/jsdom-16.2.14.tgz#26fe9da6a8870715b154bb84cd3b2e53433d8720"
|
||||
@ -5372,7 +5385,7 @@ js-yaml@^3.13.1, js-yaml@^3.14.1:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.0"
|
||||
|
||||
js-yaml@^4.1.0:
|
||||
js-yaml@^4.0.0, js-yaml@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
|
||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
|
||||
@ -6514,6 +6527,16 @@ next-compose-plugins@^2.2.1:
|
||||
resolved "https://registry.npmmirror.com/next-compose-plugins/-/next-compose-plugins-2.2.1.tgz#020fc53f275a7e719d62521bef4300fbb6fde5ab"
|
||||
integrity sha512-OjJ+fV15FXO2uQXQagLD4C0abYErBjyjE0I0FHpOEIB8upw0hg1ldFP6cqHTJBH1cZqy96OeR3u1dJ+Ez2D4Bg==
|
||||
|
||||
next-mdx-remote@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmmirror.com/next-mdx-remote/-/next-mdx-remote-4.1.0.tgz#5e063542437a8cfa3faa9623870b076c01429c2a"
|
||||
integrity sha512-ZdL5AFJcEqvInGkYYRKda930D6AJt1GOLX/OXFE/vTwaqV/Mw+l3/njZ4kWqvYSAkl89Z6W7WZrTtN0fd0XwPg==
|
||||
dependencies:
|
||||
"@mdx-js/mdx" "^2.0.0"
|
||||
"@mdx-js/react" "^2.0.0"
|
||||
vfile "^5.3.0"
|
||||
vfile-matter "^3.0.1"
|
||||
|
||||
next-themes@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmmirror.com/next-themes/-/next-themes-0.2.0.tgz#fdc507f61e95b3ae513dee8d4783bcec8c02e3a3"
|
||||
@ -8596,6 +8619,15 @@ validate-npm-package-name@^3.0.0:
|
||||
dependencies:
|
||||
builtins "^1.0.3"
|
||||
|
||||
vfile-matter@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmmirror.com/vfile-matter/-/vfile-matter-3.0.1.tgz#85e26088e43aa85c04d42ffa3693635fa2bc5624"
|
||||
integrity sha512-CAAIDwnh6ZdtrqAuxdElUqQRQDQgbbIrYtDYI8gCjXS1qQ+1XdLoK8FIZWxJwn0/I+BkSSZpar3SOgjemQz4fg==
|
||||
dependencies:
|
||||
"@types/js-yaml" "^4.0.0"
|
||||
is-buffer "^2.0.0"
|
||||
js-yaml "^4.0.0"
|
||||
|
||||
vfile-message@^3.0.0:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.npmmirror.com/vfile-message/-/vfile-message-3.1.2.tgz#a2908f64d9e557315ec9d7ea3a910f658ac05f7d"
|
||||
@ -8614,6 +8646,16 @@ vfile@^5.0.0:
|
||||
unist-util-stringify-position "^3.0.0"
|
||||
vfile-message "^3.0.0"
|
||||
|
||||
vfile@^5.3.0:
|
||||
version "5.3.4"
|
||||
resolved "https://registry.npmmirror.com/vfile/-/vfile-5.3.4.tgz#bbb8c96b956693bbf70b2c67fdb5781dff769b93"
|
||||
integrity sha512-KI+7cnst03KbEyN1+JE504zF5bJBZa+J+CrevLeyIMq0aPU681I2rQ5p4PlnQ6exFtWiUrg26QUdFMnAKR6PIw==
|
||||
dependencies:
|
||||
"@types/unist" "^2.0.0"
|
||||
is-buffer "^2.0.0"
|
||||
unist-util-stringify-position "^3.0.0"
|
||||
vfile-message "^3.0.0"
|
||||
|
||||
w3c-hr-time@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmmirror.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
||||
|