paginate projects
This commit is contained in:
parent
f766bf3eaf
commit
e7729c886b
12 changed files with 196 additions and 140 deletions
66
README.md
66
README.md
|
@ -1,45 +1,3 @@
|
|||
<!-- AUTO-GENERATED-CONTENT:START (STARTER) -->
|
||||
<p align="center">
|
||||
<a href="https://www.gatsbyjs.com">
|
||||
<img alt="Gatsby" src="https://www.gatsbyjs.com/Gatsby-Monogram.svg" width="60" />
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">
|
||||
Gatsby's hello-world starter
|
||||
</h1>
|
||||
|
||||
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)
|
||||
|
||||
<!-- AUTO-GENERATED-CONTENT:END -->
|
||||
9. **`README.md`**: A text file containing useful reference information about your project.
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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 {
|
||||
|
|
7
src/components/pagination.module.css
Normal file
7
src/components/pagination.module.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
.prev-page-link {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.next-page-link {
|
||||
margin-left: 10px;
|
||||
}
|
51
src/components/pagination.tsx
Normal file
51
src/components/pagination.tsx
Normal file
|
@ -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 = (
|
||||
<a href={rootPath} className={style.prevPageLink}>
|
||||
<<
|
||||
</a>
|
||||
);
|
||||
} else if (currentPage !== 1) {
|
||||
prevPageLink = (
|
||||
<a
|
||||
href={rootPath + '/' + (currentPage - 1)}
|
||||
className={style.prevPageLink}
|
||||
>
|
||||
<<
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
if (numPages !== 1) {
|
||||
return (
|
||||
<p className={style.paginationNav}>
|
||||
{prevPageLink}
|
||||
{currentPage}
|
||||
{currentPage !== numPages && (
|
||||
<a
|
||||
href={rootPath + '/' + (currentPage + 1)}
|
||||
className={style.nextPageLink}
|
||||
>
|
||||
>>
|
||||
</a>
|
||||
)}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
|
@ -99,7 +99,7 @@ Indented code
|
|||
|
||||
Block code "fences"
|
||||
|
||||
```
|
||||
```markdown
|
||||
Sample text here...
|
||||
```
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
import React from 'react';
|
||||
import Navbar from '../../components/navbar';
|
||||
import Item from '../../components/item';
|
||||
|
||||
export default (): JSX.Element => (
|
||||
<>
|
||||
<Navbar />
|
||||
<Item title='Shlink' subtitle='subtitle' to='test' />
|
||||
<Item title='hello world' subtitle='subtitle' />
|
||||
<Item title='hello world' subtitle='subtitle' />
|
||||
</>
|
||||
);
|
7
src/projects/shlink.mdx
Normal file
7
src/projects/shlink.mdx
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
path: "shlink"
|
||||
date: 2020-01-01
|
||||
title: "Shlink"
|
||||
---
|
||||
|
||||
Hello world
|
|
@ -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
|
||||
|
|
|
@ -2,11 +2,3 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.prev-page-link {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.next-page-link {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
|
|
@ -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 = (
|
||||
<a href={rootPath} className={style.prevPageLink}>
|
||||
<<
|
||||
</a>
|
||||
);
|
||||
} else if (currentPage !== 1) {
|
||||
prevPageLink = (
|
||||
<a
|
||||
href={rootPath + '/' + (currentPage - 1)}
|
||||
className={style.prevPageLink}
|
||||
>
|
||||
<<
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const shouldDisplayNav = numPages !== 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -51,26 +32,17 @@ export default ({ data, pageContext }): JSX.Element => {
|
|||
</article>
|
||||
);
|
||||
})}
|
||||
{shouldDisplayNav && (
|
||||
<p className={style.paginationNav}>
|
||||
{prevPageLink}
|
||||
{currentPage}
|
||||
{currentPage !== numPages && (
|
||||
<a
|
||||
href={rootPath + '/' + (currentPage + 1)}
|
||||
className={style.nextPageLink}
|
||||
>
|
||||
>>
|
||||
</a>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
<PaginationNav
|
||||
currentPage={currentPage}
|
||||
numPages={numPages}
|
||||
rootPath={rootPath}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const query = graphql`
|
||||
query IndexQuery($skip: Int!, $limit: Int!) {
|
||||
query NotesIndexQuery($skip: Int!, $limit: Int!) {
|
||||
allMdx(
|
||||
sort: { order: DESC, fields: [frontmatter___date] }
|
||||
filter: {
|
||||
|
|
56
src/templates/projects.tsx
Normal file
56
src/templates/projects.tsx
Normal file
|
@ -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 (
|
||||
<>
|
||||
<Navbar />
|
||||
{posts.map(({ node }) => {
|
||||
const frontmatter = node.frontmatter;
|
||||
return (
|
||||
<Item
|
||||
title={frontmatter.title}
|
||||
to={rootPath + '/' + frontmatter.path}
|
||||
></Item>
|
||||
);
|
||||
})}
|
||||
<PaginationNav
|
||||
currentPage={currentPage}
|
||||
numPages={numPages}
|
||||
rootPath={rootPath}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
Loading…
Reference in a new issue