Gatsby Blog + Netlify CMS Tutorial — Part 2

Note: This tutorial is not focusing on styling at all, so it will be kept very basic, as we are only focusing on the functionality of the tooling

Tutorial Preparation

Let's Get Started!

query MyQuery {
allMarkdownRemark {
edges {
node {
frontmatter {
category
height
intro
title
weight
}
html
excerpt
}
}
}
}

What’s that field type??

{
resolve: `gatsby-transformer-remark`,
options: {
excerpt_separator: `<!-- Bulbasaur used cut! -->`
}
}

Note: The string used inbetween <!-- --> can be any value you like

## DescriptionSquirtle is a small Pokémon that resembles a light blue turtle. While it typically walks on its two short legs, it has been shown to run on all fours in Super Smash Bros. <!-- Bulbasaur used cut! --> Brawl. It has large, purplish or reddish eyes and a slightly hooked upper lip. Each of its hands and

Let's Render Our Data!

import React from "react"
import { graphql } from "gatsby"
import Layout from "components/layout"
import SEO from "components/seo"
const styles = {fontWeight: 800}const IndexPage = ({ data }) => {
const {
category,
height,
intro,
title,
weight
} = data.markdownRemark.frontmatter
const { html } = data.markdownRemark
return (
<Layout>
<SEO title="Home" />
<h2>Pokemon: {title}</h2>
<p>{intro}</p>
<h4>Stats</h4>
<ul>
<li><span style={styles}>Height:</span> {height}</li>
<li><span style={styles}>Weight:</span> {weight}</li>
<li><span style={styles}>Category:</span> {category}</li>
</ul>
<div dangerouslySetInnerHTML={{ __html: html }} />
</Layout>
)
}
export default IndexPageexport const IndexQuery = graphql`
query PokemonQuery {
markdownRemark(fields: { slug: { eq: "pikachu" } }) {
frontmatter {
category
height
intro
title
weight
}
html
}
}
`;
Data! Glorious data!

The example above was simply to get a feel on how the data is handled when fetched via GraphQL, lets now make this into something more realistic!

Gatsby Page Templates

exports.createPages = async ({ graphql, actions }) => {
// You could keep the GQL Query in here - I prefer to separate
const { data } = await getPageData(graphql)

data.blogPosts.edges.forEach(({ node }) => {
const {slug} = node.fields;
actions.createPage({
path: `/blog/${slug}`,
component: path.resolve("./src/templates/blog-post-template"),
context: {slug},
})
})
}
async function getPageData(graphql) {
return await graphql(`
{
blogPosts: allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`)}

Note: In the above GQL query before allMarkdownRemark i added blogPosts: you can think this as a variable, because eventually we may add more to this GQL query, and we can easily separate the data using variables.

import React from "react"
import { graphql } from "gatsby"
import Layout from "components/layout"
import SEO from "components/seo"
const styles = {fontWeight: 800}const PokemonTemplate = ({ data }) => {
const {
category,
height,
intro,
title,
weight,
} = data.markdownRemark.frontmatter

const { html } = data.markdownRemark
return (
<Layout>
<SEO title={`Pokemon - ${title}`} />
<h2>Pokemon: {title}</h2>
<p>{intro}</p>
<h4>Stats</h4>
<ul>
<li><span style={styles}>Height:</span> {height}</li>
<li><span style={styles}>Weight:</span> {weight}</li>
<li><span style={styles}>Category:</span> {category}</li>
</ul>
<div dangerouslySetInnerHTML={{ __html: html }} />
</Layout>
)
}
export default PokemonTemplateexport const PokemonTemplateQuery = graphql`
query PokemonPageQuery($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
frontmatter {
category
height
intro
title
weight
}
html
}
}
`;

Display a List Of All Blog Posts

import React from "react"
import { graphql, navigate } from "gatsby"
import Layout from "components/layout"
import SEO from "components/seo"
const styles = {
margin: 10,
marginLeft: 0,
border: "2px solid black",
padding: 10
}
const IndexPage = ({ data }) => {
return (
<Layout>
<SEO title="Home" />
<h2>Pokemon Blog</h2>
{renderBlogs(data.allMarkdownRemark.edges)}
</Layout>
)
function renderBlogs(posts) {
return posts.map(item => {
const { slug } = item.node.fields
const { title, intro } = item.node.frontmatter
return (
<div style={styles} onClick={() => navigate(`/blog/${slug}`)}>
<div style={{ color: "black" }}>
<h4>{title}</h4>
<p>{intro}</p>
</div>
</div>
)
})
}
}
export default IndexPageexport const IndexQuery = graphql`
{
allMarkdownRemark {
edges {
node {
frontmatter {
title
intro
}
fields {
slug
}
}
}
}
}
`

Adding Images With Frontmatter

---
title: Bulbasaur
intro: Bulbasaur can be seen napping in bright sunlight. There is a seed on its back. By soaking up the sun's rays, the seed grows progressively larger.
category: Seed
height: 2' 04"
weight: 15.2lbs
featuredImage: ../../src/images/bulbasaur.png
---
...markdown
export const IndexQuery = graphql`  {
allMarkdownRemark {
edges {
node {
frontmatter {
title
intro
featuredImage {
childImageSharp {
fixed(width: 200) {
...GatsbyImageSharpFixed
}
}
}
}
fields {
slug
}
}
}
}
}
`
function renderBlogs(posts) {
return posts.map(item => {
const { slug } = item.node.fields
const { title, intro, featuredImage } = item.node.frontmatter

return (
<div style={styles} onClick={() => navigate(`/blog/${slug}`)}>
<div style={{ color: "black" }}>
<h4>{title}</h4>
<p>{intro}</p>
<Img fixed={featuredImage.childImageSharp.fixed} />
</div>
</div>
)
})
}

The End

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store