├── .gitignore ├── README.md ├── notes-2hr ├── 00 - Welcome.md ├── 01 - Intro to Gatsby.md ├── 01a - Gatsby Themes.md ├── 02 - Gatsby Plugins.md ├── 02a - Gatsby Image.md ├── 02b - Gatsby Lifecycle.md ├── 03 - Intro to JAMstack.md ├── 03a - Intro to Netlify.md ├── 03b - Netlify + Gatsby.md └── 04 - Intro to Serverless.md ├── notes-4hr ├── 00 - Welcome.md ├── 01 - Intro to JAMstack.md ├── 02 - Intro to Gatsby.md ├── 03 - Gatsby Plugins.md ├── 03a - Gatsby Image.md ├── 03b - Gatsby Lifecycle.md ├── 04 - Gatsby Themes.md ├── 05 - Intro to Serverless.md ├── 06a - Amplify CLI.md └── 07 - Bonus.md └── site ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── content ├── first-post.md ├── second-post.md └── third-post.md ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package.json └── src ├── components ├── AuthDetails.js ├── AuthError.js ├── AuthHeader.js ├── AuthHome.js ├── AuthLayout.js ├── AuthLogin.js ├── AuthPrivateRoute.js ├── AuthSignUp.js ├── header.js ├── image.js ├── layout.css ├── layout.js └── seo.js ├── example-pages ├── .gitkeep ├── 404.js ├── app.js ├── index.js └── page-2.js ├── images ├── gatsby-astronaut.png └── gatsby-icon.png ├── pages ├── .gitkeep ├── about.js └── index.js ├── templates ├── .gitkeep └── pageTemplate.js └── utils └── auth.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .cache -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JAMstack Jumpstart 2 | 3 | Welcome! the Workshop notes are in `/notes` (pick either the 2hr or 4hr version) and you can follow along. 4 | 5 | ## 2 hour Workshop 6 | 7 | In the 2 hour workshop we will start from a blank folder and code from scratch. 8 | 9 | Recorded video: https://www.youtube.com/watch?v=PoqWF9BKtOE 10 | 11 | ## 4 hour Workshop 12 | 13 | The starter site we are going to work with is in `/site`. 14 | 15 | To start the Gatsby demo, `cd` into `site` and run `npm install`. 16 | -------------------------------------------------------------------------------- /notes-2hr/00 - Welcome.md: -------------------------------------------------------------------------------- 1 | # Welcome! 2 | 3 | There are a few things you'll need to get setup for today: 4 | 5 | 1. A laptop with the latest version of [Node.js](https://nodejs.org) installed. 6 | 1. An IDE or text editor like VS Code 7 | 1. A terminal 8 | 1. [Git](https://git-scm.com/downloads) 9 | 1. (Optional) [Yarn](https://yarnpkg.com/en/) CLI (like npm's CLI, but better. You may find some bugs go away when using yarn's module resolution.) 10 | 1. (Optional) A free [Netlify](https://www.netlify.com/) account 11 | 1. (Optional) Netlify CLI: `npm i -g netlify-cli` 12 | 13 | ## Questions 14 | 15 | Feel free to ask questions at any time! My style is pretty off the cuff so I'm happy to stop and go down the roads we need to. 16 | 17 | ## What to Expect From Today 18 | 19 | Today we are going to learn about the JAMstack and build a few JAMstack sites with Gatsby. We are going to cover: 20 | 21 | 1. Intro to Gatsby and Gatsby Themes (30 mins) 22 | 1. Exercise I: Build your new blog (15 mins) 23 | 1. Guided: Gatsby Plugins (and Gatsby Image and Lifecycle) (15 mins) 24 | 1. Intro to Netlify and JAMstack (30 mins) 25 | 1. Exercise II: Deploy your new site and add serverless functions (15 mins) 26 | 1. Add Fauna DB (15 mins) 27 | 28 | ## These Notes 29 | 30 | These notes aren't comprehensive - more of a landing spot to grab the code if you get stuck. We will try and code as much of the code by hand, but if you misspell something or misplaced a curly bracket, feel free to grab the code from the notes or from the finished files. 31 | -------------------------------------------------------------------------------- /notes-2hr/01 - Intro to Gatsby.md: -------------------------------------------------------------------------------- 1 | # Intro to Gatsby 2 | 3 | ## Gatsby 101 4 | 5 | So, what is Gatsby? It's a framework for creating websites with `React`. Gatsby is considered a "_static site generator_" which means that before you put your website up online, you run a build command that will compile your website into a set of HTML, CSS and JS (React) files. 6 | 7 | This makes your website extremely fast. But Gatsby isn't _just_ another static site gen; it's much more than that. 8 | 9 | Gatsby makes it easy to build a website with all of today's best practices at the forefront, _not_ an after thought. This includes code splitting, pre-loaded routes, image loading and compression, offline ready and so much more. Along with amazing user experiences, the Gatsby developer experience is fast, hot-reloaded and easily deployable. 10 | 11 | ## What are examples of Gatsby Sites? 12 | 13 | - https://www.gatsbyjs.org/showcase/ 14 | - Blog: https://overreacted.io 15 | - Open Source: https://reactjs.org 16 | - Ecommerce: https://www.shopflamingo.com/ 17 | - Marketing: https://2018.stateofeuropeantech.com/ 18 | - Brand: https://impossiblefoods.com 19 | - Docs: https://docs.ghost.org 20 | 21 | ### From Scratch 22 | 23 | ```bash 24 | mkdir mynewblog 25 | cd mynewblog 26 | npm init -y # creates a package.json with default settings 27 | npm i gatsby react react-dom 28 | ``` 29 | 30 | We now have all we need to set up a very basic statically rendered site. We'll want to run this in local development though, so let's add some npm scripts: 31 | 32 | ```js 33 | // package.json 34 | "scripts": { 35 | "start": "gatsby develop", 36 | "build": "gatsby build" 37 | }, 38 | ``` 39 | 40 | and we can now add our first page: `src/pages/index.js`: 41 | 42 | ```js 43 | // src/pages/index.js 44 | import React from 'react' 45 | 46 | export default function() { 47 | return ( 48 |
49 |

My New Blog | About

50 |

Hello Gatsby

51 |
52 | ) 53 | } 54 | ``` 55 | 56 | Run `yarn start` and you'll see your first Gatsby page on `http://localhost:8000`! 🎉 57 | 58 | We'll discuss what `src/pages/index.js` means next. 59 | 60 | ### Pages + Routing 61 | 62 | At its core, Gatsby has pages. You know what pages are, right? Want a page called `/about`? Make an `about.js` and export a React component. 63 | 64 | Gatsby also includes a Router, which by using their `About` component, will allow you to both pre-load that page as well as use HTML5 pushstate to change the page without a browser reload. 65 | 66 | Gatsby also includes a set of APIs for dynamically creating pages; more soon. 67 | 68 | ## Exercise: Creating Pages 69 | 70 | So, let's make sure we have things up and running! 71 | 72 | Let's make a new page called `about.js`. This just needs to default export a React component (any type will do)! 73 | 74 | ```js 75 | // about.js 76 | import React from 'react' 77 | import { Link } from 'gatsby' 78 | 79 | export default function AboutPage(props) { 80 | return ( 81 |
82 |

My New Blog | About

83 |

I am the about page.

84 | To Home Page 85 |
86 | ) 87 | } 88 | ``` 89 | 90 | Now you can see your page at `localhost:8000/about`. 91 | 92 | > Tip: What if someone typo's your url? In development, Gatsby provides you a default 404 page, but you can also make a `src/pages/404.js` custom 404 page. 93 | 94 | ## GraphiQL and Site Metadata 95 | 96 | In the root of your project, add a `gatsby-config.js` file. We will use this for configuring all our data sources and plugins in the future, but for now, we can also store site metadata. 97 | 98 | ```js 99 | // gatsby-config.js 100 | 101 | module.exports = { 102 | siteMetadata: { 103 | anything: 'I want', 104 | title: `JAMstack Jumpstart`, 105 | description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, 106 | author: `@swyx`, 107 | }, 108 | plugins: [], // not technically required, but every site will probably have a few 109 | } 110 | ``` 111 | 112 | On most sites, we would just import this config and be done with it. But because Gatsby is a static site generator, Gatsby needs to be aware of the the data. 113 | 114 | Restart your application (`Ctrl + C` && `npm start`) and then open up the Graphiql interface at http://localhost:8000/__graphql 115 | 116 | We can run queries in this playground to see this data: 117 | 118 | ```graphql 119 | query { 120 | site { 121 | siteMetadata { 122 | title 123 | anything 124 | } 125 | } 126 | } 127 | ``` 128 | 129 | Now how do we get this data into our pages? 130 | 131 | Queries! 132 | 133 | There are two types of queries in Gatsby 134 | 135 | 1. **Page queries**: can be _dynamic_ but can _only be done inside a page_ 136 | 2. **Static Queries**: can be _done anywhere_, but have the limitation of _not being dynamic_. More on this when we hit images! 137 | 138 | To perform a query inside a component, first import a few things inside of `index.js`: 139 | 140 | ```js 141 | // index.js 142 | 143 | import { graphql, useStaticQuery } from 'gatsby' 144 | ``` 145 | 146 | and then inside our component, just before the return, we can run the query: 147 | 148 | ```js 149 | const data = useStaticQuery(graphql` 150 | query SiteData { 151 | site { 152 | siteMetadata { 153 | title 154 | } 155 | } 156 | } 157 | `) 158 | ``` 159 | 160 | We can then swap out that hard coded h1 with this: 161 | 162 | ```js 163 |

{data.site.siteMetadata.title}

164 | ``` 165 | 166 | > Tip: For older version of React and Gatsby, there is also a render prop component to do the same thing. But there's no reason to use it if you can `useStaticQuery` 😎 167 | 168 | ## and Static Routing 169 | 170 | Next, we have Routing. 171 | 172 | We have two pages: `/` and `/about`. 173 | 174 | We won't do it today, but know that you can make a reusable Nav component which we can inject into our pages: 175 | 176 | ```js 177 | // src/components/layout.js 178 | 179 | import React from 'react' 180 | import { Link } from 'gatsby' 181 | 182 | export default function Layout({ children }) { 183 | return ( 184 |
185 | 195 | {children} 196 |
197 | ) 198 | } 199 | ``` 200 | 201 | Import this into both your pages and wrap the Layout around them: 202 | 203 | ```js 204 | // index.js 205 | 206 | import Layout from '../components/layout' 207 | // ... 208 | export default function HomePage() { 209 | return ( 210 | 211 |

My New Blog | About

212 |

Hello Gatsby

213 |
214 | ) 215 | } 216 | ``` 217 | 218 | Now you can click around your nav like a regular single page app. 219 | 220 | Gatsby Link component is the most common way to move from one page to another. It accepts a few props including `to`, `activeClassName` and `activeStyle`. 221 | 222 | [Take a look at the docs](https://www.gatsbyjs.org/docs/linking-between-pages/) and answer a few questions: 223 | 224 | - How to I programmatically change pages? 225 | - how do I style the active page? 226 | - How do I pass state from one page to another? 227 | 228 | ## Exercise 229 | 230 | 1. Make two more pages: a 404 page, and one other page 231 | 1. Make a footer component with your name and the current year in it. 232 | 1. Style the current page to be coloured differently 233 | 1. Extract your Nav to be a reusable component 234 | 1. Figure out how to do animated page transitions 235 | 1. (Advanced) [Learn more about dynamic routing](https://www.gatsbyjs.org/blog/2018-12-17-turning-the-static-dynamic/) 236 | 237 | ## Bonus: SEO 238 | 239 | Great SEO is a fantastic reason to adopt Gatsby. Nothing is friendlier to search engines than fast, pregenerated HTML. To give the right metadata for each page, we use [`react-helmet`](https://npm.im/react-helmet). 240 | 241 | The default Gatsby template provides an `SEO` element you can use, so just go ahead and import it (see below for code) and specify your page title: 242 | 243 | ```js 244 | // index.js 245 | import React from 'react' 246 | import { Link } from 'gatsby' 247 | 248 | import Layout from '../components/layout' 249 | import SEO from '../components/seo' 250 | 251 | const IndexPage = () => ( 252 | 253 | 254 |

Hi people

255 |

Welcome to your new Gatsby site.

256 |

Now go build something great.

257 | Go to page 2 258 |
259 | ) 260 | 261 | export default IndexPage 262 | ``` 263 | 264 | Feel free to read the docs of `react-helmet` and study the source code of `SEO` to see how it works: 265 | 266 | ```js 267 | /** 268 | * SEO component that queries for data with 269 | * Gatsby's useStaticQuery React hook 270 | * 271 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 272 | */ 273 | 274 | import React from 'react' 275 | import PropTypes from 'prop-types' 276 | import Helmet from 'react-helmet' 277 | import { useStaticQuery, graphql } from 'gatsby' 278 | 279 | export default SEO({ description = '', lang = 'en', meta = [], title = '' }) { 280 | const { site } = useStaticQuery( 281 | graphql` 282 | query { 283 | site { 284 | siteMetadata { 285 | title 286 | description 287 | author 288 | } 289 | } 290 | } 291 | `, 292 | ) 293 | 294 | const metaDescription = description || site.siteMetadata.description 295 | 296 | return ( 297 | 338 | ) 339 | } 340 | ``` 341 | -------------------------------------------------------------------------------- /notes-2hr/01a - Gatsby Themes.md: -------------------------------------------------------------------------------- 1 | # Gatsby Themes 2 | 3 | ## Plugins on Steroids 4 | 5 | Gatsby Configuration can be a pain, especially for the less technical. Gatsby Themes aim to bundle up configurations and make them installable and reusable. We'll try some Gatsby themes and see how simple it is. 6 | 7 | > Note: Themes are [a recent addition](https://www.gatsbyjs.org/docs/themes/introduction/) to Gatsby, but backwards compatible, so Themes are exactly interchangeable with Plugins and have the same exact usage syntax. They just have extra abilities to ship UI components. 8 | 9 | ## How to install a theme 10 | 11 | We'll try with a simple example: 12 | 13 | ```bash 14 | npm i gatsby-theme-amsterdam 15 | ``` 16 | 17 | Add it as a plugin inside `gatsby-config.js`. If there are no options to pass, it is a simple string: 18 | 19 | ```js 20 | module.exports = { 21 | // make sure siteMetadata has the data that your theme expects 22 | 23 | siteMetadata: { 24 | anything: 'I want', 25 | title: `JAMstack Jumpstart`, 26 | description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, 27 | author: `@swyx`, 28 | menuLinks: [ 29 | { 30 | name: 'Home', 31 | slug: '/', 32 | }, 33 | { 34 | name: 'About', 35 | slug: '/about/', 36 | }, 37 | ], 38 | footerLinks: [ 39 | { 40 | name: 'Gatsby', 41 | url: 'https://www.twitter.com/gatsbyjs', 42 | }, 43 | { 44 | name: 'Netlify', 45 | url: 'https://www.twitter.com/netlify', 46 | }, 47 | ], 48 | }, 49 | // here is the theme 50 | plugins: ['gatsby-theme-amsterdam'], 51 | } 52 | ``` 53 | 54 | However, if there are options to pass, you have to use the object syntax: 55 | 56 | ```js 57 | // just for illustration, we won't do this right now 58 | module.exports = { 59 | // ... 60 | plugins: [ 61 | { 62 | resolve: `gatsby-theme-netlify-identity`, 63 | options: { 64 | url: `https://gatsby-theme-netlify-identity.netlify.com/`, 65 | }, 66 | }, 67 | ], 68 | } 69 | ``` 70 | 71 | ## Required Data and Content 72 | 73 | It is left up to themes to design their developer experience, and so you will get a very widely varied experience. Many themes require `siteMetadata` in a specific format. Most themes also require you to supply content, in a configurable folder usually named `content`, and may also require you to put some sample images in the right places before they start working correctly. 74 | 75 | This is because the community is still figuring out the right conventions for what should be provided out of the box and how to gracefully fail over. Please have patience. Look at provided demos and/or look at the theme source code to see what is going on. 76 | 77 | For example, `gatsby-theme-amsterdam` requires `menuLinks` and `footerLinks` like we demonstrated above. 78 | 79 | It also requires markdown and images: 80 | 81 | [`/content/groceries`](https://github.com/ryanwiemer/gatsby-theme-amsterdam/tree/master/site/content/groceries-on-the-move): 82 | 83 | ```md 84 | --- 85 | title: Groceries On The Move 86 | date: '2019-07-05' 87 | cover: 'cover.jpg' 88 | tags: ['photography', 'cycling'] 89 | --- 90 | 91 | Vestibulum quis est iaculis, euismod lacus sit amet, tincidunt ante. Duis convallis urna tincidunt, venenatis augue ut, tincidunt est. Duis eget ornare dui. Nunc imperdiet eu nisl vel aliquet. Sed venenatis eleifend libero a pharetra. Fusce tincidunt est nunc, eget vulputate magna luctus in. Quisque id eros mollis, ullamcorper sem in, accumsan ex. Suspendisse non sollicitudin mauris. Vivamus ac arcu non lectus auctor dapibus. Phasellus nec sapien in felis aliquam hendrerit quis id erat. Aliquam tempus, magna nec viverra consectetur, leo enim mollis neque, a consectetur orci justo in magna. Nulla ullamcorper sed sem a tempus. Vivamus ut dui nec orci vestibulum maximus vitae at libero. 92 | ``` 93 | 94 | with a corresponding colocated image for `cover.jpg` (pull one from https://unsplash.com/) 95 | 96 | ## Themes to try 97 | 98 | - `gatsby-theme-amsterdam` 99 | - Source: https://github.com/ryanwiemer/gatsby-starter-amsterdam 100 | - Demo: https://gatsby-starter-amsterdam.netlify.com/ 101 | - `emulsify-gatsby-theme-jam` 102 | - Source: https://github.com/fourkitchens/emulsify-gatsby-theme-jam 103 | - Demo: https://my-design-system-emulsify.netlify.com 104 | - (advanced) `gatsby-theme-waves` 105 | - Source: https://github.com/pomber/gatsby-theme-waves 106 | - Demo: https://gatsby-theme-waves.netlify.com/ 107 | 108 | More themes: https://www.gatsbyjs.org/plugins/?=gatsby-theme (note: some may require more work to set up!) 109 | 110 | ## Further Reading 111 | 112 | - [Docs](https://www.gatsbyjs.org/docs/themes/introduction/) 113 | - [Getting Started Instructions](https://www.gatsbyjs.org/blog/2019-02-26-getting-started-with-gatsby-themes/) 114 | - [Why Themes?](https://www.gatsbyjs.org/blog/2019-01-31-why-themes/#reach-skip-nav) ([Video](https://www.youtube.com/watch?v=wX84vXBpMR8&feature=youtu.be)) 115 | - Creating a Gatby Theme - [Egghead.io video (paid)](https://egghead.io/lessons/gatsby-creating-a-gatsby-theme-with-john-otander) 116 | - Make your own theme: https://www.youtube.com/watch?v=1zuLpkV0jK0 117 | -------------------------------------------------------------------------------- /notes-2hr/02 - Gatsby Plugins.md: -------------------------------------------------------------------------------- 1 | # Gatsby Plugins 2 | 3 | > This is the hardest part of Gatsby - It is OK to feel lost! Just be patient and ask a lot of questions. 4 | 5 | > First, we will do some reading and theory, and then practice in a couple of exercises. Have patience. 6 | 7 | You will set up Gatsby Plugins in the plugins field in `gatsby-config.js`: 8 | 9 | ```js 10 | // gatsby-config.js 11 | module.exports = { 12 | siteMetadata: { 13 | // you already know this part 14 | }, 15 | plugins: [ 16 | // your list of plugins here! 17 | // 18 | // plugin without options looks like: 19 | // "gatsby-plugin-here" 20 | // 21 | // plugin with options looks like: 22 | // 23 | // { 24 | // resolve: `gatsby-source-filesystem`, 25 | // options: { 26 | // name: `images`, 27 | // path: path.join(__dirname, `src`, `images`), 28 | // }, 29 | // }, 30 | // yes it looks ugly but it gives plugin authors and users a lot of power 31 | ] 32 | } 33 | ``` 34 | 35 | You can search the almost 1000 available plugins in [the Gatsby Plugin Library](https://www.gatsbyjs.org/plugins/) and [read the Plugin docs here](https://www.gatsbyjs.org/docs/plugins/). 36 | 37 | ## Styling 38 | 39 | All forms of styling methods are supported (regular CSS, CSS modules, SASS/LESS, etc) but we will just focus on `styled-components` here. 40 | 41 | ```js 42 | import styled from "styled-components" 43 | 44 | const CardStyles = styled.div` 45 | padding: 10px; 46 | background: green; 47 | h2 { 48 | font-size: 20px; 49 | } 50 | p { 51 | font-style: italic; 52 | } 53 | img { 54 | float: left; 55 | } 56 | ` 57 | ``` 58 | 59 | When we run this we get a Flash of Unstyled Content, because we are waiting for the JS to parse before we can display the styles. To address this, we need to add [`gatsby-plugin-styled-components`](https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled). 60 | 61 | ## Source plugins 62 | 63 | At its base, you could just have a Gatsby site that has static pages. But, you likely have data that needs to be pulled in to populate the site. 64 | 65 | Data can come from anywhere: 66 | 67 | - Raw Data: _REST APIs, CSV, etc_... 68 | - Headless CMS: _WordPress, Netlify CMS, Contentful, Sanity, Prismic_... 69 | - Files: _Markdown, txt. etc_... 70 | 71 | Since Gatsby is generated at build time, the data isn't loaded _when the user loads the page_. The data is loaded _when you generate the page_. The benefit is that it's super fast for users, but the downside is that you need to have all your data at build time. 72 | 73 | So—once you have your data—how do you get it into Gatsby? Answer: via _Source plugins_. There are dozens of source plugins available for your data type. 74 | 75 | Once this data is available from sources, you can also _transform_ it: _e.g. transforming markdown to HTML, compressing images, generating offline views, making an RSS feed..., you name it_! 76 | 77 | Finally all this data is made available to your website via a single GraphQL API. We can write queries to pull this data into our site, which will then turn static during the build. 78 | 79 | > The first and most important source plugin to know is `gatsby-source-filesystem`. You'll use it to tell Gatsby to parse an entire folder of source files. 80 | 81 | ## Exercise: Add the `/content` folder 82 | 83 | > Big picture: we are going to generate new pages in Gatsby by adding Markdown files, instead of adding JS files! 84 | 85 | [Read the docs for `gatsby-source-filesystem`](https://www.gatsbyjs.org/docs/sourcing-from-the-filesystem/). 86 | 87 | ```js 88 | // gatsby-config.js 89 | module.exports = { 90 | // ... 91 | plugins: [ 92 | { 93 | resolve: `gatsby-source-filesystem`, // make sure it is installed! 94 | options: { 95 | name: `content`, 96 | path: `${__dirname}/content` 97 | } 98 | } 99 | ] 100 | } 101 | ``` 102 | 103 | Now you can see your markdown files in GraphiQL! http://localhost:8000/__graphql 104 | 105 | ## Transformer plugins 106 | 107 | However, how do you teach Gatsby to _read_ your markdown files? With `gatsby-transformer-remark`! 108 | 109 | ```js 110 | // gatsby-config.js 111 | module.exports = { 112 | // ... 113 | plugins: [ 114 | { 115 | resolve: `gatsby-source-filesystem`, 116 | options: { 117 | name: `content`, 118 | path: `${__dirname}/content` 119 | } 120 | }, 121 | `gatsby-transformer-remark` // new 122 | ] 123 | } 124 | ``` 125 | 126 | Now rerun GraphiQL. See the new Markdown nodes? 127 | 128 | > Tip: gatsby-transformer-remark is a HUGE plugin, it even has it's own plugins! [Check out the remark ecosystem in the Plugin Library.](https://www.gatsbyjs.org/plugins/?=remark) 129 | 130 | ## Programmatically creating pages 131 | 132 | This has two steps: 133 | 134 | - first, define a template to render your markdown data with. 135 | - second, pass the data through the template with the `createPages` API! 136 | 137 | Here's a sample template you can use: 138 | 139 | ```js 140 | // src/templates/pageTemplate.js 141 | import React from "react" 142 | import { graphql } from "gatsby" 143 | 144 | export default function Template({ 145 | data // this prop will be injected by the GraphQL query below. 146 | }) { 147 | const { markdownRemark } = data // data.markdownRemark holds our post data 148 | const { frontmatter, html } = markdownRemark 149 | return ( 150 |
151 |
152 |

{frontmatter.title}

153 |

{frontmatter.date}

154 |
155 |
156 |
157 | ) 158 | } 159 | 160 | export const pageQuery = graphql` 161 | query($path: String!) { 162 | markdownRemark(frontmatter: { path: { eq: $path } }) { 163 | html 164 | frontmatter { 165 | date(formatString: "MMMM DD, YYYY") 166 | path 167 | title 168 | } 169 | } 170 | } 171 | ` 172 | ``` 173 | 174 | Now head to `gatsby-node.js` to connect the data with your templates! 175 | 176 | > Note: this is the hardest part - be careful and [study the Gatsby Node docs](https://www.gatsbyjs.org/docs/node-apis/) if you get stuck! Using [the helpers](https://www.gatsbyjs.org/docs/node-api-helpers/) can be very.. helpful for repetitive stuff. 177 | 178 | ```js 179 | // gatsby-node.js 180 | const path = require(`path`) 181 | 182 | exports.createPages = ({ actions, graphql }) => { 183 | const { createPage } = actions 184 | 185 | const pageTemplate = path.resolve(`src/templates/pageTemplate.js`) 186 | 187 | return graphql(` 188 | { 189 | allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }, limit: 1000) { 190 | edges { 191 | node { 192 | frontmatter { 193 | path 194 | } 195 | } 196 | } 197 | } 198 | } 199 | `).then((result) => { 200 | if (result.errors) { 201 | return Promise.reject(result.errors) 202 | } 203 | 204 | return result.data.allMarkdownRemark.edges.forEach(({ node }) => { 205 | createPage({ 206 | path: node.frontmatter.slug, 207 | component: pageTemplate, 208 | context: {} 209 | }) 210 | }) 211 | }) 212 | } 213 | ``` 214 | 215 | ## Exercises 216 | 217 | 1. Try adding `gatsby-remark-oembed` and embedding Tweets in your markdown! https://www.gatsbyjs.org/packages/@raae/gatsby-remark-oembed/?=oembed See [instructions](https://paper.dropbox.com/doc/7-Plugging-In-Third-Party-Services--AfA2muEZfpSlGd3LiB62zyIQAg-4m0smdgjiMo2ds4HleEFR) if you get stuck. 218 | -------------------------------------------------------------------------------- /notes-2hr/02a - Gatsby Image.md: -------------------------------------------------------------------------------- 1 | # Gatsby Image 2 | 3 | One of the best things about Gatsby is that because everything (text, images, files, data...) goes through gatsby, we're able to use plugins to massage that data before it gets outputted on the page. 4 | 5 | A huge use case for this is with images. 6 | 7 | For a speedy website, images may need to be: 8 | 9 | - compressed 10 | - converted to different formats 11 | - resized 12 | - lazy loaded 13 | 14 | These things are great for perf, but hard to do on most sites. Gatsby makes it easy! 15 | 16 | ## Show Me 17 | 18 | https://using-gatsby-image.gatsbyjs.org 19 | 20 | ## Images in React Components 21 | 22 | If you are inside a component, just import your image like so: 23 | 24 | ```js 25 | import dog from "../images/dog.jpg" 26 | ``` 27 | 28 | That will give you a path to the statically generated image, which can be used like so: 29 | 30 | ```jsx 31 | Cute Pup 32 | ``` 33 | 34 | Now this image is still huge! So we want to use a plugin called [gatsby-image](https://www.gatsbyjs.org/packages/gatsby-image/), which in turn will use a package called `sharp` to resize, compress, and provide other image benefits. 35 | 36 | Now does Gatsby know about our images? Not yet! We need to source them, and then let a plugin do the heavy lifting. Add these to your plugins array: 37 | 38 | ```js 39 | // gatsby-config.js 40 | 41 | { 42 | resolve: `gatsby-source-filesystem`, 43 | options: { 44 | name: `images`, 45 | path: path.join(__dirname, `src`, `images`), 46 | }, 47 | }, 48 | `gatsby-transformer-sharp`, 49 | `gatsby-plugin-sharp`, 50 | ``` 51 | 52 | Now here is where Gatsby falls short at the moment. 53 | 54 | If you want to display an image that has been transformed, we need to access it like we do everything else in Gatsby: GraphQL Queries. Then, use the Gatsby-image `Img` component to display it. 55 | 56 | So in order to display an image, we need to write a query like the one in the [docs](https://www.gatsbyjs.org/packages/gatsby-image/). 57 | 58 | The one in the docs is a page query. The other type of query in Gatsby is a "static query" which can be done in any component. 59 | 60 | The downside to static queries is that they aren't dynamic. That is, you can't pass it variables: e.g. an `` src. 61 | 62 | More info here: 63 | 64 | The best approach right now is to make our own component that will query all images, and then return the one we are looking for. 65 | 66 | Make a new file in `components/Img.js`: 67 | 68 | ```js 69 | // Img.js 70 | 71 | import React from "react" 72 | import { useStaticQuery, graphql } from "gatsby" 73 | import Img from "gatsby-image" 74 | 75 | export default function Image({ src, alt }) { 76 | const { allImageSharp } = useStaticQuery(graphql` 77 | query { 78 | allImageSharp { 79 | edges { 80 | node { 81 | fluid(maxWidth: 500) { 82 | ...GatsbyImageSharpFluid_withWebp_tracedSVG 83 | originalName 84 | } 85 | } 86 | } 87 | } 88 | } 89 | `) 90 | const image = allImageSharp.edges.find((edge) => edge.node.fluid.originalName === src) 91 | if (!image) { 92 | return null 93 | } 94 | return {alt} 95 | } 96 | ``` 97 | 98 | Then to use it, simply import this new component and use it like so: 99 | 100 | ```js 101 | import Img from "../components/Img" 102 | ;Cute Pup 103 | ``` 104 | 105 | ## Images in MDX 106 | 107 | Now if you want to have images in your mdx content, it's a little bit easier. We simply let the plugins sniff out the images from our markdown and handle it all for it. 108 | 109 | Put a few images into a tip: 110 | 111 | ```mdx 112 | ![](../images/dog.jpg) 113 | ![](../images/cabin.jpg) 114 | ``` 115 | 116 | Then we need to tell our `gatsby-mdx` how to handle the images in our `gatsby-config.js` file. This isn't a new plugin, but we modify the `gatsby-mdx`: 117 | 118 | ```js 119 | // gatsby-config.js 120 | 121 | { 122 | resolve: 'gatsby-mdx', 123 | options: { 124 | root: __dirname, 125 | gatsbyRemarkPlugins: [ 126 | { 127 | resolve: 'gatsby-remark-images', 128 | options: { 129 | maxWidth: 500, 130 | linkImagesToOriginal: false, 131 | }, 132 | }, 133 | ], 134 | }, 135 | }, 136 | ``` 137 | 138 | And that is it! See the [docs](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-images#options) for the possible options here. 139 | -------------------------------------------------------------------------------- /notes-2hr/02b - Gatsby Lifecycle.md: -------------------------------------------------------------------------------- 1 | # Gatsby Lifecycle 2 | 3 | STUDY THIS and you will actually know what the hell is going on in Gatsby: 4 | 5 | - https://www.gatsbyjs.org/docs/gatsby-lifecycle-apis/ 6 | - (simpler draft) https://gist.github.com/sw-yx/09306ec03df7b4cd8e7469bb74c078fb 7 | -------------------------------------------------------------------------------- /notes-2hr/03 - Intro to JAMstack.md: -------------------------------------------------------------------------------- 1 | # Intro to JAMstack 2 | 3 | The JAMstack is a modern web architecture: helping people create fast and secure sites and dynamic apps with JavaScript, APIs, and prerendered Markup, served without web servers. 4 | 5 | More introductions: 6 | 7 | - https://noti.st/philhawksworth/LuQZm6/getting-stuck-in-to-jamstack 8 | - https://noti.st/philhawksworth/tWfQIB/jamstack-silly-name-serious-stuff 9 | 10 | ## First things first 11 | 12 | Kick off a build while we talk 13 | 14 | - Click to deploy [Dimension Starter](https://app.netlify.com/start/deploy?repository=https://github.com/codebushi/gatsby-starter-dimension) 15 | - Click to deploy [Overreacted.io](https://app.netlify.com/start/deploy?repository=https://github.com/gaearon/overreacted.io) 16 | - Click to deploy [lengstorf.com](https://app.netlify.com/start/deploy?repository=https://github.com/jlengstorf/lengstorf.com) 17 | - Click to deploy [React docs](https://app.netlify.com/start/deploy?repository=https://github.com/reactjs/reactjs.org) 18 | - Fork and Deploy [Hero Blog Starter](https://github.com/greglobinski/gatsby-starter-hero-blog) 19 | 20 | ## Why now? 21 | 22 | JAMstack combines several trends and best practices: 23 | 24 | - Git based workflow 25 | - Build Tools (e.g. Webpack, Babel, TypeScript) in JS 26 | - Serverless Functions 27 | - API Economy 28 | - Next Generation Static Site Generators 29 | 30 | JAMstack has a strong opinion on static assets, but uses modern JavaScript and API's to achieve dynamic behavior, the same as mobile apps. No one thinks of mobile apps as "static" but they are indeed static assets! Indeed these are good usecases for JAMstack: 31 | 32 | - Blogs like [Smashing Magazine](https://www.netlify.com/blog/2017/03/16/smashing-magazine-just-got-10x-faster/) 33 | - Marketing sites like [Netlify.com](http://netlify.com) 34 | - Ecommerce sites like https://store.gatsbyjs.org/ 35 | - Authenticated apps with serverless functions and databases like https://app.netlify.com 36 | 37 | These usecases are more difficult with JAMstack: 38 | 39 | - Rapidly updating prerendered content 40 | - Server Session based authenticated apps 41 | 42 | Projects made with these are JAMstack: 43 | 44 | - `create-react-app` 45 | - Gatsby 46 | - React-Static 47 | - Next/Nuxt (static export mode) 48 | - Vue CLI 49 | - Hugo 50 | - Jekyll 51 | - Eleventy 52 | - (and many more) 53 | 54 | Projects made with these are _not_ JAMstack: 55 | 56 | - Squarespace 57 | - Wordpress 58 | - Drupal (unless used headlessly) 59 | - other server-run web apps 60 | 61 | We'll explain more in the workshop live, but you can get more information here: 62 | 63 | - http://jamstack.org 64 | - Mathias (Netlify Founder)'s talk: [The New Front End Stack](https://vimeo.com/163522126) 65 | - Swyx's talk: [JAMStack - The Total Victory of JavaScript](https://www.youtube.com/watch?v=vOUcPI2mljU) 66 | - Chris Coyier's talk: [The All Powerful Frontend Developer](https://www.youtube.com/watch?v=grSxHfGoaeg) and [Oops, We're Full Stack Now](https://full-stack.netlify.com/) and [JAMstack? More like SHAMstack.](https://css-tricks.com/jamstack-more-like-shamstack/) 67 | - Chris Coyier on CSS Tricks: [JAMstack? More like SHAMstack](https://css-tricks.com/jamstack-more-like-shamstack/) 68 | - [a16z on Netlify and JAMstack](https://www.netlify.com/blog/2017/08/09/netlify-raises-12m-from-a16z/) 69 | - [CRV's JAMstack Landscape](https://medium.com/crv-insights/the-jamstack-startup-landscape-c06cc3cdb917) 70 | 71 | ## Homework 72 | 73 | - Fork and Deploy [Ecommerce example](https://app.netlify.com/start/deploy?repository=https://github.com/parmsang/gatsby-starter-ecommerce) (currently has some bugs, beware/figure it out!) 74 | - Fork and deploy [Gatsby Contentful Starter](https://github.com/contentful-userland/gatsby-contentful-starter) 75 | - Click to deploy [Gatsby Shopify Starter](https://app.netlify.com/start/deploy?repository=https://github.com/AlexanderProd/gatsby-shopify-starter) 76 | -------------------------------------------------------------------------------- /notes-2hr/03a - Intro to Netlify.md: -------------------------------------------------------------------------------- 1 | # Intro to Netlify 2 | 3 | ## Brief History 4 | 5 | Netlify was founded in 2014 as BitBalloon, a drag-and-drop static site host. As [static site generators grew in popularity](https://www.smashingmagazine.com/2015/11/modern-static-website-generators-next-big-thing/), the company started adding build services and built in increasingly more CDN-like features like configurable redirects and headers. It also added Continuous Deployment, Deploy Previews, and Split Testing, all based on Git workflow. 6 | 7 | Other built-in services have also been added over time. [Form handling](https://www.netlify.com/docs/form-handling/) was added almost from the start. 8 | 9 | In 2017 it introduced [Netlify Identity](https://www.netlify.com/blog/2017/09/07/introducing-built-in-identity-service-to-streamline-user-management/) for user authentication. 10 | 11 | In 2018 it added the ability to [serve AWS Lambda functions](https://www.netlify.com/docs/functions/) with the same minimal config developer experience as the rest of Netlify. 12 | 13 | In 2019 to date it has added local development and testing tools with [Netlify Dev](https://github.com/netlify/netlify-dev-plugin/), as well as [server-side analytics](https://www.netlify.com/blog/2019/07/10/netlify-analytics---accurate-insights-without-performance-impacts/). 14 | 15 | ## Where are we now? 16 | 17 | Netlify now exists entirely to serve the growing JAMstack category. A core principle of the platform is simplicity arising from the static asset serving model, but also technology agnosticism with regards to static site generator technologies. Therefore, sites based on Go to Ruby to Python to JS are all supported, as long as they build to static artefacts. 18 | 19 | Netlify heavily dogfoods. `app.netlify.com` is run on Netlify and we will see an example of how to make changes and preview them. 20 | 21 | ## NetlifyCMS vs Netlify 22 | 23 | There is also an open source project called [NetlifyCMS](http://netlifycms.org), supported by but independently operated from Netlify, which offers a git-based, markdown based CMS solution that doesn't require a running/third party server. It doesn't require Netlify, nor does Netlify require it. 24 | -------------------------------------------------------------------------------- /notes-2hr/03b - Netlify + Gatsby.md: -------------------------------------------------------------------------------- 1 | # Netlify + Gatsby 2 | 3 | Gatsby and Netlify work very well together, however neither requires the other. 4 | 5 | ## Gatsby + NetlifyCMS 6 | 7 | The [top starter](https://www.gatsbyjs.org/starters/?v=2) after the official Gatsby Starter Blog is [gatsby-starter-netlify-cms](https://www.gatsbyjs.org/starters/netlify-templates/gatsby-starter-netlify-cms/), which shows how to integrate and deploy a git based CMS alongside Gatsby and edit and preview them together. You can try this yourself with a one click deploy: 8 | 9 | Deploy to Netlify 10 | 11 | ## Gatsby + Netlify Functions 12 | 13 | Gatsby apps rehydrate into full clientside apps powered by JavaScript, and often this means needing custom APIs for proxying APIs with secrets or communicating with databases. Netlify Functions offer a trivial way to write custom APIs for exactly this purpose. A full discussion of [Turning The Static Dynamic](https://www.gatsbyjs.org/blog/2018-12-17-turning-the-static-dynamic/) is a very popular blogpost. 14 | 15 | ## Gatsby + Netlify Identity 16 | 17 | Authentication is also a common need with Gatsby based apps and a Netlify Identity plugin is also available: http://gatsby-theme-netlify-identity.netlify.com 18 | -------------------------------------------------------------------------------- /notes-2hr/04 - Intro to Serverless.md: -------------------------------------------------------------------------------- 1 | # Intro to Serverless 2 | 3 | Slides: https://docs.google.com/presentation/d/1AbU-4GlPPp66rYjOJci82K7j8Pa6O479Kl2ShP7mHSE/edit?usp=sharing 4 | 5 | ## Why Serverless? 6 | 7 | - Pay per execution pricing 8 | - Never pay for idle servers 9 | - Auto scales for you 10 | - Event driven workflows 11 | - Leverage third party services 12 | 13 | ## Introductions to Serverless 14 | 15 | - [Applying the Serverless Mindset to Any Tech Stack](https://www.youtube.com/watch?v=8Rzv68K8ZOY) 16 | - [Serverless Architectural Patterns](https://medium.com/@eduardoromero/serverless-architectural-patterns-261d8743020) 17 | - [Serverless Microservice Patterns for AWS](https://www.jeremydaly.com/serverless-microservice-patterns-for-aws/) 18 | - [Production-Ready Serverless](https://www.manning.com/livevideo/production-ready-serverless) 19 | - [Cloud Native Development Patterns & Best Practices](https://www.amazon.com/Cloud-Native-Development-Patterns-Practices/dp/1788473922) 20 | - [JavaScript Cloud Native Development Cookbook](https://www.amazon.com/JavaScript-Cloud-Native-Development-Cookbook/dp/1788470419) 21 | - [Serverless framework workshop](https://github.com/DavidWells/serverless-workshop) 22 | - [Yos Riady's intro](https://docs.google.com/presentation/d/129ShJ6VGN_h1Hga5sqiXslAxdvLLBoEZKVkgehUXURs/edit#slide=id.g37dd1a6a4c_0_29) 23 | - [AWS Reinvent: The State of Serverless Computing](https://www.youtube.com/watch?v=AcGv3qUrRC4) from VP of AWS Lambda 24 | - https://github.com/DavidWells/serverless-workshop Do all exercises 25 | 26 | ## Examples of Apps you can build with Gatsby 27 | 28 | - https://github.com/MozillaDevelopers/playground 29 | - https://github.com/howtographql/howtographql 30 | - https://github.com/DSchau/gatsby-mail 31 | - https://github.com/gatsbyjs/store.gatsbyjs.org 32 | - https://github.com/sw-yx/jamstack-hackathon-starter 33 | -------------------------------------------------------------------------------- /notes-4hr/00 - Welcome.md: -------------------------------------------------------------------------------- 1 | # Welcome! 2 | 3 | There are a few things you'll need to get setup for today: 4 | 5 | 1. A laptop with the latest version of [Node.js](https://nodejs.org) installed. 6 | 1. An IDE or text editor like VS Code 7 | 1. A terminal 8 | 9 | ## What to Expect From Today 10 | 11 | Today we are going to learn about the JAMstack and build a few JAMstack sites with Gatsby. We are going to cover: 12 | 13 | 1. Intro to JAMstack (30 mins) 14 | 1. Intro to Gatsby (30 mins) 15 | 1. Exercise I (30 mins) 16 | 1. Gatsby Plugins (and Gatsby Image) (30 mins) 17 | 1. Exercise II (30 mins) 18 | 1. Gatsby Themes (10 mins) 19 | 1. Intro to Serverless (30 mins) 20 | 1. Amplify CLI (30 mins) 21 | 22 | ## These Notes 23 | 24 | These notes aren't comprehensive — more of a landing spot to grab the code if you get stuck. We will try and code as much of the code by hand, but if you misspell something or misplaced a curly bracket, feel free to grab the code from the notes or from the finished files. 25 | -------------------------------------------------------------------------------- /notes-4hr/01 - Intro to JAMstack.md: -------------------------------------------------------------------------------- 1 | # Intro to JAMstack 2 | 3 | The JAMstack is a modern web architecture: helping people create fast and secure sites and dynamic apps with JavaScript, APIs, and prerendered Markup, served without web servers. 4 | 5 | ## First things first 6 | 7 | Kick off a build while we talk 8 | 9 | - Click to deploy [Dimension Starter](https://console.aws.amazon.com/amplify/home?region=us-east-1#/deploy?repo=https://github.com/codebushi/gatsby-starter-dimension) 10 | - Click to deploy [Overreacted.io](https://console.aws.amazon.com/amplify/home?region=us-east-1#/deploy?repo=https://github.com/gaearon/overreacted.io) 11 | - Click to deploy [lengstorf.com](https://console.aws.amazon.com/amplify/home?region=us-east-1#/deploy?repo=https://github.com/jlengstorf/lengstorf.com) 12 | - Click to deploy [React docs](https://console.aws.amazon.com/amplify/home?region=us-east-1#/deploy?repo=https://github.com/reactjs/reactjs.org) 13 | - Fork and Deploy [Hero Blog Starter](https://github.com/greglobinski/gatsby-starter-hero-blog) 14 | 15 | ## Why now? 16 | 17 | JAMstack combines several trends and best practices: 18 | 19 | - Git based workflow 20 | - Build Tools (e.g. Webpack, Babel, TypeScript) in JS 21 | - Serverless Functions 22 | - API Economy 23 | - Next Generation Static Site Generators 24 | 25 | JAMstack has a strong opinion on static assets, but uses modern JavaScript and API's to achieve dynamic behavior, the same as mobile apps. No one thinks of mobile apps as "static" but they are indeed static assets! Indeed these are good usecases for JAMstack: 26 | 27 | - Blogs like [Smashing Magazine](https://www.netlify.com/blog/2017/03/16/smashing-magazine-just-got-10x-faster/) 28 | - Marketing sites like [Netlify.com](http://netlify.com) 29 | - Ecommerce sites like https://store.gatsbyjs.org/ 30 | - Authenticated apps with serverless functions and databases like https://app.netlify.com 31 | 32 | These usecases are more difficult with JAMstack: 33 | 34 | - Rapidly updating prerendered content 35 | - Server Session based authenticated apps 36 | 37 | Projects made with these are JAMstack: 38 | 39 | - `create-react-app` 40 | - Gatsby 41 | - React-Static 42 | - Next/Nuxt (static export mode) 43 | - Vue CLI 44 | - Hugo 45 | - Jekyll 46 | - Eleventy 47 | - (and many more) 48 | 49 | Projects made with these are _not_ JAMstack: 50 | 51 | - Squarespace 52 | - Wordpress 53 | - Drupal (unless used headlessly) 54 | - other server-run web apps 55 | 56 | We'll explain more in the workshop live, but you can get more information here: 57 | 58 | - http://jamstack.org 59 | - Mathias (Netlify Founder)'s talk: [The New Front End Stack](https://vimeo.com/163522126) 60 | - Swyx's talk: [JAMStack - The Total Victory of JavaScript](https://www.youtube.com/watch?v=vOUcPI2mljU) 61 | - Chris Coyier's talk: [The All Powerful Frontend Developer](https://www.youtube.com/watch?v=grSxHfGoaeg) 62 | - Chris Coyier on CSS Tricks: [JAMstack? More like SHAMstack](https://css-tricks.com/jamstack-more-like-shamstack/) 63 | - [a16z on Netlify and JAMstack](https://www.netlify.com/blog/2017/08/09/netlify-raises-12m-from-a16z/) 64 | - [CRV's JAMstack Landscape](https://medium.com/crv-insights/the-jamstack-startup-landscape-c06cc3cdb917) 65 | 66 | ## Homework 67 | 68 | - Fork and Deploy [Ecommerce example](https://console.aws.amazon.com/amplify/home?region=us-east-1#/deploy?repo=https://github.com/parmsang/gatsby-starter-ecommerce) (currently has some bugs, beware/figure it out!) 69 | - Fork and deploy [Gatsby Contentful Starter](https://github.com/contentful-userland/gatsby-contentful-starter) 70 | - Click to deploy [Gatsby Shopify Starter](https://app.netlify.com/start/deploy?repository=https://github.com/AlexanderProd/gatsby-shopify-starter) 71 | -------------------------------------------------------------------------------- /notes-4hr/02 - Intro to Gatsby.md: -------------------------------------------------------------------------------- 1 | # Intro to Gatsby 2 | 3 | ## Starter Files 4 | 5 | Gatsby provides a number of starter projects on their site. [You can see them here](https://www.gatsbyjs.org/starters/?v=2). 6 | 7 | I am providing you a few starter files, including a `package.json` detailing all the packages we need for today. 8 | 9 | Go ahead and cd into `site` and run `npm install`. 10 | 11 | Then to start our application we type `npm start`. 12 | 13 | ## Questions 14 | 15 | Feel free to ask questions at any time! My style is pretty off the cuff so I'm happy to stop and go down the roads we need to. 16 | 17 | ## Gatsby 101 18 | 19 | So, what is Gatsby? It's a framework for creating websites with `React.js`. Gatsby is considered a "_static site generator_" which means that before you put your website up online, you run a build command that will compile your website into a set of HTML, CSS and JS (React) files. 20 | 21 | This makes your website extremely fast. But Gatsby isn't _just_ another static site gen; it's much more than that. 22 | 23 | Gatsby makes it easy to build a website with all of today's best practices at the forefront, _not_ an after thought. This includes code splitting, pre-loaded routes, image loading and compression, offline ready and so much more. Along with amazing user experiences, the gatsby developer experience is fast, hot-reloaded and easily deployable. 24 | 25 | ### Pages + Routing 26 | 27 | At its core, Gatsby has pages. You know what pages are, right? Want a page called `/about`? Make an `about.js` and export a React component. 28 | 29 | Gatsby also includes a Router, which by using their `About` component, will allow you to both pre-load that page as well as use HTML5 pushstate to change the page without a browser reload. 30 | 31 | Gatsby also includes a set of APIs for dynamically creating pages — more soon. 32 | 33 | ## Exercise: Creating Pages 34 | 35 | So, let's make sure we have things up and running! 36 | 37 | Let's make a new page called `index.js` and `about.js`. These pages just need to default export a React component (any type will do)! 38 | 39 | ```js 40 | // index.js 41 | import React from "react" 42 | 43 | export default function HomePage(props) { 44 | return ( 45 |
46 |

I am the home page

47 |
48 | ) 49 | } 50 | 51 | // about.js 52 | import React from "react" 53 | 54 | export default function AboutPage(props) { 55 | return ( 56 |
57 |

I am the about page

58 |
59 | ) 60 | } 61 | ``` 62 | 63 | Now you can see your pages at `localhost:8000`. 64 | 65 | > Tip: What if someone typo's your url? In development, Gatsby provides you a default 404 page, but you can also make a `src/pages/404.js` custom 404 page. 66 | 67 | ## Layout 68 | 69 | Gatsby doesn't have a prescribed way of creating layouts like Next.js has `_app.js` and `_document.js`. It's just regular ol' React components on a page. 70 | 71 | Let's go ahead and make a `components/layout.js` component. 72 | 73 | > Tip: Unlike `src/pages`, `src/components` isn't a "magic directory". You can name it whatever you like. 74 | 75 | At it's simplest it looks like this: 76 | 77 | ```js 78 | // src/components/layout.js 79 | 80 | import React from 'react' 81 | 82 | export default function Layout({ children }) { 83 | return ( 84 |
85 |

My Website!

86 | {children} 87 |
88 | ) 89 | } 90 | ``` 91 | 92 | Now import that component into your pages and wrap your pages in it: 93 | 94 | ```js 95 | // index.js 96 | 97 | import Layout from '../components/layout' 98 | // ... 99 | export default function HomePage() { 100 | return ( 101 | 102 |

I'm the home page!

103 |
104 | ) 105 | } 106 | ``` 107 | 108 | ## GraphiQL and Site Metadata 109 | 110 | Now we really shouldn't hard code the data in out `layout.js`. So we can put all this data in a config file. 111 | 112 | In the root of your project you have a `gatsby-config.js` file. We will use this for configuring all our data sources and plugins in the future, but for now, we can also store site metadata. 113 | 114 | ```js 115 | // gatsby-config.js 116 | 117 | module.exports = { 118 | siteMetadata: { 119 | anything: 'I want', 120 | title: `JAMstack Jumpstart`, 121 | description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, 122 | author: `@swyx`, 123 | }, 124 | plugins: [], 125 | } 126 | ``` 127 | 128 | On most sites, we would just import this config and be done with it. But because gatsby is a a static site generator, Gatsby needs to be aware of the the data. 129 | 130 | Restart your application (`Ctrl + C` && `npm start`) and then open up the Graphiql interface at http://localhost:8000/__graphql 131 | 132 | We can run queries in this playground to see this data: 133 | 134 | ```graphql 135 | query { 136 | site { 137 | siteMetadata { 138 | title 139 | anything 140 | } 141 | } 142 | } 143 | ``` 144 | 145 | Now how do we get this data into our `layout.js`? 146 | 147 | Queries! 148 | 149 | There are two types of queries in Gatsby 150 | 151 | 1. **Page queries**: can be _dynamic_ but can _only be done inside a page_ 152 | 2. **Static Queries**: can be _done anywhere_, but have the limitation of _not being dynamic_. More on this when we hit images! 153 | 154 | To perform a query inside a component, first import a few things inside of `Layout.js`: 155 | 156 | ```js 157 | // Layout.js 158 | 159 | import { graphql, useStaticQuery } from 'gatsby' 160 | ``` 161 | 162 | and then inside our component, just before the return, we can run the query: 163 | 164 | ```js 165 | const data = useStaticQuery(graphql` 166 | query SiteData { 167 | site { 168 | siteMetadata { 169 | title 170 | } 171 | } 172 | } 173 | `) 174 | ``` 175 | 176 | We can then swap out that hard coded h1 with this: 177 | 178 | ```js 179 |

{data.site.siteMetadata.title}

180 | ``` 181 | 182 | > Tip: For older version of React and Gatsby, there is also a render prop component to do the same thing. But there's no reason to use it if you can `useStaticQuery` 😎 183 | 184 | ## and Static Routing 185 | 186 | Next, we have Routing. 187 | 188 | We have two pages: `/` and `/about`. 189 | 190 | Let's make a nav component which we can inject into our layout.js 191 | 192 | ```js 193 | // layout.js 194 | 195 | import React from 'react' 196 | import { Link } from 'gatsby' 197 | 198 | export default function Nav() { 199 | return ( 200 | 210 | ) 211 | } 212 | ``` 213 | 214 | Now you can click around your nav like a regular single page app. 215 | 216 | Gatsby Link component is the most common way to move from one page to another. It accepts a few props including `to`, `activeClassName` and `activeStyle`. 217 | 218 | [Take a look at the docs](https://www.gatsbyjs.org/docs/linking-between-pages/) and answer a few questions: 219 | 220 | - How to I programmatically change pages? 221 | - how do I style the active page? 222 | - How do I pass state from one page to another? 223 | 224 | ## Exercise 225 | 226 | 1. Make two more pages: a 404 page, and one other page 227 | 1. Make a footer component with your name and the current year in it. 228 | 1. Style the current page to be coloured differently 229 | 1. Extract your Nav to be a reusable component 230 | 1. Figure out how to do animated page transitions 231 | 1. [Learn more about dynamic routing](https://www.gatsbyjs.org/blog/2018-12-17-turning-the-static-dynamic/) 232 | 233 | ## Bonus: SEO 234 | 235 | Great SEO is a fantastic reason to adopt Gatsby. Nothing is friendlier to search engines than fast, pregenerated HTML. To give the right metadata for each page, we use [`react-helmet`](https://npm.im/react-helmet). 236 | 237 | The default Gatsby template provides an `SEO` element you can use, so just go ahead and import it and specify your page title: 238 | 239 | ```js 240 | // index.js 241 | import React from 'react' 242 | import { Link } from 'gatsby' 243 | 244 | import Layout from '../components/layout' 245 | import SEO from '../components/seo' 246 | 247 | const IndexPage = () => ( 248 | 249 | 250 |

Hi people

251 |

Welcome to your new Gatsby site.

252 |

Now go build something great.

253 | Go to page 2 254 |
255 | ) 256 | 257 | export default IndexPage 258 | ``` 259 | 260 | Feel free to read the docs of `react-helmet` and study the source code of `SEO` to see how it works. 261 | -------------------------------------------------------------------------------- /notes-4hr/03 - Gatsby Plugins.md: -------------------------------------------------------------------------------- 1 | # Gatsby Plugins 2 | 3 | > This is the hardest part of Gatsby - It is OK to feel lost! Just be patient and ask a lot of questions. 4 | 5 | > First, we will do some reading and theory, and then practice in a couple of exercises. Have patience. 6 | 7 | You will set up Gatsby Plugins in the plugins field in `gatsby-config.js`: 8 | 9 | ```js 10 | // gatsby-config.js 11 | module.exports = { 12 | siteMetadata: { 13 | // you already know this part 14 | }, 15 | plugins: [ 16 | // your list of plugins here! 17 | // 18 | // plugin without options looks like: 19 | // "gatsby-plugin-here" 20 | // 21 | // plugin with options looks like: 22 | // 23 | // { 24 | // resolve: `gatsby-source-filesystem`, 25 | // options: { 26 | // name: `images`, 27 | // path: path.join(__dirname, `src`, `images`), 28 | // }, 29 | // }, 30 | // yes it looks ugly but it gives plugin authors and users a lot of power 31 | ] 32 | } 33 | ``` 34 | 35 | You can search the almost 1000 available plugins in [the Gatsby Plugin Library](https://www.gatsbyjs.org/plugins/) and [read the Plugin docs here](https://www.gatsbyjs.org/docs/plugins/). 36 | 37 | ## Styling 38 | 39 | All forms of styling methods are supported (regular CSS, CSS modules, SASS/LESS, etc) but we will just focus on `styled-components` here. 40 | 41 | ```js 42 | import styled from "styled-components" 43 | 44 | const CardStyles = styled.div` 45 | padding: 10px; 46 | background: green; 47 | h2 { 48 | font-size: 20px; 49 | } 50 | p { 51 | font-style: italic; 52 | } 53 | img { 54 | float: left; 55 | } 56 | ` 57 | ``` 58 | 59 | When we run this we get a Flash of Unstyled Content, because we are waiting for the JS to parse before we can display the styles. To address this, we need to add [`gatsby-plugin-styled-components`](https://www.gatsbyjs.org/packages/gatsby-plugin-styled-components/?=styled). 60 | 61 | ## Source plugins 62 | 63 | At its base, you could just have a Gatsby site that has static pages. But, you likely have data that needs to be pulled in to populate the site. 64 | 65 | Data can come from anywhere: 66 | 67 | - Raw Data: _REST APIs, CSV, etc_... 68 | - Headless CMS: _WordPress, Netlify CMS, Contentful, Sanity, Prismic_... 69 | - Files: _Markdown, txt. etc_... 70 | 71 | Since Gatsby is generated at build time, the data isn't loaded _when the user loads the page_. The data is loaded _when you generate the page_. The benefit is that it's super fast for users, but the downside is that you need to have all your data at build time. 72 | 73 | So—once you have your data—how do you get it into Gatsby? Answer: via _Source plugins_. There are dozens of source plugins available for your data type. 74 | 75 | Once this data is available from sources, you can also _transform_ it: _e.g. transforming markdown to HTML, compressing images, generating offline views, making an RSS feed..., you name it_! 76 | 77 | Finally all this data is made available to your website via a single GraphQL API. We can write queries to pull this data into our site, which will then turn static during the build. 78 | 79 | > The first and most important source plugin to know is `gatsby-source-filesystem`. You'll use it to tell Gatsby to parse an entire folder of source files. 80 | 81 | ## Exercise: Add the `/content` folder 82 | 83 | > Big picture: we are going to generate new pages in Gatsby by adding Markdown files, instead of adding JS files! 84 | 85 | [Read the docs for `gatsby-source-filesystem`](https://www.gatsbyjs.org/docs/sourcing-from-the-filesystem/). 86 | 87 | ```js 88 | // gatsby-config.js 89 | module.exports = { 90 | // ... 91 | plugins: [ 92 | { 93 | resolve: `gatsby-source-filesystem`, // make sure it is installed! 94 | options: { 95 | name: `content`, 96 | path: `${__dirname}/content` 97 | } 98 | } 99 | ] 100 | } 101 | ``` 102 | 103 | Now you can see your markdown files in GraphiQL! http://localhost:8000/__graphql 104 | 105 | ## Transformer plugins 106 | 107 | However, how do you teach Gatsby to _read_ your markdown files? With `gatsby-transformer-remark`! 108 | 109 | ```js 110 | // gatsby-config.js 111 | module.exports = { 112 | // ... 113 | plugins: [ 114 | { 115 | resolve: `gatsby-source-filesystem`, 116 | options: { 117 | name: `content`, 118 | path: `${__dirname}/content` 119 | } 120 | }, 121 | `gatsby-transformer-remark` // new 122 | ] 123 | } 124 | ``` 125 | 126 | Now rerun GraphiQL. See the new Markdown nodes? 127 | 128 | > Tip: gatsby-transformer-remark is a HUGE plugin, it even has it's own plugins! [Check out the remark ecosystem in the Plugin Library.](https://www.gatsbyjs.org/plugins/?=remark) 129 | 130 | ## Programmatically creating pages 131 | 132 | This has two steps: 133 | 134 | - first, define a template to render your markdown data with. 135 | - second, pass the data through the template with the `createPages` API! 136 | 137 | Here's a sample template you can use: 138 | 139 | ```js 140 | // src/templates/pageTemplate.js 141 | import React from "react" 142 | import { graphql } from "gatsby" 143 | 144 | export default function Template({ 145 | data // this prop will be injected by the GraphQL query below. 146 | }) { 147 | const { markdownRemark } = data // data.markdownRemark holds our post data 148 | const { frontmatter, html } = markdownRemark 149 | return ( 150 |
151 |
152 |

{frontmatter.title}

153 |

{frontmatter.date}

154 |
155 |
156 |
157 | ) 158 | } 159 | 160 | export const pageQuery = graphql` 161 | query($path: String!) { 162 | markdownRemark(frontmatter: { path: { eq: $path } }) { 163 | html 164 | frontmatter { 165 | date(formatString: "MMMM DD, YYYY") 166 | path 167 | title 168 | } 169 | } 170 | } 171 | ` 172 | ``` 173 | 174 | Now head to `gatsby-node.js` to connect the data with your templates! 175 | 176 | > Note: this is the hardest part - be careful and [study the Gatsby Node docs](https://www.gatsbyjs.org/docs/node-apis/) if you get stuck! Using [the helpers](https://www.gatsbyjs.org/docs/node-api-helpers/) can be very.. helpful for repetitive stuff. 177 | 178 | ```js 179 | // gatsby-node.js 180 | const path = require(`path`) 181 | 182 | exports.createPages = ({ actions, graphql }) => { 183 | const { createPage } = actions 184 | 185 | const pageTemplate = path.resolve(`src/templates/pageTemplate.js`) 186 | 187 | return graphql(` 188 | { 189 | allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }, limit: 1000) { 190 | edges { 191 | node { 192 | frontmatter { 193 | path 194 | } 195 | } 196 | } 197 | } 198 | } 199 | `).then((result) => { 200 | if (result.errors) { 201 | return Promise.reject(result.errors) 202 | } 203 | 204 | return result.data.allMarkdownRemark.edges.forEach(({ node }) => { 205 | createPage({ 206 | path: node.frontmatter.slug, 207 | component: pageTemplate, 208 | context: {} 209 | }) 210 | }) 211 | }) 212 | } 213 | ``` 214 | 215 | ## Exercises 216 | 217 | 1. Try adding `gatsby-remark-oembed` and embedding Tweets in your markdown! https://www.gatsbyjs.org/packages/@raae/gatsby-remark-oembed/?=oembed See [instructions](https://paper.dropbox.com/doc/7-Plugging-In-Third-Party-Services--AfA2muEZfpSlGd3LiB62zyIQAg-4m0smdgjiMo2ds4HleEFR) if you get stuck. 218 | -------------------------------------------------------------------------------- /notes-4hr/03a - Gatsby Image.md: -------------------------------------------------------------------------------- 1 | # Gatsby Image 2 | 3 | One of the best things about Gatsby is that because everything (text, images, files, data...) goes through gatsby, we're able to use plugins to massage that data before it gets outputted on the page. 4 | 5 | A huge use case for this is with images. 6 | 7 | For a speedy website, images may need to be: 8 | 9 | - compressed 10 | - converted to different formats 11 | - resized 12 | - lazy loaded 13 | 14 | These things are great for perf, but hard to do on most sites. Gatsby makes it easy! 15 | 16 | ## Show Me 17 | 18 | https://using-gatsby-image.gatsbyjs.org 19 | 20 | ## Images in React Components 21 | 22 | If you are inside a component, just import your image like so: 23 | 24 | ```js 25 | import dog from "../images/dog.jpg" 26 | ``` 27 | 28 | That will give you a path to the statically generated image, which can be used like so: 29 | 30 | ```jsx 31 | Cute Pup 32 | ``` 33 | 34 | Now this image is still huge! So we want to use a plugin called [gatsby-image](https://www.gatsbyjs.org/packages/gatsby-image/), which in turn will use a package called `sharp` to resize, compress, and provide other image benefits. 35 | 36 | Now does Gatsby know about our images? Not yet! We need to source them, and then let a plugin do the heavy lifting. Add these to your plugins array: 37 | 38 | ```js 39 | // gatsby-config.js 40 | 41 | { 42 | resolve: `gatsby-source-filesystem`, 43 | options: { 44 | name: `images`, 45 | path: path.join(__dirname, `src`, `images`), 46 | }, 47 | }, 48 | `gatsby-transformer-sharp`, 49 | `gatsby-plugin-sharp`, 50 | ``` 51 | 52 | Now here is where Gatsby falls short at the moment. 53 | 54 | If you want to display an image that has been transformed, we need to access it like we do everything else in Gatsby: GraphQL Queries. Then, use the Gatsby-image `Img` component to display it. 55 | 56 | So in order to display an image, we need to write a query like the one in the [docs](https://www.gatsbyjs.org/packages/gatsby-image/). 57 | 58 | The one in the docs is a page query. The other type of query in Gatsby is a "static query" which can be done in any component. 59 | 60 | The downside to static queries is that they aren't dynamic. That is, you can't pass it variables: e.g. an `` src. 61 | 62 | More info here: 63 | 64 | The best approach right now is to make our own component that will query all images, and then return the one we are looking for. 65 | 66 | Make a new file in `components/Img.js`: 67 | 68 | ```js 69 | // Img.js 70 | 71 | import React from "react" 72 | import { useStaticQuery, graphql } from "gatsby" 73 | import Img from "gatsby-image" 74 | 75 | export default function Image({ src, alt }) { 76 | const { allImageSharp } = useStaticQuery(graphql` 77 | query { 78 | allImageSharp { 79 | edges { 80 | node { 81 | fluid(maxWidth: 500) { 82 | ...GatsbyImageSharpFluid_withWebp_tracedSVG 83 | originalName 84 | } 85 | } 86 | } 87 | } 88 | } 89 | `) 90 | const image = allImageSharp.edges.find((edge) => edge.node.fluid.originalName === src) 91 | if (!image) { 92 | return null 93 | } 94 | return {alt} 95 | } 96 | ``` 97 | 98 | Then to use it, simply import this new component and use it like so: 99 | 100 | ```js 101 | import Img from "../components/Img" 102 | ;Cute Pup 103 | ``` 104 | 105 | ## Images in MDX 106 | 107 | Now if you want to have images in your mdx content, it's a little bit easier. We simply let the plugins sniff out the images from our markdown and handle it all for it. 108 | 109 | Put a few images into a tip: 110 | 111 | ```mdx 112 | ![](../images/dog.jpg) 113 | ![](../images/cabin.jpg) 114 | ``` 115 | 116 | Then we need to tell our `gatsby-mdx` how to handle the images in our `gatsby-config.js` file. This isn't a new plugin, but we modify the `gatsby-mdx`: 117 | 118 | ```js 119 | // gatsby-config.js 120 | 121 | { 122 | resolve: 'gatsby-mdx', 123 | options: { 124 | root: __dirname, 125 | gatsbyRemarkPlugins: [ 126 | { 127 | resolve: 'gatsby-remark-images', 128 | options: { 129 | maxWidth: 500, 130 | linkImagesToOriginal: false, 131 | }, 132 | }, 133 | ], 134 | }, 135 | }, 136 | ``` 137 | 138 | And that is it! See the [docs](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-remark-images#options) for the possible options here. 139 | -------------------------------------------------------------------------------- /notes-4hr/03b - Gatsby Lifecycle.md: -------------------------------------------------------------------------------- 1 | # Gatsby Lifecycle 2 | 3 | STUDY THIS and you will actually know what the hell is going on in Gatsby: 4 | 5 | - https://www.gatsbyjs.org/docs/gatsby-lifecycle-apis/ 6 | - (simpler draft) https://gist.github.com/sw-yx/09306ec03df7b4cd8e7469bb74c078fb 7 | -------------------------------------------------------------------------------- /notes-4hr/04 - Gatsby Themes.md: -------------------------------------------------------------------------------- 1 | # Gatsby Themes 2 | 3 | ## Plugins on Steroids 4 | 5 | Configuration is a pain. Gatsby Themes solve this by abstracting configuration into a package you can npm install. We'll try some gatsby themes and see how simple it is. 6 | 7 | ## Demo 8 | 9 | - Theme: https://github.com/sw-yx/gatsby-theme-dev-blog 10 | - Demo of Theme: https://github.com/sw-yx/gatsby-theme-dev-blog-demo 11 | 12 | More official themes on the way 13 | 14 | - 15 | 16 | ## Reading 17 | 18 | - [Docs](https://www.gatsbyjs.org/docs/themes/introduction/) 19 | - [Getting Started Instructions](https://www.gatsbyjs.org/blog/2019-02-26-getting-started-with-gatsby-themes/) 20 | - [Why Themes?](https://www.gatsbyjs.org/blog/2019-01-31-why-themes/#reach-skip-nav) ([Video](https://www.youtube.com/watch?v=wX84vXBpMR8&feature=youtu.be)) 21 | - Creating a Gatby Theme - [Egghead.io video (paid)](https://egghead.io/lessons/gatsby-creating-a-gatsby-theme-with-john-otander) 22 | -------------------------------------------------------------------------------- /notes-4hr/05 - Intro to Serverless.md: -------------------------------------------------------------------------------- 1 | # Intro to Serverless 2 | 3 | Slides: https://docs.google.com/presentation/d/1AbU-4GlPPp66rYjOJci82K7j8Pa6O479Kl2ShP7mHSE/edit?usp=sharing 4 | 5 | ## Why Serverless? 6 | 7 | - Pay per execution pricing 8 | - Never pay for idle servers 9 | - Auto scales for you 10 | - Event driven workflows 11 | - Leverage third party services 12 | 13 | ## Introductions to Serverless 14 | 15 | - [Applying the Serverless Mindset to Any Tech Stack](https://www.youtube.com/watch?v=8Rzv68K8ZOY) 16 | - [Serverless Architectural Patterns](https://medium.com/@eduardoromero/serverless-architectural-patterns-261d8743020) 17 | - [Serverless Microservice Patterns for AWS](https://www.jeremydaly.com/serverless-microservice-patterns-for-aws/) 18 | - [Production-Ready Serverless](https://www.manning.com/livevideo/production-ready-serverless) 19 | - [Cloud Native Development Patterns & Best Practices](https://www.amazon.com/Cloud-Native-Development-Patterns-Practices/dp/1788473922) 20 | - [JavaScript Cloud Native Development Cookbook](https://www.amazon.com/JavaScript-Cloud-Native-Development-Cookbook/dp/1788470419) 21 | - [Serverless framework workshop](https://github.com/DavidWells/serverless-workshop) 22 | - [Yos Riady's intro](https://docs.google.com/presentation/d/129ShJ6VGN_h1Hga5sqiXslAxdvLLBoEZKVkgehUXURs/edit#slide=id.g37dd1a6a4c_0_29) 23 | - [AWS Reinvent: The State of Serverless Computing](https://www.youtube.com/watch?v=AcGv3qUrRC4) from VP of AWS Lambda 24 | - https://github.com/DavidWells/serverless-workshop Do all exercises 25 | 26 | ## Examples of Apps you can build with Gatsby 27 | 28 | - https://github.com/MozillaDevelopers/playground 29 | - https://github.com/howtographql/howtographql 30 | - https://github.com/DSchau/gatsby-mail 31 | - https://github.com/gatsbyjs/store.gatsbyjs.org 32 | - https://github.com/sw-yx/jamstack-hackathon-starter 33 | -------------------------------------------------------------------------------- /notes-4hr/06a - Amplify CLI.md: -------------------------------------------------------------------------------- 1 | # Amplify CLI 2 | 3 | You have been experiencing [the Amplify Console](https://console.aws.amazon.com/amplify/home). This is great for setting up JAMstack builds and continuous deployment from Git by default. 4 | 5 | To get extra serverless power, we're going to be using Amplify CLI: 6 | 7 | - Docs on [Github](https://github.com/aws-amplify/amplify-cli) and [Amplify](https://aws-amplify.github.io/docs/cli/concept) 8 | 9 | ## Install 10 | 11 | ```bash 12 | npm install -g @aws-amplify/cli 13 | amplify configure # optional, opens AWS Management Console, sign in if you aren't logged in 14 | # pick a AWS region 15 | # create new IAM user 16 | # get accessKeyId and secretAccessKey pair (look out for this!) 17 | # name profile whatever you want like gatsby-amplify 18 | ``` 19 | 20 | To start using it for your Gatsby project, run 21 | 22 | ```bash 23 | amplify init # default choices for everything 24 | ``` 25 | 26 | Note the new `/amplify` folder. 27 | 28 | For easier operation with React, we can now install the helper libraries as well: 29 | 30 | ```bash 31 | npm i aws-amplify aws-amplify-react 32 | ``` 33 | 34 | ## Adding AWS services 35 | 36 | There are various backend services you can addon to your app: 37 | 38 | ``` 39 | amplify add {service} 40 | ``` 41 | 42 | These are: 43 | 44 | - `auth` (Amazon Cognito) 45 | - `storage` (Amazon S3 & Amazon DynamoDB) 46 | - `function` (AWS Lambda) 47 | - `api` (AWS AppSync & Amazon API Gateway) 48 | - `analytics` (Amazon Pinpoint) 49 | - `hosting` (Amazon S3 and Amazon CloudFront distribution) 50 | - `notifications` (Amazon Pinpoint) 51 | - `interactions` (Amazon Lex) 52 | 53 | We will practice by adding auth and storage. 54 | 55 | ## Serverless Authentication with AWS Cognito 56 | 57 | ```bash 58 | amplify add auth # go with default config 59 | # Username 60 | # just Email 61 | ``` 62 | 63 | At any point, you can run `amplify status` to check that what you have configured. 64 | 65 | When you're happy you have it right, run 66 | 67 | ```bash 68 | amplify push 69 | ``` 70 | 71 | You should see a new file `src/aws-exports.js`. Don't touch it. 72 | 73 | We'll now have to pass this configuration to Amplify in our Gatsby app: 74 | 75 | ```js 76 | // pages/index.js 77 | import React from "react" 78 | import { Link } from "gatsby" 79 | 80 | import Layout from "../components/layout" 81 | 82 | import Amplify from "aws-amplify" 83 | import config from "../aws-exports" 84 | Amplify.configure(config) 85 | 86 | const IndexPage = () => ( 87 | 88 |

Hi people

89 |

90 | Welcome to your new Gatsby site with multi-user authentication powered by{" "} 91 | AWS Amplify 92 |

93 |

94 | Create a new account: Sign Up 95 |

96 | Sign In 97 |
98 | Home 99 |
100 | Your profile 101 |
102 | ) 103 | 104 | export default IndexPage 105 | ``` 106 | 107 | and we'll also have to make sure to create dynamic pages (client-only, no static pages since it's all behind an authentication wall): 108 | 109 | ```js 110 | // gatsby-node.js 111 | exports.onCreatePage = async ({ page, actions }) => { 112 | const { createPage } = actions 113 | 114 | // page.matchPath is a special key that's used for matching pages 115 | // only on the client. 116 | if (page.path.match(/^\/app/)) { 117 | page.matchPath = `/app/*` 118 | 119 | // Update the page. 120 | createPage(page) 121 | } 122 | } 123 | ``` 124 | 125 | All of these pages will match to the `/app` page: 126 | 127 | and make an `app` page as well 128 | 129 | ```js 130 | // pages/app.js 131 | import React from "react" 132 | import { Router } from "@reach/router" 133 | import Layout from "../components/layout" 134 | import Details from "../components/Details" 135 | import Home from "../components/Home" 136 | import Login from "../components/Login" 137 | import SignUp from "../components/SignUp" 138 | import PrivateRoute from "../components/PrivateRoute" 139 | 140 | const App = () => ( 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | ) 150 | 151 | export default App 152 | ``` 153 | 154 | We'll check for the authenticated user in `gatsby-browser.js`: 155 | 156 | ```js 157 | // gatsby-browser.js 158 | import Auth from "@aws-amplify/auth" 159 | import { setUser } from "./src/utils/auth" 160 | 161 | export const onRouteUpdate = (state, page, pages) => { 162 | Auth.currentAuthenticatedUser() 163 | .then((user) => { 164 | const userInfo = { 165 | ...user.attributes, 166 | username: user.username 167 | } 168 | setUser(userInfo) 169 | }) 170 | .catch((err) => { 171 | window.localStorage.setItem("gatsbyUser", null) 172 | }) 173 | } 174 | ``` 175 | 176 | For the actual signup/login components, we aren't going to go through all of them but you can [check the Gatsby Amplify Auth starter here](https://github.com/dabit3/gatsby-auth-starter-aws-amplify). 177 | 178 | ## Serverless Compute with AWS Lambda 179 | 180 | ```bash 181 | amplify add api # choose REST 182 | # name your api here, i'll use "jsconfapi" 183 | ``` 184 | 185 | Pick the local express function, and restrict it to Authenticated users only. Feel free to edit the code to your needs. 186 | 187 | When you're ready, 188 | 189 | ```bash 190 | amplify push 191 | ``` 192 | 193 | to deploy the serverless function. 194 | 195 | Now we need to access it from within our app. Head to `src/components/Home.js` (assuming you are following the starter above) and: 196 | 197 | ```js 198 | // src/components/Home.js 199 | import React from "react" 200 | import { Link } from "gatsby" 201 | import { API } from "aws-amplify" 202 | 203 | const Home = () => { 204 | const [state, setState] = React.useState([]) 205 | const getAPI = () => API.get("jsconfapi").then(setState) 206 | return ( 207 |
208 |

Home

209 |

210 | You are now logged in! View profile 211 |

212 |
213 | 214 |
{JSON.stringify(state, null, 2)}
215 |
216 |

217 | Now go build something great and deploy it using the{" "} 218 | AWS Amplify Console 219 |

220 |
221 | ) 222 | } 223 | 224 | export default Home 225 | ``` 226 | 227 | and that's it! 228 | 229 | > REMEMBER: every time you make changes to your Amplify functions, you need to run `amplify push` again. 230 | 231 | ## Serverless Storage with AWS Lambda 232 | 233 | ```bash 234 | amplify add storage # choose Content 235 | # give a friendly name 236 | ``` 237 | 238 | When you're ready, 239 | 240 | ```bash 241 | amplify push 242 | ``` 243 | 244 | In your React component, you can import accordingly: 245 | 246 | ```js 247 | import React, { Component } from "react" 248 | import logo from "./logo.svg" 249 | import "./App.css" 250 | 251 | import { withAuthenticator } from "aws-amplify-react" 252 | import { Storage } from "aws-amplify" 253 | 254 | class App extends Component { 255 | state = { fileUrl: "", file: "", filename: "", storedImgs: null } 256 | componentDidMount() { 257 | Storage.get("1500x500.jpeg") 258 | .then((data) => { 259 | this.setState({ 260 | storedImgs: data 261 | }) 262 | }) 263 | .catch((err) => { 264 | console.log("error fetching image") 265 | }) 266 | } 267 | handleChange = (e) => { 268 | const file = e.target.files[0] 269 | this.setState({ 270 | fileUrl: URL.createObjectURL(file), 271 | file, 272 | filename: file.name 273 | }) 274 | } 275 | saveFile = () => { 276 | Storage.put(this.state.filename, this.state.file) 277 | .then(() => { 278 | console.log("successfully uploading file!") 279 | this.setState({ fileUrl: "", file: "", filename: "" }) 280 | }) 281 | .catch((err) => { 282 | console.log("error uploading file!", err) 283 | }) 284 | } 285 | render() { 286 | return ( 287 |
288 |
289 | logo 290 |

Welcome to React

291 |
292 | 293 | 294 | 295 |
296 | ) 297 | } 298 | } 299 | ``` 300 | 301 | To verify you are indeed saving correctly in S3, you can open your AWS Console, head to S3 and look for the uploaded files, in the bucket we created, in the `/public` folder 302 | 303 | ## Exercise 304 | 305 | Create an Instagram clone using: 306 | 307 | - Amplify Console 308 | - Authentication 309 | - Storage 310 | - Serverless Functions 311 | 312 | You can use [the Instapaper Material UI theme](https://themes.material-ui.com/themes/instapaper/) to get a leg up on UI. 313 | -------------------------------------------------------------------------------- /notes-4hr/07 - Bonus.md: -------------------------------------------------------------------------------- 1 | # Bonus 2 | 3 | Other Gatsby Workshops you can browse: 4 | 5 | - https://github.com/JuniorDevSingapore/gatsby-workshop 6 | 7 | Extra material you can go through if you are ahead: 8 | 9 | - to be completed 10 | -------------------------------------------------------------------------------- /site/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | #amplify 72 | amplify/\#current-cloud-backend 73 | amplify/.config/local-* 74 | amplify/backend/amplify-meta.json 75 | amplify/backend/awscloudformation 76 | build/ 77 | dist/ 78 | node_modules/ 79 | aws-exports.js 80 | awsconfiguration.json -------------------------------------------------------------------------------- /site/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /site/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /site/README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | Gatsby 5 | 6 |

7 |

8 | Gatsby's default starter 9 |

10 | 11 | Kick off your project with this default 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. 12 | 13 | _Have another more specific idea? You may want to check out our vibrant collection of [official and community-created starters](https://www.gatsbyjs.org/docs/gatsby-starters/)._ 14 | 15 | ## 🚀 Quick start 16 | 17 | 1. **Create a Gatsby site.** 18 | 19 | Use the Gatsby CLI to create a new site, specifying the default starter. 20 | 21 | ```sh 22 | # create a new Gatsby site using the default starter 23 | gatsby new my-default-starter https://github.com/gatsbyjs/gatsby-starter-default 24 | ``` 25 | 26 | 1. **Start developing.** 27 | 28 | Navigate into your new site’s directory and start it up. 29 | 30 | ```sh 31 | cd my-default-starter/ 32 | gatsby develop 33 | ``` 34 | 35 | 1. **Open the source code and start editing!** 36 | 37 | Your site is now running at `http://localhost:8000`! 38 | 39 | _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.org/tutorial/part-five/#introducing-graphiql)._ 40 | 41 | Open the `my-default-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! 42 | 43 | ## 🧐 What's inside? 44 | 45 | A quick look at the top-level files and directories you'll see in a Gatsby project. 46 | 47 | . 48 | ├── node_modules 49 | ├── src 50 | ├── .gitignore 51 | ├── .prettierrc 52 | ├── gatsby-browser.js 53 | ├── gatsby-config.js 54 | ├── gatsby-node.js 55 | ├── gatsby-ssr.js 56 | ├── LICENSE 57 | ├── package-lock.json 58 | ├── package.json 59 | └── README.md 60 | 61 | 1. **`/node_modules`**: This directory contains all of the modules of code that your project depends on (npm packages) are automatically installed. 62 | 63 | 2. **`/src`**: This directory will contain all of the code related to what you will see on the front-end of your site (what you see in the browser) such as your site header or a page template. `src` is a convention for “source code”. 64 | 65 | 3. **`.gitignore`**: This file tells git which files it should not track / not maintain a version history for. 66 | 67 | 4. **`.prettierrc`**: This is a configuration file for [Prettier](https://prettier.io/). Prettier is a tool to help keep the formatting of your code consistent. 68 | 69 | 5. **`gatsby-browser.js`**: This file is where Gatsby expects to find any usage of the [Gatsby browser APIs](https://www.gatsbyjs.org/docs/browser-apis/) (if any). These allow customization/extension of default Gatsby settings affecting the browser. 70 | 71 | 6. **`gatsby-config.js`**: This is the main configuration file for a Gatsby site. This is where you can specify information about your site (metadata) like the site title and description, which Gatsby plugins you’d like to include, etc. (Check out the [config docs](https://www.gatsbyjs.org/docs/gatsby-config/) for more detail). 72 | 73 | 7. **`gatsby-node.js`**: This file is where Gatsby expects to find any usage of the [Gatsby Node APIs](https://www.gatsbyjs.org/docs/node-apis/) (if any). These allow customization/extension of default Gatsby settings affecting pieces of the site build process. 74 | 75 | 8. **`gatsby-ssr.js`**: This file is where Gatsby expects to find any usage of the [Gatsby server-side rendering APIs](https://www.gatsbyjs.org/docs/ssr-apis/) (if any). These allow customization of default Gatsby settings affecting server-side rendering. 76 | 77 | 9. **`LICENSE`**: Gatsby is licensed under the MIT license. 78 | 79 | 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).** 80 | 81 | 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. 82 | 83 | 12. **`README.md`**: A text file containing useful reference information about your project. 84 | 85 | ## 🎓 Learning Gatsby 86 | 87 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start: 88 | 89 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 90 | 91 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 92 | 93 | ## 💫 Deploy 94 | 95 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gatsbyjs/gatsby-starter-default) 96 | 97 | 98 | -------------------------------------------------------------------------------- /site/content/first-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: first-post 3 | date: 2019-06-15 4 | tags: jsconf 5 | title: First Post! 6 | --- 7 | 8 | This is my first post with Gatsby! 9 | -------------------------------------------------------------------------------- /site/content/second-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: second-post 3 | date: 2019-06-16 4 | tags: jsconf 5 | title: Second Post! 6 | --- 7 | 8 | This is my second post with Gatsby! 9 | -------------------------------------------------------------------------------- /site/content/third-post.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: third-post 3 | date: 2019-06-16 4 | tags: jsconf 5 | title: Third Post! 6 | --- 7 | 8 | This is my third post with Gatsby! 9 | -------------------------------------------------------------------------------- /site/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /site/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | anything: "I want", 4 | title: `JAMstack Jumpstart`, 5 | description: `Kick off your next, great Gatsby project with this default starter.`, 6 | author: `@swyx`, 7 | }, 8 | plugins: [ 9 | { 10 | resolve: `gatsby-source-filesystem`, 11 | options: { 12 | name: `content`, 13 | path: `${__dirname}/content`, 14 | }, 15 | }, 16 | `gatsby-transformer-remark`, 17 | ], 18 | } 19 | 20 | // // example format autogenerated by `gatsby new` 21 | // module.exports = { 22 | // siteMetadata: { 23 | // title: `Gatsby Default Starter`, 24 | // description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`, 25 | // author: `@gatsbyjs`, 26 | // }, 27 | // plugins: [ 28 | // `gatsby-plugin-react-helmet`, 29 | // { 30 | // resolve: `gatsby-source-filesystem`, 31 | // options: { 32 | // name: `images`, 33 | // path: `${__dirname}/src/images`, 34 | // }, 35 | // }, 36 | // `gatsby-transformer-sharp`, 37 | // `gatsby-plugin-sharp`, 38 | // { 39 | // resolve: `gatsby-plugin-manifest`, 40 | // options: { 41 | // name: `gatsby-starter-default`, 42 | // short_name: `starter`, 43 | // start_url: `/`, 44 | // background_color: `#663399`, 45 | // theme_color: `#663399`, 46 | // display: `minimal-ui`, 47 | // icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site. 48 | // }, 49 | // }, 50 | // // this (optional) plugin enables Progressive Web App + Offline functionality 51 | // // To learn more, visit: https://gatsby.dev/offline 52 | // // `gatsby-plugin-offline`, 53 | // ], 54 | // } 55 | -------------------------------------------------------------------------------- /site/gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require(`path`) 2 | 3 | exports.createPages = ({ actions, graphql }) => { 4 | const { createPage } = actions 5 | 6 | const pageTemplate = path.resolve(`src/templates/pageTemplate.js`) 7 | 8 | return graphql(` 9 | { 10 | allMarkdownRemark( 11 | sort: { order: DESC, fields: [frontmatter___date] } 12 | limit: 1000 13 | ) { 14 | edges { 15 | node { 16 | frontmatter { 17 | slug 18 | } 19 | } 20 | } 21 | } 22 | } 23 | `).then(result => { 24 | if (result.errors) { 25 | return Promise.reject(result.errors) 26 | } 27 | 28 | return result.data.allMarkdownRemark.edges.forEach(({ node }) => { 29 | createPage({ 30 | path: node.frontmatter.slug, 31 | component: pageTemplate, 32 | context: { 33 | slug: node.frontmatter.slug, 34 | }, 35 | }) 36 | }) 37 | }) 38 | } 39 | 40 | // // uncomment to enable dynamic /app page 41 | 42 | // exports.onCreatePage = async ({ page, actions }) => { 43 | // const { createPage } = actions 44 | 45 | // // page.matchPath is a special key that's used for matching pages 46 | // // only on the client. 47 | // if (page.path.match(/^\/app/)) { 48 | // page.matchPath = `/app/*` 49 | 50 | // // Update the page. 51 | // createPage(page) 52 | // } 53 | // } 54 | -------------------------------------------------------------------------------- /site/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-default", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.1.0", 6 | "author": "Kyle Mathews ", 7 | "dependencies": { 8 | "@mdx-js/loader": "^0.20.3", 9 | "@mdx-js/mdx": "^0.20.3", 10 | "@mdx-js/tag": "^0.20.3", 11 | "aws-amplify": "^1.1.28", 12 | "aws-amplify-react": "^2.3.8", 13 | "gatsby": "^2.9.2", 14 | "gatsby-image": "^2.1.4", 15 | "gatsby-mdx": "0.4.3", 16 | "gatsby-plugin-google-analytics": "^2.0.18", 17 | "gatsby-plugin-manifest": "^2.1.1", 18 | "gatsby-plugin-offline": "^2.1.3", 19 | "gatsby-plugin-react-helmet": "^3.0.12", 20 | "gatsby-plugin-sharp": "^2.1.5", 21 | "gatsby-plugin-transition-link": "^1.12.2", 22 | "gatsby-remark-autolink-headers": "^2.0.16", 23 | "gatsby-remark-copy-linked-files": "^2.0.11", 24 | "gatsby-remark-images": "^3.0.10", 25 | "gatsby-remark-prismjs": "^3.2.6", 26 | "gatsby-remark-responsive-iframe": "^2.1.1", 27 | "gatsby-remark-smartypants": "^2.0.9", 28 | "gatsby-source-filesystem": "^2.0.39", 29 | "gatsby-transformer-remark": "^2.4.0", 30 | "gatsby-transformer-sharp": "^2.1.21", 31 | "prop-types": "^15.7.2", 32 | "react": "^16.8.6", 33 | "react-dom": "^16.8.6", 34 | "react-helmet": "^5.2.1", 35 | "styled-components": "^4.2.0" 36 | }, 37 | "devDependencies": { 38 | "prettier": "^1.18.2" 39 | }, 40 | "keywords": [ 41 | "gatsby" 42 | ], 43 | "license": "MIT", 44 | "scripts": { 45 | "build": "gatsby build", 46 | "develop": "gatsby develop", 47 | "format": "prettier --write src/**/*.{js,jsx}", 48 | "start": "npm run develop", 49 | "serve": "gatsby serve", 50 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"" 51 | }, 52 | "repository": { 53 | "type": "git", 54 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 55 | }, 56 | "bugs": { 57 | "url": "https://github.com/gatsbyjs/gatsby/issues" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /site/src/components/AuthDetails.js: -------------------------------------------------------------------------------- 1 | // only for authentication section of workshop 2 | import React from "react" 3 | import { Link } from "gatsby" 4 | import { getCurrentUser } from "../utils/auth" 5 | 6 | const Home = () => { 7 | const user = getCurrentUser() 8 | console.log("user:", user) 9 | return ( 10 |
11 |

Profile Details

12 |

Email: {user.email}

13 |

Phone: {user.phone_number}

14 |

Username: {user.username}

15 | Home 16 |
17 | ) 18 | } 19 | 20 | export default Home 21 | -------------------------------------------------------------------------------- /site/src/components/AuthError.js: -------------------------------------------------------------------------------- 1 | //https://github.com/wesbos/dump 2 | import React from "react" 3 | 4 | const Error = props => ( 5 |
6 | {Object.entries(props).map(([err, val]) => ( 7 |
 8 |         {err}: 
 9 |         {JSON.stringify(val, "", " ")}
10 |         
11 | 12 | AWS Cognito User Pool documentation. 13 | 14 |
15 | ))} 16 |
17 | ) 18 | 19 | export default Error 20 | -------------------------------------------------------------------------------- /site/src/components/AuthHeader.js: -------------------------------------------------------------------------------- 1 | // only for authentication section of workshop 2 | import React from "react" 3 | import { Link } from "gatsby" 4 | 5 | import { navigate } from "@reach/router" 6 | 7 | import { logout, isLoggedIn } from "../utils/auth" 8 | import { Auth } from "aws-amplify" 9 | 10 | const Header = ({ siteTitle }) => ( 11 |
17 |
24 |

25 | 26 | {siteTitle} 27 | 28 |

29 | {isLoggedIn() && ( 30 |

32 | Auth.signOut() 33 | .then(logout(() => navigate("/app/login"))) 34 | .catch(err => console.log("eror:", err)) 35 | } 36 | style={styles.link} 37 | > 38 | Sign Out 39 |

40 | )} 41 |
42 |
43 | ) 44 | 45 | const styles = { 46 | headerTitle: { 47 | color: "white", 48 | textDecoration: "none", 49 | }, 50 | link: { 51 | cursor: "pointer", 52 | color: "white", 53 | textDecoration: "underline", 54 | }, 55 | } 56 | 57 | export default Header 58 | -------------------------------------------------------------------------------- /site/src/components/AuthHome.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | 4 | const Home = () => ( 5 |
6 |

Home

7 |

8 | You are now logged in! View profile 9 |

10 |

11 | Now go build something great and deploy it using the{" "} 12 | AWS Amplify Console 13 |

14 |
15 | ) 16 | 17 | export default Home 18 | -------------------------------------------------------------------------------- /site/src/components/AuthLayout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout component that queries for data 3 | * with Gatsby's StaticQuery component 4 | * 5 | * See: https://www.gatsbyjs.org/docs/static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import { useStaticQuery, graphql } from "gatsby" 10 | 11 | import Header from "./AuthHeader" 12 | import "./layout.css" 13 | 14 | const Layout = ({ children }) => { 15 | const data = useStaticQuery(graphql` 16 | query SiteTitleQuery2 { 17 | site { 18 | siteMetadata { 19 | title 20 | } 21 | } 22 | } 23 | `) 24 | return ( 25 | <> 26 |
27 |
35 |
{children}
36 |
37 | © {new Date().getFullYear()}, Built with 38 | {` `} 39 | Gatsby 40 |
41 |
42 | 43 | ) 44 | } 45 | 46 | export default Layout 47 | -------------------------------------------------------------------------------- /site/src/components/AuthLogin.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | import { navigate } from "@reach/router" 4 | import { setUser, isLoggedIn } from "../utils/auth" 5 | import Error from "./Error" 6 | import { Auth } from "aws-amplify" 7 | 8 | class Login extends React.Component { 9 | state = { 10 | username: ``, 11 | password: ``, 12 | error: ``, 13 | } 14 | 15 | handleUpdate = event => { 16 | this.setState({ 17 | [event.target.name]: event.target.value, 18 | }) 19 | } 20 | 21 | login = async () => { 22 | const { username, password } = this.state 23 | try { 24 | await Auth.signIn(username, password) 25 | const user = await Auth.currentAuthenticatedUser() 26 | const userInfo = { 27 | ...user.attributes, 28 | username: user.username, 29 | } 30 | setUser(userInfo) 31 | navigate("/app/home") 32 | } catch (err) { 33 | this.setState({ error: err }) 34 | console.log("error...: ", err) 35 | } 36 | } 37 | 38 | render() { 39 | if (isLoggedIn()) navigate("/app/profile") 40 | return ( 41 |
42 |

Sign In

43 | {this.state.error && } 44 |
45 | 52 | 60 |
61 | Sign In 62 |
63 |
64 | Need to Log In instead? Sign Up 65 |
66 |
67 | ) 68 | } 69 | } 70 | 71 | const styles = { 72 | input: { 73 | height: 40, 74 | margin: "10px 0px", 75 | padding: 7, 76 | }, 77 | formContainer: { 78 | display: "flex", 79 | flexDirection: "column", 80 | }, 81 | button: { 82 | backgroundColor: "rebeccapurple", 83 | padding: "15px 7px", 84 | cursor: "pointer", 85 | textAlign: "center", 86 | marginBottom: 10, 87 | }, 88 | buttonText: { 89 | color: "white", 90 | }, 91 | } 92 | 93 | export default Login 94 | -------------------------------------------------------------------------------- /site/src/components/AuthPrivateRoute.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { navigate } from "@reach/router" 3 | import { isLoggedIn } from "../utils/auth" 4 | 5 | class PrivateRoute extends React.Component { 6 | render() { 7 | const { component: Component, location, ...rest } = this.props 8 | if (!isLoggedIn()) { 9 | navigate(`/app/login`) 10 | return null 11 | } 12 | return 13 | } 14 | } 15 | 16 | export default PrivateRoute 17 | -------------------------------------------------------------------------------- /site/src/components/AuthSignUp.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { navigate } from "@reach/router" 3 | import { Link } from "gatsby" 4 | import Error from "./AuthError" 5 | import { Auth } from "aws-amplify" 6 | 7 | const initialState = { 8 | username: ``, 9 | password: ``, 10 | email: "", 11 | phone_number: "", 12 | authCode: "", 13 | stage: 0, 14 | error: "", 15 | } 16 | 17 | class SignUp extends React.Component { 18 | state = initialState 19 | 20 | handleUpdate = event => { 21 | this.setState({ 22 | [event.target.name]: event.target.value, 23 | }) 24 | } 25 | 26 | signUp = async () => { 27 | const { username, password, email, phone_number } = this.state 28 | try { 29 | await Auth.signUp({ 30 | username, 31 | password, 32 | attributes: { email, phone_number }, 33 | }) 34 | this.setState({ stage: 1 }) 35 | } catch (err) { 36 | this.setState({ error: err }) 37 | console.log("error signing up...", err) 38 | } 39 | } 40 | 41 | confirmSignUp = async () => { 42 | const { username, authCode } = this.state 43 | try { 44 | await Auth.confirmSignUp(username, authCode) 45 | alert("Successfully signed up!") 46 | navigate("/app/login") 47 | } catch (err) { 48 | this.setState({ error: err }) 49 | console.log("error confirming signing up...", err) 50 | } 51 | } 52 | 53 | render() { 54 | return ( 55 |
56 |

Sign Up

57 | {this.state.stage === 0 && ( 58 |
59 | {this.state.error && } 60 | 67 | 75 | 82 | 89 |
90 | Sign Up 91 |
92 |
93 | )} 94 | {this.state.stage === 1 && ( 95 |
96 | {this.state.error && } 97 | 104 |
105 | Confirm Sign Up 106 |
107 |
108 | )} 109 | Need to Sign In instead? Sign In 110 |
111 | ) 112 | } 113 | } 114 | 115 | const styles = { 116 | input: { 117 | height: 40, 118 | margin: "10px 0px", 119 | padding: 7, 120 | }, 121 | formContainer: { 122 | display: "flex", 123 | flexDirection: "column", 124 | }, 125 | button: { 126 | backgroundColor: "rebeccapurple", 127 | padding: "15px 7px", 128 | cursor: "pointer", 129 | textAlign: "center", 130 | marginBottom: 10, 131 | }, 132 | buttonText: { 133 | color: "white", 134 | }, 135 | } 136 | 137 | export default SignUp 138 | -------------------------------------------------------------------------------- /site/src/components/header.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import React from "react" 3 | 4 | const Header = ({ siteTitle }) => ( 5 |
11 |
18 |

19 | 26 | {siteTitle} 27 | 28 |

29 |
30 |
31 | ) 32 | 33 | export default Header 34 | -------------------------------------------------------------------------------- /site/src/components/image.js: -------------------------------------------------------------------------------- 1 | // import React from "react" 2 | // import { StaticQuery, graphql } from "gatsby" 3 | // import Img from "gatsby-image" 4 | 5 | // /* 6 | // * This component is built using `gatsby-image` to automatically serve optimized 7 | // * images with lazy loading and reduced file sizes. The image is loaded using a 8 | // * `StaticQuery`, which allows us to load the image from directly within this 9 | // * component, rather than having to pass the image data down from pages. 10 | // * 11 | // * For more information, see the docs: 12 | // * - `gatsby-image`: https://gatsby.dev/gatsby-image 13 | // * - `StaticQuery`: https://gatsby.dev/staticquery 14 | // */ 15 | 16 | // const Image = () => ( 17 | // } 30 | // /> 31 | // ) 32 | // export default Image 33 | -------------------------------------------------------------------------------- /site/src/components/layout.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: sans-serif; 3 | -ms-text-size-adjust: 100%; 4 | -webkit-text-size-adjust: 100%; 5 | } 6 | body { 7 | margin: 0; 8 | -webkit-font-smoothing: antialiased; 9 | -moz-osx-font-smoothing: grayscale; 10 | } 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | main, 19 | menu, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | audio, 26 | canvas, 27 | progress, 28 | video { 29 | display: inline-block; 30 | } 31 | audio:not([controls]) { 32 | display: none; 33 | height: 0; 34 | } 35 | progress { 36 | vertical-align: baseline; 37 | } 38 | [hidden], 39 | template { 40 | display: none; 41 | } 42 | a { 43 | background-color: transparent; 44 | -webkit-text-decoration-skip: objects; 45 | } 46 | a:active, 47 | a:hover { 48 | outline-width: 0; 49 | } 50 | abbr[title] { 51 | border-bottom: none; 52 | text-decoration: underline; 53 | text-decoration: underline dotted; 54 | } 55 | b, 56 | strong { 57 | font-weight: inherit; 58 | font-weight: bolder; 59 | } 60 | dfn { 61 | font-style: italic; 62 | } 63 | h1 { 64 | font-size: 2em; 65 | margin: 0.67em 0; 66 | } 67 | mark { 68 | background-color: #ff0; 69 | color: #000; 70 | } 71 | small { 72 | font-size: 80%; 73 | } 74 | sub, 75 | sup { 76 | font-size: 75%; 77 | line-height: 0; 78 | position: relative; 79 | vertical-align: baseline; 80 | } 81 | sub { 82 | bottom: -0.25em; 83 | } 84 | sup { 85 | top: -0.5em; 86 | } 87 | img { 88 | border-style: none; 89 | } 90 | svg:not(:root) { 91 | overflow: hidden; 92 | } 93 | code, 94 | kbd, 95 | pre, 96 | samp { 97 | font-family: monospace, monospace; 98 | font-size: 1em; 99 | } 100 | figure { 101 | margin: 1em 40px; 102 | } 103 | hr { 104 | box-sizing: content-box; 105 | height: 0; 106 | overflow: visible; 107 | } 108 | button, 109 | input, 110 | optgroup, 111 | select, 112 | textarea { 113 | font: inherit; 114 | margin: 0; 115 | } 116 | optgroup { 117 | font-weight: 700; 118 | } 119 | button, 120 | input { 121 | overflow: visible; 122 | } 123 | button, 124 | select { 125 | text-transform: none; 126 | } 127 | [type="reset"], 128 | [type="submit"], 129 | button, 130 | html [type="button"] { 131 | -webkit-appearance: button; 132 | } 133 | [type="button"]::-moz-focus-inner, 134 | [type="reset"]::-moz-focus-inner, 135 | [type="submit"]::-moz-focus-inner, 136 | button::-moz-focus-inner { 137 | border-style: none; 138 | padding: 0; 139 | } 140 | [type="button"]:-moz-focusring, 141 | [type="reset"]:-moz-focusring, 142 | [type="submit"]:-moz-focusring, 143 | button:-moz-focusring { 144 | outline: 1px dotted ButtonText; 145 | } 146 | fieldset { 147 | border: 1px solid silver; 148 | margin: 0 2px; 149 | padding: 0.35em 0.625em 0.75em; 150 | } 151 | legend { 152 | box-sizing: border-box; 153 | color: inherit; 154 | display: table; 155 | max-width: 100%; 156 | padding: 0; 157 | white-space: normal; 158 | } 159 | textarea { 160 | overflow: auto; 161 | } 162 | [type="checkbox"], 163 | [type="radio"] { 164 | box-sizing: border-box; 165 | padding: 0; 166 | } 167 | [type="number"]::-webkit-inner-spin-button, 168 | [type="number"]::-webkit-outer-spin-button { 169 | height: auto; 170 | } 171 | [type="search"] { 172 | -webkit-appearance: textfield; 173 | outline-offset: -2px; 174 | } 175 | [type="search"]::-webkit-search-cancel-button, 176 | [type="search"]::-webkit-search-decoration { 177 | -webkit-appearance: none; 178 | } 179 | ::-webkit-input-placeholder { 180 | color: inherit; 181 | opacity: 0.54; 182 | } 183 | ::-webkit-file-upload-button { 184 | -webkit-appearance: button; 185 | font: inherit; 186 | } 187 | html { 188 | font: 112.5%/1.45em georgia, serif; 189 | box-sizing: border-box; 190 | overflow-y: scroll; 191 | } 192 | * { 193 | box-sizing: inherit; 194 | } 195 | *:before { 196 | box-sizing: inherit; 197 | } 198 | *:after { 199 | box-sizing: inherit; 200 | } 201 | body { 202 | color: hsla(0, 0%, 0%, 0.8); 203 | font-family: georgia, serif; 204 | font-weight: normal; 205 | word-wrap: break-word; 206 | font-kerning: normal; 207 | -moz-font-feature-settings: "kern", "liga", "clig", "calt"; 208 | -ms-font-feature-settings: "kern", "liga", "clig", "calt"; 209 | -webkit-font-feature-settings: "kern", "liga", "clig", "calt"; 210 | font-feature-settings: "kern", "liga", "clig", "calt"; 211 | } 212 | img { 213 | max-width: 100%; 214 | margin-left: 0; 215 | margin-right: 0; 216 | margin-top: 0; 217 | padding-bottom: 0; 218 | padding-left: 0; 219 | padding-right: 0; 220 | padding-top: 0; 221 | margin-bottom: 1.45rem; 222 | } 223 | h1 { 224 | margin-left: 0; 225 | margin-right: 0; 226 | margin-top: 0; 227 | padding-bottom: 0; 228 | padding-left: 0; 229 | padding-right: 0; 230 | padding-top: 0; 231 | margin-bottom: 1.45rem; 232 | color: inherit; 233 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 234 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 235 | font-weight: bold; 236 | text-rendering: optimizeLegibility; 237 | font-size: 2.25rem; 238 | line-height: 1.1; 239 | } 240 | h2 { 241 | margin-left: 0; 242 | margin-right: 0; 243 | margin-top: 0; 244 | padding-bottom: 0; 245 | padding-left: 0; 246 | padding-right: 0; 247 | padding-top: 0; 248 | margin-bottom: 1.45rem; 249 | color: inherit; 250 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 251 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 252 | font-weight: bold; 253 | text-rendering: optimizeLegibility; 254 | font-size: 1.62671rem; 255 | line-height: 1.1; 256 | } 257 | h3 { 258 | margin-left: 0; 259 | margin-right: 0; 260 | margin-top: 0; 261 | padding-bottom: 0; 262 | padding-left: 0; 263 | padding-right: 0; 264 | padding-top: 0; 265 | margin-bottom: 1.45rem; 266 | color: inherit; 267 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 268 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 269 | font-weight: bold; 270 | text-rendering: optimizeLegibility; 271 | font-size: 1.38316rem; 272 | line-height: 1.1; 273 | } 274 | h4 { 275 | margin-left: 0; 276 | margin-right: 0; 277 | margin-top: 0; 278 | padding-bottom: 0; 279 | padding-left: 0; 280 | padding-right: 0; 281 | padding-top: 0; 282 | margin-bottom: 1.45rem; 283 | color: inherit; 284 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 285 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 286 | font-weight: bold; 287 | text-rendering: optimizeLegibility; 288 | font-size: 1rem; 289 | line-height: 1.1; 290 | } 291 | h5 { 292 | margin-left: 0; 293 | margin-right: 0; 294 | margin-top: 0; 295 | padding-bottom: 0; 296 | padding-left: 0; 297 | padding-right: 0; 298 | padding-top: 0; 299 | margin-bottom: 1.45rem; 300 | color: inherit; 301 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 302 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 303 | font-weight: bold; 304 | text-rendering: optimizeLegibility; 305 | font-size: 0.85028rem; 306 | line-height: 1.1; 307 | } 308 | h6 { 309 | margin-left: 0; 310 | margin-right: 0; 311 | margin-top: 0; 312 | padding-bottom: 0; 313 | padding-left: 0; 314 | padding-right: 0; 315 | padding-top: 0; 316 | margin-bottom: 1.45rem; 317 | color: inherit; 318 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 319 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 320 | font-weight: bold; 321 | text-rendering: optimizeLegibility; 322 | font-size: 0.78405rem; 323 | line-height: 1.1; 324 | } 325 | hgroup { 326 | margin-left: 0; 327 | margin-right: 0; 328 | margin-top: 0; 329 | padding-bottom: 0; 330 | padding-left: 0; 331 | padding-right: 0; 332 | padding-top: 0; 333 | margin-bottom: 1.45rem; 334 | } 335 | ul { 336 | margin-left: 1.45rem; 337 | margin-right: 0; 338 | margin-top: 0; 339 | padding-bottom: 0; 340 | padding-left: 0; 341 | padding-right: 0; 342 | padding-top: 0; 343 | margin-bottom: 1.45rem; 344 | list-style-position: outside; 345 | list-style-image: none; 346 | } 347 | ol { 348 | margin-left: 1.45rem; 349 | margin-right: 0; 350 | margin-top: 0; 351 | padding-bottom: 0; 352 | padding-left: 0; 353 | padding-right: 0; 354 | padding-top: 0; 355 | margin-bottom: 1.45rem; 356 | list-style-position: outside; 357 | list-style-image: none; 358 | } 359 | dl { 360 | margin-left: 0; 361 | margin-right: 0; 362 | margin-top: 0; 363 | padding-bottom: 0; 364 | padding-left: 0; 365 | padding-right: 0; 366 | padding-top: 0; 367 | margin-bottom: 1.45rem; 368 | } 369 | dd { 370 | margin-left: 0; 371 | margin-right: 0; 372 | margin-top: 0; 373 | padding-bottom: 0; 374 | padding-left: 0; 375 | padding-right: 0; 376 | padding-top: 0; 377 | margin-bottom: 1.45rem; 378 | } 379 | p { 380 | margin-left: 0; 381 | margin-right: 0; 382 | margin-top: 0; 383 | padding-bottom: 0; 384 | padding-left: 0; 385 | padding-right: 0; 386 | padding-top: 0; 387 | margin-bottom: 1.45rem; 388 | } 389 | figure { 390 | margin-left: 0; 391 | margin-right: 0; 392 | margin-top: 0; 393 | padding-bottom: 0; 394 | padding-left: 0; 395 | padding-right: 0; 396 | padding-top: 0; 397 | margin-bottom: 1.45rem; 398 | } 399 | pre { 400 | margin-left: 0; 401 | margin-right: 0; 402 | margin-top: 0; 403 | margin-bottom: 1.45rem; 404 | font-size: 0.85rem; 405 | line-height: 1.42; 406 | background: hsla(0, 0%, 0%, 0.04); 407 | border-radius: 3px; 408 | overflow: auto; 409 | word-wrap: normal; 410 | padding: 1.45rem; 411 | } 412 | table { 413 | margin-left: 0; 414 | margin-right: 0; 415 | margin-top: 0; 416 | padding-bottom: 0; 417 | padding-left: 0; 418 | padding-right: 0; 419 | padding-top: 0; 420 | margin-bottom: 1.45rem; 421 | font-size: 1rem; 422 | line-height: 1.45rem; 423 | border-collapse: collapse; 424 | width: 100%; 425 | } 426 | fieldset { 427 | margin-left: 0; 428 | margin-right: 0; 429 | margin-top: 0; 430 | padding-bottom: 0; 431 | padding-left: 0; 432 | padding-right: 0; 433 | padding-top: 0; 434 | margin-bottom: 1.45rem; 435 | } 436 | blockquote { 437 | margin-left: 1.45rem; 438 | margin-right: 1.45rem; 439 | margin-top: 0; 440 | padding-bottom: 0; 441 | padding-left: 0; 442 | padding-right: 0; 443 | padding-top: 0; 444 | margin-bottom: 1.45rem; 445 | } 446 | form { 447 | margin-left: 0; 448 | margin-right: 0; 449 | margin-top: 0; 450 | padding-bottom: 0; 451 | padding-left: 0; 452 | padding-right: 0; 453 | padding-top: 0; 454 | margin-bottom: 1.45rem; 455 | } 456 | noscript { 457 | margin-left: 0; 458 | margin-right: 0; 459 | margin-top: 0; 460 | padding-bottom: 0; 461 | padding-left: 0; 462 | padding-right: 0; 463 | padding-top: 0; 464 | margin-bottom: 1.45rem; 465 | } 466 | iframe { 467 | margin-left: 0; 468 | margin-right: 0; 469 | margin-top: 0; 470 | padding-bottom: 0; 471 | padding-left: 0; 472 | padding-right: 0; 473 | padding-top: 0; 474 | margin-bottom: 1.45rem; 475 | } 476 | hr { 477 | margin-left: 0; 478 | margin-right: 0; 479 | margin-top: 0; 480 | padding-bottom: 0; 481 | padding-left: 0; 482 | padding-right: 0; 483 | padding-top: 0; 484 | margin-bottom: calc(1.45rem - 1px); 485 | background: hsla(0, 0%, 0%, 0.2); 486 | border: none; 487 | height: 1px; 488 | } 489 | address { 490 | margin-left: 0; 491 | margin-right: 0; 492 | margin-top: 0; 493 | padding-bottom: 0; 494 | padding-left: 0; 495 | padding-right: 0; 496 | padding-top: 0; 497 | margin-bottom: 1.45rem; 498 | } 499 | b { 500 | font-weight: bold; 501 | } 502 | strong { 503 | font-weight: bold; 504 | } 505 | dt { 506 | font-weight: bold; 507 | } 508 | th { 509 | font-weight: bold; 510 | } 511 | li { 512 | margin-bottom: calc(1.45rem / 2); 513 | } 514 | ol li { 515 | padding-left: 0; 516 | } 517 | ul li { 518 | padding-left: 0; 519 | } 520 | li > ol { 521 | margin-left: 1.45rem; 522 | margin-bottom: calc(1.45rem / 2); 523 | margin-top: calc(1.45rem / 2); 524 | } 525 | li > ul { 526 | margin-left: 1.45rem; 527 | margin-bottom: calc(1.45rem / 2); 528 | margin-top: calc(1.45rem / 2); 529 | } 530 | blockquote *:last-child { 531 | margin-bottom: 0; 532 | } 533 | li *:last-child { 534 | margin-bottom: 0; 535 | } 536 | p *:last-child { 537 | margin-bottom: 0; 538 | } 539 | li > p { 540 | margin-bottom: calc(1.45rem / 2); 541 | } 542 | code { 543 | font-size: 0.85rem; 544 | line-height: 1.45rem; 545 | } 546 | kbd { 547 | font-size: 0.85rem; 548 | line-height: 1.45rem; 549 | } 550 | samp { 551 | font-size: 0.85rem; 552 | line-height: 1.45rem; 553 | } 554 | abbr { 555 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 556 | cursor: help; 557 | } 558 | acronym { 559 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 560 | cursor: help; 561 | } 562 | abbr[title] { 563 | border-bottom: 1px dotted hsla(0, 0%, 0%, 0.5); 564 | cursor: help; 565 | text-decoration: none; 566 | } 567 | thead { 568 | text-align: left; 569 | } 570 | td, 571 | th { 572 | text-align: left; 573 | border-bottom: 1px solid hsla(0, 0%, 0%, 0.12); 574 | font-feature-settings: "tnum"; 575 | -moz-font-feature-settings: "tnum"; 576 | -ms-font-feature-settings: "tnum"; 577 | -webkit-font-feature-settings: "tnum"; 578 | padding-left: 0.96667rem; 579 | padding-right: 0.96667rem; 580 | padding-top: 0.725rem; 581 | padding-bottom: calc(0.725rem - 1px); 582 | } 583 | th:first-child, 584 | td:first-child { 585 | padding-left: 0; 586 | } 587 | th:last-child, 588 | td:last-child { 589 | padding-right: 0; 590 | } 591 | tt, 592 | code { 593 | background-color: hsla(0, 0%, 0%, 0.04); 594 | border-radius: 3px; 595 | font-family: "SFMono-Regular", Consolas, "Roboto Mono", "Droid Sans Mono", 596 | "Liberation Mono", Menlo, Courier, monospace; 597 | padding: 0; 598 | padding-top: 0.2em; 599 | padding-bottom: 0.2em; 600 | } 601 | pre code { 602 | background: none; 603 | line-height: 1.42; 604 | } 605 | code:before, 606 | code:after, 607 | tt:before, 608 | tt:after { 609 | letter-spacing: -0.2em; 610 | content: " "; 611 | } 612 | pre code:before, 613 | pre code:after, 614 | pre tt:before, 615 | pre tt:after { 616 | content: ""; 617 | } 618 | @media only screen and (max-width: 480px) { 619 | html { 620 | font-size: 100%; 621 | } 622 | } 623 | -------------------------------------------------------------------------------- /site/src/components/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout component that queries for data 3 | * with Gatsby's StaticQuery component 4 | * 5 | * See: https://www.gatsbyjs.org/docs/static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import { useStaticQuery, graphql } from "gatsby" 10 | 11 | import Header from "./header" 12 | import "./layout.css" 13 | 14 | const Layout = ({ children }) => { 15 | const data = useStaticQuery(graphql` 16 | query SiteTitleQuery { 17 | site { 18 | siteMetadata { 19 | title 20 | } 21 | } 22 | } 23 | `) 24 | return ( 25 | <> 26 |
27 |
35 |
{children}
36 |
37 | © {new Date().getFullYear()}, Built with 38 | {` `} 39 | Gatsby 40 |
41 |
42 | 43 | ) 44 | } 45 | 46 | export default Layout 47 | -------------------------------------------------------------------------------- /site/src/components/seo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SEO component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import Helmet from "react-helmet" 11 | import { useStaticQuery, graphql } from "gatsby" 12 | 13 | function SEO({ description = "", lang = "en", meta = [], title = "" }) { 14 | const { site } = useStaticQuery( 15 | graphql` 16 | query { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | author 22 | } 23 | } 24 | } 25 | ` 26 | ) 27 | 28 | const metaDescription = description || site.siteMetadata.description 29 | 30 | return ( 31 | 72 | ) 73 | } 74 | 75 | export default SEO 76 | -------------------------------------------------------------------------------- /site/src/example-pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swyxio/jamstack-jumpstart/3190e15ce05893208083fed7569109d4041a682d/site/src/example-pages/.gitkeep -------------------------------------------------------------------------------- /site/src/example-pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /site/src/example-pages/app.js: -------------------------------------------------------------------------------- 1 | // only for authentication section of workshop 2 | import React from "react" 3 | import { Router } from "@reach/router" 4 | import Layout from "../components/AuthLayout" 5 | import Details from "../components/AuthDetails" 6 | import Home from "../components/AuthHome" 7 | import Login from "../components/AuthLogin" 8 | import SignUp from "../components/AuthSignUp" 9 | import PrivateRoute from "../components/AuthPrivateRoute" 10 | 11 | const App = () => ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | 22 | export default App 23 | -------------------------------------------------------------------------------- /site/src/example-pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | 4 | import Layout from "../components/layout" 5 | import Image from "../components/image" 6 | import SEO from "../components/seo" 7 | 8 | const IndexPage = () => ( 9 | 10 | 11 |

Hi people

12 |

Welcome to your new Gatsby site.

13 |

Now go build something great.

14 |
15 | 16 |
17 | Go to page 2 18 |
19 | ) 20 | 21 | export default IndexPage 22 | -------------------------------------------------------------------------------- /site/src/example-pages/page-2.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Link } from "gatsby" 3 | 4 | import Layout from "../components/layout" 5 | import SEO from "../components/seo" 6 | 7 | const SecondPage = () => ( 8 | 9 | 10 |

Hi from the second page

11 |

Welcome to page 2

12 | Go back to the homepage 13 |
14 | ) 15 | 16 | export default SecondPage 17 | -------------------------------------------------------------------------------- /site/src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swyxio/jamstack-jumpstart/3190e15ce05893208083fed7569109d4041a682d/site/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /site/src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swyxio/jamstack-jumpstart/3190e15ce05893208083fed7569109d4041a682d/site/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /site/src/pages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swyxio/jamstack-jumpstart/3190e15ce05893208083fed7569109d4041a682d/site/src/pages/.gitkeep -------------------------------------------------------------------------------- /site/src/pages/about.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | export default function() { 4 | return

ABout page!!!!!

5 | } 6 | -------------------------------------------------------------------------------- /site/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import { graphql, useStaticQuery } from "gatsby" 4 | 5 | export default function() { 6 | const data = useStaticQuery(graphql` 7 | query SiteData { 8 | site { 9 | siteMetadata { 10 | title 11 | } 12 | } 13 | } 14 | `) 15 | return ( 16 |
17 | page one
{JSON.stringify(data, null, 2)}
18 |
19 | ) 20 | } 21 | -------------------------------------------------------------------------------- /site/src/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swyxio/jamstack-jumpstart/3190e15ce05893208083fed7569109d4041a682d/site/src/templates/.gitkeep -------------------------------------------------------------------------------- /site/src/templates/pageTemplate.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { graphql } from "gatsby" 3 | 4 | export default function Template({ 5 | data, // this prop will be injected by the GraphQL query below. 6 | }) { 7 | const { markdownRemark } = data // data.markdownRemark holds our post data 8 | const { frontmatter, html } = markdownRemark 9 | return ( 10 |
11 |
12 |

{frontmatter.title}

13 |

{frontmatter.date}

14 |
18 |
19 |
20 | ) 21 | } 22 | 23 | export const pageQuery = graphql` 24 | query PageTemplate($slug: String!) { 25 | markdownRemark(frontmatter: { slug: { eq: $slug } }) { 26 | html 27 | frontmatter { 28 | date(formatString: "MMMM DD, YYYY") 29 | slug 30 | title 31 | } 32 | } 33 | } 34 | ` 35 | -------------------------------------------------------------------------------- /site/src/utils/auth.js: -------------------------------------------------------------------------------- 1 | const isBrowser = typeof window !== `undefined` 2 | 3 | export const setUser = user => 4 | (window.localStorage.gatsbyUser = JSON.stringify(user)) 5 | 6 | const getUser = () => { 7 | if (window.localStorage.gatsbyUser) { 8 | let user = JSON.parse(window.localStorage.gatsbyUser) 9 | return user ? user : {} 10 | } 11 | return {} 12 | } 13 | 14 | export const isLoggedIn = () => { 15 | if (!isBrowser) return false 16 | 17 | const user = getUser() 18 | if (user) return !!user.username 19 | } 20 | 21 | export const getCurrentUser = () => isBrowser && getUser() 22 | 23 | export const logout = callback => { 24 | if (!isBrowser) return 25 | setUser({}) 26 | callback() 27 | } 28 | --------------------------------------------------------------------------------