├── .eslintrc
├── .gitignore
├── README.md
├── components
├── Button.jsx
├── Nav.jsx
└── index.js
├── next.config.js
├── package-lock.json
├── package.json
├── pages
├── _app.js
├── bio.js
├── blog
│ └── [slug].js
└── index.js
├── posts
├── functions-for-beginners.mdx
├── solidjs-for-beginners.mdx
├── tailwind-setup.mdx
└── variables-in-python.mdx
├── public
├── favicon.ico
├── javascript-functions-thumbnail.jpeg
├── python-variables-thumbnail.jpeg
├── solidjs-thumbnail.jpeg
├── tailwindcss-thumbnail.jpg
└── vercel.svg
└── styles
├── Home.module.css
└── globals.css
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["next", "next/core-web-vitals"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # next.js
12 | /.next/
13 | /out/
14 |
15 | # production
16 | /build
17 |
18 | # misc
19 | .DS_Store
20 | *.pem
21 |
22 | # debug
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # local env files
28 | .env.local
29 | .env.development.local
30 | .env.test.local
31 | .env.production.local
32 |
33 | # vercel
34 | .vercel
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### A Next.js and MDX blog
2 |
3 | Tutorial: https://blog.jetbrains.com/webstorm/2021/10/building-a-blog-with-next-js-and-mdx/
4 |
5 | Built by [Ebenezer Don on YouTube](https://youtube.com/ebenezerdon)
6 |
--------------------------------------------------------------------------------
/components/Button.jsx:
--------------------------------------------------------------------------------
1 | const Button = ({ text }) => {
2 | return (
3 |
9 | )
10 | }
11 |
12 | export default Button
13 |
--------------------------------------------------------------------------------
/components/Nav.jsx:
--------------------------------------------------------------------------------
1 | import Link from 'next/link'
2 |
3 | const Nav = () => {
4 | return (
5 |
14 | )
15 | }
16 |
17 | export default Nav
18 |
--------------------------------------------------------------------------------
/components/index.js:
--------------------------------------------------------------------------------
1 | import Nav from './Nav'
2 | import Button from './Button'
3 |
4 | export { Nav, Button }
5 |
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | reactStrictMode: true,
3 | }
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "next-markdown",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@mdx-js/loader": "^1.6.22",
13 | "@next/mdx": "^11.0.1",
14 | "gray-matter": "^4.0.3",
15 | "marked": "^2.1.3",
16 | "next": "11.0.1",
17 | "next-mdx-remote": "^3.0.4",
18 | "react": "17.0.2",
19 | "react-dom": "17.0.2",
20 | "react-syntax-highlighter": "^15.4.4"
21 | },
22 | "devDependencies": {
23 | "eslint": "7.31.0",
24 | "eslint-config-next": "11.0.1"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/pages/_app.js:
--------------------------------------------------------------------------------
1 | // import { MDXProvider } from '@mdx-js/react'
2 | import '../styles/globals.css'
3 | import Nav from '../components/Nav'
4 | import Head from 'next/head'
5 |
6 | function MyApp({ Component, pageProps }) {
7 | return (
8 | <>
9 |
10 | Next and MDX Blog
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | >
22 | )
23 | }
24 |
25 | export default MyApp
26 |
--------------------------------------------------------------------------------
/pages/bio.js:
--------------------------------------------------------------------------------
1 | const Bio = () => {
2 | return (
3 |
4 |
I'm Ebenezer Don
5 |
Ebenezer Don's bio here
6 |
7 | )
8 | }
9 |
10 | export default Bio
11 |
--------------------------------------------------------------------------------
/pages/blog/[slug].js:
--------------------------------------------------------------------------------
1 | import { serialize } from 'next-mdx-remote/serialize'
2 | import { MDXRemote } from 'next-mdx-remote'
3 | import fs from 'fs'
4 | import path from 'path'
5 | import matter from 'gray-matter'
6 | import SyntaxHighlighter from 'react-syntax-highlighter'
7 |
8 | import { Nav, Button } from '../../components'
9 |
10 | const components = { Nav, Button, SyntaxHighlighter }
11 |
12 | const PostPage = ({ frontMatter: { title, date }, mdxSource }) => {
13 | return (
14 |
15 |
{title}
16 |
17 |
18 | )
19 | }
20 |
21 | const getStaticPaths = async () => {
22 | const files = fs.readdirSync(path.join('posts'))
23 |
24 | const paths = files.map(filename => ({
25 | params: {
26 | slug: filename.replace('.mdx', '')
27 | }
28 | }))
29 |
30 | return {
31 | paths,
32 | fallback: false
33 | }
34 | }
35 |
36 | const getStaticProps = async ({ params: { slug } }) => {
37 | const markdownWithMeta = fs.readFileSync(path.join('posts',
38 | slug + '.mdx'), 'utf-8')
39 |
40 | const { data: frontMatter, content } = matter(markdownWithMeta)
41 | const mdxSource = await serialize(content)
42 |
43 | return {
44 | props: {
45 | frontMatter,
46 | slug,
47 | mdxSource
48 | }
49 | }
50 | }
51 |
52 | export { getStaticProps, getStaticPaths }
53 | export default PostPage
54 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import path from 'path'
3 | import matter from 'gray-matter'
4 | import Link from 'next/link'
5 | import Image from 'next/image'
6 |
7 | const Home = ({ posts }) => {
8 | return (
9 |
10 | {posts.map((post, index) => (
11 |
12 |
13 |
14 |
15 |
16 |
{post.frontMatter.title}
17 |
{post.frontMatter.description}
18 |
19 | {post.frontMatter.date}
20 |
21 |
22 |
23 |
24 |
32 |
33 |
34 |
35 |
36 | ))}
37 |
38 | )
39 | }
40 |
41 | export const getStaticProps = async () => {
42 | const files = fs.readdirSync(path.join('posts'))
43 |
44 | const posts = files.map(filename => {
45 | const markdownWithMeta = fs.readFileSync(path.join('posts', filename), 'utf-8')
46 | const { data: frontMatter } = matter(markdownWithMeta)
47 |
48 | return {
49 | frontMatter,
50 | slug: filename.split('.')[0]
51 | }
52 | })
53 |
54 | return {
55 | props: {
56 | posts
57 | }
58 | }
59 | }
60 |
61 | export default Home
62 |
--------------------------------------------------------------------------------
/posts/functions-for-beginners.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Functions for Beginners
3 | date: 'August 4, 2021'
4 | description: Learn how to create and use functions
5 | thumbnailUrl: '/javascript-functions-thumbnail.jpeg'
6 | tags: ['functions', 'javascript']
7 | ---
8 |
9 |
10 | This is a blog post about functions.
11 | We'll learn what functions are, how to write functions, and how to use them.
12 |
13 |
14 |
15 |
16 | ### This is a Markdown sub-heading
17 | We just used a `###` subheading in our blog post.
18 |
19 |
20 | {`
21 | const doStuff = () => {
22 | return console.log('hey')
23 | }
24 | `}
25 |
26 |
27 | ```
28 | // this is a code block
29 | const doSomething = () => {
30 | return console.log('hey')
31 | }
32 | ```
33 |
34 | Here, I'm using a component inside my MarkDown file: {}
35 |
--------------------------------------------------------------------------------
/posts/solidjs-for-beginners.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'SolidJS: A Beginners Guide'
3 | date: 'September 11, 2021'
4 | description: "Here's an introduction to SolidJS"
5 | thumbnailUrl: "/solidjs-thumbnail.jpeg"
6 | tags: ['JavaScript', 'solidjs']
7 | ---
8 |
9 | This is a blog post about SolidJS.
10 | We'll learn about SolidJS and how to build with it.
11 |
12 |
13 |
14 |
15 | ### This is a Markdown sub-heading
16 | We just used a `###` subheading in our blog post.
17 |
18 |
19 | {`
20 | const doStuff = () => {
21 | return console.log('hey')
22 | }
23 | `}
24 |
25 |
26 | ```
27 | // this is a code block
28 | const doSomething = () => {
29 | return console.log('hey')
30 | }
31 | ```
32 |
33 | Here, I'm using a component inside my MarkDown file: {}
34 |
--------------------------------------------------------------------------------
/posts/tailwind-setup.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'How to set up Tailwind CSS'
3 | date: 'September 2, 2021'
4 | description: "Here's a short guide on setting up Tailwind CSS"
5 | thumbnailUrl: "/tailwindcss-thumbnail.jpg"
6 | tags: ['tailwindcss', 'styling']
7 | ---
8 |
9 |
10 | This is a blog post about Tailwind CSS.
11 | We'll learn how to set up and use Tailwind CSS.
12 |
13 |
14 |
15 |
16 | ### This is a Markdown sub-heading
17 | We just used a `###` subheading in our blog post.
18 |
19 |
20 | {`
21 | const doStuff = () => {
22 | return console.log('hey')
23 | }
24 | `}
25 |
26 |
27 | ```
28 | // this is a code block
29 | const doSomething = () => {
30 | return console.log('hey')
31 | }
32 | ```
33 |
34 | Here, I'm using a component inside my MarkDown file: {}
35 |
--------------------------------------------------------------------------------
/posts/variables-in-python.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: 'A simple introduction to Python variables'
3 | date: 'July 25, 2021'
4 | description: "Let's learn about Python variables"
5 | thumbnailUrl: "/python-variables-thumbnail.jpeg"
6 | tags: ['variables', 'python']
7 | ---
8 |
9 |
10 | This is a blog post about variables.
11 | We'll learn about Python variables.
12 |
13 |
14 |
15 |
16 | ### This is a Markdown sub-heading
17 | We just used a `###` subheading in our blog post.
18 |
19 |
20 | {`
21 | const doStuff = () => {
22 | return console.log('hey')
23 | }
24 | `}
25 |
26 |
27 | ```
28 | // this is a code block
29 | const doSomething = () => {
30 | return console.log('hey')
31 | }
32 | ```
33 |
34 | Here, I'm using a component inside my MarkDown file: {}
35 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebenezerdon/nextjs-mdx-blog/29ecf25d1e8d5710ec0b391aa23976bf054b080c/public/favicon.ico
--------------------------------------------------------------------------------
/public/javascript-functions-thumbnail.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebenezerdon/nextjs-mdx-blog/29ecf25d1e8d5710ec0b391aa23976bf054b080c/public/javascript-functions-thumbnail.jpeg
--------------------------------------------------------------------------------
/public/python-variables-thumbnail.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebenezerdon/nextjs-mdx-blog/29ecf25d1e8d5710ec0b391aa23976bf054b080c/public/python-variables-thumbnail.jpeg
--------------------------------------------------------------------------------
/public/solidjs-thumbnail.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebenezerdon/nextjs-mdx-blog/29ecf25d1e8d5710ec0b391aa23976bf054b080c/public/solidjs-thumbnail.jpeg
--------------------------------------------------------------------------------
/public/tailwindcss-thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ebenezerdon/nextjs-mdx-blog/29ecf25d1e8d5710ec0b391aa23976bf054b080c/public/tailwindcss-thumbnail.jpg
--------------------------------------------------------------------------------
/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/styles/Home.module.css:
--------------------------------------------------------------------------------
1 | .container {
2 | min-height: 100vh;
3 | padding: 0 0.5rem;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: center;
7 | align-items: center;
8 | height: 100vh;
9 | }
10 |
11 | .main {
12 | padding: 5rem 0;
13 | flex: 1;
14 | display: flex;
15 | flex-direction: column;
16 | justify-content: center;
17 | align-items: center;
18 | }
19 |
20 | .footer {
21 | width: 100%;
22 | height: 100px;
23 | border-top: 1px solid #eaeaea;
24 | display: flex;
25 | justify-content: center;
26 | align-items: center;
27 | }
28 |
29 | .footer a {
30 | display: flex;
31 | justify-content: center;
32 | align-items: center;
33 | flex-grow: 1;
34 | }
35 |
36 | .title a {
37 | color: #0070f3;
38 | text-decoration: none;
39 | }
40 |
41 | .title a:hover,
42 | .title a:focus,
43 | .title a:active {
44 | text-decoration: underline;
45 | }
46 |
47 | .title {
48 | margin: 0;
49 | line-height: 1.15;
50 | font-size: 4rem;
51 | }
52 |
53 | .title,
54 | .description {
55 | text-align: center;
56 | }
57 |
58 | .description {
59 | line-height: 1.5;
60 | font-size: 1.5rem;
61 | }
62 |
63 | .code {
64 | background: #fafafa;
65 | border-radius: 5px;
66 | padding: 0.75rem;
67 | font-size: 1.1rem;
68 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
69 | Bitstream Vera Sans Mono, Courier New, monospace;
70 | }
71 |
72 | .grid {
73 | display: flex;
74 | align-items: center;
75 | justify-content: center;
76 | flex-wrap: wrap;
77 | max-width: 800px;
78 | margin-top: 3rem;
79 | }
80 |
81 | .card {
82 | margin: 1rem;
83 | padding: 1.5rem;
84 | text-align: left;
85 | color: inherit;
86 | text-decoration: none;
87 | border: 1px solid #eaeaea;
88 | border-radius: 10px;
89 | transition: color 0.15s ease, border-color 0.15s ease;
90 | width: 45%;
91 | }
92 |
93 | .card:hover,
94 | .card:focus,
95 | .card:active {
96 | color: #0070f3;
97 | border-color: #0070f3;
98 | }
99 |
100 | .card h2 {
101 | margin: 0 0 1rem 0;
102 | font-size: 1.5rem;
103 | }
104 |
105 | .card p {
106 | margin: 0;
107 | font-size: 1.25rem;
108 | line-height: 1.5;
109 | }
110 |
111 | .logo {
112 | height: 1em;
113 | margin-left: 0.5rem;
114 | }
115 |
116 | @media (max-width: 600px) {
117 | .grid {
118 | width: 100%;
119 | flex-direction: column;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/styles/globals.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
7 | }
8 |
9 | a {
10 | color: inherit;
11 | text-decoration: none;
12 | }
13 |
14 | * {
15 | box-sizing: border-box;
16 | }
17 |
18 | .pointer {
19 | cursor: pointer;
20 | }
21 |
--------------------------------------------------------------------------------