From e7729c886b07fae7a690b806c28f6786762cc32f Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Fri, 27 Nov 2020 22:35:36 -0500 Subject: [PATCH] paginate projects --- README.md | 66 +-------------------------- gatsby-config.js | 13 ++++-- gatsby-node.js | 68 +++++++++++++++++++++++----- src/components/pagination.module.css | 7 +++ src/components/pagination.tsx | 51 +++++++++++++++++++++ src/notes/2020-01-01-lorem-ipsum.mdx | 2 +- src/pages/projects/index.tsx | 12 ----- src/projects/shlink.mdx | 7 +++ src/templates/note.tsx | 2 +- src/templates/notes.module.css | 8 ---- src/templates/notes.tsx | 44 ++++-------------- src/templates/projects.tsx | 56 +++++++++++++++++++++++ 12 files changed, 196 insertions(+), 140 deletions(-) create mode 100644 src/components/pagination.module.css create mode 100644 src/components/pagination.tsx delete mode 100644 src/pages/projects/index.tsx create mode 100644 src/projects/shlink.mdx create mode 100644 src/templates/projects.tsx diff --git a/README.md b/README.md index b40d274..0628163 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,3 @@ - -

- - Gatsby - -

-

- Gatsby's hello-world starter -

- -Kick off your project with this hello-world boilerplate. This starter ships with the main Gatsby configuration files you might need to get up and running blazing fast with the blazing fast app generator for React. - -_Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.com/docs/gatsby-starters/)._ - -## 🚀 Quick start - -1. **Create a Gatsby site.** - - Use the Gatsby CLI to create a new site, specifying the hello-world starter. - - ```shell - # create a new Gatsby site using the hello-world starter - gatsby new my-hello-world-starter https://github.com/gatsbyjs/gatsby-starter-hello-world - ``` - -1. **Start developing.** - - Navigate into your new site’s directory and start it up. - - ```shell - cd my-hello-world-starter/ - gatsby develop - ``` - -1. **Open the source code and start editing!** - - Your site is now running at `http://localhost:8000`! - - _Note: You'll also see a second link: _`http://localhost:8000/___graphql`_. This is a tool you can use to experiment with querying your data. Learn more about using this tool in the [Gatsby tutorial](https://www.gatsbyjs.com/tutorial/part-five/#introducing-graphiql)._ - - Open the `my-hello-world-starter` directory in your code editor of choice and edit `src/pages/index.js`. Save your changes and the browser will update in real time! - ## 🧐 What's inside? A quick look at the top-level files and directories you'll see in a Gatsby project. @@ -74,26 +32,4 @@ A quick look at the top-level files and directories you'll see in a Gatsby proje 8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.com/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering. -9. **`LICENSE`**: This Gatsby starter is licensed under the 0BSD license. This means that you can see this file as a placeholder and replace it with your own license. - -10. **`package-lock.json`** (See `package.json` below, first). This is an automatically generated file based on the exact versions of your npm dependencies that were installed for your project. **(You won’t change this file directly).** - -11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the project’s name, author, etc). This manifest is how npm knows which packages to install for your project. - -12. **`README.md`**: A text file containing useful reference information about your project. - -## 🎓 Learning Gatsby - -Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.com/). Here are some places to start: - -- **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.com/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. - -- **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.com/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. - -## 💫 Deploy - -[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-hello-world) - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/gatsbyjs/gatsby-starter-hello-world) - - +9. **`README.md`**: A text file containing useful reference information about your project. diff --git a/gatsby-config.js b/gatsby-config.js index 9af589b..bc249c9 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -1,8 +1,4 @@ -/** - * Configure your Gatsby site with this file. - * - * See: https://www.gatsbyjs.com/docs/gatsby-config/ - */ +/* eslint-env node */ module.exports = { plugins: [ @@ -21,6 +17,13 @@ module.exports = { path: `${__dirname}/src/notes`, }, }, + { + resolve: 'gatsby-source-filesystem', + options: { + name: 'notes', + path: `${__dirname}/src/projects`, + }, + }, { resolve: 'gatsby-plugin-typography', options: { diff --git a/gatsby-node.js b/gatsby-node.js index 3dc119c..b4408a0 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,14 +1,36 @@ +/* eslint-env node */ const path = require('path'); -exports.createPages = async ({ actions, graphql, reporter }) => { - const { createPage } = actions; - - const noteTemplate = path.resolve(`src/templates/note.tsx`); +/** + * Generates a set of pages that are blog-like, where there should be an + * "landing page" that needs to be paginated followed by individual items. + * + * This function does two essential features: + * 1. renders individual pages + * 2. renders index pages with context needed for pagination + * + * @param {function} createPage Gatsby createPage function + * @param {function} graphql Gatsby graphql function + * @param {object} reporter Gatbsy reporter object + * @param {string} queryAbsolutePathGlob The source code glob to find the pages + * for rendering + * @param {string} siteRootPath The public root path to generate the pages under + * @param {string} indexFilePath The source code path to the index template file + * @param {string} itemFilePath The source code path to the item template file + */ +async function generatePages( + createPage, + graphql, + reporter, + queryAbsolutePathGlob, + siteRootPath, + indexFilePath, + itemFilePath +) { const result = await graphql(` { allMdx( - limit: 10 - filter: { fileAbsolutePath: { glob: "**/src/notes/*" } } + filter: { fileAbsolutePath: { glob: "${queryAbsolutePathGlob}" } } ) { edges { node { @@ -33,18 +55,17 @@ exports.createPages = async ({ actions, graphql, reporter }) => { ); const postsPerPage = 10; const numPages = Math.ceil(posts.length / postsPerPage); - const rootPath = '/notes'; Array.from({ length: numPages }).forEach((_, i) => { createPage({ - path: rootPath + (i === 0 ? '' : `/${i + 1}`), - component: path.resolve('./src/templates/notes.tsx'), + path: siteRootPath + (i === 0 ? '' : `/${i + 1}`), + component: path.resolve(indexFilePath), context: { limit: postsPerPage, skip: i * postsPerPage, numPages, currentPage: i + 1, - rootPath, + rootPath: siteRootPath, }, }); }); @@ -53,14 +74,37 @@ exports.createPages = async ({ actions, graphql, reporter }) => { // notes mapping result.data.allMdx.edges.forEach(({ node }) => { createPage({ - path: `${rootPath}/${node.frontmatter.path}`, - component: noteTemplate, + path: `${siteRootPath}/${node.frontmatter.path}`, + component: path.resolve(itemFilePath), context: { id: node.id, }, }); }); +} + +exports.createPages = async ({ actions, graphql, reporter }) => { + const { createPage } = actions; + await generatePages( + createPage, + graphql, + reporter, + '**/src/notes/*', + '/notes', + './src/templates/notes.tsx', + './src/templates/note.tsx' + ); + await generatePages( + createPage, + graphql, + reporter, + '**/src/projects/*', + '/projects', + './src/templates/projects.tsx', + './src/templates/note.tsx' + ); }; + exports.createSchemaCustomization = ({ actions: { createTypes } }) => { createTypes(` type Mdx implements Node { diff --git a/src/components/pagination.module.css b/src/components/pagination.module.css new file mode 100644 index 0000000..a10af35 --- /dev/null +++ b/src/components/pagination.module.css @@ -0,0 +1,7 @@ +.prev-page-link { + margin-right: 10px; +} + +.next-page-link { + margin-left: 10px; +} diff --git a/src/components/pagination.tsx b/src/components/pagination.tsx new file mode 100644 index 0000000..f4d4b46 --- /dev/null +++ b/src/components/pagination.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import style from './pagination.module.css'; + +interface Pagination { + currentPage: number; + numPages: number; + rootPath: string; +} + +export default ({ + currentPage, + numPages, + rootPath, +}: Pagination): JSX.Element => { + let prevPageLink = null; + if (currentPage === 2) { + prevPageLink = ( + + << + + ); + } else if (currentPage !== 1) { + prevPageLink = ( + + << + + ); + } + + if (numPages !== 1) { + return ( +

+ {prevPageLink} + {currentPage} + {currentPage !== numPages && ( + + >> + + )} +

+ ); + } + + return null; +}; diff --git a/src/notes/2020-01-01-lorem-ipsum.mdx b/src/notes/2020-01-01-lorem-ipsum.mdx index a505c02..bd97ea9 100644 --- a/src/notes/2020-01-01-lorem-ipsum.mdx +++ b/src/notes/2020-01-01-lorem-ipsum.mdx @@ -99,7 +99,7 @@ Indented code Block code "fences" -``` +```markdown Sample text here... ``` diff --git a/src/pages/projects/index.tsx b/src/pages/projects/index.tsx deleted file mode 100644 index 2c3c775..0000000 --- a/src/pages/projects/index.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import Navbar from '../../components/navbar'; -import Item from '../../components/item'; - -export default (): JSX.Element => ( - <> - - - - - -); diff --git a/src/projects/shlink.mdx b/src/projects/shlink.mdx new file mode 100644 index 0000000..e342c4a --- /dev/null +++ b/src/projects/shlink.mdx @@ -0,0 +1,7 @@ +--- +path: "shlink" +date: 2020-01-01 +title: "Shlink" +--- + +Hello world diff --git a/src/templates/note.tsx b/src/templates/note.tsx index 1e29781..37ae0fa 100644 --- a/src/templates/note.tsx +++ b/src/templates/note.tsx @@ -18,7 +18,7 @@ export default ({ data }) => { }; export const query = graphql` - query NotesIndexQuery($id: String!) { + query NotesItemQuery($id: String!) { mdx(id: { eq: $id }) { frontmatter { title diff --git a/src/templates/notes.module.css b/src/templates/notes.module.css index 6239ce1..6f130a4 100644 --- a/src/templates/notes.module.css +++ b/src/templates/notes.module.css @@ -2,11 +2,3 @@ display: flex; justify-content: space-between; } - -.prev-page-link { - margin-right: 10px; -} - -.next-page-link { - margin-left: 10px; -} diff --git a/src/templates/notes.tsx b/src/templates/notes.tsx index df7586c..104cf27 100644 --- a/src/templates/notes.tsx +++ b/src/templates/notes.tsx @@ -3,34 +3,15 @@ * See note.tsx for rendering a single note. */ -import React from 'react'; import Navbar from '../components/navbar'; +import PaginationNav from '../components/pagination'; +import React from 'react'; import { graphql } from 'gatsby'; import style from './notes.module.css'; export default ({ data, pageContext }): JSX.Element => { const posts = data.allMdx.edges; const { currentPage, numPages, rootPath } = pageContext; - let prevPageLink = null; - - if (currentPage === 2) { - prevPageLink = ( - - << - - ); - } else if (currentPage !== 1) { - prevPageLink = ( - - << - - ); - } - - const shouldDisplayNav = numPages !== 1; return ( <> @@ -51,26 +32,17 @@ export default ({ data, pageContext }): JSX.Element => { ); })} - {shouldDisplayNav && ( -

- {prevPageLink} - {currentPage} - {currentPage !== numPages && ( - - >> - - )} -

- )} + ); }; export const query = graphql` - query IndexQuery($skip: Int!, $limit: Int!) { + query NotesIndexQuery($skip: Int!, $limit: Int!) { allMdx( sort: { order: DESC, fields: [frontmatter___date] } filter: { diff --git a/src/templates/projects.tsx b/src/templates/projects.tsx new file mode 100644 index 0000000..5834578 --- /dev/null +++ b/src/templates/projects.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import Navbar from '../components/navbar'; +import PaginationNav from '../components/pagination'; +import Item from '../components/item'; +import { graphql } from 'gatsby'; + +export default ({ data, pageContext }): JSX.Element => { + const posts = data.allMdx.edges; + const { currentPage, numPages, rootPath } = pageContext; + + return ( + <> + + {posts.map(({ node }) => { + const frontmatter = node.frontmatter; + return ( + + ); + })} + + + ); +}; + +export const query = graphql` + query ProjectsIndexQuery($skip: Int!, $limit: Int!) { + allMdx( + sort: { order: DESC, fields: [frontmatter___date] } + filter: { + fileAbsolutePath: { glob: "**/src/projects/*" } + frontmatter: { hidden: { ne: true } } + } + limit: $limit + skip: $skip + ) { + edges { + node { + excerpt(pruneLength: 250) + frontmatter { + title + date(formatString: "YYYY-MM-DD") + path + } + id + } + } + } + } +`;