Building a Personal Site with Gatsby

Part 5: Adding Thumbnail Images to a Blog List

January 11, 2019

Note: This is a 9 part post that begins here: Part 1: Introduction and Setup

The Gatsby Image component provides optimized images that "blur up" images as they load.

Now that we have a list of blog posts, let's add thumbnail images to them. Download a few placeholder images and save them in the src/images folder. I used placekitten.

Gatsby Image should already be set up if you're using the default starter. Here is what you should see in your gatsby-config.js. Note that gatsby-image, gatsby-transformer-sharp, and gatsby-plugin-sharp must all be installed.

gatsby-config.js
module.exports = {
  // ...
  plugins: [
    // ...
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    // ...
  ],
};

Add a thumbnail property to each blog post's frontmatter.

src/pages/blog/hello-world.md
---
title: Hello World
date: 2018-12-29
thumbnail: "../../images/kitten-1.jpeg"
---

This is my first blog post. Hello World!

Adding a relative path as a value allows you to query the file in your with GraphQL markdown query. Restart your server to be able to read your new field and try it out with GraphiQL.

We're going to edit our page query in src/pages/blog.js to grab a fixed image with a height and width of 200px.

src/pages/blog.js
//blog.js
export const pageQuery = graphql`
  query {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          id
          excerpt(pruneLength: 250)
          fields {
            slug
          }
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            title
            thumbnail {              childImageSharp {                fixed(width: 200, height: 200) {                  ...GatsbyImageSharpFixed                }              }            }          }
        }
      }
    }
  }
`;

...GatsbyImageSharpFixed is a query fragment, basically a set of fields that include sizes, originalName, originalImage, etc. Use this fragment if you know the size of your image and it doesn't change. Use ...GatsbyImageSharpFluid for images that stretch as the page size changes (we will use this later).

Now, update the actual BlogPage component:

src/pages/blog.js
// src/pages/blog.js
import React from 'react';
import { graphql, Link } from 'gatsby';
import Layout from '../components/layout';
import Img from 'gatsby-image';
const BlogPage = ({ data }) => {
  const posts = data.allMarkdownRemark.edges;
  return (
    <Layout>
      <div className="post-list">
        {posts.map(post => (
          <div key={post.node.id} className="post-list__item">
            <div className="post-list__thumbnail">              <Link to={post.node.fields.slug}>                <Img                  fixed={post.node.frontmatter.thumbnail.childImageSharp.fixed}                />              </Link>            </div>            <div className="post-list__content">              <h2>{post.node.frontmatter.title}</h2>
              <p>{post.node.frontmatter.date}</p>
              <div className="post-list__excerpt">{post.node.excerpt}</div>
              <Link to={post.node.fields.slug}>Read More</Link>
            </div>          </div>
        ))}
      </div>
    </Layout>
  );
};

In line 5, we import the Img component and use it as a replacement for our usual <img /> in line 16.

Then create a src/styles/_posts.scss file and add the following basic styles:

src/styles/_posts.scss
.post-list__item {
  display: flex;
  flex-direction: row;
  @media (max-width: 500px) {
    flex-direction: column;
    text-align: center;
  }
  padding: 1rem;
}
.post-list__thumbnail {
  padding: 1rem;
}

.post-list__content {
  padding: 1rem;
  text-align: left;
}

Import this into your src/styles/styles.scss file, which is imported into src/components/layout.js.

src/styles/styles.scss
@import 'posts';