DEV Community

loading...
Cover image for Image Gallery with Gatsby, Netlify and Airtable.

Image Gallery with Gatsby, Netlify and Airtable.

Ramón Chancay 👨🏻‍💻
・4 min read

Hello everyone!

Let's do a project similar to: https://momazos.netlify.app/

It's basically a list of images stored on Airtable and consumed by Gatsby through a source plugin called gatsby-source-airtable.

For the "UI design" we will use chakra-ui, which has several default components.

as of the date I published this post Gatsby is in version 3

Start the project

We're going to start the project with the following command:

$ npx gatsby new momazos
Enter fullscreen mode Exit fullscreen mode

this creates a folder structure based on the Gatsby Starter Default, At this point you should have a folder structure similar to this:

- .gitignore
- .prettierignore
- .prettierrc
- LICENSE
- README.md
- gatsby-browser.js
- gatsby-config.js
- gatsby-node.js
- gatsby-ssr.js
- node_modules
- package-lock.json
- package.json
- src
  - pages
    - index.js
Enter fullscreen mode Exit fullscreen mode

✨ now run in the terminal the following command:

 $ npm start
Enter fullscreen mode Exit fullscreen mode

and you should see the development server at https://localhost:8000

image

Airtable table structure

for this case we have the following structure:

  • Name (name of image)
  • Attachments (field with image )
  • Tags - (image related tags)
  • Status - (Active / Inactive)
  • Created - (creation date)
  • Last Modified Time (edition date)

image

👀 You can see it here

Install Gatsby Airtable Source plugin

now we're going to install the Airtable plugin by running the following command:

$ npm install gatsby-source-airtable
Enter fullscreen mode Exit fullscreen mode

to configure it in Gatsby we need modify the gatsby-config.js

plugins: [
  {
    resolve: `gatsby-source-airtable`,
    options: {
      apiKey: `I-C-WIENER-405-XXX-XXX-XXX`, 
      tables: [
        {
          baseId: `YOUR_AIRTABLE_BASE_ID`,
          tableName: `Memes`,
          mapping: { Attachments: `fileNode` },
         },
      ]
    }
  }
];
Enter fullscreen mode Exit fullscreen mode

you can get an apiKey at https://airtable.com/api

In my case "Memes" is the name of the database and the mapping is the way a file type is related in Gatsby.

Interacting with the data

at this point, you have access to the airtable data and you can run queries to the graphql schema.

Now when I start the development server, Gatsby will store the data to be able to make graphql queries at the URL https://localhost:8000/__graphql

📋 We're going to copy the following query:

{
  allAirtable(
    filter: {table: {eq: "Memes"}, data: {Status: {eq: "Active"}}}
    sort: {fields: data___Created, order: DESC}
  ) {
    edges {
      node {
        id
        data {
          Name
          Attachments {
            localFiles {
              childImageSharp {
                gatsbyImageData(layout: FULL_WIDTH, formats: [AUTO, AVIF, WEBP])
              }
            }
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

image

As you can see, we have access to all the data available in our Gatsby project.

Install chakra-ui 💅🏼

To use Chakra UI in your Gatsby site, you need to install the plugin and its peer dependencies

npm i @chakra-ui/gatsby-plugin @chakra-ui/react @emotion/react @emotion/styled framer-motion
Enter fullscreen mode Exit fullscreen mode
  • 1 Add @chakra-ui/gatsby-plugin to gatsby-config.js
plugins: [
  {
    resolve: `gatsby-source-airtable`,
    options: {
      apiKey: `I-C-WIENER-405-XXX-XXX-XXX`, 
      tables: [
        {
          baseId: `YOUR_AIRTABLE_BASE_ID`,
          tableName: `Memes`,
          mapping: { Attachments: `fileNode` },
         },
      ]
    }
  },
`@chakra-ui/gatsby-plugin`
];

Enter fullscreen mode Exit fullscreen mode
  • 2 configure the chakra provider in the file gatsby-browser.js

const React = require("react");
const ChakraProvider = require("@chakra-ui/react").ChakraProvider;
const extendTheme = require("@chakra-ui/react").extendTheme;

const config = {
  useSystemColorMode: true,
};

const theme = extendTheme({ config });


exports.wrapRootElement = ({ element }) => {
  return (
    <ChakraProvider resetCss theme={theme}>
      {element}
    </ChakraProvider>
  );
};

Enter fullscreen mode Exit fullscreen mode

you can check the chakra-UI documentation, it is very clear and intuitive, similar to that of tailwindcss.

📚 Docs

now create a file in src/components/List.jsx this component is responsible for rendering the name and image.

import React from "react";
import { GatsbyImage } from "gatsby-plugin-image";
import { Box, AspectRatio, Badge, useColorModeValue } from "@chakra-ui/react";

function Item({ node, loading }) {
  const bg = useColorModeValue("white", "gray.900");
  const [file] = node.data.Attachments.localFiles;
  return (
    <Box
      borderWidth="1px"
      borderRadius="lg"
      overflow="hidden"
      key={node.id}
      position="relative"
      bg={bg}
    >
      <AspectRatio maxW="620px" ratio={4 / 3}>
        <GatsbyImage
          loading={loading}
          image={
            file.childImageSharp.gatsbyImageData
          }
          alt={node.data.Name}
        />
      </AspectRatio>

      <Box py={2} px={2}>
        <Box d="flex" alignItems="baseline">
          {node?.data?.tags?.map((tag) => {
            return (
              <Badge id={tag} borderRadius="full" px="2" colorScheme="facebook">
                {tag}
              </Badge>
            );
          })}
        </Box>
        <Box
          mt="1"
          fontWeight="semibold"
          as="h3"
          lineHeight="tight"
          isTruncated
          px={1}
        >
          {node.data.Name}
        </Box>
      </Box>
    </Box>
  );
}

export default React.memo(Item);
Enter fullscreen mode Exit fullscreen mode

With all this, now you just have to join everything on the Home page.

src/pages/index.jsx

import React from "react"
import List from "../components/List";
import { Container, Grid } from "@chakra-ui/react";
import { graphql } from "gatsby"

const IndexPage = ({ data }) => {
   return (
       <Container maxW="container.xl"> 
         <Box px={4} mt={4}>
          <Grid
            templateColumns={{
              base: `repeat(1, 1fr)`,
              sm: `repeat(3, 1fr)`,
              xl: `repeat(4, 1fr)`,
            }}
            gap={{
              base: 4,
              xl: 6,
            }}
          >
          {data.allAirtable.edges.map(({ node }, index) => {
              const loading = index <= 4 ? "eager" : "lazy";
              return <List node={node} loading={loading} />;
            })}
          </Grid>
       </Container>
)
}

export const query = graphql`
  {
    allAirtable(
      filter: {table: {eq: "Memes"}, data: {Status: {eq: "Active"}}}
      sort: {fields: data___Created, order: DESC}
    ) {
      edges {
        node {
          id
          data {
            Name
            Attachments {
              localFiles {
                childImageSharp {
                  gatsbyImageData(layout: FULL_WIDTH, formats: [AUTO, AVIF, WEBP])
                }
              }
            }
          }
        }
      }
    }
  }
`

export default Index

Enter fullscreen mode Exit fullscreen mode

✨ Thanks for reading, if you have any questions feel free to DM me on Twitter.

Discussion (1)

Collapse
alexandprivate profile image
Alex Suarez

Amazing Panda!!!!