├── .env.development ├── .env.production ├── .gitignore ├── .kodiak.toml ├── .nvmrc ├── .prettierrc ├── LICENSE ├── README.md ├── config └── website.js ├── content └── blog │ ├── demo01 │ ├── banner.png │ └── index.md │ ├── demo02 │ ├── banner.png │ └── index.md │ ├── demo03 │ ├── banner.png │ └── index.md │ ├── demo04 │ ├── banner.png │ ├── example.png │ └── index.mdx │ ├── demo05 │ ├── banner.png │ └── index.md │ ├── demo06 │ ├── banner.png │ └── index.md │ ├── demo07 │ ├── banner.png │ └── index.md │ ├── demo08 │ ├── banner.png │ └── index.md │ ├── demo09 │ ├── banner.png │ └── index.md │ └── frontmatter-placeholder │ ├── images │ └── banner.jpg │ └── index.md ├── gatsby-config.js ├── gatsby-node.js ├── now.json.v1.template ├── now.json.v2.template ├── package.json ├── src ├── components │ ├── ConfirmMessage │ │ ├── Illustrations.js │ │ └── Message.js │ ├── Container.js │ ├── Footer.js │ ├── Forms │ │ └── Subscribe.js │ ├── Header │ │ ├── Button.js │ │ ├── Links.js │ │ ├── MobileMenu.js │ │ ├── ThemeToggler.js │ │ └── index.js │ ├── Layout.js │ ├── Link.js │ ├── SEO │ │ ├── SchemaOrg.js │ │ └── index.js │ ├── Share.js │ ├── Social.js │ ├── Theming.js │ └── mdx │ │ ├── Code.js │ │ ├── Paragraph.js │ │ ├── Subtitle.js │ │ ├── Title.js │ │ └── index.js ├── fonts │ ├── Inter-UI-Bold.woff │ ├── Inter-UI-BoldItalic.woff │ ├── Inter-UI-Italic.woff │ ├── Inter-UI-Regular.woff │ ├── Inter-UI-SemiBold.woff │ ├── Inter-UI-SemiBoldItalic.woff │ └── fonts.css ├── html.js ├── lib │ ├── breakpoints.js │ ├── colors.js │ ├── reset.js │ └── typography.js ├── pages │ ├── 404.js │ ├── index.js │ ├── messages.js │ └── subscribe.js └── templates │ ├── blog.js │ └── post.js ├── static ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── images │ └── logo.png ├── mstile-150x150.png ├── readme.md └── safari-pinned-tab.svg └── yarn.lock /.env.development: -------------------------------------------------------------------------------- 1 | CONVERTKIT_PUBLIC_KEY=SOME_KEY 2 | CONVERTKIT_SIGNUP_FORM=SOME_FORM_ID 3 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | CONVERTKIT_PUBLIC_KEY=SOME_KEY 2 | CONVERTKIT_SIGNUP_FORM=SOME_FORM_ID 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | .gatsby-context.js 29 | .sass-cache/ 30 | .cache/ 31 | .DS_Store 32 | public 33 | -------------------------------------------------------------------------------- /.kodiak.toml: -------------------------------------------------------------------------------- 1 | # version is the only required field 2 | version = 1 3 | 4 | # the following settings can be omitted since they have defaults 5 | 6 | [merge] 7 | blacklist_labels = ["NO MERGE"] # default: [] 8 | method = "squash" # default: "merge", options: "merge", "squash", "rebase" 9 | delete_branch_on_merge = true # default: false 10 | 11 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "printWidth": 80, 6 | "tabWidth": 2, 7 | "useTabs": false, 8 | "bracketSpacing": true, 9 | "jsxBracketSameLine": false 10 | } 11 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # egghead.io creator MDX Blog Starter Project 2 | 3 | This is based on Robin Wieruch's https://github.com/rwieruch/gatsby-mdx-blog-starter-project 4 | 5 | Lots of nice pieces are also borrowed from Jason Lengstorf https://github.com/jlengstorf/lengstorf.com 6 | 7 | A starter project in [Gatsby.js](https://www.gatsbyjs.org/) with [MDX](https://github.com/mdx-js/mdx). 8 | 9 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/eggheadio/gatsby-starter-egghead-blog) 10 | 11 | ## Features 12 | 13 | - MDX: JavaScript/React in Markdown 14 | - Prism.js: Syntax Highlighting 15 | - Pagination 16 | - Emotion 17 | - Typography.js 18 | - Self-hosted fonts ([Inter UI](https://rsms.me/inter/)) 19 | - Social media share buttons 20 | - Site & Theme config files 21 | - ConvertKit subscribe form (Formik and Yup) 22 | - Placeholder illustrations by [Katerina Limpitsouni](https://twitter.com/ninalimpi) from [undraw.co](https://undraw.co/) 23 | 24 | ## [➞ Demo](https://egghead-gatsby-starter.netlify.com/) 25 | 26 | ## Setup 27 | 28 | - `git clone git@github.com:eggheadio/gatsby-starter-egghead-blog.git` 29 | - `cd gatsby-starter-egghead-blog` 30 | - `yarn` 31 | - `gatsby develop` 32 | - visit http://localhost:8000 33 | 34 | ## Setup via Gatsby CLI 35 | 36 | - `gatsby new gatsby-starter-egghead-blog git@github.com:eggheadio/gatsby-starter-egghead-blog.git` 37 | - `cd gatsby-starter-egghead-blog` 38 | - `yarn` 39 | - `gatsby develop` 40 | - visit http://localhost:8000 41 | 42 | ## Set up Redirects 43 | This starter supports a `redirects` property on posts so that you can define alias urls for blog posts. This won't work out of the box. We use the `createRedirect` Gatsby actions ([docs](https://www.gatsbyjs.org/docs/actions/#createRedirect)) which requires an additional plugin to be added to your site, given what provider you deploy your site to. Two popular ones are [`gatsby-plugin-netlify`](https://www.gatsbyjs.org/packages/gatsby-plugin-netlify/) or [`gatsby-plugin-s3`](https://www.gatsbyjs.org/packages/gatsby-plugin-s3/). 44 | -------------------------------------------------------------------------------- /config/website.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pathPrefix: '/', // Prefix for all links. If you deploy your site to example.com/blog your pathPrefix should be "blog" 3 | siteTitle: 'My Blog', // Navigation and Site Title 4 | siteTitleAlt: 'The blog of an egghead creator', // Alternative Site title for SEO 5 | siteTitleShort: 'Starter Blog', // short_name for manifest 6 | siteUrl: 'https://your-site.io', // Domain of your site. No trailing slash! 7 | siteLanguage: 'en', // Language Tag on element 8 | siteLogo: 'images/logo.png', // Used for SEO and manifest, path to your image you placed in the 'static' folder 9 | siteDescription: 'This is where they post things!', 10 | author: 'Author', // Author for schemaORGJSONLD 11 | organization: 'egghead.io LLC', 12 | 13 | // siteFBAppID: '123456789', // Facebook App ID - Optional 14 | userTwitter: '@eggheadio', // Twitter Username 15 | ogSiteName: 'egghead.io Gatsby Starter Blog', // Facebook Site Name 16 | ogLanguage: 'en_US', 17 | googleAnalyticsID: '', 18 | 19 | // Manifest and Progress color 20 | themeColor: '#5348FF', 21 | backgroundColor: '#2b2e3c', 22 | 23 | // Social component 24 | twitter: 'https://twitter.com/eggheadio/', 25 | twitterHandle: '@eggheadio', 26 | github: 'https://github.com/eggheadio/', 27 | linkedin: '', 28 | } 29 | -------------------------------------------------------------------------------- /content/blog/demo01/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo01/banner.png -------------------------------------------------------------------------------- /content/blog/demo01/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-01 3 | date: 2017-01-01 4 | title: 'A Lovely Walk In The Park' 5 | description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed molestie leo ut sodales porta. Vivamus pharetra risus ac fermentum faucibus. Nam in sodales ex.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo02/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo02/banner.png -------------------------------------------------------------------------------- /content/blog/demo02/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-02 3 | date: 2018-01-01 4 | title: 'Please, Tell Me More' 5 | description: 'Sed vehicula mauris vel felis faucibus placerat. Quisque sed justo quis tellus aliquam tincidunt. Vestibulum sit amet ante sit amet nibh accumsan viverra.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo03/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo03/banner.png -------------------------------------------------------------------------------- /content/blog/demo03/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-03 3 | date: 2018-02-01 4 | title: 'The One Time And The One Thing' 5 | description: 'Morbi ut dapibus sem. Interdum et malesuada fames ac ante ipsum primis in faucibus.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo04/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo04/banner.png -------------------------------------------------------------------------------- /content/blog/demo04/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo04/example.png -------------------------------------------------------------------------------- /content/blog/demo04/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-04 3 | date: 2019-01-13 4 | title: 'Thought Leadering Considered Harmful' 5 | description: 'This is dummy description. It has been placed here solely to demonstrate the look and feel of finished, typeset text.' 6 | published: true 7 | author: 'Joe Gatsby' 8 | banner: './banner.png' 9 | --- 10 | 11 | This exists to populate GraphQL fields and avoid null errors. It should contain all of the available frontmatter. 12 | 13 | Fusce ac urna egestas mi ornare rutrum. Ut fringilla, mauris 14 | non vulputate luctus, nunc tortor tempus nunc, ut tincidunt mi 15 | magna id nulla. Nunc id **convallis metus**. Pellentesque at laoreet 16 | ex. Vestibulum hendrerit, nibh eget [tristique finibus](/), nibh eros 17 | cursus lacus, eget semper nisi libero eu libero. 18 | 19 | Integer condimentum _aliquam massa_, id aliquet ante ullamcorper at. 20 | Mauris nibh mi, eleifend nec venenatis et, mattis et felis. Etiam 21 | fringilla libero sit amet tortor congue, et _**tempor tortor**_ ullamcorper. 22 | Phasellus pretium pharetra tortor. 23 | 24 | ```jsx 25 | // footer.jsx 26 | import React from 'react' 27 | 28 | const Footer = () => ( 29 | // highlight-next-line 30 | 31 | Copyright {`©`} {new Date().getFullYear()} 32 | 33 | ) 34 | 35 | export default Footer 36 | 37 | // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. 38 | ``` 39 | 40 | # Praesent sollicitudin finibus rhoncus. 41 | 42 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse potenti. 43 | Vivamus accumsan leo enim, ut elementum magna ultricies at. Curabitur dictum, 44 | libero vitae tempus gravida, justo nibh accumsan libero, rutrum iaculis nisi sem 45 | at est. Vestibulum egestas tellus et lectus volutpat, at tristique justo malesuada. 46 | Phasellus velit tellus, dictum nec rhoncus et, blandit vehicula arcu. 47 | 48 | > “This is a quote. Lorem ipsum dolor sit amet.” 49 | 50 | Vivamus non eros sit amet sem venenatis porta. Nulla eu massa non ante vestibulum 51 | aliquam quis sed nisi. Quisque massa risus, vulputate a ullamcorper eget, semper ac 52 | orci. Aenean arcu massa, consectetur sed arcu id, consequat ullamcorper nisi. Sed sit 53 | amet semper turpis, sit amet tincidunt felis. Etiam eu mollis augue, maximus iaculis 54 | lectus. Morbi sit amet sem a est rhoncus aliquam. Pellentesque nibh libero, pellentesque 55 | ut leo et, scelerisque interdum augue. 56 | 57 | ![Example](./example.png) 58 | 59 | ## Lorem ipsum dolor sit amet 60 | 61 | Aenean fringilla sapien vitae maximus lobortis. Vivamus luctus purus nisi. Aenean quis 62 | ipsum turpis. Ut ut rutrum orci. Duis in mi lacus. Nullam rhoncus at nulla eu aliquam. 63 | Curabitur vitae augue justo. 64 | 65 | ```css 66 | /* styles.css */ 67 | a { 68 | cursor: pointer; 69 | text-decoration: none; 70 | color: blue; 71 | &:hover { 72 | text-decoration: underline; 73 | text-decoration-color: #c4c4c4; 74 | outline: none; 75 | } 76 | } 77 | ``` 78 | 79 | ### Nullam rhoncus 80 | 81 | - Lorem ipsum 82 | - Dolor sit amet 83 | - Duis in mi lacus 84 | 85 | Integer sed sapien sed arcu faucibus dictum. Duis scelerisque 86 | bibendum viverra. Donec sodales fringilla sapien vitae tempor. 87 | 88 | ### Duis scelerisque 89 | 90 | 1. Lorem ipsum 91 | 2. Dolor sit amet 92 | 3. Duis in mi lacus 93 | 94 | Quisque massa risus, vulputate a ullamcorper eget, semper ac 95 | orci. Aenean arcu massa, consectetur sed arcu id, consequat ullamcorper nisi. Sed sit 96 | amet semper turpis, sit amet tincidunt felis. 97 | -------------------------------------------------------------------------------- /content/blog/demo05/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo05/banner.png -------------------------------------------------------------------------------- /content/blog/demo05/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-05 3 | date: 2018-08-22 4 | title: 'Do Less Better' 5 | description: 'Vestibulum quis bibendum nulla, dignissim faucibus orci. Sed purus nisl, hendrerit id suscipit sit amet.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo06/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo06/banner.png -------------------------------------------------------------------------------- /content/blog/demo06/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-06 3 | date: 2010-10-05 4 | title: 'Everybody Is Above Average' 5 | description: 'Nulla vel libero quis sem convallis aliquam.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo07/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo07/banner.png -------------------------------------------------------------------------------- /content/blog/demo07/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-07 3 | date: 2010-10-05 4 | title: 'Lorem ipsum dolor sit amet' 5 | description: 'Aliquam at mauris leo. Duis neque eros, malesuada non mauris eget, volutpat imperdiet enim.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo08/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo08/banner.png -------------------------------------------------------------------------------- /content/blog/demo08/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-08 3 | date: 2010-10-05 4 | title: 'Lorem ipsum dolor sit amet' 5 | description: 'Ut elementum urna quis ex porta, eu porta ante porta. Curabitur a lectus fringilla, condimentum sem eu, efficitur ligula.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/demo09/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/demo09/banner.png -------------------------------------------------------------------------------- /content/blog/demo09/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: demo-09 3 | date: 2010-10-05 4 | title: 'Lorem ipsum dolor sit amet' 5 | description: 'Curabitur fringilla vel purus sit amet malesuada.' 6 | published: true 7 | banner: './banner.png' 8 | --- 9 | 10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi rhoncus sem non eros semper posuere. Quisque scelerisque non diam in fringilla. Praesent dignissim eros vel urna tincidunt pharetra. Fusce cursus, est quis vestibulum facilisis, elit diam convallis orci, eu convallis metus leo vitae massa. Mauris id nisi ut erat auctor fermentum. Sed purus nisl, hendrerit id suscipit sit amet, consectetur ut magna. Donec cursus accumsan lectus vel porta. Proin ac mollis arcu. Integer nec dictum sapien, dignissim semper dui. Quisque porta ipsum sit amet lorem feugiat tincidunt. Nam vel purus dolor. Donec semper tortor lacus, sed blandit sapien rutrum id. Fusce gravida tortor ultrices magna auctor, at bibendum est pellentesque. Vivamus porttitor ultrices varius. 11 | 12 | Phasellus nulla justo, auctor in ornare sit amet, volutpat at sapien. Donec non turpis nec ligula finibus finibus quis id lorem. Vestibulum sodales ornare lorem, sed dapibus justo sagittis non. Curabitur rutrum, eros quis iaculis commodo, sem turpis blandit quam, eu egestas risus nunc quis sapien. Aliquam erat volutpat. In leo massa, pellentesque non mollis ac, tristique vitae neque. Donec nunc magna, pharetra quis iaculis sit amet, molestie non est. Sed ornare urna id molestie convallis. 13 | 14 | Cras ut nulla pellentesque, convallis orci vel, ultricies augue. Cras imperdiet magna sit amet vestibulum dictum. Maecenas ac tortor vel nisl luctus blandit. Nunc bibendum commodo aliquet. Nunc urna tellus, sagittis vitae mollis vel, venenatis et lectus. Morbi lacus felis, fringilla a feugiat eget, imperdiet ac odio. Duis tortor tellus, vulputate eget arcu eget, pulvinar porta odio. 15 | 16 | Cras tincidunt, massa vel pulvinar mollis, purus ex aliquam justo, at blandit turpis metus sit amet felis. Cras at nibh odio. Nulla ultrices metus sed est porta bibendum. Quisque efficitur nisl eget odio fringilla mollis. Vivamus vel lectus sem. Sed sit amet nisi aliquet, suscipit quam at, congue lacus. Pellentesque volutpat, ante ac mollis iaculis, est enim eleifend quam, id molestie est felis in sem. Nullam ac rutrum tortor, sed venenatis lectus. Nullam quis imperdiet urna. Integer mauris mi, tincidunt sit amet finibus eget, posuere eu leo. Fusce sodales convallis convallis. Pellentesque at augue id nulla convallis aliquam et id tellus. Praesent non nibh viverra odio mattis congue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; 17 | 18 | Curabitur aliquam hendrerit imperdiet. Sed fringilla dui velit, et suscipit diam bibendum vitae. Nulla eu ultricies tellus. Pellentesque ex quam, blandit ut varius ut, varius vel sapien. Quisque nec dolor a lectus porttitor vehicula. Nunc condimentum semper sem, vitae dapibus orci hendrerit vitae. Nullam cursus, elit viverra consectetur pharetra, dolor mauris sodales dolor, sit amet rutrum metus ex non est. Pellentesque eu sapien cursus, feugiat metus ut, tempor justo. Morbi et commodo risus. In hac habitasse platea dictumst. Aliquam eget consectetur metus. 19 | -------------------------------------------------------------------------------- /content/blog/frontmatter-placeholder/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/content/blog/frontmatter-placeholder/images/banner.jpg -------------------------------------------------------------------------------- /content/blog/frontmatter-placeholder/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: invisible-post 3 | date: 2019-01-01 4 | title: 'this post is a ghost' 5 | description: 'this post has all of the right fields' 6 | categories: ['test'] 7 | keywords: ['test'] 8 | banner: './images/banner.jpg' 9 | published: false 10 | author: 'author' 11 | redirects: 12 | - '/invisible-post-423123' 13 | --- 14 | 15 | This exists to populate GraphQL fields and avoid null errors. It should contain all of the available frontmatter. 16 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | const config = require('./config/website') 2 | const pathPrefix = config.pathPrefix === '/' ? '' : config.pathPrefix 3 | 4 | require('dotenv').config({ 5 | path: `.env.${process.env.NODE_ENV}`, 6 | }) 7 | 8 | module.exports = { 9 | pathPrefix: config.pathPrefix, 10 | siteMetadata: { 11 | siteUrl: config.siteUrl + pathPrefix, 12 | title: config.siteTitle, 13 | twitterHandle: config.twitterHandle, 14 | description: config.siteDescription, 15 | keywords: ['Video Blogger'], 16 | canonicalUrl: config.siteUrl, 17 | image: config.siteLogo, 18 | author: { 19 | name: config.author, 20 | minibio: ` 21 | egghead is the premier place on the internet for 22 | experienced developers to enhance their skills and stay current 23 | in the fast-faced field of web development. 24 | `, 25 | }, 26 | organization: { 27 | name: config.organization, 28 | url: config.siteUrl, 29 | logo: config.siteLogo, 30 | }, 31 | social: { 32 | twitter: config.twitterHandle, 33 | fbAppID: '', 34 | }, 35 | }, 36 | plugins: [ 37 | { 38 | resolve: 'gatsby-source-filesystem', 39 | options: { 40 | path: `${__dirname}/content/blog`, 41 | name: 'blog', 42 | }, 43 | }, 44 | { 45 | resolve: `gatsby-plugin-mdx`, 46 | options: { 47 | extensions: ['.mdx', '.md', '.markdown'], 48 | gatsbyRemarkPlugins: [ 49 | { 50 | resolve: 'gatsby-remark-images', 51 | options: { 52 | backgroundColor: '#fafafa', 53 | maxWidth: 1035, 54 | }, 55 | }, 56 | ], 57 | }, 58 | }, 59 | 'gatsby-plugin-sharp', 60 | 'gatsby-transformer-sharp', 61 | 'gatsby-plugin-emotion', 62 | 'gatsby-plugin-catch-links', 63 | 'gatsby-plugin-react-helmet', 64 | { 65 | resolve: 'gatsby-plugin-manifest', 66 | options: { 67 | name: config.siteTitle, 68 | short_name: config.siteTitleShort, 69 | description: config.siteDescription, 70 | start_url: config.pathPrefix, 71 | background_color: config.backgroundColor, 72 | theme_color: config.themeColor, 73 | display: 'standalone', 74 | icons: [ 75 | { 76 | src: '/android-chrome-192x192.png', 77 | sizes: '192x192', 78 | type: 'image/png', 79 | }, 80 | { 81 | src: '/android-chrome-512x512.png', 82 | sizes: '512x512', 83 | type: 'image/png', 84 | }, 85 | ], 86 | }, 87 | }, 88 | { 89 | resolve: `gatsby-plugin-google-analytics`, 90 | options: { 91 | trackingId: `GOOGLE_ID`, 92 | }, 93 | }, 94 | { 95 | resolve: `gatsby-plugin-feed`, 96 | options: { 97 | query: ` 98 | { 99 | site { 100 | siteMetadata { 101 | title 102 | description 103 | siteUrl 104 | site_url: siteUrl 105 | } 106 | } 107 | } 108 | `, 109 | feeds: [ 110 | { 111 | serialize: ({ query: { site, allMdx } }) => { 112 | return allMdx.edges.map(edge => { 113 | return Object.assign({}, edge.node.frontmatter, { 114 | description: edge.node.excerpt, 115 | date: edge.node.fields.date, 116 | url: site.siteMetadata.siteUrl + '/' + edge.node.fields.slug, 117 | guid: site.siteMetadata.siteUrl + '/' + edge.node.fields.slug, 118 | }) 119 | }) 120 | }, 121 | query: ` 122 | { 123 | allMdx( 124 | limit: 1000, 125 | filter: { frontmatter: { published: { ne: false } } } 126 | sort: { order: DESC, fields: [frontmatter___date] } 127 | ) { 128 | edges { 129 | node { 130 | excerpt(pruneLength: 250) 131 | fields { 132 | slug 133 | date 134 | } 135 | frontmatter { 136 | title 137 | } 138 | } 139 | } 140 | } 141 | } 142 | `, 143 | output: '/rss.xml', 144 | title: 'Blog RSS Feed', 145 | }, 146 | ], 147 | }, 148 | }, 149 | { 150 | resolve: `gatsby-plugin-typography`, 151 | options: { 152 | pathToConfigModule: `src/lib/typography`, 153 | }, 154 | }, 155 | 'gatsby-plugin-offline', 156 | ], 157 | } 158 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const _ = require('lodash') 4 | const PAGINATION_OFFSET = 7 5 | 6 | const createPosts = (createPage, createRedirect, edges) => { 7 | edges.forEach(({ node }, i) => { 8 | const prev = i === 0 ? null : edges[i - 1].node 9 | const next = i === edges.length - 1 ? null : edges[i + 1].node 10 | const pagePath = node.fields.slug 11 | 12 | if (node.fields.redirects) { 13 | node.fields.redirects.forEach(fromPath => { 14 | createRedirect({ 15 | fromPath, 16 | toPath: pagePath, 17 | redirectInBrowser: true, 18 | isPermanent: true, 19 | }) 20 | }) 21 | } 22 | 23 | createPage({ 24 | path: pagePath, 25 | component: path.resolve(`./src/templates/post.js`), 26 | context: { 27 | id: node.id, 28 | prev, 29 | next, 30 | }, 31 | }) 32 | }) 33 | } 34 | 35 | exports.createPages = ({ actions, graphql }) => 36 | graphql(` 37 | query { 38 | allMdx( 39 | filter: { frontmatter: { published: { ne: false } } } 40 | sort: { order: DESC, fields: [frontmatter___date] } 41 | ) { 42 | edges { 43 | node { 44 | id 45 | parent { 46 | ... on File { 47 | name 48 | sourceInstanceName 49 | } 50 | } 51 | excerpt(pruneLength: 250) 52 | fields { 53 | title 54 | slug 55 | date 56 | } 57 | } 58 | } 59 | } 60 | } 61 | `).then(({ data, errors }) => { 62 | if (errors) { 63 | return Promise.reject(errors) 64 | } 65 | 66 | if (_.isEmpty(data.allMdx)) { 67 | return Promise.reject('There are no posts!') 68 | } 69 | 70 | const { edges } = data.allMdx 71 | const { createRedirect, createPage } = actions 72 | createPosts(createPage, createRedirect, edges) 73 | createPaginatedPages(actions.createPage, edges, '/blog', { 74 | categories: [], 75 | }) 76 | }) 77 | 78 | exports.onCreateWebpackConfig = ({ actions }) => { 79 | actions.setWebpackConfig({ 80 | resolve: { 81 | modules: [path.resolve(__dirname, 'src'), 'node_modules'], 82 | alias: { 83 | 'react-dom': '@hot-loader/react-dom', 84 | $components: path.resolve(__dirname, 'src/components'), 85 | }, 86 | }, 87 | }) 88 | } 89 | 90 | const createPaginatedPages = (createPage, edges, pathPrefix, context) => { 91 | const pages = edges.reduce((acc, value, index) => { 92 | const pageIndex = Math.floor(index / PAGINATION_OFFSET) 93 | 94 | if (!acc[pageIndex]) { 95 | acc[pageIndex] = [] 96 | } 97 | 98 | acc[pageIndex].push(value.node.id) 99 | 100 | return acc 101 | }, []) 102 | 103 | pages.forEach((page, index) => { 104 | const previousPagePath = `${pathPrefix}/${index + 1}` 105 | const nextPagePath = index === 1 ? pathPrefix : `${pathPrefix}/${index - 1}` 106 | 107 | createPage({ 108 | path: index > 0 ? `${pathPrefix}/${index}` : `${pathPrefix}`, 109 | component: path.resolve(`src/templates/blog.js`), 110 | context: { 111 | pagination: { 112 | page, 113 | nextPagePath: index === 0 ? null : nextPagePath, 114 | previousPagePath: 115 | index === pages.length - 1 ? null : previousPagePath, 116 | pageCount: pages.length, 117 | pathPrefix, 118 | }, 119 | ...context, 120 | }, 121 | }) 122 | }) 123 | } 124 | 125 | exports.onCreateNode = ({ node, getNode, actions }) => { 126 | const { createNodeField } = actions 127 | 128 | if (node.internal.type === `Mdx`) { 129 | const parent = getNode(node.parent) 130 | const titleSlugged = _.join(_.drop(parent.name.split('-'), 3), '-') 131 | 132 | const slug = 133 | parent.sourceInstanceName === 'legacy' 134 | ? `blog/${node.frontmatter.date 135 | .split('T')[0] 136 | .replace(/-/g, '/')}/${titleSlugged}` 137 | : node.frontmatter.slug || titleSlugged 138 | 139 | createNodeField({ 140 | name: 'id', 141 | node, 142 | value: node.id, 143 | }) 144 | 145 | createNodeField({ 146 | name: 'published', 147 | node, 148 | value: node.frontmatter.published, 149 | }) 150 | 151 | createNodeField({ 152 | name: 'title', 153 | node, 154 | value: node.frontmatter.title, 155 | }) 156 | 157 | createNodeField({ 158 | name: 'description', 159 | node, 160 | value: node.frontmatter.description, 161 | }) 162 | 163 | createNodeField({ 164 | name: 'slug', 165 | node, 166 | value: slug, 167 | }) 168 | 169 | createNodeField({ 170 | name: 'date', 171 | node, 172 | value: node.frontmatter.date ? node.frontmatter.date.split(' ')[0] : '', 173 | }) 174 | 175 | createNodeField({ 176 | name: 'banner', 177 | node, 178 | value: node.frontmatter.banner, 179 | }) 180 | 181 | createNodeField({ 182 | name: 'categories', 183 | node, 184 | value: node.frontmatter.categories || [], 185 | }) 186 | 187 | createNodeField({ 188 | name: 'keywords', 189 | node, 190 | value: node.frontmatter.keywords || [], 191 | }) 192 | 193 | createNodeField({ 194 | name: 'redirects', 195 | node, 196 | value: node.frontmatter.redirects, 197 | }) 198 | 199 | createNodeField({ 200 | name: 'isPost', 201 | node, 202 | value: true, 203 | }) 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /now.json.v1.template: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "GOOGLE_ANALYTICS": "GA_GOES_HERE", 4 | "NODE_ENV": "production" 5 | }, 6 | "alias": "DOMAIN_GOES_HERE", 7 | "scale": { 8 | "sfo1": { 9 | "min": 1, 10 | "max": "auto" 11 | } 12 | }, 13 | "static": { 14 | "trailingSlash": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /now.json.v2.template: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "NODE_ENV": "production", 4 | "GOOGLE_ANALYTICS": "GA_GOES_HERE" 5 | }, 6 | "name": "PROJECT_NAME", 7 | "alias": ["DOMAIN_NAME", "www.DOMAIN_NAME"], 8 | "version": 2, 9 | "regions": ["sfo1", "gru1", "bru1"], 10 | "builds": [ 11 | { 12 | "src": "package.json", 13 | "use": "@now/static-build", 14 | "config": { "distDir": "public" } 15 | } 16 | ], 17 | "routes": [ 18 | {"src": "^/public/static/(.*)", "headers": {"cache-control": "public,max-age=31536000,immutable"} }, 19 | {"src": "^/(.*).(css|js)", "headers": {"cache-control": "public,max-age=31536000,immutable"} }, 20 | {"src": "^/(.*).html", "headers": {"cache-control": "public,max-age=0,must-revalidate"} } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-egghead-blog", 3 | "description": "This is a starter for egghead content creator blogs", 4 | "version": "1.0.0", 5 | "author": "egghead.io (https://egghead.io)", 6 | "repository": "https://github.com/eggheadio/gatsby-starter-egghead-blog", 7 | "dependencies": { 8 | "@callstack/react-theme-provider": "^3.0.5", 9 | "@emotion/core": "^10.0.22", 10 | "@emotion/styled": "^10.0.22", 11 | "@hot-loader/react-dom": "16.10.2", 12 | "@mdx-js/mdx": "^1.5.1", 13 | "@mdx-js/react": "^1.5.1", 14 | "core-js": "^3.3.3", 15 | "dotenv": "^8.2.0", 16 | "dotenv-parse-variables": "^0.2.3", 17 | "emotion": "^10.0.17", 18 | "emotion-server": "^10.0.17", 19 | "emotion-theming": "^10.0.19", 20 | "formik": "^1.5.8", 21 | "gatsby": "^2.17.2", 22 | "gatsby-cli": "^2.8.5", 23 | "gatsby-image": "^2.2.29", 24 | "gatsby-link": "^2.2.22", 25 | "gatsby-plugin-catch-links": "^2.1.15", 26 | "gatsby-plugin-emotion": "^4.1.12", 27 | "gatsby-plugin-feed": "^2.3.19", 28 | "gatsby-plugin-google-analytics": "^2.1.23", 29 | "gatsby-plugin-manifest": "^2.2.23", 30 | "gatsby-plugin-mdx": "^1.0.53", 31 | "gatsby-plugin-meta-redirect": "^1.1.1", 32 | "gatsby-plugin-offline": "^3.0.16", 33 | "gatsby-plugin-react-helmet": "^3.1.13", 34 | "gatsby-plugin-sharp": "^2.2.32", 35 | "gatsby-plugin-typography": "^2.3.14", 36 | "gatsby-remark-copy-linked-files": "^2.1.28", 37 | "gatsby-remark-images": "^3.1.28", 38 | "gatsby-remark-prismjs": "^3.3.20", 39 | "gatsby-source-filesystem": "^2.1.33", 40 | "gatsby-transformer-remark": "^2.6.30", 41 | "gatsby-transformer-sharp": "^2.3.0", 42 | "polished": "^3.4.1", 43 | "prism-react-renderer": "^1.0.2", 44 | "prism-themes": "^1.3.0", 45 | "prismjs": "^1.17.1", 46 | "react": "^16.11.0", 47 | "react-dom": "^16.11.0", 48 | "react-helmet": "~5.2.1", 49 | "react-icons": "^3.7.0", 50 | "react-live": "^2.2.1", 51 | "react-markdown": "^4.2.2", 52 | "react-share": "^3.0.1", 53 | "react-typography": "^0.16.19", 54 | "serve": "^11.2.0", 55 | "typescript": "^3.6.4", 56 | "typography": "^0.16.19", 57 | "yup": "^0.27.0" 58 | }, 59 | "devDependencies": { 60 | "babel-preset-gatsby": "^0.2.20", 61 | "prettier": "1.18.2" 62 | }, 63 | "keywords": [ 64 | "gatsby" 65 | ], 66 | "license": "MIT", 67 | "main": "n/a", 68 | "scripts": { 69 | "build": "gatsby build", 70 | "develop": "gatsby develop", 71 | "start": "serve public/", 72 | "now-build": "npm run build" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/components/ConfirmMessage/Illustrations.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css, keyframes } from '@emotion/core' 3 | import { fonts } from '../../lib/typography' 4 | import { useTheme } from '../Theming' 5 | 6 | // PleaseConfirmIllustration 7 | const PaperRollOut = keyframes` 8 | from, 0% { 9 | transform: translate(10px, 80px); 10 | } 11 | to, 100% { 12 | transform: translate(10px, 0); 13 | 14 | } 15 | ` 16 | const ButtonRollOut = keyframes` 17 | from, 0% { 18 | opacity: 0; 19 | transform: translate(0px, 80px) scale(1); 20 | transform-origin: center center; 21 | } 22 | 70% { 23 | transform: scale(1); 24 | } 25 | 90% { 26 | transform: scale(0.95); 27 | transform-origin: center center; 28 | } 29 | to, 100% { 30 | opacity: 1; 31 | transform: translate(0px, 0) scale(1); 32 | transform-origin: center center; 33 | } 34 | ` 35 | const TextCopyRollOut = keyframes` 36 | from, 0% { 37 | opacity: 0; 38 | transform: translate(0px, 80px); 39 | } 40 | to, 100% { 41 | opacity: 1; 42 | transform: translate(0px, 0); 43 | } 44 | ` 45 | const TextCopyWidth1 = keyframes` 46 | from, 0% { 47 | width: 0; 48 | } 49 | to, 100% { 50 | width: 25; 51 | } 52 | ` 53 | const TextCopyWidth2 = keyframes` 54 | from, 0% { 55 | width: 0; 56 | } 57 | to, 100% { 58 | width: 47; 59 | } 60 | ` 61 | const NotificationFadeIn = keyframes` 62 | 0% { 63 | opacity: 0; 64 | r: 0; 65 | } 66 | 50% { 67 | opacity: 0; 68 | r: 0; 69 | } 70 | 100% { 71 | opacity: 1; 72 | r: 9.5; 73 | 74 | } 75 | ` 76 | // SVG 77 | export const PleaseConfirmIllustration = () => { 78 | const theme = useTheme() 79 | return ( 80 |
116 | 123 | 124 | 125 | 126 | 127 | 131 | 132 | 133 | 134 | 135 | 140 | 141 | 149 | 156 | 157 | 1 158 | 159 | 160 | 161 | 171 | 177 | 178 | 188 | 198 | 208 | 209 | 216 | 220 | 224 | 225 | 226 |
227 | ) 228 | } 229 | 230 | // ThankYouIllustration 231 | const SlopeRollOut = keyframes` 232 | from, 0% { 233 | //transform: translate(0, 115px) rotate(90deg); 234 | transform: translate(0, 115px); 235 | } 236 | to, 100% { 237 | //transform: translate(0, 0) rotate(0); 238 | transform: translate(0, 0); 239 | } 240 | ` 241 | const SheetGrow = keyframes` 242 | from, 0% { 243 | transform: scale(0, 1) rotate(-20deg) skew(30deg); 244 | } 245 | to, 100% { 246 | transform: scale(1, 1) rotate(0) skew(0); 247 | } 248 | ` 249 | const TextFadeIn = keyframes` 250 | from, 0% { 251 | opacity: 0; 252 | //transform: rotate(-20deg); 253 | } 254 | 5% { 255 | opacity: 0; 256 | //transform: rotate(-20deg); 257 | } 258 | to, 100% { 259 | opacity: 1; 260 | //transform: rotate(0); 261 | } 262 | ` 263 | const GrassGrow = keyframes` 264 | from, 0% { 265 | 266 | transform: translate(-35px, 20px); 267 | } 268 | 40% { 269 | transform: translate(-35px, 20px); 270 | } 271 | to, 100% { 272 | 273 | transform: translate(-35px, 0); 274 | } 275 | ` 276 | const SlopeGrow = keyframes` 277 | from, 0% { 278 | transform: translate(0, 80px); 279 | } 280 | to, 100% { 281 | transform: translate(0, 0); 282 | } 283 | ` 284 | // SVG 285 | export const ThankYouIllustration = () => { 286 | const theme = useTheme() 287 | return ( 288 |
310 | 317 | 318 | 319 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 343 | 351 | 359 | 367 | 377 | 383 | 384 | WELCOME 385 | 386 | 387 | 388 | 389 | 390 | 391 |
392 | ) 393 | } 394 | 395 | // UnsubscribeIllustration 396 | const MailSlide = keyframes` 397 | from, 0% { 398 | opacity: 0; 399 | transform: translate(18px, 20px); 400 | } 401 | 20% { 402 | opacity: 1; 403 | 404 | } 405 | to, 100% { 406 | opacity: 1; 407 | transform: translate(18px, 75px); 408 | } 409 | ` 410 | const PiecesSlide = keyframes` 411 | from, 0% { 412 | transform: scale(1, 0); 413 | opacity: 0; 414 | } 415 | 20% { 416 | transform: scale(1, 0); 417 | opacity: 1; 418 | } 419 | 85% { 420 | opacity: 1; 421 | transform: scale(1, 1); 422 | } 423 | to, 100% { 424 | transform: scale(1,1) translate(0, 50px); 425 | opacity: 1; 426 | } 427 | ` 428 | const LightBlink = keyframes` 429 | from, 20% { 430 | opacity: 0.4; 431 | } 432 | 80% { 433 | fill: white; 434 | opacity: 1; 435 | } 436 | to, 100% { 437 | opacity: 0.4; 438 | } 439 | ` 440 | const ShadowOpacity = keyframes` 441 | from, 0% { 442 | opacity: 0; 443 | } 444 | 80% { 445 | opacity: 1; 446 | } 447 | to, 100% { 448 | opacity: 0; 449 | } 450 | ` 451 | const LoadShredder = keyframes` 452 | from, 0% { 453 | transform: scale(0, 1) translate(0, 67px); 454 | } 455 | to, 100% { 456 | transform: scale(1, 1) translate(0, 67px); 457 | } 458 | ` 459 | // SVG 460 | export const UnsubscribeIllustration = ( 461 |
496 | 503 | 504 | 505 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 527 | 531 | 535 | 536 | 537 | 546 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 |
573 | ) 574 | -------------------------------------------------------------------------------- /src/components/ConfirmMessage/Message.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css, keyframes } from '@emotion/core' 3 | import styled from '@emotion/styled' 4 | import Markdown from 'react-markdown' 5 | import Link from '../Link' 6 | import { bpMaxSM } from '../../lib/breakpoints' 7 | 8 | export default ({ 9 | illustration, 10 | title, 11 | body, 12 | note, 13 | fullscreen = false, 14 | articleTitle, 15 | articleSlug, 16 | }) => ( 17 |
25 |
{illustration}
26 |

{title}

27 | {body && {body}} 28 | {note && ( 29 |
39 | 40 | {note} 41 | 42 |
43 | )} 44 | {articleTitle && ( 45 |
46 | {articleTitle} 47 |
48 | )} 49 |
50 | ) 51 | 52 | const FadeIn = keyframes` 53 | from, 0% { 54 | opacity: 0; 55 | } 56 | to, 100% { 57 | opacity: 1; 58 | } 59 | ` 60 | const Center = styled.div` 61 | width: 100vw; 62 | max-width: 100% !important; 63 | padding: 30px; 64 | display: flex; 65 | flex-direction: column; 66 | align-items: center; 67 | justify-content: center; 68 | text-align: center; 69 | p { 70 | margin-top: 10px; 71 | max-width: 400px; 72 | line-height: 1.5; 73 | font-weight: 400; 74 | strong { 75 | font-weight: 600; 76 | } 77 | animation: ${FadeIn} 600ms ease-in-out 1; 78 | } 79 | h2 { 80 | font-size: 26px; 81 | font-weight: 400; 82 | margin-bottom: 0; 83 | margin-top: 25px; 84 | animation: ${FadeIn} 400ms ease-in-out 1; 85 | } 86 | ` 87 | -------------------------------------------------------------------------------- /src/components/Container.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css } from '@emotion/core' 3 | import { bpMaxSM } from 'lib/breakpoints' 4 | 5 | const Container = props => { 6 | const { 7 | maxWidth = 700, 8 | noHorizontalPadding = false, 9 | noVerticalPadding = false, 10 | ...restProps 11 | } = props 12 | return ( 13 |
27 | {props.children} 28 |
29 | ) 30 | } 31 | 32 | export default Container 33 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css } from '@emotion/core' 3 | import { bpMaxSM } from '../lib/breakpoints' 4 | import SubscribeForm from './Forms/Subscribe' 5 | import { Twitter, GitHub } from './Social' 6 | import Container from './Container' 7 | 8 | const Footer = ({ author, noSubscribeForm }) => ( 9 | 47 | ) 48 | 49 | export default Footer 50 | -------------------------------------------------------------------------------- /src/components/Forms/Subscribe.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Formik, Field, Form, ErrorMessage } from 'formik' 3 | import * as Yup from 'yup' 4 | import { css } from '@emotion/core' 5 | import { withTheme } from '../Theming' 6 | import { rhythm } from '../../lib/typography' 7 | import { bpMaxSM } from '../../lib/breakpoints' 8 | import Message from '../ConfirmMessage/Message' 9 | import { PleaseConfirmIllustration } from '../ConfirmMessage/Illustrations' 10 | 11 | const FORM_ID = process.env.CONVERTKIT_SIGNUP_FORM 12 | 13 | const SubscribeSchema = Yup.object().shape({ 14 | email_address: Yup.string() 15 | .email('Invalid email address') 16 | .required('Required'), 17 | first_name: Yup.string(), 18 | }) 19 | 20 | const PostSubmissionMessage = ({ response }) => { 21 | return ( 22 |
23 | 29 |
30 | ) 31 | } 32 | 33 | class SignUp extends React.Component { 34 | state = { 35 | submitted: false, 36 | } 37 | 38 | async handleSubmit(values) { 39 | this.setState({ submitted: true }) 40 | try { 41 | const response = await fetch( 42 | `https://app.convertkit.com/forms/${FORM_ID}/subscriptions`, 43 | { 44 | method: 'post', 45 | body: JSON.stringify(values, null, 2), 46 | headers: { 47 | Accept: 'application/json', 48 | 'Content-Type': 'application/json', 49 | }, 50 | }, 51 | ) 52 | 53 | const responseJson = await response.json() 54 | 55 | this.setState({ 56 | submitted: true, 57 | response: responseJson, 58 | errorMessage: null, 59 | }) 60 | } catch (error) { 61 | this.setState({ 62 | submitted: false, 63 | errorMessage: 'Something went wrong!', 64 | }) 65 | } 66 | } 67 | 68 | render() { 69 | const { submitted, response, errorMessage } = this.state 70 | const { theme } = this.props 71 | const successful = response && response.status === 'success' 72 | 73 | return ( 74 |
75 | {!successful && ( 76 |

82 | Join the Newsletter 83 |

84 | )} 85 | 86 | this.handleSubmit(values)} 93 | render={({ errors, touched, isSubmitting }) => ( 94 | <> 95 | {!successful && ( 96 |
130 | 153 | 181 | 189 |
190 | )} 191 | {submitted && 192 | !isSubmitting && } 193 | {errorMessage &&
{errorMessage}
} 194 | 195 | )} 196 | /> 197 |
198 | ) 199 | } 200 | } 201 | 202 | export default withTheme(SignUp) 203 | -------------------------------------------------------------------------------- /src/components/Header/Button.js: -------------------------------------------------------------------------------- 1 | import { React } from 'react' 2 | import { css } from '@emotion/core' 3 | import { Link } from 'gatsby' 4 | import { useTheme } from '../Theming' 5 | import { rgba, darken } from 'polished' 6 | 7 | const Button = ({ to, children, secondary, ...restProps }) => { 8 | const theme = useTheme() 9 | const styles = css({ 10 | display: 'inline-flex', 11 | border: 'none', 12 | borderRadius: '4px', 13 | background: secondary 14 | ? rgba(theme.colors.primary, 0.1) 15 | : theme.colors.primary, 16 | color: secondary ? theme.colors.primary : theme.colors.white, 17 | padding: '10px 15px', 18 | cursor: 'pointer', 19 | transition: 'all 150ms ease', 20 | '@media (hover: hover)': { 21 | ':hover': { 22 | color: theme.colors.white, 23 | background: darken(0.1, theme.colors.primary), 24 | }, 25 | }, 26 | }) 27 | return to ? ( 28 | 29 | {children} 30 | 31 | ) : ( 32 | 35 | ) 36 | } 37 | 38 | export default Button 39 | -------------------------------------------------------------------------------- /src/components/Header/Links.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import { useTheme } from '../Theming' 4 | import ThemeToggler from './ThemeToggler' 5 | 6 | export default () => { 7 | const theme = useTheme() 8 | return ( 9 | 10 | 11 | Blog 12 | 13 | 14 | About 15 | 16 | 17 | Contact 18 | 19 | 20 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Header/MobileMenu.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { css } from '@emotion/core' 3 | import Container from '../Container' 4 | 5 | import { bpMaxSM } from '../../lib/breakpoints' 6 | 7 | import { useTheme } from '../Theming' 8 | 9 | const Toggle = ({ children }) => { 10 | const [isToggledOn, setToggle] = useState(false) 11 | const toggle = () => setToggle(!isToggledOn) 12 | const theme = useTheme() 13 | const color = theme.colors.white 14 | 15 | return ( 16 |
26 | 82 | {isToggledOn && ( 83 |
96 | 117 | {children} 118 | 119 |
120 | )} 121 |
122 | ) 123 | } 124 | 125 | export default Toggle 126 | -------------------------------------------------------------------------------- /src/components/Header/ThemeToggler.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Button from './Button' 3 | import styled from '@emotion/styled' 4 | import { FiMoon, FiSun } from 'react-icons/fi' 5 | import { useTheme } from '../Theming' 6 | 7 | const DarkMode = styled(FiMoon)({ 8 | display: 'flex', 9 | alignItems: 'center', 10 | justifyContent: 'center', 11 | margin: '0', 12 | }) 13 | 14 | const DefaultMode = styled(FiSun)({ 15 | display: 'flex', 16 | alignItems: 'center', 17 | justifyContent: 'center', 18 | margin: '0', 19 | }) 20 | 21 | const ThemeToggler = ({ toggleTheme, themeName }) => { 22 | const theme = useTheme() 23 | return ( 24 | 58 | ) 59 | } 60 | export default ThemeToggler 61 | -------------------------------------------------------------------------------- /src/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, StaticQuery, graphql } from 'gatsby' 3 | import { css } from '@emotion/core' 4 | import { useTheme } from '../Theming' 5 | import { bpMaxSM } from '../../lib/breakpoints' 6 | import MobileMenu from './MobileMenu' 7 | import Links from './Links' 8 | 9 | import Container from '../Container' 10 | 11 | const Header = ({ siteTitle }) => { 12 | const theme = useTheme() 13 | return ( 14 |
23 | 24 | 79 | 80 |
81 | ) 82 | } 83 | 84 | const ConnectedHeader = props => ( 85 | ( 96 |
97 | )} 98 | /> 99 | ) 100 | 101 | export default ConnectedHeader 102 | -------------------------------------------------------------------------------- /src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useEffect } from 'react' 2 | import Helmet from 'react-helmet' 3 | import { graphql } from 'gatsby' 4 | import { MDXProvider } from '@mdx-js/react' 5 | import { lighten } from 'polished' 6 | import { Global, css } from '@emotion/core' 7 | import { ThemeProvider, themes } from './Theming' 8 | import { bpMaxSM } from '../lib/breakpoints' 9 | import mdxComponents from './mdx' 10 | import Header from './Header' 11 | import reset from '../lib/reset' 12 | import { fonts } from '../lib/typography' 13 | import config from '../../config/website' 14 | import Footer from '../components/Footer' 15 | 16 | const getGlobalStyles = theme => { 17 | return css` 18 | body { 19 | background: ${theme.colors.bodyBg}; 20 | color: ${theme.colors.text}; 21 | } 22 | &::selection { 23 | color: ${theme.colors.white}; 24 | background-color: ${theme.colors.primary}; 25 | } 26 | a { 27 | color: ${theme.colors.link}; 28 | text-decoration: none; 29 | &:hover, 30 | &:focus { 31 | color: ${theme.colors.link}; 32 | } 33 | &:hover { 34 | text-decoration: underline; 35 | } 36 | } 37 | h1, 38 | h2, 39 | h3, 40 | h4, 41 | h5, 42 | h6 { 43 | color: ${theme.colors.text}; 44 | a { 45 | color: ${theme.colors.text}; 46 | &:hover, 47 | &:focus { 48 | color: ${theme.colors.text}; 49 | } 50 | } 51 | } 52 | ${bpMaxSM} { 53 | p, 54 | em, 55 | strong { 56 | font-size: 90%; 57 | } 58 | h1 { 59 | font-size: 30px; 60 | } 61 | h2 { 62 | font-size: 24px; 63 | } 64 | } 65 | hr { 66 | margin: 50px 0; 67 | border: none; 68 | border-top: 1px solid ${theme.colors.gray}; 69 | background: none; 70 | } 71 | em { 72 | font-family: ${fonts.regularItalic}; 73 | } 74 | strong { 75 | em { 76 | font-family: ${fonts.semiboldItalic}; 77 | } 78 | } 79 | input { 80 | border-radius: 4px; 81 | border: 1px solid ${theme.colors.gray}; 82 | padding: 5px 10px; 83 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.1); 84 | font-family: ${fonts.regular}; 85 | margin-top: 5px; 86 | ::placeholder { 87 | opacity: 0.4; 88 | } 89 | } 90 | .gatsby-resp-image-image { 91 | background: none !important; 92 | box-shadow: 0; 93 | } 94 | button { 95 | border-radius: 4px; 96 | background-color: ${theme.colors.primary}; 97 | border: none; 98 | color: ${theme.colors.white}; 99 | padding: 5px 10px; 100 | cursor: pointer; 101 | border: 1px solid ${theme.colors.primary}; 102 | transition: all 150ms; 103 | :hover { 104 | background: ${lighten(0.05, theme.colors.primary)}; 105 | border: 1px solid ${lighten(0.05, theme.colors.primary)}; 106 | } 107 | } 108 | pre { 109 | background-color: #061526 !important; 110 | border-radius: 4px; 111 | font-size: 16px; 112 | padding: 10px; 113 | overflow-x: auto; 114 | /* Track */ 115 | ::-webkit-scrollbar { 116 | width: 100%; 117 | height: 5px; 118 | border-radius: 0 0 5px 5px; 119 | } 120 | ::-webkit-scrollbar-track { 121 | background: #061526; 122 | border-radius: 0 0 4px 4px; 123 | border: 1px solid rgba(0, 0, 0, 0.2); 124 | } 125 | /* Handle */ 126 | ::-webkit-scrollbar-thumb { 127 | background: #888; 128 | border-radius: 5px; 129 | } 130 | } 131 | ` 132 | } 133 | 134 | export default ({ 135 | site, 136 | frontmatter = {}, 137 | children, 138 | noFooter, 139 | noSubscribeForm, 140 | }) => { 141 | const initializeTheme = () => { 142 | if (typeof window !== 'undefined') { 143 | return localStorage.getItem('theme') || 'default' 144 | } else { 145 | return 'default' 146 | } 147 | } 148 | 149 | const [themeName, setTheme] = useState(initializeTheme) 150 | 151 | useEffect(() => { 152 | localStorage.setItem('theme', themeName) 153 | }, [themeName]) 154 | 155 | const toggleTheme = name => setTheme(name) 156 | const theme = { 157 | ...themes[themeName], 158 | toggleTheme: toggleTheme, 159 | } 160 | const { 161 | description: siteDescription, 162 | keywords: siteKeywords, 163 | } = site.siteMetadata 164 | 165 | const { 166 | keywords: frontmatterKeywords, 167 | description: frontmatterDescription, 168 | } = frontmatter 169 | 170 | const keywords = (frontmatterKeywords || siteKeywords).join(', ') 171 | const description = frontmatterDescription || siteDescription 172 | 173 | return ( 174 | 175 | 176 | 177 | 178 |
186 | 193 | 194 | 195 | 196 |
197 | 198 | {children} 199 | 200 | {!noFooter && ( 201 |
205 | )} 206 |
207 |
208 |
209 | ) 210 | } 211 | 212 | export const pageQuery = graphql` 213 | fragment site on Site { 214 | siteMetadata { 215 | title 216 | description 217 | author { 218 | name 219 | } 220 | keywords 221 | } 222 | } 223 | ` 224 | -------------------------------------------------------------------------------- /src/components/Link.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import GatsbyLink from 'gatsby-link' 3 | 4 | const Link = ({ children, to, ...other }) => { 5 | const internal = /^\/(?!\/)/.test(to) 6 | 7 | if (internal) { 8 | return ( 9 | 10 | {children} 11 | 12 | ) 13 | } 14 | 15 | return ( 16 | 17 | {children} 18 | 19 | ) 20 | } 21 | 22 | export default Link 23 | -------------------------------------------------------------------------------- /src/components/SEO/SchemaOrg.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Helmet from 'react-helmet' 3 | 4 | export default React.memo( 5 | ({ 6 | author, 7 | canonicalUrl, 8 | datePublished, 9 | defaultTitle, 10 | description, 11 | image, 12 | isBlogPost, 13 | organization, 14 | title, 15 | url, 16 | }) => { 17 | const baseSchema = [ 18 | { 19 | '@context': 'http://schema.org', 20 | '@type': 'WebSite', 21 | url, 22 | name: title, 23 | alternateName: defaultTitle, 24 | }, 25 | ] 26 | 27 | const schema = isBlogPost 28 | ? [ 29 | ...baseSchema, 30 | { 31 | '@context': 'http://schema.org', 32 | '@type': 'BreadcrumbList', 33 | itemListElement: [ 34 | { 35 | '@type': 'ListItem', 36 | position: 1, 37 | item: { 38 | '@id': url, 39 | name: title, 40 | image, 41 | }, 42 | }, 43 | ], 44 | }, 45 | { 46 | '@context': 'http://schema.org', 47 | '@type': 'BlogPosting', 48 | url, 49 | name: title, 50 | alternateName: defaultTitle, 51 | headline: title, 52 | image: { 53 | '@type': 'ImageObject', 54 | url: image, 55 | }, 56 | description, 57 | author: { 58 | '@type': 'Person', 59 | name: author.name, 60 | }, 61 | publisher: { 62 | '@type': 'Organization', 63 | url: organization.url, 64 | logo: organization.logo, 65 | name: organization.name, 66 | }, 67 | mainEntityOfPage: { 68 | '@type': 'WebSite', 69 | '@id': canonicalUrl, 70 | }, 71 | datePublished, 72 | }, 73 | ] 74 | : baseSchema 75 | 76 | return ( 77 | 78 | {/* Schema.org tags */} 79 | 80 | 81 | ) 82 | }, 83 | ) 84 | -------------------------------------------------------------------------------- /src/components/SEO/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import React from 'react' 3 | import Helmet from 'react-helmet' 4 | import { StaticQuery, graphql } from 'gatsby' 5 | import PropTypes from 'prop-types' 6 | import SchemaOrg from './SchemaOrg' 7 | import config from '../../../config/website' 8 | 9 | const SEO = ({ postData, frontmatter = {}, postImage, isBlogPost }) => ( 10 | { 36 | const postMeta = 37 | frontmatter || postData.childMarkdownRemark.frontmatter || {} 38 | const title = isBlogPost ? postMeta.title : config.siteTitle 39 | const description = postMeta.description || seo.description 40 | const image = postImage ? `${seo.canonicalUrl}${postImage}` : seo.image 41 | const url = postMeta.slug 42 | ? `${seo.canonicalUrl}${path.sep}${postMeta.slug}` 43 | : seo.canonicalUrl 44 | const datePublished = isBlogPost ? postMeta.datePublished : false 45 | 46 | return ( 47 | 48 | 49 | {/* General tags */} 50 | {title} 51 | 52 | 53 | 54 | {/* OpenGraph tags */} 55 | 56 | {isBlogPost ? : null} 57 | 58 | 59 | 60 | 61 | 62 | {/* Twitter Card tags */} 63 | 64 | 65 | 66 | 67 | 68 | 69 | 81 | 82 | ) 83 | }} 84 | /> 85 | ) 86 | 87 | SEO.propTypes = { 88 | isBlogPost: PropTypes.bool, 89 | postData: PropTypes.shape({ 90 | childMarkdownRemark: PropTypes.shape({ 91 | frontmatter: PropTypes.any, 92 | excerpt: PropTypes.any, 93 | }), 94 | }), 95 | postImage: PropTypes.string, 96 | } 97 | 98 | SEO.defaultProps = { 99 | isBlogPost: false, 100 | postData: { childMarkdownRemark: {} }, 101 | postImage: null, 102 | } 103 | 104 | export default SEO 105 | -------------------------------------------------------------------------------- /src/components/Share.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { css } from '@emotion/core' 3 | import { useTheme } from './Theming' 4 | 5 | import { TwitterShareButton, FacebookShareButton } from 'react-share' 6 | 7 | const Share = ({ url, title, twitterHandle }) => { 8 | const theme = useTheme() 9 | return ( 10 |
31 |
37 | Share article 38 | 43 | Twitter 44 | 45 | 53 | Facebook 54 | 55 |
56 | ) 57 | } 58 | 59 | export default Share 60 | -------------------------------------------------------------------------------- /src/components/Social.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Link from './Link' 3 | import { useTheme } from './Theming' 4 | import { css } from '@emotion/core' 5 | import config from '../../config/website' 6 | 7 | export const Twitter = ({ url = `${config.twitter}` }) => { 8 | const theme = useTheme() 9 | return ( 10 | 21 | 27 | 32 | 33 | 34 | ) 35 | } 36 | 37 | export const LinkedIn = ({ url = `${config.linkedin}` }) => { 38 | const theme = useTheme() 39 | return ( 40 | 51 | 57 | 61 | 62 | 63 | ) 64 | } 65 | 66 | export const GitHub = ({ url = `${config.github}` }) => { 67 | const theme = useTheme() 68 | return ( 69 | 80 | 86 | 91 | 92 | 93 | ) 94 | } 95 | -------------------------------------------------------------------------------- /src/components/Theming.js: -------------------------------------------------------------------------------- 1 | import { createTheming } from '@callstack/react-theme-provider' 2 | import { lighten } from 'polished' 3 | import colors from '../lib/colors' 4 | 5 | const themes = { 6 | default: { 7 | themeName: 'default', 8 | colors: { 9 | primary: colors.blue, 10 | text: colors.black, 11 | bodyBg: colors.gray, 12 | headerBg: colors.blue, 13 | link: colors.blue, 14 | ...colors, 15 | }, 16 | }, 17 | dark: { 18 | themeName: 'dark', 19 | colors: { 20 | primary: lighten(0.05, colors.blue), 21 | text: colors.white, 22 | bodyBg: colors.black, 23 | headerBg: colors.black, 24 | link: lighten(0.05, colors.blue), 25 | ...colors, 26 | }, 27 | }, 28 | } 29 | 30 | const { ThemeProvider, withTheme, useTheme } = createTheming(themes.default) 31 | 32 | export { ThemeProvider, withTheme, useTheme, themes, colors } 33 | -------------------------------------------------------------------------------- /src/components/mdx/Code.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import theme from 'prism-react-renderer/themes/oceanicNext' 3 | import Highlight, { defaultProps } from 'prism-react-renderer' 4 | import { LiveProvider, LiveEditor, LiveError, LivePreview } from 'react-live' 5 | 6 | const Code = ({children, codeString, className = 'language-js', ...props }) => { 7 | const language = className.replace(/language-/, '') 8 | if (props['react-live']) { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 | ) 16 | } else { 17 | return ( 18 | 24 | {({ className, style, tokens, getLineProps, getTokenProps }) => ( 25 |
26 |             {tokens.map((line, i) => (
27 |               
28 | {line.map((token, key) => ( 29 | 30 | ))} 31 |
32 | ))} 33 |
34 | )} 35 |
36 | ) 37 | } 38 | } 39 | 40 | export default Code 41 | -------------------------------------------------------------------------------- /src/components/mdx/Paragraph.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export default styled.p` 4 | text-align: left; 5 | line-height: 1.7; 6 | ` 7 | -------------------------------------------------------------------------------- /src/components/mdx/Subtitle.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export default styled.h2` 4 | text-align: left; 5 | font-size: 18px; 6 | margin-top: 20px; 7 | margin-bottom: 20px; 8 | font-weight: 900; 9 | line-height: 1.1; 10 | ` 11 | -------------------------------------------------------------------------------- /src/components/mdx/Title.js: -------------------------------------------------------------------------------- 1 | import styled from '@emotion/styled' 2 | 3 | export default styled.h1` 4 | font-size: 24px; 5 | font-weight: 400; 6 | line-height: 1.1; 7 | margin-top: 20px; 8 | margin-bottom: 20px; 9 | padding-top: 30px; 10 | padding-bottom: 10px; 11 | ` 12 | -------------------------------------------------------------------------------- /src/components/mdx/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Title from './Title' 4 | import Subtitle from './Subtitle' 5 | import Paragraph from './Paragraph' 6 | import Code from './Code' 7 | 8 | export default { 9 | h1: props => , 10 | h2: props => <Subtitle {...props} />, 11 | p: props => <Paragraph {...props} />, 12 | code: Code, 13 | pre: preProps => <pre {...preProps} />, 14 | } 15 | -------------------------------------------------------------------------------- /src/fonts/Inter-UI-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-Bold.woff -------------------------------------------------------------------------------- /src/fonts/Inter-UI-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-BoldItalic.woff -------------------------------------------------------------------------------- /src/fonts/Inter-UI-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-Italic.woff -------------------------------------------------------------------------------- /src/fonts/Inter-UI-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-Regular.woff -------------------------------------------------------------------------------- /src/fonts/Inter-UI-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-SemiBold.woff -------------------------------------------------------------------------------- /src/fonts/Inter-UI-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/src/fonts/Inter-UI-SemiBoldItalic.woff -------------------------------------------------------------------------------- /src/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Inter UI Regular'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: url('Inter-UI-Regular.woff') format('woff'); 6 | font-display: fallback; 7 | } 8 | @font-face { 9 | font-family: 'Inter UI Regular Italic'; 10 | font-style: italic; 11 | font-weight: 400; 12 | src: url('Inter-UI-Italic.woff') format('woff'); 13 | font-display: fallback; 14 | } 15 | @font-face { 16 | font-family: 'Inter UI SemiBold'; 17 | font-style: normal; 18 | font-weight: 600; 19 | src: url('Inter-UI-SemiBold.woff') format('woff'); 20 | font-display: fallback; 21 | } 22 | @font-face { 23 | font-family: 'Inter UI SemiBold Italic'; 24 | font-style: italic; 25 | font-weight: 600; 26 | src: url('Inter-UI-SemiBoldItalic.woff') format('woff'); 27 | font-display: fallback; 28 | } 29 | @font-face { 30 | font-family: 'Inter UI Bold'; 31 | font-style: normal; 32 | font-weight: 700; 33 | src: url('Inter-UI-Bold.woff') format('woff'); 34 | font-display: fallback; 35 | } 36 | @font-face { 37 | font-family: 'Inter UI Bold Italic'; 38 | font-style: italic; 39 | font-weight: 700; 40 | src: url('Inter-UI-BoldItalic.woff') format('woff'); 41 | font-display: fallback; 42 | } 43 | -------------------------------------------------------------------------------- /src/html.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | export default class HTML extends React.Component { 5 | render() { 6 | return ( 7 | <html {...this.props.htmlAttributes}> 8 | <head> 9 | <meta charSet="utf-8" /> 10 | <meta httpEquiv="x-ua-compatible" content="ie=edge" /> 11 | <meta 12 | name="viewport" 13 | content="width=device-width, initial-scale=1, shrink-to-fit=no" 14 | /> 15 | {this.props.headComponents} 16 | </head> 17 | <body {...this.props.bodyAttributes}> 18 | {this.props.preBodyComponents} 19 | <noscript>This site runs best with JavaScript enabled.</noscript> 20 | <div 21 | key={`body`} 22 | id="___gatsby" 23 | dangerouslySetInnerHTML={{ __html: this.props.body }} 24 | /> 25 | {this.props.postBodyComponents} 26 | </body> 27 | </html> 28 | ) 29 | } 30 | } 31 | 32 | HTML.propTypes = { 33 | htmlAttributes: PropTypes.object, 34 | headComponents: PropTypes.array, 35 | bodyAttributes: PropTypes.object, 36 | preBodyComponents: PropTypes.array, 37 | body: PropTypes.string, 38 | postBodyComponents: PropTypes.array, 39 | } 40 | -------------------------------------------------------------------------------- /src/lib/breakpoints.js: -------------------------------------------------------------------------------- 1 | const minSM = 545 2 | const minMD = 768 3 | const minLG = 992 4 | const minXL = 1200 5 | const minXXL = 1920 6 | 7 | export const bpMinSM = `@media (min-width: ${minSM}px)` 8 | export const bpMinMD = `@media (min-width: ${minMD}px)` 9 | export const bpMinLG = `@media (min-width: ${minLG}px)` 10 | export const bpMinXL = `@media (min-width: ${minXL}px)` 11 | export const bpMinXXL = `@media (min-width: ${minXXL}px)` 12 | 13 | export const bpMaxXS = `@media (max-width: ${minSM - 1}px)` 14 | export const bpMaxSM = `@media (max-width: ${minMD - 1}px)` 15 | export const bpMaxMD = `@media (max-width: ${minLG - 1}px)` 16 | export const bpMaxLG = `@media (max-width: ${minXL - 1}px)` 17 | -------------------------------------------------------------------------------- /src/lib/colors.js: -------------------------------------------------------------------------------- 1 | const colors = { 2 | black: '#131415', 3 | white: '#fff', 4 | gray: '#fafafa', 5 | red: '#E74C3C', 6 | blue: '#5348ff', 7 | green: '#29B573', 8 | } 9 | 10 | export default colors 11 | -------------------------------------------------------------------------------- /src/lib/reset.js: -------------------------------------------------------------------------------- 1 | import { css } from '@emotion/core' 2 | import { useTheme } from '../components/Theming' 3 | import typography, { fonts } from '../lib/typography' 4 | 5 | const ResetStyles = () => { 6 | const theme = useTheme() 7 | return css` 8 | form { 9 | margin: 0; 10 | } 11 | ul, ol { 12 | list-style-position: inside; 13 | margin-left: 0; 14 | font-size: ${typography.baseFontSize}; 15 | } 16 | *, 17 | *:before, 18 | *:after { 19 | box-sizing: inherit; 20 | } 21 | html, 22 | body { 23 | font-family: ${fonts.regular}, sans-serif; 24 | font-style: normal; 25 | padding: 0; 26 | margin: 0; 27 | } 28 | html { 29 | text-rendering: optimizeLegibility; 30 | overflow-x: hidden; 31 | overflow-y: auto !important; 32 | box-sizing: border-box; 33 | -ms-overflow-style: scrollbar; 34 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0); 35 | -webkit-font-smoothing: antialiased; 36 | -moz-osx-font-smoothing: grayscale; 37 | } 38 | a { 39 | transition: 100ms; 40 | text-decoration: none; 41 | } 42 | 43 | a:not([href]):not([tabindex]) { 44 | color: inherit; 45 | text-decoration: none; 46 | &:hover, 47 | &:focus { 48 | color: inherit; 49 | text-decoration: none; 50 | } 51 | &:focus { 52 | outline: 0; 53 | } 54 | } 55 | 56 | blockquote { 57 | border-left: 5px solid ${theme.colors.link}; 58 | padding-left: 1rem !important; 59 | margin-left: 0 !important; 60 | margin-right: 0 !important; 61 | font-style: italic; 62 | p { 63 | line-height: 1.3 !important; 64 | } 65 | } 66 | [tabindex='-1']:focus { 67 | outline: none !important; 68 | } 69 | pre { 70 | margin-top: 0; 71 | margin-bottom: 1rem; 72 | overflow: auto; 73 | } 74 | figure { 75 | margin: 0 0 1rem 0; 76 | } 77 | img { 78 | vertical-align: middle; 79 | } 80 | [role='button'] { 81 | cursor: pointer; 82 | } 83 | a, 84 | area, 85 | button, 86 | [role='button'], 87 | input, 88 | label, 89 | select, 90 | summary, 91 | textarea { 92 | touch-action: manipulation; 93 | } 94 | table { 95 | border-collapse: collapse; 96 | background-color: ${theme.colors.bodyBg}; 97 | } 98 | caption { 99 | padding-top: 1.5rem; 100 | padding-bottom: 1.5rem; 101 | color: ${theme.colors.bodyBg}; 102 | text-align: center; 103 | caption-side: bottom; 104 | } 105 | th { 106 | text-align: left; 107 | } 108 | label { 109 | display: inline-block; 110 | margin-bottom: 0.5rem; 111 | } 112 | button:focus { 113 | outline: 1px dotted; 114 | outline: 5px auto -webkit-focus-ring-color; 115 | } 116 | input, 117 | button, 118 | select, 119 | textarea { 120 | line-height: inherit; 121 | } 122 | input[type='date'], 123 | input[type='time'], 124 | input[type='datetime-local'], 125 | input[type='month'] { 126 | -webkit-appearance: listbox; 127 | } 128 | textarea { 129 | resize: vertical; 130 | } 131 | fieldset { 132 | min-width: 0; 133 | padding: 0; 134 | margin: 0; 135 | border: 0; 136 | } 137 | legend { 138 | display: block; 139 | width: 100%; 140 | padding: 0; 141 | margin-bottom: 0.5rem; 142 | font-size: 1.5rem; 143 | line-height: inherit; 144 | } 145 | input[type='search'] { 146 | -webkit-appearance: none; 147 | } 148 | output { 149 | display: inline-block; 150 | } 151 | svg:not(:root) { 152 | overflow: hidden; 153 | vertical-align: middle; 154 | } 155 | [hidden] { 156 | display: none !important; 157 | } 158 | ` 159 | } 160 | 161 | export default ResetStyles 162 | -------------------------------------------------------------------------------- /src/lib/typography.js: -------------------------------------------------------------------------------- 1 | import Typography from 'typography' 2 | import '../fonts/fonts.css' 3 | 4 | export const fonts = { 5 | regular: 'Inter UI Regular', 6 | regularItalic: 'Inter UI Regular Italic', 7 | semibold: 'Inter UI Semibold', 8 | semiboldItalic: 'Inter UI Semibold Italic', 9 | bold: 'Inter UI Bold', 10 | boldItalic: 'Inter UI Bold Italic', 11 | } 12 | 13 | const typography = new Typography({ 14 | baseFontSize: '18px', 15 | baseLineHeight: 1.55, 16 | headerLineHeight: 1.4, 17 | headerFontFamily: [fonts.bold, 'sans-serif'], 18 | bodyFontFamily: [fonts.regular, 'sans-serif'], 19 | headerColor: 'hsla(0,0%,0%,0.9)', 20 | bodyColor: 'hsla(0,0%,0%,0.8)', 21 | 22 | overrideStyles: ({ rhythm }) => ({ 23 | h1: { 24 | color: 'hsla(0,0%,0%,0.75)', 25 | }, 26 | h2: { 27 | color: 'hsla(0,0%,0%,0.775)', 28 | }, 29 | h3: { 30 | color: 'hsla(0,0%,0%,0.8)', 31 | }, 32 | 'h1,h2,h3,h4,h5,h6': { 33 | lineHeight: 1, 34 | }, 35 | 'h1,h2,h3,h4': { 36 | lineHeight: 1.25, 37 | marginTop: rhythm(1), 38 | marginBottom: rhythm(1 / 2), 39 | }, 40 | }), 41 | }) 42 | // Hot reload typography in development. 43 | if (process.env.NODE_ENV !== 'production') { 44 | typography.injectStyles() 45 | } 46 | 47 | export default typography 48 | export const rhythm = typography.rhythm 49 | export const scale = typography.scale 50 | -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default () => ( 4 | <div> 5 | <h1>NOT FOUND</h1> 6 | <p>You just hit a route that doesn't exist... the sadness.</p> 7 | </div> 8 | ) 9 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { graphql } from 'gatsby' 3 | import { css } from '@emotion/core' 4 | import styled from '@emotion/styled' 5 | import Layout from 'components/Layout' 6 | import Link from 'components/Link' 7 | import { useTheme } from 'components/Theming' 8 | import Container from 'components/Container' 9 | import { rhythm } from '../lib/typography' 10 | 11 | const Hero = () => { 12 | const theme = useTheme() 13 | return ( 14 | <section 15 | css={css` 16 | color: ${theme.colors.white}; 17 | width: 100%; 18 | background: ${theme.colors.primary}; 19 | padding: 20px 0 30px 0; 20 | display: flex; 21 | `} 22 | > 23 | <Container 24 | css={css` 25 | display: flex; 26 | flex-direction: column; 27 | `} 28 | > 29 | <h1 30 | css={css` 31 | color: ${theme.colors.white}; 32 | position: relative; 33 | z-index: 5; 34 | line-height: 1.5; 35 | margin: 0; 36 | max-width: ${rhythm(15)}; 37 | `} 38 | > 39 | Your blog says the things you want to say. 40 | </h1> 41 | </Container> 42 | <div 43 | css={css` 44 | height: 150px; 45 | overflow: hidden; 46 | `} 47 | /> 48 | </section> 49 | ) 50 | } 51 | 52 | const Description = styled.p` 53 | margin-bottom: 10px; 54 | display: inline-block; 55 | ` 56 | 57 | export default function Index({ data: { site, allMdx } }) { 58 | const theme = useTheme() 59 | return ( 60 | <Layout site={site}> 61 | <Hero /> 62 | <Container 63 | css={css` 64 | padding-bottom: 0; 65 | `} 66 | > 67 | {allMdx.edges.map(({ node: post }) => ( 68 | <div 69 | key={post.id} 70 | css={css` 71 | margin-bottom: 40px; 72 | `} 73 | > 74 | <h2 75 | css={css({ 76 | marginBottom: rhythm(0.3), 77 | transition: 'all 150ms ease', 78 | ':hover': { 79 | color: theme.colors.primary, 80 | }, 81 | })} 82 | > 83 | <Link 84 | to={post.frontmatter.slug} 85 | aria-label={`View ${post.frontmatter.title}`} 86 | > 87 | {post.frontmatter.title} 88 | </Link> 89 | </h2> 90 | <Description> 91 | {post.excerpt}{' '} 92 | <Link 93 | to={post.frontmatter.slug} 94 | aria-label={`View ${post.frontmatter.title}`} 95 | > 96 | Read Article → 97 | </Link> 98 | </Description> 99 | </div> 100 | ))} 101 | <Link to="/blog" aria-label="Visit blog page"> 102 | View all articles 103 | </Link> 104 | <hr /> 105 | </Container> 106 | </Layout> 107 | ) 108 | } 109 | 110 | export const pageQuery = graphql` 111 | query { 112 | site { 113 | ...site 114 | siteMetadata { 115 | title 116 | } 117 | } 118 | allMdx( 119 | limit: 5 120 | sort: { fields: [frontmatter___date], order: DESC } 121 | filter: { frontmatter: { published: { ne: false } } } 122 | ) { 123 | edges { 124 | node { 125 | excerpt(pruneLength: 190) 126 | id 127 | fields { 128 | title 129 | slug 130 | date 131 | } 132 | parent { 133 | ... on File { 134 | sourceInstanceName 135 | } 136 | } 137 | frontmatter { 138 | title 139 | date(formatString: "MMMM DD, YYYY") 140 | description 141 | banner { 142 | childImageSharp { 143 | sizes(maxWidth: 720) { 144 | ...GatsbyImageSharpSizes 145 | } 146 | } 147 | } 148 | slug 149 | keywords 150 | } 151 | } 152 | } 153 | } 154 | } 155 | ` 156 | -------------------------------------------------------------------------------- /src/pages/messages.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { graphql } from 'gatsby' 3 | import Layout from '../components/Layout' 4 | import Message from '../components/ConfirmMessage/Message' 5 | import { 6 | PleaseConfirmIllustration, 7 | ThankYouIllustration, 8 | UnsubscribeIllustration, 9 | } from '../components/ConfirmMessage/Illustrations' 10 | 11 | export default ({ data: { site, allMdx, latestArticle } }) => { 12 | return ( 13 | <Layout site={site} noSubscribeForm> 14 | <div> 15 | <Message 16 | fullscreen 17 | illustration={PleaseConfirmIllustration} 18 | title={`Great, one last thing...`} 19 | body={`We just sent you an email with the confirmation link. 20 | **Please check your inbox!**`} 21 | /> 22 | </div> 23 | <div> 24 | {latestArticle.edges.map(({ node: post }) => ( 25 | <Message 26 | fullscreen 27 | key={post.id} 28 | illustration={ThankYouIllustration} 29 | title={`Success! Thank you!`} 30 | body={`In case you haven’t seen already, here’s my latest article:`} 31 | articleTitle={post.frontmatter.title} 32 | articleSlug={post.frontmatter.slug} 33 | /> 34 | ))} 35 | </div> 36 | <div> 37 | <Message 38 | fullscreen 39 | illustration={UnsubscribeIllustration} 40 | title={`You have been unsubscribed.`} 41 | body={`As per your request, you have been unsubscribed from all our mailings.`} 42 | note={`Changed your mind? [Click here to resubscribe](#)`} 43 | /> 44 | </div> 45 | </Layout> 46 | ) 47 | } 48 | 49 | export const latestArticle = graphql` 50 | query { 51 | site { 52 | ...site 53 | siteMetadata { 54 | title 55 | } 56 | } 57 | latestArticle: allMdx( 58 | limit: 1 59 | sort: { fields: [frontmatter___date], order: DESC } 60 | filter: { frontmatter: { published: { ne: false } } } 61 | ) { 62 | totalCount 63 | edges { 64 | node { 65 | id 66 | fields { 67 | title 68 | slug 69 | } 70 | parent { 71 | ... on File { 72 | sourceInstanceName 73 | } 74 | } 75 | frontmatter { 76 | title 77 | date(formatString: "MMMM DD, YYYY") 78 | 79 | slug 80 | } 81 | } 82 | } 83 | } 84 | } 85 | ` 86 | -------------------------------------------------------------------------------- /src/pages/subscribe.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { graphql } from 'gatsby' 3 | import Layout from '../components/Layout' 4 | import Container from '../components/Container' 5 | import Subscribe from '../components/Forms/Subscribe' 6 | 7 | export default ({ data: { site } }) => ( 8 | <Layout site={site} noFooter> 9 | <Container> 10 | <Subscribe /> 11 | </Container> 12 | </Layout> 13 | ) 14 | 15 | export const pageQuery = graphql` 16 | query { 17 | site { 18 | ...site 19 | } 20 | } 21 | ` 22 | -------------------------------------------------------------------------------- /src/templates/blog.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { graphql } from 'gatsby' 3 | import Img from 'gatsby-image' 4 | import { css } from '@emotion/core' 5 | import Container from 'components/Container' 6 | import SEO from '../components/SEO' 7 | import Layout from '../components/Layout' 8 | import Link from '../components/Link' 9 | import { bpMaxSM, bpMaxMD } from '../lib/breakpoints' 10 | 11 | const Blog = ({ 12 | data: { site, allMdx }, 13 | pageContext: { pagination, categories }, 14 | }) => { 15 | const { page, nextPagePath, previousPagePath } = pagination 16 | 17 | const posts = page 18 | .map(id => allMdx.edges.find(edge => edge.node.id === id)) 19 | .filter(post => post !== undefined) 20 | 21 | return ( 22 | <Layout site={site}> 23 | <SEO /> 24 | <Container noVerticalPadding> 25 | {posts.map(({ node: post }) => ( 26 | <div 27 | key={post.id} 28 | css={css` 29 | :not(:first-of-type) { 30 | margin-top: 60px; 31 | ${bpMaxMD} { 32 | margin-top: 40px; 33 | } 34 | ${bpMaxSM} { 35 | margin-top: 20px; 36 | } 37 | } 38 | :first-of-type { 39 | margin-top: 20px; 40 | ${bpMaxSM} { 41 | margin-top: 20px; 42 | } 43 | } 44 | .gatsby-image-wrapper { 45 | } 46 | ${bpMaxSM} { 47 | padding: 20px; 48 | } 49 | display: flex; 50 | flex-direction: column; 51 | `} 52 | > 53 | {post.frontmatter.banner && ( 54 | <div 55 | css={css` 56 | padding: 60px 60px 40px 60px; 57 | ${bpMaxSM} { 58 | padding: 20px; 59 | } 60 | `} 61 | > 62 | <Link 63 | aria-label={`View ${post.frontmatter.title} article`} 64 | to={`/${post.fields.slug}`} 65 | > 66 | <Img sizes={post.frontmatter.banner.childImageSharp.fluid} /> 67 | </Link> 68 | </div> 69 | )} 70 | <h2 71 | css={css` 72 | margin-top: 30px; 73 | margin-bottom: 10px; 74 | `} 75 | > 76 | <Link 77 | aria-label={`View ${post.frontmatter.title} article`} 78 | to={`/${post.fields.slug}`} 79 | > 80 | {post.frontmatter.title} 81 | </Link> 82 | </h2> 83 | {/* <small>{post.frontmatter.date}</small> */} 84 | <p 85 | css={css` 86 | margin-top: 10px; 87 | `} 88 | > 89 | {post.excerpt} 90 | </p>{' '} 91 | <Link 92 | to={`/${post.fields.slug}`} 93 | aria-label={`view "${post.frontmatter.title}" article`} 94 | > 95 | Read Article → 96 | </Link> 97 | </div> 98 | ))} 99 | <div css={css({ marginTop: '30px' })}> 100 | {nextPagePath && ( 101 | <Link to={nextPagePath} aria-label="View next page"> 102 | Next Page → 103 | </Link> 104 | )} 105 | {previousPagePath && ( 106 | <Link to={previousPagePath} aria-label="View previous page"> 107 | ← Previous Page 108 | </Link> 109 | )} 110 | </div> 111 | <hr 112 | css={css` 113 | margin: 50px 0; 114 | `} 115 | /> 116 | </Container> 117 | </Layout> 118 | ) 119 | } 120 | 121 | export default Blog 122 | 123 | export const pageQuery = graphql` 124 | query { 125 | site { 126 | ...site 127 | } 128 | allMdx( 129 | sort: { fields: [frontmatter___date], order: DESC } 130 | filter: { fields: { isPost: { eq: true } } } 131 | ) { 132 | edges { 133 | node { 134 | excerpt(pruneLength: 300) 135 | id 136 | fields { 137 | title 138 | slug 139 | date 140 | } 141 | frontmatter { 142 | title 143 | date(formatString: "MMMM DD, YYYY") 144 | banner { 145 | childImageSharp { 146 | fluid(maxWidth: 600) { 147 | ...GatsbyImageSharpFluid_withWebp_tracedSVG 148 | } 149 | } 150 | } 151 | slug 152 | keywords 153 | } 154 | } 155 | } 156 | } 157 | } 158 | ` 159 | -------------------------------------------------------------------------------- /src/templates/post.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { graphql } from 'gatsby' 3 | import Img from 'gatsby-image' 4 | import { MDXRenderer } from 'gatsby-plugin-mdx' 5 | import SEO from 'components/SEO' 6 | import { css } from '@emotion/core' 7 | import Container from 'components/Container' 8 | import Layout from '../components/Layout' 9 | import { fonts } from '../lib/typography' 10 | import Share from '../components/Share' 11 | import config from '../../config/website' 12 | import { bpMaxSM } from '../lib/breakpoints' 13 | 14 | export default function Post({ 15 | data: { site, mdx }, 16 | pageContext: { next, prev }, 17 | }) { 18 | const author = mdx.frontmatter.author || config.author 19 | const date = mdx.frontmatter.date 20 | const title = mdx.frontmatter.title 21 | const banner = mdx.frontmatter.banner 22 | 23 | return ( 24 | <Layout site={site} frontmatter={mdx.frontmatter}> 25 | <SEO frontmatter={mdx.frontmatter} isBlogPost /> 26 | <article 27 | css={css` 28 | width: 100%; 29 | display: flex; 30 | `} 31 | > 32 | <Container> 33 | <h1 34 | css={css` 35 | text-align: center; 36 | margin-bottom: 20px; 37 | `} 38 | > 39 | {title} 40 | </h1> 41 | <div 42 | css={css` 43 | display: flex; 44 | justify-content: center; 45 | margin-bottom: 20px; 46 | h3, 47 | span { 48 | text-align: center; 49 | font-size: 15px; 50 | opacity: 0.6; 51 | font-family: ${fonts.regular}, sans-serif; 52 | font-weight: normal; 53 | margin: 0 5px; 54 | } 55 | `} 56 | > 57 | {author && <h3>{author}</h3>} 58 | {author && <span>—</span>} 59 | {date && <h3>{date}</h3>} 60 | </div> 61 | {banner && ( 62 | <div 63 | css={css` 64 | padding: 30px; 65 | ${bpMaxSM} { 66 | padding: 0; 67 | } 68 | `} 69 | > 70 | <Img 71 | sizes={banner.childImageSharp.fluid} 72 | alt={site.siteMetadata.keywords.join(', ')} 73 | /> 74 | </div> 75 | )} 76 | <br /> 77 | <MDXRenderer>{mdx.body}</MDXRenderer> 78 | </Container> 79 | {/* <SubscribeForm /> */} 80 | </article> 81 | <Container noVerticalPadding> 82 | <Share 83 | url={`${config.siteUrl}/${mdx.frontmatter.slug}/`} 84 | title={title} 85 | twitterHandle={config.twitterHandle} 86 | /> 87 | <br /> 88 | </Container> 89 | </Layout> 90 | ) 91 | } 92 | 93 | export const pageQuery = graphql` 94 | query($id: String!) { 95 | site { 96 | ...site 97 | } 98 | mdx(fields: { id: { eq: $id } }) { 99 | frontmatter { 100 | title 101 | date(formatString: "MMMM DD, YYYY") 102 | author 103 | banner { 104 | childImageSharp { 105 | fluid(maxWidth: 900) { 106 | ...GatsbyImageSharpFluid_withWebp_tracedSVG 107 | } 108 | } 109 | } 110 | slug 111 | keywords 112 | } 113 | body 114 | } 115 | } 116 | ` 117 | -------------------------------------------------------------------------------- /static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/apple-touch-icon.png -------------------------------------------------------------------------------- /static/browserconfig.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="utf-8"?> 2 | <browserconfig> 3 | <msapplication> 4 | <tile> 5 | <square150x150logo src="/mstile-150x150.png"/> 6 | <TileColor>#da532c</TileColor> 7 | </tile> 8 | </msapplication> 9 | </browserconfig> 10 | -------------------------------------------------------------------------------- /static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/favicon.ico -------------------------------------------------------------------------------- /static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/images/logo.png -------------------------------------------------------------------------------- /static/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eggheadio/gatsby-starter-egghead-blog/d4d4641b2cebd061a6b4de2bb9121ab8413f108c/static/mstile-150x150.png -------------------------------------------------------------------------------- /static/readme.md: -------------------------------------------------------------------------------- 1 | # Static HTML exported from a wordpress blog 2 | 3 | generate favico stuff from https://realfavicongenerator.net/ 4 | -------------------------------------------------------------------------------- /static/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?> 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" 3 | "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> 4 | <svg version="1.0" xmlns="http://www.w3.org/2000/svg" 5 | width="805.000000pt" height="805.000000pt" viewBox="0 0 805.000000 805.000000" 6 | preserveAspectRatio="xMidYMid meet"> 7 | <metadata> 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | </metadata> 10 | <g transform="translate(0.000000,805.000000) scale(0.100000,-0.100000)" 11 | fill="#000000" stroke="none"> 12 | <path d="M3843 8039 c-153 -19 -238 -38 -368 -81 -219 -72 -453 -205 -665 13 | -375 -123 -99 -362 -340 -460 -463 -14 -17 -32 -40 -40 -49 -8 -10 -26 -33 14 | -40 -51 -14 -19 -41 -54 -60 -79 -52 -67 -238 -351 -304 -464 -94 -160 -132 15 | -231 -244 -458 l-106 -216 -96 -18 c-52 -9 -133 -26 -180 -37 -47 -11 -92 -21 16 | -100 -23 -44 -9 -147 -38 -230 -64 -302 -94 -433 -162 -561 -291 -115 -116 17 | -192 -249 -240 -415 -20 -68 -23 -103 -24 -240 0 -145 8 -300 19 -365 2 -14 7 18 | -50 11 -80 8 -72 44 -304 49 -322 3 -7 8 -30 11 -52 7 -50 43 -229 57 -281 6 19 | -22 12 -51 14 -65 16 -90 73 -270 114 -356 102 -212 272 -389 457 -475 57 -26 20 | 59 -30 68 -104 3 -27 7 -57 10 -65 2 -8 6 -37 10 -65 9 -79 63 -260 110 -370 21 | 7 -16 34 -84 60 -150 186 -469 505 -910 890 -1230 33 -28 62 -52 65 -55 7 -8 22 | 176 -129 230 -166 69 -47 255 -154 268 -154 7 0 12 -4 12 -10 0 -5 4 -10 9 23 | -10 5 0 51 -19 103 -43 51 -24 125 -56 163 -71 39 -16 79 -32 90 -37 77 -31 24 | 387 -116 485 -133 19 -3 46 -8 59 -11 13 -2 49 -7 80 -11 31 -3 59 -8 62 -10 25 | 38 -22 730 -22 768 0 3 2 33 7 66 11 32 3 62 8 65 10 3 1 28 6 55 9 79 11 279 26 | 62 415 107 523 173 984 477 1352 892 40 45 75 84 78 87 29 26 185 246 251 355 27 | 172 280 361 742 398 975 7 41 14 86 17 100 2 14 7 46 10 71 6 45 8 46 73 78 28 | 194 96 367 279 467 496 30 66 101 311 118 410 3 17 14 73 25 125 29 139 35 29 | 169 45 238 2 15 9 54 15 87 6 33 13 83 17 110 3 28 8 58 10 69 2 10 6 51 10 30 | 90 3 39 8 73 10 76 3 6 15 198 18 304 2 55 -5 140 -19 215 -10 57 -53 171 -91 31 | 240 -89 162 -239 302 -409 381 -159 73 -498 177 -695 214 -14 2 -72 14 -130 32 | 25 -58 12 -106 21 -106 21 -1 0 -12 24 -24 53 -19 43 -82 172 -166 337 -148 33 | 293 -404 683 -609 929 -426 512 -900 813 -1405 891 -91 14 -332 19 -417 9z"/> 34 | </g> 35 | </svg> 36 | --------------------------------------------------------------------------------