{"id":22039545,"url":"https://github.com/mpolinowski/gatsby-wiki","last_synced_at":"2025-06-11T08:07:58.124Z","repository":{"id":111483327,"uuid":"105438140","full_name":"mpolinowski/gatsby-wiki","owner":"mpolinowski","description":"Creating a Knowledgbase using Gatsby.js and React.js (see final product -\u003e ","archived":false,"fork":false,"pushed_at":"2017-11-26T11:41:41.000Z","size":1649,"stargazers_count":32,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-11T08:07:14.904Z","etag":null,"topics":["elasticsearch","elasticsearch-client","elasticstack","gatsby","gatsby-starter","gatsbyjs","graphql","material-ui","react","reactjs","single-page-app"],"latest_commit_sha":null,"homepage":"https://github.com/mpolinowski/material-ui-gatsby-wiki","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpolinowski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-01T11:42:48.000Z","updated_at":"2024-06-15T10:59:37.000Z","dependencies_parsed_at":null,"dependency_job_id":"201dd1c0-ad9b-4e54-a710-abdce8a23258","html_url":"https://github.com/mpolinowski/gatsby-wiki","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fgatsby-wiki","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fgatsby-wiki/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fgatsby-wiki/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fgatsby-wiki/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpolinowski","download_url":"https://codeload.github.com/mpolinowski/gatsby-wiki/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpolinowski%2Fgatsby-wiki/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259227951,"owners_count":22824903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elasticsearch","elasticsearch-client","elasticstack","gatsby","gatsby-starter","gatsbyjs","graphql","material-ui","react","reactjs","single-page-app"],"created_at":"2024-11-30T11:11:11.605Z","updated_at":"2025-06-11T08:07:58.105Z","avatar_url":"https://github.com/mpolinowski.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gatsby-starter-default\nThe default Gatsby starter\n\nFor an overview of the project structure please refer to the [Gatsby documentation - Building with Components](https://www.gatsbyjs.org/docs/building-with-components/)\n\nInstall this starter (assuming Gatsby is installed) by running from your CLI:\n```\ngatsby new gatsby-wiki\n```\n\n1. [Start your Gatsby Development Environment](#01-start-your-gatsby-development-environment)\n2. [Adding Content and Linking Pages](#02-adding-content-and-linking-pages)\n3. [Styling your JSX](#03-styling-your-jsx)\n4. [Adding Interactive Components](#04-adding-interactive-components)\n5. [Importing Components to your Sites](#05-importing-components-to-your-sites)\n6. [Passing down Props](#06-passing-down-props)\n7. [Gatsby Plugins](#07-gatsby-plugins)\n8. [Single Page Application](#08-single-page-application)\n9. [GraphQL](#09-graphql)\n10. [Adding File Data](#10-adding-file-data)\n11. [Working with Markdown](#11-working-with-markdown)\n12. [Adding Material-UI](#12-adding-material-ui)\n13. [Adding Elasticsearch](#13-adding-elasticsearch)\n14. [Build the Static Page](#xx-build-the-static-page)\n---\n\n\n## 01 Start your Gatsby development environment\n\n\nNow change into your site directory and run the Gatsby development environment using npm:\n\n```\ncd gatsby-wiki\n\nnpm run development\n```\n\nYou can now access your website on http://localhost:8000 :\n\n\n![](./gatsby_01.png)\n\n\n\n\n## 02 Adding content and Linking Pages\n\n\nThe _/src/pages/index.js_ file contains regular JSX - add any HTML inside the /\u003cdiv/\u003e tag to make it appear inside your website (Gatsby is hot-reloading).\n\n```js\nimport React from 'react'\nimport Link from 'gatsby-link'\n\nconst IndexPage = () =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003eHi people\u003c/h1\u003e\n    \u003cp\u003eWelcome to your new Gatsby site.\u003c/p\u003e\n    \u003cp\u003eNow go build something great.\u003c/p\u003e\n    \u003cLink to=\"/page-2/\"\u003eGo to page 2\u003c/Link\u003e\n  \u003c/div\u003e\n)\n\nexport default IndexPage\n```\n\nYou need to import Link from gatsby-link to use the Link Component and link to other pages - above you see the:\n\n```html\n\u003cLink to=\"/page-2/\"\u003eGo to page 2\u003c/Link\u003e\n```\n\ncomponent, linking our __index.js__ page to another page inside the same folder with the name __page-2.js__. Every js file inside the _/src/pages_ folder will automagically be routed by Gatsby!\n\n\n![](./gatsby_02.png)\n\n\n\n\n## 03 Styling your JSX\n\n\nYou can use simply add inline styles to your component, e.g.\n\n```js\nconst IndexPage = () =\u003e (\n  \u003cdiv style={{color: 'tomato', background: 'blue'}}\u003e\n    \u003ch1\u003eHi people\u003c/h1\u003e\n    \u003cp\u003eWelcome to your new Gatsby site.\u003c/p\u003e\n    \u003cp\u003eNow go build something great.\u003c/p\u003e\n    \u003cLink to=\"/page-2/\"\u003eGo to page 2\u003c/Link\u003e\n  \u003c/div\u003e\n)\n```\n\nFor some advanced styles check out the Gatsby plugins [Glamor](https://www.gatsbyjs.org/packages/gatsby-plugin-glamor/) or [Styled Components](https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/).\n\nHow to install those plugins is explained below - [Gatsby Plugins](#07-gatsby-plugins) .\n\n\n\n\n## 04 Adding Interactive Components\n\n\nReact allows you to add interaction to your page - we want to add a counter, set it's state to 0 on load and have two buttons that use onClick events to increment or decrement the state of the counter.\n\nWe can just add a new file _/src/pages/counter.js_ and link to it from the index page _\\\u003cLink to=\"/counter/\"\\\u003eGo to Counter\\\u003c/Link\\\u003e_:\n\n```js\nimport React from 'react'\n\nclass Counter extends React.Component {\n  constructor() {\n    super()\n    this.state = { count: 0 }\n  }\n  render() {\n    return \u003cdiv\u003e\n            \u003ch1\u003eCounter\u003c/h1\u003e\n            \u003cp\u003ecurrent count: {this.state.count}\u003c/p\u003e\n            \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count + 1 })}\u003eplus\u003c/button\u003e\n            \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count - 1 })}\u003eminus\u003c/button\u003e\n          \u003c/div\u003e\n  }\n}\n\nexport default Counter\n```\n\n\n![](./gatsby_03.png)\n\n\n\n\n## 05 Importing Components to your Sites\n\n\nSo far, we used every file inside the pages directory as a separate site. But React.js allows us to take the default component - that is exported at the bottom of the file - and import it into another page. For example, we could take the \\\u003cCounter /\\\u003e component above and add it to the index page (instead of just linking to it).\n\nWe just need to add an import line to the beginning of _/src/pages/index.js_:\n\n```js\nimport React from 'react'\nimport Link from 'gatsby-link'\n\nimport Counter from './counter'\n```\n\nAnd reference the Counter inside the JSX code of index.js, like this:\n\n```js\nconst IndexPage = () =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003eHi people\u003c/h1\u003e\n    \u003cp\u003eWelcome to your new Gatsby site.\u003c/p\u003e\n    \u003cp\u003eNow go build something great.\u003c/p\u003e\n    \u003cLink to=\"/page-2/\"\u003eGo to Page 2\u003c/Link\u003e\u003cbr/\u003e\u003cbr/\u003e\n    \u003cCounter /\u003e\n  \u003c/div\u003e\n)\n```\n\n\n![](./gatsby_04.png)\n\n\n\n\n## 06 Passing down Props\n\n\nWe can now pass properties, from the parent component, down to the Counter component - e.g. we can change the title of our counter, depending on the page it is displayed on:\n\n\n### Changing Headers\n\n```js\n\u003cCounter header=\"This is the Index Counter\" /\u003e\n```\n\nThe prop header is now available to the render function inside the Counter component. Now we can get different headers for our Counter component, depending on the parent component that called it - awesome!\n\n```js\nrender() {\n  return \u003cdiv\u003e\n          \u003ch3\u003e{this.props.header}\u003c/h3\u003e\n          \u003cp\u003ecurrent count: {this.state.count}\u003c/p\u003e\n          \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count + 1 })}\u003eplus\u003c/button\u003e\n          \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count - 1 })}\u003eminus\u003c/button\u003e\n        \u003c/div\u003e\n}\n```\n\n\n### Changing Styles\n\nThe same goes with styles - if we want the header to match the colour scheme of our parent component, we can just pass down a color prop to the Counter component:\n\n```js\n\u003cCounter header=\"This is the Index Counter\" color=\"rebeccapurple\" /\u003e\n```\n\nAnd add the necessary inline styles in the component itself:\n\n```js\nrender() {\n  return \u003cdiv\u003e\n          \u003ch3 style={{color: this.props.color}}\u003e{this.props.header}\u003c/h3\u003e\n          \u003cp\u003ecurrent count: {this.state.count}\u003c/p\u003e\n          \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count + 1 })}\u003eplus\u003c/button\u003e\n          \u003cbutton onClick={() =\u003e this.setState({ count: this.state.count - 1 })}\u003eminus\u003c/button\u003e\n        \u003c/div\u003e\n}\n```\n\n\n### Setting Default Props\n\nTo be able to still open the _localhost:8000/counter_ URL, we now have to define a default prop inside the counter component - the header tag and font colour will be undefined, if there is no parent component passing down props! This can be done by Prop-Types, that we need to install:\n\n```\nnpm install --save prop-types\n```\n\nNow we can import it into _/src/pages/counter.js_ :\n\n```js\nimport React from 'react'\nimport PropTypes from 'prop-types'\n```\n\nAnd define a default value for the header prop below the Counter component (above the export statement):\n\n```js\nCounter.defaultProps = {\n  header: 'Default Counter',\n  color: 'black'\n}\n```\n\n\n\n## 07 Gatsby Plugins\n\n[Plugins](https://www.gatsbyjs.org/docs/plugins/) are Node.js packages that implement Gatsby APIs. They enable you to easily solve common website build problems e.g. setup Sass, add markdown support, process images, etc.\n\n\n### Progress Animation\n\nIn this example, we want to use a plugin for [NProgress.js](http://ricostacruz.com/nprogress/) to add a loading animation to our site. You install the [NProgress plugin](https://www.gatsbyjs.org/packages/gatsby-plugin-nprogress/) with npm:\n\n```\nnpm install --save gatsby-plugin-nprogress\n```\n\nNow we have to tell Gatsby to use the plugin by editing (creating if file doesn't exist) the gatsby-config.js file inside the root directory of our app. Coming from the starter template, we already have the react-helmet plugin installed (This plugin is described below: [Page Layout](#08-page-layout)). Now simply add the gatsby-plugin-nprogress to the array:\n\n```js\nmodule.exports = {\n  siteMetadata: {\n    title: `Gatsby Wiki`,\n  },\n  plugins: [\n      `gatsby-plugin-react-helmet`,\n      {\n        resolve: `gatsby-plugin-nprogress`,\n        options: {\n          // Setting a color is optional.\n          color: `rebeccapurple`,\n          // Disable the loading spinner.\n          showSpinner: false,\n      }\n    }\n  ],\n}\n```\n\n### Offline Support and Manifest\n\nWe now want to add a Serviceworker to our site that helps us cache important parts of our application, giving us a certain amount of offline support - as the [Offline Plugin](https://www.gatsbyjs.org/packages/gatsby-plugin-offline/) tells us, we will also install the [Manifest Plugin](https://www.gatsbyjs.org/packages/gatsby-plugin-manifest/) (make sure, that it is listed before the Offline Plugin!).\n\n```\nnpm install --save gatsby-plugin-manifest\n\nnpm install --save gatsby-plugin-offline\n```\n\nNow we add them to our Gatsby configuration:\n\n\n```js\nmodule.exports = {\n  siteMetadata: {\n    title: `Gatsby Wiki`,\n  },\n  plugins: [\n      `gatsby-plugin-react-helmet`,\n      {\n        resolve: `gatsby-plugin-nprogress`,\n        options: {\n          // Setting a color is optional.\n          color: `rebeccapurple`,\n          // Disable the loading spinner.\n          showSpinner: false,\n      }\n    },\n    {\n    resolve: `gatsby-plugin-manifest`,\n      options: {\n          name: \"Gatsby Wiki\",\n          short_name: \"Gatsby Wiki\",\n          start_url: \"/\",\n          background_color: \"white\",\n          theme_color: \"rebeccapurple\",\n          display: \"minimal-ui\",\n          icons: [\n            {\n              // Everything in /static will be copied to an equivalent\n              // directory in /public during development and build, so\n              // assuming your favicons are in /static/favicons,\n              // you can reference them here\n              src: `/apple-touch-icon.png`,\n              sizes: `180x180`,\n              type: `image/png`,\n            },\n            {\n              src: `/favicon.ico`,\n              sizes: `256x256`,\n              type: `image/png`,\n            },\n          ],\n        },\n      },\n      `gatsby-plugin-offline`,\n  ],\n}\n```\n\n\n\n## 08 Single-Page-Application\n\nGatsby offers an easy way to create Single-Page-Applications (__SPA's__) with it's layout feature. You can find the JSX and CSS inside _/src/layout_. The Gatsby Starter, that we are using, already uses a header navbar, that is defined inside the index.js file (and comes with the necessary css).\n\nYou can see that the app already uses [React-Helmet](https://github.com/nfl/react-helmet) as a Gatsby plugin. This reusable React component will manage all of your changes to the document \\\u003chead\\\u003e. Helmet takes plain HTML tags and outputs plain HTML tags.\n\nThe layout defines a \\\u003cHeader /\\\u003e component, that - together with the \\\u003cHelmet /\\\u003e component - is used inside the \\\u003cTemplateWrapper /\\\u003e\n\nAll your content, from the pages that we created so far, is then injected into the Wrapper via the {children} tag. This way, you can create top-navbars, headers, side-navigations and footers, that are then displayed on all of your websites.\n\n\n\n## 09 GraphQL\n\nWe can define some global variables inside gatsby-config.js in the root directory of our app:\n\n```js\nmodule.exports = {\n  siteMetadata: {\n    title: `Gatsby Wiki`,\n    author: `Mike Polinowski`,\n    description: `Trying out Gatsby`\n  }\n}\n```\n\nThis Data will be available to every page and can be queried usind __GraphQL__. Just add the following GraphQL query to _/src/pages/index.js_, to get a hold of those values:\n\n```js\nexport const query = graphql`\n  query FirstQuery {\n    site {\n      siteMetadata {\n        title\n        author\n        description\n      }\n    }\n  }\n`\n```\n\nThen we have to inject this __{data}__ into the parent component \\\u003cIndexPage /\\\u003e:\n\n```js\nconst IndexPage = ({data}) =\u003e\n```\n\nNow we are able to query this data inside the component:\n\n```js\n\u003ch1\u003e{data.site.siteMetadata.description}\u003c/h1\u003e\n```\n\nWhy is it __data.site.siteMetadata__? Gatsby's graphql debugger is running at _http://localhost:8000/___graphql_ you can also use it to test your queries and see how the results look. Just open the debugger and try out our previous query:\n\n\n![](./gatsby_05.png)\n\n\n\n\n## 10 Adding File Data\n\nWith Gatsby you can use GraphQL to query Data from your files directly. Transformer plugins transform File nodes into various other types of data e.g. [gatsby-transformer-json](https://www.gatsbyjs.org/packages/gatsby-transformer-json/) transforms JSON files into JSON data nodes and [gatsby-transformer-remark](https://www.gatsbyjs.org/packages/gatsby-transformer-remark/) transforms markdown files into MarkdownRemark nodes from which you can query an HTML representation of the markdown.\n\nIn this case we will use [gatsby-source-filesystem](https://www.gatsbyjs.org/packages/gatsby-source-filesystem/) to create file nodes from our file system.\n\n```\nnpm install --save gatsby-source-filesystem\n```\n\nAfter installation, add the plugin to gatsby-config.js. You can have multiple instances of this plugin to read source nodes from different locations on your filesystem.\n\nThe following sets up the Jekyll pattern of having a _pages_ directory for __Markdown files__ and a _data_ directory for __.json__, __.yaml__, __.csv__.:\n\n```js\n{\n  resolve: `gatsby-source-filesystem`,\n  options: {\n    name: `pages`,\n    path: `${__dirname}/src/pages/`,\n  },\n},\n{\n  resolve: `gatsby-source-filesystem`,\n  options: {\n    name: `data`,\n    path: `${__dirname}/src/data/`,\n  },\n}\n```\n\nYou can now open the GraphiQL debugger put in curly brackets - when you start typing allFiles, it should offer autocompletion. Just press enter to accept and __CTRL + ENTER__ again to fill out the query for all page ID's:\n\n```\n{\n\tallFile {\n\t  edges {\n\t    node {\n\t      id\n\t    }\n\t  }\n\t}\n}\n```\n\n\n![](./gatsby_06.png)\n\n\nWhen you delete _id_ and press __CTRL + SPACE__, you will be given a drop down menu with all options that you can query:\n\n\n![](./gatsby_07.png)\n\n\nUsing the _parent_, _children_ and _relativePath_ attribute enables you to create e.g. a breadcrumb navigation:\n\n\n![](./gatsby_08.png)\n\n\n\nWe can now add a GraphQL query to _/src/pages/page-2.js_ to loop through all of our pages and display some data:\n\n```js\nexport const query = graphql`\n  query MyFilesQuery {\n    allFile {\n      edges {\n          node {\n            relativePath\n            prettySize\n            extension\n            birthTime(fromNow: true)\n        }\n      }\n    }\n  }\n`\n```\n\nDon't forget to inject the __{data}__ to the page component:\n\n```js\nconst SecondPage = ({data}) =\u003e\n```\n\nNow we can add some JSX that loops through all of our files and outputs the information inside a \\\u003ctable\\\u003e\n\n```js\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003erelativePath\u003c/th\u003e\n      \u003cth\u003eprettySize\u003c/th\u003e\n      \u003cth\u003eextension\u003c/th\u003e\n      \u003cth\u003ebirthTime\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    {data.allFile.edges.map(({node}, index) =\u003e\n      \u003ctr key={index}\u003e\n        \u003ctd\u003e\n          {node.relativePath}\n        \u003c/td\u003e\n        \u003ctd\u003e\n          {node.prettySize}\n        \u003c/td\u003e\n        \u003ctd\u003e\n          {node.extension}\n        \u003c/td\u003e\n        \u003ctd\u003e\n          {node.birthTime}\n        \u003c/td\u003e\n      \u003c/tr\u003e\n    )}\n  \u003c/tbody\u003e\n\u003c/table\u003e\n```\n\n\n![](./gatsby_09.png)\n\n\n\n\n\n## 11 Working with Markdown\n\nNow we are able to access information about all of our pages. But as mentioned, in the beginning of the last paragraph, we are also able to use __Gatsby Transformer Plugins__ to look into files and make their content available to GraphQL.\n\nIn this case we want to use Markdown files and transform them, to be able to display their content in our website. The Transformer Plugin needed for this is [gatsby-transformer-remark](https://www.gatsbyjs.org/packages/gatsby-transformer-remark/). First we need to install the plugin:\n\n```\nnpm install --save gatsby-transformer-remark\n```\n\nAnd add it to our _gatsby-config.js_:\n\n```js\nplugins: [\n  `gatsby-transformer-remark`,\n]\n```\n\nThen create a markdown page inside _/src/pages/FirstMDpost/index.md_ that contains some __FrontMatter__ (metadata in the beginning of the file, that can later be queried by GraphQL) and some text:\n\n\n```\n---\npath: '/md-posts'\ntitle: 'My first Post'\ndate:   '2017-10-05'\nauthor: 'Mike Polinowski'\nchapter: 'Index'\n---\n\n# This is my first mardown Post!\n```\n\nNow we have Markdown available in GraphQL - as before, just start typing allMardownRemark (ENTER autocompletes) and then press __CTRL + ENTER__ to complete your query:\n\n\n![](./gatsby_10.png)\n\n\n\nNow we can query for the FrontMatter as well as the MD-to-HTML transformed content of each MD file we add to our pages folder:\n\n\n![](./gatsby_11.png)\n\n\n### Post Template for our Markdown Data\n\nThe markdown represents the data that is going to be displayed. But now we need to create a style template that is used with this data. Lets start by adding a new folder inside _/src_ called templates. Now add a file to it called __post.js__ that will contain the structure template for every post entry. The file contains the JSX markup for our post:\n\n```js\nimport React from 'react'\n\nexport default function Template({data}) {\n  const {markdownRemark: post} = data\n  \n  return (\n    \u003cdiv\u003e\n      \u003ch1\u003e{post.frontmatter.title}\u003c/h1\u003e\n      \u003cdiv dangerouslySetInnerHTML={{__html: post.html}} /\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport const postQuery = graphql`\n  query BlogPostByPath($path: String!) {\n    markdownRemark(frontmatter: { path: { eq: $path} }) {\n      html\n      frontmatter {\n        path\n        title\n      }\n    }\n  }\n`\n```\nThe \\\u003cTemplate /\\\u003e component receives \\{data\\} props, that are retrieved by an GraphQL query.\n\nThe query looks for a markdown post, where the called URL equals the $path given inside it's frontmatter. So if the URL that you type into your browser was _/md-posts_, a markdown file with a path: _'/md-posts'_ inside it's frontmatter, would be a hit.\n\nThe query then uses the markdownRemark plugin to transform the post markdown to HTML and make both the path and title from it's frontmatter available iside {data}, that is passed down into the \u003cTemplate /\u003e component and then rendered.\n\nGatsby is already configured to route all pages inside /src/pages as pages for our website. But now we have to register our posts, that are from the markdown files and the post.js template. To do this, we have to create a file named __gatsby-node.js__ inside the root directory of our app. We are going to use the [createPages Gatsby API](https://www.gatsbyjs.org/docs/node-apis/#createPages) to create pages from our post template:\n\n\n```js\nconst path = require('path');\n\nexports.createPages = ({boundActionCreators, graphql}) =\u003e {\n  const {createPage} = boundActionCreators;\n  // const createPage = boundActionCreators.createPage;\n\n  const postTemplate = path.resolve('src/templates/post.js');\n\n  return graphql(`{\n    allMarkdownRemark {\n      edges {\n        node {\n          html\n          id\n          frontmatter {\n            path\n            title\n          }\n        }\n      }\n    }\n  }`)\n  .then(res =\u003e {\n    if(res.errors) {\n      return Promise.reject(res.errors);\n    }\n\n    res.data.allMarkdownRemark.edges.forEach(({node}) =\u003e {\n      createPage({\n        path: node.frontmatter.path,\n        component: postTemplate\n      })\n    })\n\n  })\n}\n```\n\nSave and restart your app - then open _http://localhost:8000/md-posts_ inside your web browser - Voila` !\n\n\n### Nested Routes with Markdown\n\nTo create children post for the _./src/pages/FirstMDpost/index.md_ file, we can simply add more files to the folder and define nested routes inside their frontmatter - e.g.  _./src/pages/FirstMDpost/myfirstpost.md_:\n\n\n```\n---\npath: '/md-posts/first-post'\ntitle: 'First Blog Post'\ndate:   '2017-10-05'\nauthor: 'Mike Polinowski'\nchapter: 'Markdown Posts'\n---\n\n# This is my first markdown Post!\n```\n\nand _./src/pages/FirstMDpost/mysecondpost.md_:\n\n```\n---\npath: '/md-posts/second-post'\ntitle: 'Second Blog Post'\ndate:   '2017-10-05'\nauthor: 'Mike Polinowski'\nchapter: 'Markdown Posts'\n---\n\n# A dive into Markdown Syntax\n```\n\nThey will be accessible via _http://localhost:8000/md-posts/first-post_ and _http://localhost:8000/md-posts/second-post_ respectively.\n\n\n### Creating an Index Page\n\n\nWe can now use GraphQL to retrieve all of our Markdown pages and apply filter to them. For this test, we will just add the a table to our start page, showing the last 10 posts (I know we only made 3 so far...), we want to order them descending by date and only display pages that are inside the _chapter: 'Markdown Posts'_, which will exclude our _index.md_:\n\n\n```js\nconst IndexPage = ({data}) =\u003e (\n  \u003cdiv\u003e\n      \u003ch2\u003eMarkdown Index\u003c/h2\u003e\n      \u003cp\u003eThe table below sorts out all Markdown pages that are not inside the \"Markdown Posts\" chapter - as defined inside their frontmatter. It also applies a filter, to only display the latest 10 posts. Click on here to display \u0026nbsp;\n      \u003cLink to=\"/md-posts/\"\u003e\n          all Markdown pages\n      \u003c/Link\u003e\n      .\u003c/p\u003e\n      \u003ctable\u003e\n        \u003cthead\u003e\n          \u003ctr\u003e\n            \u003cth\u003eDate\u003c/th\u003e\n            \u003cth\u003eLink\u003c/th\u003e\n          \u003c/tr\u003e\n        \u003c/thead\u003e\n        \u003ctbody\u003e\n        {data.allMarkdownRemark.edges.map(post =\u003e (\n          \u003ctr key={post.node.id}\u003e\n            \u003ctd\u003e\n              {post.node.frontmatter.date}\n            \u003c/td\u003e\n            \u003ctd\u003e\n              \u003cLink\n                to={post.node.frontmatter.path}\u003e\n                {post.node.frontmatter.title}\n              \u003c/Link\u003e\n            \u003c/td\u003e\n          \u003c/tr\u003e\n        ))}\n        \u003c/tbody\u003e\n      \u003c/table\u003e\n  \u003c/div\u003e\n)\n\nexport const pageQuery = graphql`\n  query IndexQuery {\n      allMarkdownRemark(limit: 10\n      sort: {fields: [frontmatter___date], order: DESC}\n      filter: { frontmatter: { chapter: {eq: \"Markdown Posts\"} }}\n    ) {\n      edges {\n        node {\n          id\n          frontmatter {\n            path\n            title\n            date\n          }\n        }\n      }\n    }\n  }\n`\n```\n\n\n### Catching Links from Markdown\n\n\nOnce you start adding links inside your Markdown files, you will notice that clicking them will reload your application - which isn't good :( But no worries here is [gatsby-plugin-catch-links](https://www.gatsbyjs.org/packages/gatsby-plugin-catch-links/) coming to your rescue! And the nice thing about it - you install it, add to your Gatsby plugins inside _./gatsby-config.js_ and it just works:\n\n```\nnpm install --save gatsby-plugin-catch-links\n```\n\n```js\n// In your gatsby-config.js\nplugins: [\n  `gatsby-plugin-catch-links`,\n]\n```\n\nSweet!\n\n\n## 12 Adding Material-UI\n\nTo make our life easier, we want to include ready-to-use material design components from the guys @ [Material-UI](https://material-ui-next.com/getting-started/installation/). We are going to install the beta version of v.1.0.0 - which also requires the [Roboto Fontface](https://material-ui-next.com/style/typography/#general) and the [Material-UI Icons](https://www.npmjs.com/package/material-ui-icons):\n\n```\nnpm install material-ui@next --save\n\nnpm install typeface-roboto --save\n\nnpm install material-ui-icons --save\n```\n\nWe can now easily import Material-UI components into our app:\n\n```js\nimport React from 'react'\nimport { render } from 'react-dom'\nimport Button from 'material-ui/Button'\nimport 'typeface-roboto'\n\nfunction AppWithButton() {\n  return (\n    \u003cButton\u003e\n      Hello World\n    \u003c/Button\u003e\n  );\n}\n\nrender(\u003cAppWithButton /\u003e, document.querySelector('#app'));\n```\n\n\n\n## 13 Adding Elasticsearch\n\nOne of the pre-requisites for this project is, that we need to create a lightning-fast interface for [our ElasticSearch Index](https://github.com/mpolinowski/express-static/tree/master/elasticsearch). We already build the [ES6 Class component](https://github.com/mpolinowski/elasticsearch-react-example) for it. And adding it to Gatsby / Material-UI turned out to be surprisingly straight-forward.\n\nFirst, add _./src/pages/search/jsx_ and modify the [ElasticSearch Component](https://github.com/mpolinowski/elasticsearch-react-example) to play nice with our UI:\n\n```js\nimport React, { Component } from 'react'\nimport Link from 'gatsby-link'\nimport elasticsearch from 'elasticsearch'\n\nimport { withStyles } from 'material-ui/styles'\nimport Grid from 'material-ui/Grid'\nimport Button from 'material-ui/Button'\n\nimport ResultCards from '../components/ResultCards'\n\nconst connectionString = 'localhost:9200'\nconst _index = 'wiki2_de_2017_09_09'\nconst _type = 'article'\n\nlet client = new elasticsearch.Client({\n  host: connectionString,\n  log: \"trace\"\n})\n\nconst rootStyle = {\n    flexGrow: 1,\n    marginTop: 30,\n  }\n\nexport class Search extends Component {\n  constructor(props) {\n    super(props)\n      this.state = { results: [] };\n      this.handleChange = this.handleChange.bind(this)\n    }\n\n    handleChange(event) {\n      const search_query = event.target.value;\n\n      client.search({\n  \t\t\tindex: _index,\n  \t\t\ttype: _type,\n  \t\t\tbody: {\n  \t\t\t\tquery: {\n  \t\t\t\t\t\tmulti_match: {\n  \t\t\t\t\t\t\t\tquery: search_query,\n  \t\t\t\t\t\t\t\tfields: ['title^100', 'tags^100', 'abstract^20', 'description^10', 'chapter^5', 'title2^10', 'description2^10'],\n  \t\t\t\t\t\t\t\tfuzziness: 1,\n  \t\t\t\t\t\t\t},\n  \t\t\t\t\t},\n  \t\t\t},\n  \t\t}).then(function(body) {\n            this.setState({ results: body.hits.hits });\n          }.bind(this),\n          function(error) {\n            console.trace(error.message);\n          }\n        );\n    }\n\n    render() {\n      return (\n        \u003cdiv className=\"container\"\u003e\n          \u003cinput type=\"text\" onChange={this.handleChange} /\u003e\n          \u003cSearchResults results={this.state.results} /\u003e\n        \u003c/div\u003e\n      );\n    }\n}\n\nconst SearchResults = ({results}) =\u003e (\n  \u003cdiv className=\"search_results\"\u003e\n  \u003cbr/\u003e\u003chr/\u003e\n\n  \u003cdiv className={rootStyle}\u003e\n    \u003cGrid container spacing={24}\u003e\n      {results.map((result , i) =\u003e\n        \u003cResultCards key={i}\n                     image={result._source.image}\n                     title={result._source.title2}\n                     link={result._source.link}\n                     abstract={result._source.abstract}/\u003e\n      )}\n\n      \u003c/Grid\u003e\n    \u003c/div\u003e\n    \u003cbr/\u003e\u003cbr/\u003e\u003cLink to=\"/\" style={{ textDecoration: 'none' }}\u003e\u003cButton raised color=\"primary\"\u003eGo back to the homepage\u003c/Button\u003e\u003c/Link\u003e\n  \u003c/div\u003e\n)\n\nexport default Search\n```\n\nThe \\\u003cSearchResults /\\\u003e component iterates over the Material UI card inside \\\u003cResultCards /\\\u003e:\n\n\n```js\nimport React from 'react'\nimport Link from 'gatsby-link'\n\nimport Card, { CardActions, CardContent, CardMedia } from 'material-ui/Card'\nimport Button from 'material-ui/Button'\nimport Typography from 'material-ui/Typography'\nimport Grid from 'material-ui/Grid'\n\nconst ResultCards = ({image, title, abstract, link}) =\u003e (\n\n    \u003cGrid item xs={12} sm={6} lg={4}\u003e\n      \u003cCard style={{ maxWidth: 345 }}\u003e\n        \u003cCardMedia\n          style={{ height: 200 }}\n          image={image}\n          title={abstract}\n        /\u003e\n        \u003cCardContent\u003e\n          \u003cTypography type=\"headline\" component=\"h4\" style={{ minHeight: 60, marginBottom: \"10px\" }}\u003e\n            {title}\n          \u003c/Typography\u003e\n          \u003cTypography component=\"p\" style={{ minHeight: 50, marginBottom: \"10px\" }}\u003e\n            {abstract}\n          \u003c/Typography\u003e\n        \u003c/CardContent\u003e\n        \u003cCardActions\u003e\n          \u003cLink to={link} style={{ textDecoration: 'none' }}\u003e\n            \u003cButton dense color=\"primary\"\u003e\n              Read\n            \u003c/Button\u003e\n          \u003c/Link\u003e\n          \u003cButton dense color=\"primary\"\u003e\n            Learn More\n          \u003c/Button\u003e\n        \u003c/CardActions\u003e\n      \u003c/Card\u003e\n    \u003c/Grid\u003e\n)\n\nexport default ResultCards\n```\n\n\nand adds the results from the ElasticSearch JSON response - giving us a nice responsive card grid (the images used below are not inside this repository - just add a few PNG files (597x382) to _./public/images/Search_, named according to the image URL defined inside [our ElasticSearch Index](https://github.com/mpolinowski/express-static/tree/master/elasticsearch):\n\n\n![](./gatsby_12.png)\n\n\n\n## XX Build the Static Page\n\nWe now want to move our website from the development environment to our webserver. Gatsby offers us a simple command to build render our React.js page into a static website:\n\n```\nnpm run build\n```\n\nYou can find the output inside the _/public_ folder of your Gatsby App.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolinowski%2Fgatsby-wiki","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpolinowski%2Fgatsby-wiki","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpolinowski%2Fgatsby-wiki/lists"}