├── demo ├── .eslintrc.js ├── src │ ├── index.js │ ├── pages │ │ ├── about.mdx │ │ ├── contact.mdx │ │ ├── index.mdx │ │ ├── sub-pages │ │ │ ├── sub-page-1.mdx │ │ │ └── sub-page-items │ │ │ │ ├── sub-page-item-1.mdx │ │ │ │ └── sub-page-items-again │ │ │ │ └── sub-page-item-again-1.mdx │ │ ├── other-pages │ │ │ └── some-other-page.mdx │ │ └── 404.js │ ├── posts │ │ └── some-mdx.mdx │ ├── layouts │ │ ├── layout.css │ │ └── layout.js │ └── components │ │ └── seo.js ├── .prettierrc ├── static │ └── images │ │ └── mdx-routes-main-og-image.jpg ├── LICENSE ├── gatsby-config.js ├── .gitignore ├── package.json └── README.md ├── @pauliescanlon └── gatsby-mdx-routes │ ├── .eslintrc.js │ ├── src │ ├── index.js │ ├── components │ │ └── MdxRoutes │ │ │ ├── index.ts │ │ │ └── MdxRoutes.tsx │ ├── gatsby-node.js │ └── utils │ │ └── recursiveMenu.ts │ ├── .npmignore │ ├── .prettierrc │ ├── .babelrc │ ├── CHANGELOG.md │ ├── .gitignore │ ├── package.json │ ├── tsconfig.json │ └── README.md ├── netlify.toml ├── .prettierrc ├── copy-readme.js ├── package.json ├── .gitignore └── README.md /demo/.eslintrc.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | // boop 2 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/.eslintrc.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "yarn build" 3 | publish = "demo/public" 4 | -------------------------------------------------------------------------------- /demo/src/pages/about.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: about 3 | --- 4 | 5 | # About 6 | -------------------------------------------------------------------------------- /demo/src/pages/contact.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: contact 3 | --- 4 | 5 | # Contact 6 | -------------------------------------------------------------------------------- /demo/src/pages/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: home 3 | --- 4 | 5 | # Home (Index) 6 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/src/index.js: -------------------------------------------------------------------------------- 1 | export { MdxRoutes } from "./components/MdxRoutes" 2 | -------------------------------------------------------------------------------- /demo/src/posts/some-mdx.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: some other mdx 3 | --- 4 | 5 | # Some Other Mdx 6 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/src/components/MdxRoutes/index.ts: -------------------------------------------------------------------------------- 1 | export { MdxRoutes } from "./MdxRoutes" 2 | -------------------------------------------------------------------------------- /demo/src/pages/sub-pages/sub-page-1.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: sub page 1 3 | --- 4 | 5 | # Sub Page 1 6 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/.npmignore: -------------------------------------------------------------------------------- 1 | .prettierrc 2 | jest.config.js 3 | refs.md 4 | coverage 5 | yarn-error.log 6 | src -------------------------------------------------------------------------------- /demo/src/pages/other-pages/some-other-page.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: some other page 3 | --- 4 | 5 | # Some other page 6 | -------------------------------------------------------------------------------- /demo/src/pages/sub-pages/sub-page-items/sub-page-item-1.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: sub page item 1 3 | --- 4 | 5 | # Sub Page Item 1 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /demo/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /demo/static/images/mdx-routes-main-og-image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaulieScanlon/gatsby-mdx-routes/HEAD/demo/static/images/mdx-routes-main-og-image.jpg -------------------------------------------------------------------------------- /demo/src/pages/sub-pages/sub-page-items/sub-page-items-again/sub-page-item-again-1.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | navigationLabel: sub page item again 1 3 | --- 4 | 5 | # Sub Page Item Again 1 6 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /demo/src/layouts/layout.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | color: #333333; 4 | margin: 16px; 5 | font-size: 14px; 6 | font-family: system-ui, sans-serif; 7 | font-weight: 400; 8 | } 9 | -------------------------------------------------------------------------------- /copy-readme.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs") 2 | 3 | fs.copyFile( 4 | "./README.md", 5 | "./@pauliescanlon/gatsby-mdx-routes/README.md", 6 | err => { 7 | if (err) { 8 | throw err 9 | } 10 | console.log("README copied to theme ok!") 11 | } 12 | ) 13 | -------------------------------------------------------------------------------- /demo/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react" 2 | 3 | const NotFoundPage = () => ( 4 | 5 |

NOT FOUND

6 |

You just hit a route that doesn't exist... the sadness.

7 |
8 | ) 9 | 10 | export default NotFoundPage 11 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | // [ 4 | // "@babel/preset-env", 5 | // { 6 | // "targets": ">0.25%, not ie <= 11, not android 4.4.3" 7 | // } 8 | // ], 9 | "@babel/preset-react", 10 | "@babel/preset-typescript" 11 | ], 12 | "plugins": [ 13 | "@babel/plugin-proposal-class-properties", 14 | "@babel/plugin-proposal-object-rest-spread" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/src/gatsby-node.js: -------------------------------------------------------------------------------- 1 | const { createFilePath } = require(`gatsby-source-filesystem`) 2 | 3 | exports.onCreateNode = ({ node, getNode, actions }) => { 4 | const { createNodeField } = actions 5 | 6 | // only create the slug for mdx files sourced from pages directory 7 | if ( 8 | node.internal.type === `Mdx` && 9 | node.fileAbsolutePath && 10 | node.fileAbsolutePath.includes(`pages`) 11 | ) { 12 | const slug = createFilePath({ node, getNode, basePath: `pages` }) 13 | 14 | createNodeField({ 15 | node, 16 | name: `slug`, 17 | value: slug, 18 | }) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.0.4] - 2019-12-18 9 | 10 | ### Removed 11 | 12 | - return key `title` changed to `navigationLabel` 13 | 14 | ### Add 15 | 16 | - add README.md 17 | 18 | ## [0.0.3] - 2019-12-17 19 | 20 | ### Removed 21 | 22 | - return key `route` changed to `slug` 23 | 24 | ## [0.0.2] - 2019-12-17 25 | 26 | ### Add 27 | 28 | - return key `title` 29 | 30 | ## [0.0.1] - 2019-12-15 31 | 32 | ### Added 33 | 34 | - initial commmit and demo release 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "clean": "yarn workspace demo clean", 5 | "serve": "yarn workspace demo serve", 6 | "develop:demo": "yarn workspace demo develop", 7 | "develop:plugin": "yarn workspace @pauliescanlon/gatsby-mdx-routes build:watch", 8 | "build": "yarn workspace @pauliescanlon/gatsby-mdx-routes build && yarn workspace demo build", 9 | "test": "yarn workspace @pauliescanlon/gatsby-mdx-routes test", 10 | "test:watch": "yarn workspace @pauliescanlon/gatsby-mdx-routes test:watch", 11 | "test:coverage": "yarn workspace @pauliescanlon/gatsby-mdx-routes test:coverage", 12 | "release": "node copy-readme.js && yarn workspace @pauliescanlon/gatsby-mdx-routes publish", 13 | "develop": "npm-run-all --parallel develop:demo develop:plugin" 14 | }, 15 | "workspaces": [ 16 | "demo", 17 | "@pauliescanlon/gatsby-mdx-routes" 18 | ], 19 | "devDependencies": { 20 | "npm-run-all": "^4.1.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /demo/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /demo/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `@pauliescanlon/gatsby-mdx-routes`, 4 | description: `gatsby-mdx-routes is....`, 5 | siteURL: "https://gatsby-mdx-routes.netlify.com", 6 | siteImage: "mdx-routes-main-og-image.jpg", 7 | author: "@pauliescanlon", 8 | }, 9 | plugins: [ 10 | `gatsby-plugin-react-helmet`, 11 | { 12 | resolve: "gatsby-plugin-google-analytics", 13 | options: { 14 | trackingId: "UA-76055934-6", 15 | }, 16 | }, 17 | { 18 | resolve: `gatsby-source-filesystem`, 19 | options: { 20 | name: `pages`, 21 | path: `${__dirname}/src/pages/`, 22 | }, 23 | }, 24 | // test source file system to ensure routes are only created for files sourced from src/pages 25 | { 26 | resolve: `gatsby-source-filesystem`, 27 | options: { 28 | name: `posts`, 29 | path: `${__dirname}/src/posts/`, 30 | }, 31 | }, 32 | { 33 | resolve: `gatsby-plugin-mdx`, 34 | options: { 35 | defaultLayouts: { 36 | default: `${__dirname}/src/layouts/layout.js`, 37 | }, 38 | plugins: [`@pauliescanlon/gatsby-mdx-routes`], 39 | }, 40 | }, 41 | ], 42 | } 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "demo", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.1.0", 6 | "author": "Kyle Mathews ", 7 | "dependencies": { 8 | "@mdx-js/mdx": "^1.5.1", 9 | "@mdx-js/react": "^1.5.1", 10 | "@pauliescanlon/gatsby-mdx-routes": "*", 11 | "gatsby": "^2.18.4", 12 | "gatsby-plugin-google-analytics": "^2.1.34", 13 | "gatsby-plugin-mdx": "^1.0.62", 14 | "gatsby-plugin-react-helmet": "^3.1.16", 15 | "gatsby-source-filesystem": "^2.1.39", 16 | "prop-types": "^15.7.2", 17 | "react": "^16.12.0", 18 | "react-dom": "^16.12.0", 19 | "react-helmet": "^5.2.1" 20 | }, 21 | "devDependencies": { 22 | "prettier": "^1.19.1" 23 | }, 24 | "keywords": [ 25 | "gatsby" 26 | ], 27 | "license": "MIT", 28 | "scripts": { 29 | "build": "gatsby build", 30 | "develop": "gatsby develop", 31 | "format": "prettier --write \"**/*.{js,jsx,json,mdx}\"", 32 | "start": "npm run develop", 33 | "serve": "gatsby serve", 34 | "clean": "gatsby clean", 35 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" 36 | }, 37 | "repository": { 38 | "type": "git", 39 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 40 | }, 41 | "bugs": { 42 | "url": "https://github.com/gatsbyjs/gatsby/issues" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/.gitignore: -------------------------------------------------------------------------------- 1 | # Dev references 2 | refs.md 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | *.pid.lock 16 | 17 | # Directory for instrumented libs generated by babel and tsconfig 18 | components 19 | utils 20 | gatsby-node.d.ts 21 | gatsby-node.js 22 | index.d.ts 23 | index.js 24 | 25 | # Coverage directory used by tools like istanbul 26 | coverage 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (http://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # Typescript v1 declaration files 48 | typings/ 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Optional REPL history 57 | .node_repl_history 58 | 59 | # Output of 'npm pack' 60 | *.tgz 61 | 62 | # dotenv environment variable files 63 | .env* 64 | 65 | # gatsby files 66 | .cache/ 67 | public 68 | 69 | # Mac files 70 | .DS_Store 71 | 72 | # Yarn 73 | yarn-error.log 74 | .pnp/ 75 | .pnp.js 76 | # Yarn Integrity file 77 | .yarn-integrity 78 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/src/utils/recursiveMenu.ts: -------------------------------------------------------------------------------- 1 | export const recursiveMenu = (routes: any) => { 2 | const createItemsFromSlugs = routes 3 | .map((route: any) => { 4 | let paths = route.slug.split("/").filter((s: any) => s) 5 | return { 6 | ...route, 7 | id: paths.length > 1 ? paths[paths.length - 1] : "", 8 | parent: paths.length > 1 ? paths[paths.length - 2] : null, 9 | paths: paths, 10 | menu: null, 11 | } 12 | }) 13 | .reduce((items: any, item: any, index: any) => { 14 | items.push(item) 15 | 16 | if (items[index].id && items[index].id !== item.parent) { 17 | const { paths } = item 18 | items.push({ 19 | navigationLabel: item.parent && item.parent.replace(/-/g, " "), 20 | id: item.parent, 21 | slug: null, 22 | paths: null, 23 | parent: paths.length > 2 ? paths[paths.length - 3] : null, 24 | }) 25 | } 26 | 27 | return items 28 | }, []) 29 | .filter((route: any) => route.navigationLabel) 30 | 31 | const createRecursiveMenu = (array: any, parent: any) => { 32 | let result: any = [] 33 | 34 | array 35 | .filter((route: any) => route.parent === parent) 36 | .forEach((route: any) => { 37 | route.menu = createRecursiveMenu(array, route.id) 38 | return result.push(route) 39 | }) 40 | 41 | return result 42 | } 43 | 44 | return createRecursiveMenu(createItemsFromSlugs, null) 45 | } 46 | -------------------------------------------------------------------------------- /demo/src/components/seo.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Helmet from "react-helmet" 3 | 4 | import PropTypes from "prop-types" 5 | 6 | const Seo = ({ lang, title, description, siteURL, siteImage, author }) => { 7 | return ( 8 | 9 | 10 | 11 | 12 | 13 | 14 | {/* Facebook */} 15 | 16 | 17 | 18 | 19 | 20 | 21 | {/* Twitter */} 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | 33 | Seo.propTypes = { 34 | lang: PropTypes.string.isRequired, 35 | title: PropTypes.string.isRequired, 36 | description: PropTypes.string.isRequired, 37 | siteURL: PropTypes.string.isRequired, 38 | siteImage: PropTypes.string.isRequired, 39 | author: PropTypes.string.isRequired, 40 | } 41 | 42 | export default Seo 43 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pauliescanlon/gatsby-mdx-routes", 3 | "author": "Paul Scanlon ", 4 | "repository": { 5 | "type": "git", 6 | "url": "git+https://github.com/PaulieScanlon/gatsby-mdx-routes.git" 7 | }, 8 | "version": "0.0.11", 9 | "main": "index.js", 10 | "license": "MIT", 11 | "scripts": { 12 | "test": "jest", 13 | "test:watch": "jest --watch", 14 | "test:coverage": "jest --coverage", 15 | "publish": "npm run build && npm login", 16 | "type-check": "tsc --noEmit", 17 | "type-check:watch": "npm run type-check -- --watch", 18 | "build": "npm run build:types && npm run build:js", 19 | "build:types": "tsc --emitDeclarationOnly", 20 | "build:js": "babel src --out-dir . --extensions \".js,.ts,.tsx\" --source-maps inline", 21 | "build:watch": "babel src --out-dir . --extensions \".js,.ts,.tsx\" --watch", 22 | "tsc": "tsc" 23 | }, 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "@babel/cli": "^7.8.3", 27 | "@babel/core": "^7.8.3", 28 | "@babel/plugin-proposal-class-properties": "^7.8.3", 29 | "@babel/plugin-proposal-object-rest-spread": "^7.8.3", 30 | "@babel/preset-react": "^7.8.3", 31 | "@babel/preset-typescript": "^7.8.3", 32 | "@types/node": "^13.1.7", 33 | "@types/react": "^16.9.17", 34 | "@types/react-dom": "^16.9.4", 35 | "prettier": "^1.19.1", 36 | "typescript": "^3.7.5" 37 | }, 38 | "peerDependencies": { 39 | "gatsby": "^2.18.12", 40 | "react": "^16.12.0" 41 | }, 42 | "keywords": [ 43 | "gatsby", 44 | "gatsby-plugin", 45 | "gatsby-mdx" 46 | ], 47 | "description": "Routes and Recursive Navigation menus for Mdx files", 48 | "bugs": { 49 | "url": "https://github.com/PaulieScanlon/gatsby-mdx-routes/issues" 50 | }, 51 | "homepage": "https://github.com/PaulieScanlon/gatsby-mdx-routes#readme" 52 | } 53 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/src/components/MdxRoutes/MdxRoutes.tsx: -------------------------------------------------------------------------------- 1 | import React, { FunctionComponent, Fragment } from "react" 2 | import { useStaticQuery, graphql } from "gatsby" 3 | 4 | import { recursiveMenu } from "../../utils/recursiveMenu" 5 | 6 | interface IMdxRoutesProps { 7 | /** Navigation order */ 8 | navigationOrder: string[] 9 | /** Custom children */ 10 | children: any 11 | } 12 | 13 | interface IMdxData { 14 | /** navigationLabel from frontmatter */ 15 | navigationLabel: string 16 | /** slug from graphql query */ 17 | slug: string 18 | } 19 | 20 | export const MdxRoutes: FunctionComponent = ({ 21 | children, 22 | navigationOrder, 23 | }) => { 24 | // the filter is to project the query against other mdx queries in the host site 25 | // by filter out anything that's not in pages we safe guard the routes which 26 | // are only supposed to be sourced from `pages` 27 | const data = useStaticQuery(graphql` 28 | query { 29 | allMdx(filter: { fileAbsolutePath: { regex: "//pages//" } }) { 30 | edges { 31 | node { 32 | id 33 | fields { 34 | slug 35 | } 36 | frontmatter { 37 | title 38 | navigationLabel 39 | } 40 | } 41 | } 42 | } 43 | } 44 | `) 45 | const { edges } = data.allMdx 46 | 47 | const sortOrder = (array: IMdxData[]) => { 48 | if (navigationOrder) { 49 | return array.sort((a: any, b: any) => { 50 | return ( 51 | navigationOrder.indexOf(a.navigationLabel) - 52 | navigationOrder.indexOf(b.navigationLabel) 53 | ) 54 | }) 55 | } 56 | 57 | return array.reduce((routes: any, route: any) => { 58 | if (route.slug === "/") { 59 | return [route, ...routes] 60 | } 61 | return [...routes, route] 62 | }, []) 63 | } 64 | 65 | const mdxData = edges.map( 66 | (data: any): IMdxData => { 67 | const { frontmatter, fields } = data.node 68 | return { 69 | navigationLabel: frontmatter.navigationLabel, 70 | slug: fields.slug, 71 | } 72 | } 73 | ) 74 | 75 | const routes = sortOrder(mdxData) 76 | const menus = sortOrder(recursiveMenu(mdxData)) 77 | 78 | return {children(routes, menus)} 79 | } 80 | -------------------------------------------------------------------------------- /demo/src/layouts/layout.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from "react" 2 | import { StaticQuery, graphql, Link } from "gatsby" 3 | 4 | import PropTypes from "prop-types" 5 | 6 | import { MdxRoutes } from "@pauliescanlon/gatsby-mdx-routes" 7 | 8 | import Seo from "../components/seo" 9 | 10 | import "./layout.css" 11 | 12 | const Tree = ({ menus }) => { 13 | const createTree = menus => { 14 | return ( 15 |
    16 | {menus.map(route => ( 17 |
  • 18 | {route.slug ? ( 19 | 20 | {route.navigationLabel} 21 | {route.menu && createTree(route.menu)} 22 | 23 | ) : ( 24 | 25 | {route.navigationLabel} 26 | {route.menu && createTree(route.menu)} 27 | 28 | )} 29 |
  • 30 | ))} 31 |
32 | ) 33 | } 34 | 35 | return createTree(menus) 36 | } 37 | 38 | const Layout = ({ children }) => { 39 | return ( 40 | { 55 | const { 56 | title, 57 | description, 58 | siteImage, 59 | siteURL, 60 | author, 61 | } = data.site.siteMetadata 62 | 63 | return ( 64 | 65 | 73 | 91 | 92 |
{children}
93 |

routes

94 |

95 | Simple example routes.map 96 |

97 | 110 |

routes navigationOrder

111 |

112 | Simple example routes.map with{" "} 113 | navigationOrder 114 |

115 | 138 |

menus

139 |

140 | Recursive example createTree 141 |

142 | 145 |

menus navigationOrder

146 |

147 | Recursive example createTree with{" "} 148 | navigationOrder 149 |

150 | 163 |
164 | ) 165 | }} 166 | /> 167 | ) 168 | } 169 | 170 | Layout.propTypes = { 171 | children: PropTypes.node.isRequired, 172 | } 173 | 174 | export default Layout 175 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | Gatsby 5 | 6 |

7 |

8 | Gatsby's default starter 9 |

10 | 11 | Kick off your project with this default boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React. 12 | 13 | _Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._ 14 | 15 | ## 🚀 Quick start 16 | 17 | 1. **Create a Gatsby site.** 18 | 19 | Use the Gatsby CLI to create a new site, specifying the default starter. 20 | 21 | ```shell 22 | # create a new Gatsby site using the default starter 23 | gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default 24 | ``` 25 | 26 | 1. **Start developing.** 27 | 28 | Navigate into your new site’s directory and start it up. 29 | 30 | ```shell 31 | cd my-default-starter/ 32 | gatsby develop 33 | ``` 34 | 35 | 1. **Open the source code and start editing!** 36 | 37 | Your site is now running at `http://localhost:8000`! 38 | 39 | _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.org/tutorial/part-five/#introducing-graphiql)._ 40 | 41 | Open the `my-default-starter` directory in your code editor of choice and edit `src/pages/index.js`. Save your changes and the browser will update in real time! 42 | 43 | ## 🧐 What's inside? 44 | 45 | A quick look at the top-level files and directories you'll see in a Gatsby project. 46 | 47 | . 48 | ├── node_modules 49 | ├── src 50 | ├── .gitignore 51 | ├── .prettierrc 52 | ├── gatsby-browser.js 53 | ├── gatsby-config.js 54 | ├── gatsby-node.js 55 | ├── gatsby-ssr.js 56 | ├── LICENSE 57 | ├── package-lock.json 58 | ├── package.json 59 | └── README.md 60 | 61 | 1. **`/node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages) are automatically installed. 62 | 63 | 2. **`/src`**: This directory will contain all of the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”. 64 | 65 | 3. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for. 66 | 67 | 4. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent. 68 | 69 | 5. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/) (if any). These allow customization/extension of default Gatsby settings affecting the browser. 70 | 71 | 6. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more detail). 72 | 73 | 7. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process. 74 | 75 | 8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering. 76 | 77 | 9. **`LICENSE`**: Gatsby is licensed under the MIT license. 78 | 79 | 10. **`package-lock.json`** (See `package.json` below, first). This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(You won’t change this file directly).** 80 | 81 | 11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc). This manifest is how npm knows which packages to install for your project. 82 | 83 | 12. **`README.md`**: A text file containing useful reference information about your project. 84 | 85 | ## 🎓 Learning Gatsby 86 | 87 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start: 88 | 89 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 90 | 91 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 92 | 93 | ## 💫 Deploy 94 | 95 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default) 96 | 97 | 98 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | // "incremental": true, /* Enable incremental compilation */ 5 | "target": "ES6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */, 6 | "module": "none" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, 7 | // "lib": [], /* Specify library files to be included in the compilation. */ 8 | "allowJs": true /* Allow javascript files to be compiled. */, 9 | // "checkJs": true, /* Report errors in .js files. */ 10 | "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, 11 | "declaration": true /* Generates corresponding '.d.ts' file. */, 12 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 13 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 14 | // "outFile": "./", /* Concatenate and emit output to single file. */ 15 | "outDir": "." /* Redirect output structure to the directory. */, 16 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 17 | // "composite": true, /* Enable project compilation */ 18 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 19 | // "removeComments": true, /* Do not emit comments to output. */ 20 | // "noEmit": true, /* Do not emit outputs. */ 21 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 22 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 23 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 24 | 25 | /* Strict Type-Checking Options */ 26 | "strict": true /* Enable all strict type-checking options. */, 27 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | 35 | /* Additional Checks */ 36 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 37 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 38 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 39 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 40 | 41 | /* Module Resolution Options */ 42 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, 43 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 44 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 45 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 46 | // "typeRoots": [], /* List of folders to include type definitions from. */ 47 | // "types": [], /* Type declaration files to be included in compilation. */ 48 | "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, 49 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 50 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 51 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 52 | 53 | /* Source Map Options */ 54 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 55 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 56 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 57 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 58 | 59 | /* Experimental Options */ 60 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 61 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 62 | 63 | /* Advanced Options */ 64 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 65 | }, 66 | "include": ["./src/**/*"], 67 | "exclude": ["./node_modules/*"] 68 | } 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![npm (scoped)](https://img.shields.io/npm/v/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 4 | 5 | ![npm](https://img.shields.io/npm/dt/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 6 | 7 | ![NPM](https://img.shields.io/npm/l/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 8 | 9 |
10 | 11 | # gatsby-mdx-routes 12 | 13 | gatsby-mdx-routes is a plugin that exposes links to `.mdx` files sourced from `src/pages`. 14 | 15 | This plugin aims to separate the data from the ui, which means the styling of your navigation is up to you. 16 | 17 | ## 👁️ Preview 18 | 19 | - [Live Demo](https://gatsby-mdx-routes.netlify.com/) 20 | 21 | ## 🚀 Getting started 22 | 23 | ### Install 24 | 25 | ``` 26 | npm install @pauliescanlon/gatsby-mdx-routes 27 | ``` 28 | 29 | ### Setup 30 | 31 | To source `.mdx` files from `src/pages` you'll need `gatsby-source-filesystem` and `gatsby-plugin-mdx` installed. 32 | 33 | Your `gatsby-config` should look something like this... 34 | 35 | ```js 36 | module.exports = { 37 | plugins: [ 38 | { 39 | resolve: `gatsby-source-filesystem`, 40 | options: { 41 | name: `pages`, 42 | path: `${__dirname}/src/pages/`, 43 | }, 44 | }, 45 | { 46 | resolve: `gatsby-plugin-mdx`, 47 | options: { 48 | defaultLayouts: { 49 | default: `${__dirname}/src/layouts/layout.js`, 50 | }, 51 | }, 52 | }, 53 | ], 54 | } 55 | ``` 56 | 57 | If that's all setup you'll now need to add `@pauliescanlon/gatsby-mdx-routes` as a plugin of `gatsby-plugin-mdx` 😅 58 | 59 | ```js 60 | module.exports = { 61 | { 62 | resolve: `gatsby-plugin-mdx`, 63 | options: { 64 | defaultLayouts: { 65 | default: `${__dirname}/src/layouts/layout.js`, 66 | }, 67 | plugins: [`@pauliescanlon/gatsby-mdx-routes`], 68 | }, 69 | }, 70 | } 71 | ``` 72 | 73 | Using the `defaultLayouts` from `gatsby-plugin-mdx` allows you to create one file that will be repeated across pages. 74 | 75 | This is where we'll add `MdxRoutes`. 76 | 77 | ## MdxRoutes 78 | 79 | MdxRoutes returns two arrays, _routes_ which is a flat array and _menus_ which is created recursively and contains a `menu` array. 80 | 81 | You will probably use one or the other, not both. 82 | 83 | ### routes 84 | 85 | The `routes` array returns two object keys, one is the actual route to the file in question (`slug`), the other is the `navigationLabel` from _frontmatter_ 86 | 87 | | Key | Description | 88 | | --------------- | ------------------------------------------ | 89 | | slug | Route to `.mdx` file | 90 | | navigationLabel | navigationLabel extracted from frontmatter | 91 | 92 | src/pages/a-page.mdx 93 | 94 | #### frontmatter 95 | 96 | ```js 97 | --- 98 | navigationLabel: Page Title 99 | --- 100 | 101 | ``` 102 | 103 | src/layouts/layout.js 104 | 105 | ```js 106 | import React, { Fragment } from "react" 107 | import { Link } from "gatsby" 108 | 109 | import { MdxRoutes } from "@pauliescanlon/gatsby-mdx-routes" 110 | 111 | export default ({ children }) => ( 112 | 113 | 126 |
{children}
127 |
128 | ) 129 | ``` 130 | 131 | ### menus 132 | 133 | The `menus` array also returns the two object keys mentioned above, it also returns the following 134 | 135 | | Key | Description | 136 | | --------------- | ------------------------------------------- | 137 | | slug | Route to `.mdx` file | 138 | | navigationLabel | navigationLabel extracted from frontmatter | 139 | | id | key to use in recursive function | 140 | | parent | string to determine parent | 141 | | menu | array of routes grouped by parent | 142 | | paths | internal array to use in recursive function | 143 | 144 | The _menus_ array is constructed by looking at the file paths on disk and determining what depth a file lives. This is calculated by the amount of forward slashes in the `slug` 145 | 146 | **To create the menus array `MdxRoutes` will mirror the directory structure in your project** 147 | 148 | your project 149 | 150 | 151 | ``` 152 | └─ src 153 | └─ pages 154 | └─ other-pages 155 | └─ some-other-page.mdx 156 | ├─ sub-pages 157 | ├─ sub-page-items 158 | ├─ sub-page-items-again 159 | └─ sub-page-item-again-1.mdx 160 | └─ sub-page-item-1.mdx 161 | └─ sub-page-1.mdx 162 | ├─ about.mdx 163 | ├─ contact.mdx 164 | └─ index.mdx 165 | ``` 166 | 167 | To use the **menus** array you'll also need a recursive **Tree** function to create your navigation list. 168 | 169 | Watch out for the conditional `slug`, we need this to determine if the object key is a parent or an actual route to a file. 170 | 171 | src/layouts/layout.js 172 | 173 | ```js 174 | import React, { Fragment } from "react" 175 | import { Link } from "gatsby" 176 | 177 | import { MdxRoutes } from "@pauliescanlon/gatsby-mdx-routes" 178 | 179 | const Tree = ({ menus }) => { 180 | const createTree = menus => { 181 | return ( 182 |
    183 | {menus.map(route => ( 184 |
  • 185 | {route.slug ? ( 186 | 187 | {route.navigationLabel} 188 | {route.menu && createTree(route.menu)} 189 | 190 | ) : ( 191 | 192 | {route.navigationLabel} 193 | {route.menu && createTree(route.menu)} 194 | 195 | )} 196 |
  • 197 | ))} 198 |
199 | ) 200 | } 201 | 202 | return createTree(menus, null) 203 | } 204 | 205 | export default ({ children }) => ( 206 | 207 | 210 |
{children}
211 |
212 | ) 213 | ``` 214 | 215 | ### props 216 | 217 | | Prop | Type | Required | Description | 218 | | --------------- | ------------- | -------- | ----------------------------- | 219 | | navigationOrder | Array[string] | no | A reference array to order by | 220 | 221 | #### navigationOrder 222 | 223 | By passing in an array of strings `MdxRoutes` can use this to sort the returned **routes** or **menus** array, otherwise everything is just returned alphabetically in an ascending order based on the slug, with the index ("/") being first in the list. 224 | 225 | ```js 226 | 227 | {(routes, menus) => ( 228 |
    229 | {routes.map((route, index) => ( 230 |
  • 231 | {route.navigationLabel} 232 |
  • 233 | ))} 234 |
235 | )} 236 |
237 | ``` 238 | 239 | If you're using **gatsby-mdx-routes** in your project i'd love to hear from you [@pauliescanlon](https://twitter.com/PaulieScanlon) 240 | 241 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/P5P31B7G8) 242 | -------------------------------------------------------------------------------- /@pauliescanlon/gatsby-mdx-routes/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ![npm (scoped)](https://img.shields.io/npm/v/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 4 | 5 | ![npm](https://img.shields.io/npm/dt/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 6 | 7 | ![NPM](https://img.shields.io/npm/l/@pauliescanlon/gatsby-mdx-routes?style=flat-square) 8 | 9 |
10 | 11 | # gatsby-mdx-routes 12 | 13 | gatsby-mdx-routes is a plugin that exposes links to `.mdx` files sourced from `src/pages`. 14 | 15 | This plugin aims to separate the data from the ui, which means the styling of your navigation is up to you. 16 | 17 | ## 👁️ Preview 18 | 19 | - [Live Demo](https://gatsby-mdx-routes.netlify.com/) 20 | 21 | ## 🚀 Getting started 22 | 23 | ### Install 24 | 25 | ``` 26 | npm install @pauliescanlon/gatsby-mdx-routes 27 | ``` 28 | 29 | ### Setup 30 | 31 | To source `.mdx` files from `src/pages` you'll need `gatsby-source-filesystem` and `gatsby-plugin-mdx` installed. 32 | 33 | Your `gatsby-config` should look something like this... 34 | 35 | ```js 36 | module.exports = { 37 | plugins: [ 38 | { 39 | resolve: `gatsby-source-filesystem`, 40 | options: { 41 | name: `pages`, 42 | path: `${__dirname}/src/pages/`, 43 | }, 44 | }, 45 | { 46 | resolve: `gatsby-plugin-mdx`, 47 | options: { 48 | defaultLayouts: { 49 | default: `${__dirname}/src/layouts/layout.js`, 50 | }, 51 | }, 52 | }, 53 | ], 54 | } 55 | ``` 56 | 57 | If that's all setup you'll now need to add `@pauliescanlon/gatsby-mdx-routes` as a plugin of `gatsby-plugin-mdx` 😅 58 | 59 | ```js 60 | module.exports = { 61 | { 62 | resolve: `gatsby-plugin-mdx`, 63 | options: { 64 | defaultLayouts: { 65 | default: `${__dirname}/src/layouts/layout.js`, 66 | }, 67 | plugins: [`@pauliescanlon/gatsby-mdx-routes`], 68 | }, 69 | }, 70 | } 71 | ``` 72 | 73 | Using the `defaultLayouts` from `gatsby-plugin-mdx` allows you to create one file that will be repeated across pages. 74 | 75 | This is where we'll add `MdxRoutes`. 76 | 77 | ## MdxRoutes 78 | 79 | MdxRoutes returns two arrays, _routes_ which is a flat array and _menus_ which is created recursively and contains a `menu` array. 80 | 81 | You will probably use one or the other, not both. 82 | 83 | ### routes 84 | 85 | The `routes` array returns two object keys, one is the actual route to the file in question (`slug`), the other is the `navigationLabel` from _frontmatter_ 86 | 87 | | Key | Description | 88 | | --------------- | ------------------------------------------ | 89 | | slug | Route to `.mdx` file | 90 | | navigationLabel | navigationLabel extracted from frontmatter | 91 | 92 | src/pages/a-page.mdx 93 | 94 | #### frontmatter 95 | 96 | ```js 97 | --- 98 | navigationLabel: Page Title 99 | --- 100 | 101 | ``` 102 | 103 | src/layouts/layout.js 104 | 105 | ```js 106 | import React, { Fragment } from "react" 107 | import { Link } from "gatsby" 108 | 109 | import { MdxRoutes } from "@pauliescanlon/gatsby-mdx-routes" 110 | 111 | export default ({ children }) => ( 112 | 113 | 126 |
{children}
127 |
128 | ) 129 | ``` 130 | 131 | ### menus 132 | 133 | The `menus` array also returns the two object keys mentioned above, it also returns the following 134 | 135 | | Key | Description | 136 | | --------------- | ------------------------------------------- | 137 | | slug | Route to `.mdx` file | 138 | | navigationLabel | navigationLabel extracted from frontmatter | 139 | | id | key to use in recursive function | 140 | | parent | string to determine parent | 141 | | menu | array of routes grouped by parent | 142 | | paths | internal array to use in recursive function | 143 | 144 | The _menus_ array is constructed by looking at the file paths on disk and determining what depth a file lives. This is calculated by the amount of forward slashes in the `slug` 145 | 146 | **To create the menus array `MdxRoutes` will mirror the directory structure in your project** 147 | 148 | your project 149 | 150 | 151 | ``` 152 | |-- src 153 | |-- pages 154 | |-- other-pages 155 | |-- some-other-page.mdx 156 | |-- sub-pages 157 | |-- sub-page-items 158 | |-- sub-page-items-again 159 | |-- sub-page-item-again-1.mdx 160 | |-- sub-page-item-1.mdx 161 | |-- sub-page-1.mdx 162 | |-- about.mdx 163 | |-- contact.mdx 164 | |-- index.mdx 165 | ``` 166 | 167 | To use the **menus** array you'll also need a recursive **Tree** function to create your navigation list. 168 | 169 | Watch out for the conditional `slug`, we need this to determine if the object key is a parent or an actual route to a file. 170 | 171 | src/layouts/layout.js 172 | 173 | ```js 174 | import React, { Fragment } from "react" 175 | import { Link } from "gatsby" 176 | 177 | import { MdxRoutes } from "@pauliescanlon/gatsby-mdx-routes" 178 | 179 | const Tree = ({ menus }) => { 180 | const createTree = menus => { 181 | return ( 182 |
    183 | {menus.map(route => ( 184 |
  • 185 | {route.slug ? ( 186 | 187 | {route.navigationLabel} 188 | {route.menu && createTree(route.menu)} 189 | 190 | ) : ( 191 | 192 | {route.navigationLabel} 193 | {route.menu && createTree(route.menu)} 194 | 195 | )} 196 |
  • 197 | ))} 198 |
199 | ) 200 | } 201 | 202 | return createTree(menus, null) 203 | } 204 | 205 | export default ({ children }) => ( 206 | 207 | 210 |
{children}
211 |
212 | ) 213 | ``` 214 | 215 | ### props 216 | 217 | | Prop | Type | Required | Description | 218 | | --------------- | ------------- | -------- | ----------------------------- | 219 | | navigationOrder | Array[string] | no | A reference array to order by | 220 | 221 | #### navigationOrder 222 | 223 | By passing in an array of strings `MdxRoutes` can use this to sort the returned **routes** or **menus** array, otherwise everything is just returned alphabetically in an ascending order based on the slug, with the index ("/") being first in the list. 224 | 225 | ```js 226 | 227 | {(routes, menus) => ( 228 |
    229 | {routes.map((route, index) => ( 230 |
  • 231 | {route.navigationLabel} 232 |
  • 233 | ))} 234 |
235 | )} 236 |
237 | ``` 238 | 239 | If you're using **gatsby-mdx-routes** in your project i'd love to hear from you [@pauliescanlon](https://twitter.com/PaulieScanlon) 240 | 241 | [![ko-fi](https://www.ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/P5P31B7G8) 242 | --------------------------------------------------------------------------------