├── .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 |
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 | thumbnail 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 | 3 | 4 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------