# getting AT data to a website! ## the steps if you don't have node, git and gatsby installed, check out [these instructions](https://www.gatsbyjs.com/docs/tutorial/part-zero/) to get your machine ready for development. If you just have node and git, enter `npm install -g gatsby-cli` to install the `gatsby-cli` start up a gatsby project with ``` cd ~/Development gatsby new my-gatsby-project cd my-gatsby-project code . gatsby develop ``` Then go to [localhost:8000](http://localhost:8000) to see if it's working. In your code editor, let's get rid of all the default gatsby pages except the index, so delete all of the files in `/src/pages` except `index.js` (alternatively, you could throw them all in a folder called `/reference/gatsby` if you want to be able to reference them later on. We are mainly going to emphasize getting the airtable data in for this tutorial, so we'll actually start by doing that. Let's install the airtable plugin: ``` npm i gatsby-source-airtable ``` Then let's add it to our `gatsby-config.js`, something like ``` { resolve: "gatsby-source-airtable", options: { apiKey: process.env.AIRTABLE_API_KEY, tables: [ { baseId: process.env.AIRTABLE_BASE_ID, tableName: "MyTable", }, ] } }, ``` you'll need to store your environment variables in a `.env.development` file: ``` AIRTABLE_API_KEY=keyxxxxxxxxxxxxx AIRTABLE_BASE_ID=appxxxxxxxxxxxxx ``` then you'll need to pull these environment variables in to `gatsby-config.js` with `dotenv`. So install it with `npm i dotenv` and then add the following lines at the top of `gatsby-config.js` ``` require("dotenv").config({ path: `.env.${process.env.NODE_ENV}`, }) ``` now that you've done this, you should be able to stop the server, then run `gatsby develop` and see the Airtable data show up in [GraphiQL](http://localhost:8000/___graphql) ## MAKING AN INDEX OF RECORDS something like this: ``` /** @jsx jsx */ import { jsx } from 'theme-ui' import { graphql } from "gatsby" export default ({data}) => { const allAirtableData = data.allAirtable.edges; return ( <div sx={{padding: "4em"}} > {/* <pre> {JSON.stringify(allAirtableData, null, 4)} </pre> */} { allAirtableData.map(({node}) => ( <div sx={{width: "100%", textAlign: "center"}} > <a href={`/yokai/${node.recordId}`} sx={{ // color: "rgba(0,0,30,.9" }} ><h1 sx={{ fontFamily: "Avenir Next, sans-serif", fontSize: "3em", fontWeight: "900", color: "rgba(0,0,30,.9)", textDecoration: "none" }} >{node.data.Name}</h1></a> </div> )) } </div> ) } export const query = graphql` query { allAirtable { edges { node { id recordId data { Description mainFeature Creator Link_to_Project secondFeature Name weight type mainAttack region specialAttack height backgroundColor foregroundColor canvaCardLink canvaCardBack { id thumbnails { large { url width height } } } canvaCardFront { id thumbnails { large { url width height } } } } } } } } ` ``` ## CREATING INDIVIDUAL PAGES To create a page per record, we'll need to add to our `gatsby-node.js` file. maybe something like this? ``` const { createFilePath } = require(`gatsby-source-filesystem`) const path = require(`path`) exports.onCreateNode = ({ node, getNode, actions }) => { const { createNodeField } = actions if (node.internal.type === `Mdx`) { console.log(`found mdx node of type ${node.internal.type}`) const fileNode = getNode(node.parent) const slugStem = createFilePath({ node, getNode }) const slugRoot = fileNode.sourceInstanceName ? fileNode.sourceInstanceName : "content" createNodeField({ node, name: `slug`, value: `/${slugRoot}${slugStem}`, }) createNodeField({ node, name: `pageType`, value: slugRoot, }) createNodeField({ node, name: `title`, value: node.frontmatter.title || fileNode.name || "no title", }) createNodeField({ node, name: `mainImage`, value: node.frontmatter.mainImage || "/gatsby.jpg", }) } } exports.createPages = async ({ graphql, actions, reporter }) => { const { createPage } = actions const mdxResult = await graphql(` query { allMdx { edges { node { id fields { slug title pageType } headings(depth: h1) { value } } } } } `) if (mdxResult.errors) { reporter.panicOnBuild('🚨 ERROR: Loading "createPages" query') } const mdx = mdxResult.data.allMdx.edges mdx.forEach(({ node }, index) => { console.log( `creating page for id ${node.id} with slug ${node.fields.slug} with initial h1 of ${(node.headings && node.headings[0]) ? node.headings[0].value : "no h1"}` ) createPage({ path: node.fields.slug, component: path.resolve( `./src/templates/test-layout.js` ), context: { id: node.id }, }) }) const yokaiResult = await graphql(` query { allAirtable { edges { node { id recordId } } } } `) if (yokaiResult.errors) { reporter.panicOnBuild('🚨 ERROR: Loading "yokai" query') } const yokai = yokaiResult.data.allAirtable.edges yokai.forEach(({ node }, index) => { console.log( `creating page for id ${node.id} with slug /yokai/${node.recordId} ` ) console.log(JSON.stringify(node, null, 4)) createPage({ path: `/yokai/${node.recordId}`, component: path.resolve( `./src/templates/yokai-template.js` ), context: { recordId: node.recordId }, }) }) } ``` as you can guess, this is for a specific type of Airtable record, so you'll have to tweak it a bit. It also requires you to have a page-template that you use, referenced in this little chunk: ``` createPage({ path: `/yokai/${node.recordId}`, component: path.resolve( `./src/templates/yokai-template.js` ), context: { recordId: node.recordId }, }) ``` here's what's in our `yokai-template.js` (which appears to need `theme-ui`, which you can add with `npm i theme-ui`) ``` /** @jsx jsx */ import { jsx } from 'theme-ui' import YokaiFlip from "../components/yokai-flip.js" export default ({ data }) => { return ( <div sx={{ width: "80%", margin: "auto", padding: "2em", }} > <div sx={{ width: "100%", textAlign: "center" }} > <h1 sx={{ fontFamily: "Avenir Next, sans-serif", fontWeight: "900", fontSize: "4em" }} >{data.airtable.data.Name}</h1> </div> <YokaiFlip front={ data.airtable.data.canvaCardFront ? data.airtable.data.canvaCardFront[0].thumbnails.large.url : data.airtable.data.cleanImageJPG ? data.airtable.data.cleanImageJPG[0].thumbnails.full.url : "/_images/gatsby.jpg"} back= { data.airtable.data.canvaCardBack ? data.airtable.data.canvaCardBack[0].thumbnails.large.url : data.airtable.data.cleanImageJPG ? data.airtable.data.cleanImageJPG[0].thumbnails.full.url : "/_images/gatsby.jpg"} /> <div sx={{ height: "300px" }} ></div> {/* <pre>{JSON.stringify(data, null, 4)}</pre> */} </div> ) } export const query = graphql` query GetRecord($recordId: String!){ airtable(recordId: { eq: $recordId}) { id table recordId data { Description mainFeature Creator Link_to_Project secondFeature Name weight type mainAttack region specialAttack height backgroundColor foregroundColor canvaCardLink canvaCardBack { id thumbnails { large { url width height } } } canvaCardFront { id thumbnails { large { url width height } } } cleanImageJPG { thumbnails { full { url } } } } } }` ```