Compare commits

..

No commits in common. "e7729c886b07fae7a690b806c28f6786762cc32f" and "e4df0010b5f7864152d77a38e9c9663312adbb17" have entirely different histories.

18 changed files with 216 additions and 300 deletions

View file

@ -1,9 +1,14 @@
module.exports = { module.exports = {
root: true, root: true,
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'], plugins: [
'@typescript-eslint',
],
globals: { globals: {
__PATH_PREFIX__: true, __PATH_PREFIX__: true,
}, },
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], extends: [
}; 'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
};

View file

@ -1,4 +1,4 @@
{ {
"singleQuote": true, "arrowParens": "avoid",
"jsxSingleQuote": true, "semi": false
} }

View file

@ -1,3 +1,45 @@
<!-- 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 sites 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? ## 🧐 What's inside?
A quick look at the top-level files and directories you'll see in a Gatsby project. A quick look at the top-level files and directories you'll see in a Gatsby project.
@ -32,4 +74,26 @@ 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. 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. **`README.md`**: A text file containing useful reference information about your project. 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 wont change this file directly).**
11. **`package.json`**: A manifest file for Node.js projects, which includes things like metadata (the projects 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 -->

View file

@ -1,4 +1,8 @@
/* eslint-env node */ /**
* Configure your Gatsby site with this file.
*
* See: https://www.gatsbyjs.com/docs/gatsby-config/
*/
module.exports = { module.exports = {
plugins: [ plugins: [
@ -17,13 +21,6 @@ module.exports = {
path: `${__dirname}/src/notes`, path: `${__dirname}/src/notes`,
}, },
}, },
{
resolve: 'gatsby-source-filesystem',
options: {
name: 'notes',
path: `${__dirname}/src/projects`,
},
},
{ {
resolve: 'gatsby-plugin-typography', resolve: 'gatsby-plugin-typography',
options: { options: {
@ -44,7 +41,7 @@ module.exports = {
// you may use this to prevent Prism from re-processing syntax. // you may use this to prevent Prism from re-processing syntax.
// This is an uncommon use-case though; // This is an uncommon use-case though;
// If you're unsure, it's best to use the default value. // If you're unsure, it's best to use the default value.
classPrefix: 'language-', classPrefix: "language-",
// This is used to allow setting a language for inline code // This is used to allow setting a language for inline code
// (i.e. single backticks) by creating a separator. // (i.e. single backticks) by creating a separator.
// This separator is a string and will do no white-space // This separator is a string and will do no white-space
@ -74,8 +71,8 @@ module.exports = {
// existing language" below. // existing language" below.
languageExtensions: [ languageExtensions: [
{ {
language: 'superscript', language: "superscript",
extend: 'javascript', extend: "javascript",
definition: { definition: {
superscript_types: /(SuperType)/, superscript_types: /(SuperType)/,
}, },
@ -89,8 +86,8 @@ module.exports = {
// Customize the prompt used in shell output // Customize the prompt used in shell output
// Values below are default // Values below are default
prompt: { prompt: {
user: 'root', user: "root",
host: 'localhost', host: "localhost",
global: false, global: false,
}, },
// By default the HTML entities <>&'" are escaped. // By default the HTML entities <>&'" are escaped.
@ -103,13 +100,13 @@ module.exports = {
resolve: 'gatsby-remark-smartypants', resolve: 'gatsby-remark-smartypants',
options: { options: {
dashes: 'oldschool', dashes: 'oldschool',
}, }
}, },
], ]
}, }
}, },
{ {
resolve: 'gatsby-plugin-mdx-frontmatter', resolve: 'gatsby-plugin-mdx-frontmatter'
}, },
], ],
}; };

View file

@ -1,36 +1,14 @@
/* eslint-env node */ const path = require("path");
const path = require('path');
/** exports.createPages = async ({ actions, graphql, reporter }) => {
* Generates a set of pages that are blog-like, where there should be an const { createPage } = actions;
* "landing page" that needs to be paginated followed by individual items.
* const noteTemplate = path.resolve(`src/templates/note.tsx`);
* 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(` const result = await graphql(`
{ {
allMdx( allMdx(
filter: { fileAbsolutePath: { glob: "${queryAbsolutePathGlob}" } } limit: 10
filter: { fileAbsolutePath: { glob: "**/src/notes/*" } }
) { ) {
edges { edges {
node { node {
@ -50,61 +28,37 @@ async function generatePages(
return; return;
} }
const posts = result.data.allMdx.edges.filter( const posts = result.data.allMdx.edges.filter(({ node }) => !node.frontmatter.hidden);
({ node }) => !node.frontmatter.hidden
);
const postsPerPage = 10; const postsPerPage = 10;
const numPages = Math.ceil(posts.length / postsPerPage); const numPages = Math.ceil(posts.length / postsPerPage);
const rootPath = "/notes";
Array.from({ length: numPages }).forEach((_, i) => { Array.from({ length: numPages }).forEach((_, i) => {
createPage({ createPage({
path: siteRootPath + (i === 0 ? '' : `/${i + 1}`), path: rootPath + (i === 0 ? '' : `/${i + 1}`),
component: path.resolve(indexFilePath), component: path.resolve("./src/templates/notes.tsx"),
context: { context: {
limit: postsPerPage, limit: postsPerPage,
skip: i * postsPerPage, skip: i * postsPerPage,
numPages, numPages,
currentPage: i + 1, currentPage: i + 1,
rootPath: siteRootPath, rootPath,
}, },
}); })
}); });
// Must decouple to ensure hidden pages are still rendered, just excluded from // Must decouple to ensure hidden pages are still rendered, just excluded from
// notes mapping // notes mapping
result.data.allMdx.edges.forEach(({ node }) => { result.data.allMdx.edges.forEach(({ node }) => {
createPage({ createPage({
path: `${siteRootPath}/${node.frontmatter.path}`, path: `${rootPath}/${node.frontmatter.path}`,
component: path.resolve(itemFilePath), component: noteTemplate,
context: { context: {
id: node.id, 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 } }) => { exports.createSchemaCustomization = ({ actions: { createTypes } }) => {
createTypes(` createTypes(`
type Mdx implements Node { type Mdx implements Node {

View file

@ -1,10 +1,10 @@
import React from 'react'; import React from "react";
import style from './item.module.css'; import style from "./item.module.css";
import { Link } from 'gatsby'; import { Link } from "gatsby";
export default (props) => ( export default (props) => (
<Link to={props.to} className={style.projectItem}> <Link to={props.to} className={style.projectItem}>
<h3 className={style.projectTitle}>{props.title}</h3> <h3 className={style.projectTitle}>{props.title}</h3>
<p className={style.projectSubtitle}>{props.subtitle}</p> <p className={style.projectSubtitle}>{props.subtitle}</p>
</Link> </Link>
); );

View file

@ -1,31 +1,20 @@
import React from 'react'; import React from 'react';
import { Link } from 'gatsby'; import { Link } from "gatsby";
const ExactLink = (props) => ( const ExactLink = (props) => <Link
<Link to={props.to}
to={props.to} style={{ textDecoration: "none" }}
style={{ textDecoration: 'none' }} activeStyle={{ color: "red" }}
activeStyle={{ color: 'red' }} partiallyActive={!props.home}>
partiallyActive={!props.home} {props.children}
> </Link >;
{props.children}
</Link>
);
export default function Navbar() { export default function Navbar() {
return ( return (
<nav> <nav>
<h1> <h1><ExactLink to="/" home={true}>Edward Shen</ExactLink></h1>
<ExactLink to='/' home={true}> <h3><ExactLink to="/projects">Projects</ExactLink></h3>
Edward Shen <h3><ExactLink to="/notes">Notes</ExactLink></h3>
</ExactLink> </nav >
</h1>
<h3>
<ExactLink to='/projects'>Projects</ExactLink>
</h3>
<h3>
<ExactLink to='/notes'>Notes</ExactLink>
</h3>
</nav>
); );
} };

View file

@ -1,7 +0,0 @@
.prev-page-link {
margin-right: 10px;
}
.next-page-link {
margin-left: 10px;
}

View file

@ -1,51 +0,0 @@
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}>
&lt;&lt;
</a>
);
} else if (currentPage !== 1) {
prevPageLink = (
<a
href={rootPath + '/' + (currentPage - 1)}
className={style.prevPageLink}
>
&lt;&lt;
</a>
);
}
if (numPages !== 1) {
return (
<p className={style.paginationNav}>
{prevPageLink}
{currentPage}
{currentPage !== numPages && (
<a
href={rootPath + '/' + (currentPage + 1)}
className={style.nextPageLink}
>
&gt;&gt;
</a>
)}
</p>
);
}
return null;
};

View file

@ -99,7 +99,7 @@ Indented code
Block code "fences" Block code "fences"
```markdown ```
Sample text here... Sample text here...
``` ```

View file

@ -1,22 +1,17 @@
import { PageProps } from 'gatsby'; import { PageProps } from 'gatsby';
import React from 'react'; import React from 'react';
import Navbar from '../components/navbar'; import Navbar from "../components/navbar";
export default ({ location }: PageProps): JSX.Element => { export default ({ location }: PageProps): JSX.Element => {
const messages = [ const messages = [
<p> <p>
In your attempt to search for <code>{location.pathname}</code>, you seem In your attempt to search for <code>{location.pathname}</code>, you seem to
to have gotten lost instead. Fret not, for there is always a path{' '} have gotten lost instead. Fret not, for there is always a path <a href="/">home</a>.
<a href='/'>home</a>.
</p>,
<p>
Not all who wander are lost, but you seem to be. Go <a href='/'>home</a>?
</p>, </p>,
<p>Not all who wander are lost, but you seem to be. Go <a href="/">home</a>?</p>
]; ];
return ( return <>
<> <Navbar />
<Navbar /> {messages[Math.floor(Math.random() * messages.length)]}
{messages[Math.floor(Math.random() * messages.length)]} </>;
</>
);
}; };

View file

@ -0,0 +1,22 @@
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"
/>
</>
);

View file

@ -1,7 +0,0 @@
---
path: "shlink"
date: 2020-01-01
title: "Shlink"
---
Hello world

View file

@ -1,30 +1,27 @@
import React from 'react'; import React from "react";
import Navbar from '../components/navbar'; import Navbar from '../components/navbar';
import { graphql } from 'gatsby'; import { graphql } from "gatsby";
import { MDXRenderer } from 'gatsby-plugin-mdx'; import { MDXRenderer } from 'gatsby-plugin-mdx';
export default ({ data }) => { export default ({ data }) => {
const { frontmatter, body } = data.mdx; const { frontmatter, body } = data.mdx;
return ( return <>
<> <Navbar />
<Navbar /> <main>
<main> <h1>{frontmatter.title}</h1>
<h1>{frontmatter.title}</h1> <MDXRenderer>{body}</MDXRenderer>
<MDXRenderer>{body}</MDXRenderer> </main>
</main> </>;
</>
);
}; };
export const query = graphql` export const query = graphql`
query NotesItemQuery($id: String!) { query NotesIndexQuery($id: String!) {
mdx(id: { eq: $id }) { mdx(id: {eq: $id}) {
frontmatter { frontmatter {
title title
}
tableOfContents
body
} }
tableOfContents
body
} }
`; }`;

View file

@ -2,3 +2,11 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.prev-page-link {
margin-right: 10px;
}
.next-page-link {
margin-left: 10px;
}

View file

@ -3,52 +3,63 @@
* See note.tsx for rendering a single note. * See note.tsx for rendering a single note.
*/ */
import Navbar from '../components/navbar'; import React from "react";
import PaginationNav from '../components/pagination'; import Navbar from "../components/navbar";
import React from 'react'; import { graphql } from "gatsby";
import { graphql } from 'gatsby'; import style from "./notes.module.css";
import style from './notes.module.css';
export default ({ data, pageContext }): JSX.Element => { export default ({ data, pageContext }): JSX.Element => {
const posts = data.allMdx.edges; const posts = data.allMdx.edges;
const { currentPage, numPages, rootPath } = pageContext; const { currentPage, numPages, rootPath } = pageContext;
let prevPageLink = null;
if (currentPage === 2) {
prevPageLink = <a href={rootPath} className={style.prevPageLink}>&lt;&lt;</a>;
} else if (currentPage !== 1) {
prevPageLink = <a href={rootPath + '/' + (currentPage - 1)} className={style.prevPageLink}>&lt;&lt;</a>;
}
const shouldDisplayNav = numPages !== 1;
return ( return (
<> <>
<Navbar /> <Navbar />
{posts.map(({ node }) => { {posts.map(({ node }) => {
const frontmatter = node.frontmatter; const frontmatter = node.frontmatter
return ( return (
<article key={frontmatter.title}> <article key={frontmatter.title}>
<div className={style.noteTitle}> <div className={style.noteTitle}>
<h3> <h3>
<a href={`${rootPath + '/' + frontmatter.path}`}> <a href={`${rootPath + '/' + frontmatter.path}`}>{frontmatter.title}</a>
{frontmatter.title}
</a>
</h3> </h3>
<time dateTime={frontmatter.date}>{frontmatter.date}</time> <time dateTime={frontmatter.date}>{frontmatter.date}</time>
</div> </div>
<p>{node.excerpt}</p> <p>{node.excerpt}</p>
</article> </article>
); )
})} })}
<PaginationNav {shouldDisplayNav &&
currentPage={currentPage} <p className={style.paginationNav}>
numPages={numPages} {prevPageLink}
rootPath={rootPath} {currentPage}
/> {currentPage !== numPages &&
<a
href={rootPath + '/' + (currentPage + 1)}
className={style.nextPageLink}>
&gt;&gt;
</a>
}
</p>
}
</> </>
); )
}; }
export const query = graphql` export const query = graphql`
query NotesIndexQuery($skip: Int!, $limit: Int!) { query IndexQuery($skip: Int!, $limit: Int!) {
allMdx( allMdx(
sort: { order: DESC, fields: [frontmatter___date] } sort: { order: DESC, fields: [frontmatter___date] }
filter: { filter: { fileAbsolutePath: { glob: "**/src/notes/*" }, frontmatter: {hidden: {ne: true}} }
fileAbsolutePath: { glob: "**/src/notes/*" }
frontmatter: { hidden: { ne: true } }
}
limit: $limit limit: $limit
skip: $skip skip: $skip
) { ) {
@ -65,4 +76,4 @@ export const query = graphql`
} }
} }
} }
`; `

View file

@ -1,56 +0,0 @@
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
}
}
}
}
`;

View file

@ -1,25 +1,20 @@
import Typography from 'typography'; import Typography from "typography";
const typography = new Typography({ const typography = new Typography({
baseFontSize: '18px', baseFontSize: '18px',
baseLineHeight: 1.666, baseLineHeight: 1.666,
headerFontFamily: [ headerFontFamily: [
'M PLUS 1p', 'M PLUS 1p', 'Helvetica Neue', 'Segoe UI', 'Helvetica', 'Arial', 'sans-serif'
'Helvetica Neue',
'Segoe UI',
'Helvetica',
'Arial',
'sans-serif',
], ],
bodyFontFamily: ['Georgia', 'serif'], bodyFontFamily: ['Georgia', 'serif'],
googleFonts: [ googleFonts: [
{ {
name: 'M PLUS 1p', name: "M PLUS 1p",
styles: ['100', '400'], styles: ['100', '400'],
}, }
], ]
}); });
// Export helper functions // Export helper functions
export const { scale, rhythm, options } = typography; export const { scale, rhythm, options } = typography;
export default typography; export default typography;