R note

Gatsby + Airtableサイトにカテゴリを追加した(2)

GatsbyJSAirtable

パート1の続きです。Gatsby + Airtable + Netlifyで作っているこのサイトにカテゴリを追加した時の手順の記録です。

パート1では以下の1を書いたので、パート2では2と3を記録しておきます。

  1. 記事ページでカテゴリ表示を追加
  2. 各カテゴリの記事一覧ページを追加
  3. カテゴリ一覧ページを追加

2. 各カテゴリの記事一覧ページを追加

各カテゴリの記事一覧ページを追加しました。記事ページと同じ要領で、テンプレートを作ってgatsby-node.jscreatePageでページを生成しました。

テンプレートページの作成

以下にソースコードを晒しちゃいます。

import React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"
import styles from "./blog-post.module.scss"
import indexStyles from "../pages/index.module.scss"
import Meta from "../components/meta"

class categoryTemplate extends React.Component {
  render(){
    const cat = this.props.data.category
    const posts = this.props.data.posts

    const postCount = posts.edges.length

    return (
      <Layout location="category" backLink={true}>
        <Meta
          page="category"
          title={`「${cat.data.catname}」関連のノート`}
          description={`「${cat.data.catname}」関連のノート`}
          slug={cat.data.slug}
        />
        <h1 className={styles.postTitle}>{`Note${postCount > 1 ? `s` : ``} on ${cat.data.catname}`}</h1>

        <ul className={indexStyles.postlist}>
          {posts.edges.map(({ node }, index) => (
            <li key={index}>
              <span>{node.data.date}</span><br />
              <Link
                to={`${node.data.slug}/`}
              >{node.data.title}
              </Link>
            </li>
          ))}
        </ul>
      </Layout>
    )
  }
}

export default categoryTemplate

export const query = graphql`
  query($slug: String!){
    category: airtable(data: {slug: {eq: $slug}}) {
      data {
        catname
        slug
      }
    }
    posts: allAirtable(
      filter: {
        table: {eq: "entry"},
        data: {category: {elemMatch: {data: {slug: {eq: $slug}}}}}
      },
      sort: {fields: [data___date], order: DESC}
    ) {
      edges {
        node {
          data {
            title
            slug
            date(formatString: "YYYY/MM/DD @HH:mm")
          }
        }
      }
    }
  }
`

gatsby-node.jsの変更

カテゴリの記事一覧ページ用のコードを追加しました。loadPagesで記事を、loadCategoriesでカテゴリの記事一覧ページを生成しています。

exports.createPages = ({ graphql, actions}) => {
   const { createPage } = actions

   const loadPages = new Promise((resolve, reject) => {
      graphql(`
         {
            allAirtable(
               filter: { table: {eq: "entry"} },
            ) {
               edges {
                  node {
                     data {
                        slug
                     }
                  }
               }
            }
         }
      `
      ).then(result => {
         result.data.allAirtable.edges.forEach(({ node }) => {
            createPage({
              path: node.data.slug,
              component: path.resolve(`./src/templates/blog-post.js`),
              context: {
                slug: node.data.slug,
              },
            })
          })
         resolve()
      })
   })

   const loadCategories = new Promise((resolve, reject) => {
      graphql(`
         {
            allAirtable(
               filter: {
                  table: {eq: "category"},
                  data: {entry: {ne: null}},
               },
               sort: {fields: [data___slug], order: ASC}
            ) {
               edges {
                  node {
                     data {
                        slug
                     }
                  }
               }
            }
         }
      `).then(result => {
         result.data.allAirtable.edges.forEach(({ node }) => {
            createPage({
               path: `/category/${node.data.slug}`,
               component: path.resolve(`./src/templates/category.js`),
               context: {
                  slug: node.data.slug,
               },
            })
         })
         resolve()
      })
   })

   return Promise.all([loadPages, loadCategories])
}

3. カテゴリ一覧ページを追加

カテゴリ一覧ページは、Airtableから取得したデータを書き出すだけなので簡単にできました。GraphQLのクエリにfilterdata: {entry: {ne: null}}を追加して記事に使われていないカテゴリを表示しないようにしました。

import React from "react"
import { graphql, Link } from "gatsby"
import Layout from "../components/layout"
import Meta from "../components/meta"
import postStyles from "../templates/blog-post.module.scss"
import styles from "./category.module.scss"

class catListTemplate extends React.Component {
   render() {
      const cats = this.props.data

      return (
        <Layout backLink={false}>
          <Meta
            page="category"
            title="カテゴリ一覧"
            description="R noteのカテゴリ一覧"
            slug="categories"
          />
          <h1 className={postStyles.postTitle}>カテゴリ一覧</h1>
          <ul className={styles.catList}>
            {cats.allAirtable.edges.map(({ node }, index) => (
              <li key={index}>
                <Link
                  to={`category/${node.data.slug}/`}
                >{node.data.catname}
                </Link>
              </li>
            ))}
          </ul>
        </Layout>
      )
   }
}

export default catListTemplate

export const query = graphql`
query{
  allAirtable(
    filter: {
      table: {eq: "category"},
      data: {entry: {ne: null}}
    },
    sort: {fields: data___slug, order: ASC}
  ) {
    edges {
      node {
        data {
          catname
          slug
        }
      }
    }
  }
}
`

以上です!