diff --git a/config.js b/config.js index 9afbf64f..ae3990b3 100644 --- a/config.js +++ b/config.js @@ -28,7 +28,7 @@ module.exports = { }, { title: 'Goodies', - link: '/goodies' + link: '/tags/goodies' } ] } diff --git a/gatsby-node.js b/gatsby-node.js index 08d79243..2a7190a0 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -7,7 +7,6 @@ const { generateRedirectPages } = require('./gatsby/createPages') const { generateJsonFeed } = require('./gatsby/feeds') -const { itemsPerPage } = require('./config') exports.onCreateNode = ({ node, actions, getNode, createNodeId }) => { // Markdown files @@ -26,7 +25,7 @@ exports.createPages = async ({ graphql, actions }) => { const result = await graphql(` { - allMarkdownRemark { + posts: allMarkdownRemark { edges { node { fields { @@ -38,19 +37,26 @@ exports.createPages = async ({ graphql, actions }) => { } } } + + tags: allMarkdownRemark { + group(field: frontmatter___tags) { + tag: fieldValue + totalCount + } + } } `) if (result.errors) throw result.errors - const posts = result.data.allMarkdownRemark.edges - const numPages = Math.ceil(posts.length / itemsPerPage) + const posts = result.data.posts.edges + const tags = result.data.tags.group // Generate posts & posts index - generatePostPages(createPage, posts, numPages) + generatePostPages(createPage, posts) // Generate tag pages - generateTagPages(createPage, posts, numPages) + generateTagPages(createPage, tags) // Create manual redirects generateRedirectPages(createRedirect) diff --git a/gatsby/createPages.js b/gatsby/createPages.js index 653a097e..9d7fd6e4 100644 --- a/gatsby/createPages.js +++ b/gatsby/createPages.js @@ -1,12 +1,29 @@ const path = require('path') const postsTemplate = path.resolve('src/templates/Posts.tsx') +const { itemsPerPage } = require('../config') const redirects = [ { f: '/feed', t: '/feed.xml' }, - { f: '/feed/', t: '/feed.xml' } + { f: '/feed/', t: '/feed.xml' }, + { f: '/goodies/', t: '/tags/goodies/' } ] -exports.generatePostPages = (createPage, posts, numPages) => { +function getPaginationData(i, numPages, slug) { + const currentPage = i + 1 + const prevPageNumber = currentPage <= 1 ? null : currentPage - 1 + const nextPageNumber = currentPage + 1 > numPages ? null : currentPage + 1 + const prevPagePath = prevPageNumber + ? prevPageNumber === 1 + ? slug + : `${slug}page/${prevPageNumber}/` + : null + const nextPagePath = nextPageNumber ? `${slug}page/${nextPageNumber}/` : null + const path = i === 0 ? slug : `${slug}page/${i + 1}` + + return { prevPagePath, nextPagePath, path } +} + +exports.generatePostPages = (createPage, posts) => { const postTemplate = path.resolve('src/templates/Post/index.tsx') // Create Post pages @@ -21,33 +38,59 @@ exports.generatePostPages = (createPage, posts, numPages) => { }) // Create paginated Blog index pages + const numPages = Math.ceil(posts.length / itemsPerPage) + const slug = `/` + Array.from({ length: numPages }).forEach((_, i) => { + const { prevPagePath, nextPagePath, path } = getPaginationData( + i, + numPages, + slug + ) + createPage({ - path: i === 0 ? '/' : `/page/${i + 1}`, + path, component: postsTemplate, context: { - limit: numPages, - skip: i * numPages, + slug, + limit: itemsPerPage, + skip: i * itemsPerPage, numPages, currentPageNumber: i + 1, - prevPage: i - 1, - nextPage: i + 2 + prevPagePath, + nextPagePath } }) }) } -exports.generateTagPages = (createPage, posts) => { - const tagList = arrayReducer(posts, 'tags') +exports.generateTagPages = (createPage, tags) => { + tags.forEach(({ tag, totalCount }) => { + // Create paginated tag pages + const numPages = Math.ceil(totalCount / itemsPerPage) + const slug = `/tags/${tag}/` - tagList.forEach(tag => { - if (tag === 'goodies') return + Array.from({ length: numPages }).forEach((_, i) => { + const { prevPagePath, nextPagePath, path } = getPaginationData( + i, + numPages, + slug + ) - // Create tag pages - createPage({ - path: `/tags/${tag}/`, - component: postsTemplate, - context: { tag } + createPage({ + path, + component: postsTemplate, + context: { + tag, + slug, + limit: itemsPerPage, + skip: i * itemsPerPage, + numPages, + currentPageNumber: i + 1, + prevPagePath, + nextPagePath + } + }) }) }) } @@ -61,21 +104,3 @@ exports.generateRedirectPages = createRedirect => { }) }) } - -// -// ---------------------- -// -// https://www.adamjberkowitz.com/tags-and-categories-in-gatsby-js/ -const arrayReducer = (postsArray, type) => { - return (postsArray = postsArray - .map(({ node }) => { - return node.frontmatter[type] - }) - .reduce((a, b) => { - return a.concat(b) - }, []) - .filter((type, index, array) => { - return array.indexOf(type) === index - }) - .sort()) -} diff --git a/src/components/molecules/Pagination.module.scss b/src/components/molecules/Pagination.module.scss index 2e48ef90..de982858 100644 --- a/src/components/molecules/Pagination.module.scss +++ b/src/components/molecules/Pagination.module.scss @@ -4,7 +4,7 @@ display: flex; margin-top: $spacer * 2; margin-bottom: $spacer; - justify-content: center; + justify-content: space-between; > div { &:first-child { @@ -40,4 +40,8 @@ pointer-events: none; border: 1px solid darken($brand-grey-dimmed, 5%); color: $brand-grey-light; + + :global(.dark) & { + border-color: darken($brand-grey-light, 15%); + } } diff --git a/src/components/molecules/Pagination.tsx b/src/components/molecules/Pagination.tsx index b1fc066a..89469d25 100644 --- a/src/components/molecules/Pagination.tsx +++ b/src/components/molecules/Pagination.tsx @@ -1,11 +1,18 @@ import React from 'react' import { Link } from 'gatsby' -import shortid from 'shortid' import styles from './Pagination.module.scss' -function PageNumber({ i, current }: { i: number; current?: boolean }) { +const PageNumber = ({ + i, + slug, + current +}: { + i: number + slug: string + current?: boolean +}) => { const classes = current ? styles.current : styles.number - const link = i === 0 ? '' : `/page/${i + 1}` + const link = i === 0 ? slug : `${slug}page/${i + 1}` return ( @@ -36,28 +43,29 @@ export default function Pagination({ pageContext }: { pageContext: { + slug: string currentPageNumber: number numPages: number - prevPage?: number - nextPage?: number + prevPagePath?: string + nextPagePath?: string } }) { - const { currentPageNumber, numPages, prevPage, nextPage } = pageContext + const { + slug, + currentPageNumber, + numPages, + prevPagePath, + nextPagePath + } = pageContext const isFirst = currentPageNumber === 1 const isLast = currentPageNumber === numPages - const prevPagePath = currentPageNumber === 2 ? '/' : `/page/${prevPage}` - const nextPagePath = `/page/${nextPage}` return (