Generate beautiful notes from Markdown files using Gatsby, React and GraphQL that supports code-blocks, maths equations and more

Patrick Ferris
Jan 25 · 7 min read

Originally as a personal project to itch a scratch, since having my Gatsby starter template merged with the official branch I thought it would be productive to share the key things I learned whilst building a simple Gatsby static site to host my notes and revision material. If you want to build your note-taking, organisation site using markdown then fork the Github page. If you want to learn more about Gatsby, React and Markdown then continue forth!

The Itch

As a computer science student, I need my note-taking tool to:

  • make writing code easy and hassle-free, syntax-highlighting within my notes would be a big plus
  • support LaTeX-style equations so I can add maths
  • embed images for things like diagrams and images
  • be highly automated; I should be able to focus on the content and not the managing the system that is doing the heavy lifting

Markdown is a popular, flexible file format that supports all these requirements (and more). Converters like Pandoc are great for writing in Markdown and converting to PDF with a latex converter. The problem with this approach, is that I would just have lots of files scattered everywhere! Markdown files, logs and PDFs would clutter the directories and revising my notes would be a fairly painful process.

It was around this point I realised the similarities between my current blog (powered by Gatsby) and what I needed for my note taking. The only real requirements where to improve the code and math insertion into the document and also the organisation of the markdown files.

Gatsby

Gatsby is a powerful, ‘blazingly’ fast static-site generator. It allows you to write reusable, and often minimal amounts of code to build a robust static site and with the myriad of plugins you can extend its capabilities to do many useful tasks.

When I first started learning more web development the idea of Gatsby confused me. What does it provide me? What’s wrong with the holy trinity of HTML, CSS and Javascript? The answer is that there’s nothing wrong with it. Gatsby can just offer some amazing tools to improve your overall development experience and also your users’ experience.

To be fair to Gatsby, they no longer promote themselves as a static-site generator. Instead, they are a static progressive web app generator. Gatsby is like the project manager — they know how to manage all of the individual parts in order to get the best productivity and efficiency out of everyone and deliver the best product at the end. These individuals include React (a front-end framework), Webpack (for all your file bundling needs), GraphQL (for easy data handling) and modern Javascript.

Before diving in further I will mention as a disclaimer that I’m assuming some knowledge of React and GraphQL for this blog post. I do have a handy GraphQL primer later, but if you need some more information check out these sources.

The basic structure of the note-taking Gatsby project looks something like this:

|-- /src 
|-- /components (All of the React Components)
|-- /pages (All of the Markdown Content)
|-- /templates (Layouts for the Content)
|-- package.json (Node package management data)
|-- gatsby-config.js (Config - like package.json only for Gatsby)
|-- gatsby-node.js (Node APIs - createPages, onCreateNode...)
|-- gatsby-browser.js (Browser APIs/external js and css loaded here)

In this article we’ll spend a lot of time in the pages folder as well as the gatsby-config.js and gatsby-node.js files respectively as this is where all the magic happens. To get up and running with a simple Gatsby site maybe try installing the command line interface and run gatsby new awesome-site . Otherwise let’s dive in.

Gatsby Node APIs

Nodes in Gatsby are the central unit of data. All data added to your site tends to be modelled using nodes and they have useful member fields such as parent , fields object which plugins may use to extend the node and the internal object with type information. These will become useful.

The first thing we need to do is access the files in our project and be able to generate pages based on this. Sounds like the Node API to me. To access the useful functions like createPage and onCreateNode we need to add gatsby-source-filename to our project either using yarn or npm.

Let’s take the simpler function first of what we should do whenever we create a new node. Our issue is that there is no way of knowing where our new page should be, it needs a new field property of slug . Unfortunately this does not refer to the shell-less terrestrial gastropod mollusc, but to the unique identifier in the URL that distinguishes a given page. But this should only take place for our Markdown files. A useful thing to know is when we create these, the nodes will have: node.internal.type = 'MarkdownRemark' so we can use this to check we’re adding the slug property to correct files.

Creating a new field for any nodes we make

Now for the slightly more complicated but super important step of creating our new pages. To do this we use the createPage API and also GraphQL. If you’re new to GraphQL (as I was) here is a quick, one paragraph primer with links to learn the syntax and important concepts.

GraphQL Primer

GraphQL is a query language, as the name suggests, with a focus on making data easily queryable and very flexible for the person submitting the query returning just the data you want. Syntactically it is reminiscent of JSON. And a typical query might look something like this, taken from the Gatsby site:

// Normal imports into the project
import React from "react"
import { graphql } from "gatsby"
// Simple functional component that consumes the data we get
export default ({ data }) => (
<div>
<h1>About {data.site.siteMetadata.title}</h1>
<p>We're a very cool website you should return to often.</p>
</div>
)
// The graphql query to get the site title (from the config file)
export const query = graphql`
query {
site {
siteMetadata {
title
}
}
}
`

At its core, GraphQL is all about specifying fields from objects. In the above query we are asking for the title of our site which is found in siteMetadata . One of the most important aspects of GraphQL is that the return type is exactly the same as what you specified making manipulating and working with data that much easier. Below is the result of running this query.

{
"data": {
"site": {
"siteMetadata": {
"title": "Gatsby Notes Starter"
}
}
}
}

Whenever we create a new page from our Markdown files we need to query them to get the data necessary for generating new pages. To do this we use the gatsby-transformer-remark plugin. The full details of the plugin can be found here, but essentially it looks for our .md files and parses them. To get our MarkdownRemark nodes and generate new pages we use the following:

Note how we can now access our newly defined slug property in the fields. If you’ve made it this far, congratulations! The most complex parts of the setup are more or less done and now we just need to generate our notes.

The Template

Our notes template is going to be super simple and make use of the <Layout/> component Gatsby so graciously provides. First, we need to define a query that gets the data and passes it to our functional component. The query will be injected along with the current $slug we are viewing. Using the eq operator we then get the specific markdownremark data to be passed into the component which renders are page. In our component we just pull out the data we need and put in the places we want it to go.

Great! Now we’re generating our pages all we need is some simple front-end structure for displaying all of our pages in an organised way. This will preferably be by subject. To do this I used the brilliant react-accessible-accordion from springload. I also used lodash for the data-wrangling.

And that’s it! All of our notes are now being displayed and the true power of the Gatsby plugin library becomes apparent: to include code and maths in the notes, we just need to add the following plugins to our gatsby-config.js file under the transformer plugin. Remember to add them with yarn or npm too.

plugins: [
`gatsby-remark-prismjs`,
`gatsby-remark-katex`,
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 650,
},
},
]

You can then specify what prismjs themes you want in the gatsby-browser.js file as well as getting the katex css. I used the following defaults:

require('prismjs/themes/prism-tomorrow.css');
require('katex/dist/katex.min.css');

We know have a working Gatsby-powered note-taking and presenting tool. Here is a quick example of the markdown file and what are site produces in the browser.

Markdown and generate site page

If you are curious to see what this looks like, go to the demo site hosted on Netlify (a perfect hosting platform for any Gatsby site). What started as a “an itch to scratch”, turned into a really enjoyable project that taught me a lot about Gatsby, React and GraphQL. Not to mention that I ended up with a pretty useful and cool (if I may say so myself) tool for displaying and generating all my notes from university. Feel free to fork the project for your own ideas and note-taking.

Hackers at Cambridge

We are a student-run technology society, promoting a culture of creators and innovators by organising workshops and events for any student who wants to take part. This blog is a platform to spread the thoughts, opinions and projects of the tech-enthusiasts who write for it.

Thanks to Eliot Lim

Patrick Ferris

Written by

Computer Science Undergraduate at Cambridge University https://www.linkedin.com/in/patrick-ferris-742b79167/

Hackers at Cambridge

We are a student-run technology society, promoting a culture of creators and innovators by organising workshops and events for any student who wants to take part. This blog is a platform to spread the thoughts, opinions and projects of the tech-enthusiasts who write for it.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade