Skip to content

Commit e155f66

Browse files
johnoChristopherBiscardi
authored andcommitted
feat(theme): Implement MDX blog theme (#12675)
* feat(theme): Implement MDX blog theme * Remove pagination
1 parent 11b68cf commit e155f66

28 files changed

+619
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react"
2+
3+
import MDXThemeProvider from "./src/components/mdx-theme-provider"
4+
5+
export const wrapRootElement = ({ element }) => (
6+
<MDXThemeProvider>{element}</MDXThemeProvider>
7+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const path = require(`path`)
2+
3+
module.exports = ({ defaultLayouts = {} } = {}) => {
4+
const themeLayouts = {
5+
posts: require.resolve(`./src/templates/post`),
6+
}
7+
8+
return {
9+
siteMetadata: {
10+
title: `Gatsby MDX Blog`,
11+
siteUrl: `https://gatsbyjs.org`,
12+
},
13+
mapping: {
14+
"Mdx.frontmatter.author": `AuthorYaml`,
15+
},
16+
plugins: [
17+
{
18+
resolve: `gatsby-mdx`,
19+
options: {
20+
defaultLayouts: {
21+
...themeLayouts,
22+
...defaultLayouts,
23+
},
24+
},
25+
},
26+
{
27+
resolve: `gatsby-source-filesystem`,
28+
options: {
29+
path: `posts`,
30+
name: `posts`,
31+
},
32+
},
33+
{
34+
resolve: `gatsby-source-filesystem`,
35+
options: {
36+
path: path.join(__dirname, `posts`),
37+
},
38+
},
39+
{
40+
// This will eventually be the default
41+
resolve: `gatsby-plugin-page-creator`,
42+
options: {
43+
path: path.join(__dirname, `src`, `pages`),
44+
},
45+
},
46+
{
47+
resolve: `gatsby-source-filesystem`,
48+
options: {
49+
name: `data`,
50+
path: path.join(`src`, `data`),
51+
ignore: [`**/.*`],
52+
},
53+
},
54+
{
55+
resolve: `gatsby-source-filesystem`,
56+
options: {
57+
name: `data`,
58+
path: path.join(__dirname, `src`, `data`),
59+
ignore: [`**/.*`],
60+
},
61+
},
62+
{
63+
// This will eventually be the default
64+
resolve: `gatsby-plugin-compile-es6-packages`,
65+
options: {
66+
modules: [`gatsby-theme-mdx-blog`, `typography-system`],
67+
},
68+
},
69+
`gatsby-transformer-yaml`,
70+
`gatsby-plugin-meta-redirect`,
71+
`gatsby-plugin-emotion`,
72+
],
73+
}
74+
}
+131
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
const fs = require(`fs`)
2+
const path = require(`path`)
3+
const mkdirp = require(`mkdirp`)
4+
const kebab = require(`lodash.kebabcase`)
5+
const Debug = require(`debug`)
6+
7+
const Posts = require.resolve(`./src/templates/posts`)
8+
const Post = require.resolve(`./src/templates/post`)
9+
const Tag = require.resolve(`./src/templates/tag`)
10+
11+
const debug = Debug(`gatsby-theme-blog-mdx`)
12+
13+
exports.createPages = async ({ graphql, actions }, pluginOptions) => {
14+
const { createPage, createRedirect } = actions
15+
16+
const { postsPath = `/blog` } = pluginOptions
17+
18+
const result = await graphql(`
19+
{
20+
mdxPages: allMdx(
21+
sort: { fields: [frontmatter___date], order: DESC }
22+
filter: { frontmatter: { draft: { ne: true }, archived: { ne: true } } }
23+
) {
24+
edges {
25+
node {
26+
id
27+
excerpt
28+
timeToRead
29+
tableOfContents
30+
headings {
31+
value
32+
}
33+
parent {
34+
... on File {
35+
name
36+
sourceInstanceName
37+
}
38+
}
39+
frontmatter {
40+
path
41+
tags
42+
title
43+
redirects
44+
date(formatString: "MMMM DD, YYYY")
45+
}
46+
code {
47+
scope
48+
}
49+
}
50+
}
51+
}
52+
}
53+
`)
54+
55+
if (result.errors) {
56+
console.log(result.errors)
57+
throw new Error(`Could not query posts`, result.errors)
58+
}
59+
60+
const { mdxPages } = result.data
61+
62+
// Collect tags
63+
const allTags = mdxPages.edges.reduce((acc, post) => {
64+
const {
65+
node: { frontmatter = {} },
66+
} = post
67+
return acc.concat(frontmatter.tags || [])
68+
}, [])
69+
const tags = [...new Set(allTags)]
70+
71+
// Create post pages and redirects
72+
mdxPages.edges.forEach(({ node }) => {
73+
const fallbackPath = `/${node.parent.sourceInstanceName}/${
74+
node.parent.name
75+
}`
76+
const path = node.frontmatter.path || fallbackPath
77+
78+
if (node.frontmatter.redirects) {
79+
node.frontmatter.redirects.forEach(fromPath => {
80+
createRedirect({
81+
fromPath,
82+
toPath: path,
83+
redirectInBrowser: true,
84+
isPermanent: true,
85+
})
86+
})
87+
}
88+
89+
createPage({
90+
path,
91+
context: node,
92+
component: Post,
93+
})
94+
})
95+
96+
// Create post list page
97+
createPage({
98+
path: postsPath,
99+
component: Posts,
100+
})
101+
102+
// Create tag list pages
103+
tags.forEach(tag => {
104+
const path = `/tags/${kebab(tag)}`
105+
106+
createPage({
107+
path,
108+
component: Tag,
109+
context: {
110+
tag,
111+
},
112+
})
113+
})
114+
}
115+
116+
exports.onPreBootstrap = ({ store }) => {
117+
const { program } = store.getState()
118+
119+
const dirs = [
120+
path.join(program.directory, `posts`),
121+
path.join(program.directory, `src/pages`),
122+
path.join(program.directory, `src/data`),
123+
]
124+
125+
dirs.forEach(dir => {
126+
debug(`Initializing ${dir} directory`)
127+
if (!fs.existsSync(dir)) {
128+
mkdirp.sync(dir)
129+
}
130+
})
131+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import React from "react"
2+
3+
import MDXThemeProvider from "./src/components/mdx-theme-provider"
4+
5+
export const wrapRootElement = ({ element }) => (
6+
<MDXThemeProvider>{element}</MDXThemeProvider>
7+
)

themes/gatsby-theme-blog-mdx/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// noop
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "gatsby-theme-blog-mdx",
3+
"description": "Base MDX blog theme functionality for Gatsby",
4+
"version": "0.0.1-alpha.0",
5+
"license": "MIT",
6+
"author": "John Otander",
7+
"main": "index.js",
8+
"scripts": {},
9+
"keywords": [
10+
"gatsby",
11+
"gatsby-theme"
12+
],
13+
"dependencies": {
14+
"@mdx-js/mdx": "^0.20.3",
15+
"@mdx-js/tag": "^0.20.3",
16+
"gatsby-mdx": "^0.4.3",
17+
"gatsby-plugin-compile-es6-packages": "^1.0.6",
18+
"gatsby-plugin-emotion": "^4.0.6",
19+
"gatsby-plugin-meta-redirect": "^1.1.1",
20+
"gatsby-plugin-page-creator": "^2.0.10",
21+
"gatsby-source-filesystem": "^2.0.27",
22+
"gatsby-transformer-yaml": "^2.1.10",
23+
"lodash.kebabcase": "^4.1.1",
24+
"mkdirp": "^0.5.1",
25+
"prop-types": "^15.7.2",
26+
"typography-system": "^0.0.6",
27+
"typography-theme-bootstrap": "^0.16.19"
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: Example
3+
path: /____fake
4+
archived: true
5+
draft: true
6+
author: jay
7+
date: 2019-03-03
8+
tags:
9+
- fake
10+
redirects:
11+
- /____this-is-not-a-real-redirect
12+
---
13+
14+
This is a hidden piece of content for setting the frontmatter.
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# gatsby-theme-blog-mdx
2+
3+
> :warning: This is experimental and subject to breaking changes.
4+
5+
## Installation
6+
7+
```sh
8+
yarn add gatsby-theme-blog-mdx
9+
```
10+
11+
## Usage
12+
13+
```js
14+
// gatsby-config.js
15+
module.exports = {
16+
return {
17+
__experimentalThemes: [
18+
{
19+
resolve: `gatsby-theme-blog-mdx`,
20+
options: {
21+
postsPath: `/writing`
22+
}
23+
}
24+
]
25+
}
26+
}
27+
```
28+
29+
### Configuration
30+
31+
| Key | Default | Description |
32+
| ----------- | ------- | --------------------- |
33+
| `postsPath` | `/blog` | Path for post listing |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from "react"
2+
3+
import { Link } from "gatsby"
4+
5+
export default ({ children, to, href, activeClassName, ...other }) => {
6+
const path = to || href
7+
8+
const internal = /^\/(?!\/)/.test(path)
9+
10+
if (internal) {
11+
return (
12+
<Link to={path} activeClassName={activeClassName} {...other}>
13+
{children}
14+
</Link>
15+
)
16+
}
17+
18+
return (
19+
<a href={to} {...other}>
20+
{children}
21+
</a>
22+
)
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import React from "react"
2+
import { MDXProvider } from "@mdx-js/tag"
3+
import { TypographyProvider } from "typography-system"
4+
5+
import theme from "../tokens"
6+
import mdxComponents from "./mdx"
7+
8+
export default ({ children }) => (
9+
<TypographyProvider theme={theme}>
10+
<MDXProvider theme={mdxComponents}>{children}</MDXProvider>
11+
</TypographyProvider>
12+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from "react"
2+
import { Link } from "gatsby"
3+
4+
const Pagination = ({ isFirst, isLast, nextPage, prevPage }) => (
5+
<>
6+
{isFirst ? null : <Link to={prevPage}>Previous</Link>}
7+
{isLast ? null : <Link to={nextPage}>Next</Link>}
8+
</>
9+
)
10+
11+
export default Pagination
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react"
2+
import { Link } from "gatsby"
3+
4+
export const toPath = ({ frontmatter, parent = {} }) => {
5+
if (frontmatter.path) {
6+
return frontmatter.path
7+
}
8+
9+
return [parent.sourceInstanceName, parent.name].join(`/`)
10+
}
11+
12+
const PostLink = ({ post }) => {
13+
const path = toPath(post)
14+
15+
return (
16+
<Link to={path}>
17+
<h3>{post.frontmatter.title}</h3>
18+
</Link>
19+
)
20+
}
21+
22+
export default PostLink
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from "react"
2+
3+
import PostLink from "./post-link"
4+
5+
const PostList = ({ data }) => {
6+
const {
7+
allMdx: { edges: posts },
8+
} = data
9+
10+
return (
11+
<>
12+
{posts.map(post => (
13+
<PostLink key={post.node.id} post={post.node} />
14+
))}
15+
</>
16+
)
17+
}
18+
19+
export default PostList

0 commit comments

Comments
 (0)