├── .eslintrc.json ├── .prettierrc ├── src ├── images │ ├── gatsby-icon.png │ └── gatsby-astronaut.png ├── pages │ ├── 404.js │ ├── index.js │ └── app.js ├── components │ ├── common │ │ ├── Layout │ │ │ ├── index.jsx │ │ │ ├── styles.js │ │ │ └── layout.css │ │ ├── Container │ │ │ └── index.js │ │ ├── NotFound │ │ │ └── index.jsx │ │ ├── Flex │ │ │ └── index.jsx │ │ ├── PostLoader │ │ │ ├── styles.js │ │ │ └── index.jsx │ │ ├── Item │ │ │ └── index.js │ │ └── SEO │ │ │ └── index.jsx │ └── app │ │ └── Launches │ │ ├── getLaunches.graphql │ │ ├── styles.js │ │ └── index.jsx ├── data │ └── index.js └── providers │ └── Apollo.js ├── .vscode └── settings.json ├── gatsby-ssr.js ├── static └── _redirects ├── gatsby-browser.js ├── jsconfig.json ├── gatsby-node.js ├── gatsby-config.js ├── LICENSE ├── .gitignore ├── README.md └── package.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smakosh/gatsby-apollo-starter/HEAD/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smakosh/gatsby-apollo-starter/HEAD/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import NotFound from 'components/common/NotFound' 3 | 4 | export default () => 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "javascript.format.enable": false, 4 | "prettier.eslintIntegration": true 5 | } 6 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Apollo from 'providers/Apollo' 3 | 4 | export const wrapRootElement = ({ element }) => {element} 5 | -------------------------------------------------------------------------------- /static/_redirects: -------------------------------------------------------------------------------- 1 | # Redirect default Netlify subdomain to primary domain 2 | https://gatsby-apollo-starter.netlify.com/* https://gatsby-starter-apollo.smakosh.com/:splat 301! 3 | -------------------------------------------------------------------------------- /src/components/common/Layout/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { GlobalStyle } from './styles' 3 | import './layout.css' 4 | 5 | export default ({ children }) => ( 6 | <> 7 | 8 | {children} 9 | 10 | ) 11 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import 'core-js/modules/es6.set' 3 | import 'core-js/modules/es6.map' 4 | import 'raf/polyfill' 5 | import Apollo from 'providers/Apollo' 6 | 7 | export const wrapRootElement = ({ element }) => {element} 8 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES6", 4 | "module": "commonjs", 5 | "baseUrl": "src", 6 | "experimentalDecorators": true, 7 | "allowSyntheticDefaultImports": true, 8 | "jsx": "react" 9 | }, 10 | "include": ["src/**/*"] 11 | } 12 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | import Layout from 'components/common/Layout' 4 | 5 | export default () => ( 6 | 7 |

Gatsby Apollo starter

8 | Go to app 9 |
10 | ) 11 | -------------------------------------------------------------------------------- /src/components/common/Container/index.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | const Container = styled.div` 4 | max-width: 1200px; 5 | margin: 0 auto; 6 | width: 100%; 7 | 8 | @media (max-width: 1400px) { 9 | width: 90%; 10 | } 11 | ` 12 | 13 | export default Container 14 | -------------------------------------------------------------------------------- /src/components/common/NotFound/index.jsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Layout from "components/common/Layout" 3 | 4 | export default () => ( 5 | 6 |

NOT FOUND

7 |

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

8 |
9 | ) 10 | -------------------------------------------------------------------------------- /src/pages/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Router } from '@reach/router' 3 | import NotFound from 'components/common/NotFound' 4 | import Launches from 'components/app/Launches' 5 | 6 | export default () => ( 7 | 8 | 9 | 10 | 11 | ) 12 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | exports.onCreateWebpackConfig = ({ actions }) => { 4 | actions.setWebpackConfig({ 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.(graphql|gql)$/, 9 | exclude: /node_modules/, 10 | loader: 'graphql-tag/loader', 11 | }, 12 | ], 13 | }, 14 | resolve: { 15 | modules: [path.resolve(__dirname, 'src'), 'node_modules'], 16 | }, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /src/components/common/Flex/index.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | const Flex = styled.div` 4 | display: flex; 5 | align-items: ${({ align }) => align || "center"}; 6 | justify-content: space-between; 7 | flex-wrap: wrap; 8 | 9 | &:after { 10 | content: ""; 11 | max-width: ${({ col }) => `${100 / col - 2}%` || "100%"}; 12 | width: 100%; 13 | 14 | @media (max-width: 960px) { 15 | max-width: 100%; 16 | } 17 | } 18 | `; 19 | 20 | export default Flex; 21 | -------------------------------------------------------------------------------- /src/components/app/Launches/getLaunches.graphql: -------------------------------------------------------------------------------- 1 | { 2 | launchesPast(limit: 10) { 3 | id 4 | mission_name 5 | launch_site { 6 | site_name 7 | } 8 | links { 9 | video_link 10 | } 11 | rocket { 12 | rocket_name 13 | first_stage { 14 | cores { 15 | flight 16 | core { 17 | reuse_count 18 | } 19 | } 20 | } 21 | } 22 | ships { 23 | name 24 | home_port 25 | image 26 | } 27 | launch_date_utc 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/components/common/PostLoader/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export const Wrapper = styled.div` 4 | padding: 4rem 0; 5 | display: flex; 6 | align-items: center; 7 | flex-wrap: wrap; 8 | justify-content: space-between; 9 | 10 | &:after { 11 | content: ''; 12 | width: 100%; 13 | max-width: 32%; 14 | 15 | @media (max-width: 960px) { 16 | max-width: 100%; 17 | } 18 | } 19 | ` 20 | 21 | export const Item = styled.div` 22 | width: 100%; 23 | max-width: 32%; 24 | 25 | @media (max-width: 960px) { 26 | max-width: 100%; 27 | } 28 | ` 29 | -------------------------------------------------------------------------------- /src/components/common/Layout/styles.js: -------------------------------------------------------------------------------- 1 | import { createGlobalStyle } from 'styled-components' 2 | 3 | export const GlobalStyle = createGlobalStyle` 4 | body { 5 | @import url('https://fonts.googleapis.com/css?family=Roboto&display=swap'); 6 | font-family: 'Roboto', 'Helvetica', sans-serif; 7 | margin: 0; 8 | padding: 0; 9 | 10 | iframe, object, embed { 11 | max-width: 100%; 12 | max-height: 100%; 13 | margin-bottom: unset; 14 | display: block; 15 | } 16 | 17 | input, select, textarea, button { 18 | &:focus { 19 | outline: none; 20 | } 21 | } 22 | 23 | a { 24 | text-decoration: none; 25 | } 26 | } 27 | ` 28 | -------------------------------------------------------------------------------- /src/components/common/PostLoader/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ContentLoader from 'react-content-loader' 3 | import { Wrapper, Item } from './styles' 4 | 5 | export default () => ( 6 | 7 | {[0, 1].map(item => ( 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | ))} 24 | 25 | ) 26 | -------------------------------------------------------------------------------- /src/data/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | defaultTitle: 'Gatsby Apollo app starter', 3 | logo: 'https://gatsby-apollo-starter.smakosh.com/favicon.ico', 4 | author: 'smakosh', 5 | url: 'https://gatsby-apollo-starter.smakosh.com', 6 | legalName: 'Ismail Ghallou', 7 | defaultDescription: `Gatsby Apollo starter to build apps`, 8 | socialLinks: { 9 | twitter: 'http://www.twitter.com/smakosh', 10 | github: 'https://github.com/smakosh', 11 | instagram: 'https://instagram.com/smakosh19', 12 | }, 13 | googleAnalyticsID: 'UA-xxxx-x', 14 | themeColor: '#151436', 15 | backgroundColor: '#151436', 16 | social: { 17 | facebook: 'appId', 18 | twitter: '@smakosh', 19 | }, 20 | address: { 21 | city: 'Internet', 22 | region: 'Earth', 23 | country: 'Meh', 24 | zipCode: '99999', 25 | }, 26 | contact: { 27 | email: 'ismai23l@hotmail.com', 28 | phone: '+212663532761', 29 | }, 30 | foundingDate: '2019', 31 | } 32 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `Gatsby Apollo Starter`, 4 | description: `Kick off your next, great Gatsby project with this Apollo starter. This starter ships with Apollo configured and client side routes.`, 5 | author: `@smakosh`, 6 | }, 7 | plugins: [ 8 | `gatsby-plugin-react-helmet`, 9 | { 10 | resolve: `gatsby-source-filesystem`, 11 | options: { 12 | name: `images`, 13 | path: `${__dirname}/src/images`, 14 | }, 15 | }, 16 | `gatsby-transformer-sharp`, 17 | `gatsby-plugin-sharp`, 18 | { 19 | resolve: `gatsby-plugin-manifest`, 20 | options: { 21 | name: `gatsby-starter-default`, 22 | short_name: `starter`, 23 | start_url: `/`, 24 | background_color: `#663399`, 25 | theme_color: `#663399`, 26 | display: `minimal-ui`, 27 | icon: `src/images/gatsby-icon.png`, 28 | }, 29 | }, 30 | ], 31 | } 32 | -------------------------------------------------------------------------------- /src/components/common/Item/index.js: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | const Item = styled.div` 4 | width: 100%; 5 | max-width: ${({ col }) => 6 | col && col > 1 ? `${100 / col - 2}%` || "100%" : "100%"}; 7 | 8 | ${({ marginBottom }) => 9 | marginBottom && 10 | ` 11 | margin-bottom: ${marginBottom}; 12 | `} 13 | 14 | @media (max-width: 960px) { 15 | max-width: ${({ colTablet }) => 16 | colTablet && colTablet > 1 17 | ? `${100 / colTablet - 2}%` || "100%" 18 | : "100%"}; 19 | margin-bottom: ${({ marginBottom }) => marginBottom || "3rem"}; 20 | 21 | &:last-child { 22 | margin-bottom: unset; 23 | } 24 | } 25 | 26 | @media (max-width: 680px) { 27 | max-width: ${({ colMobile }) => 28 | colMobile && colMobile > 1 29 | ? `${100 / colMobile - 2}%` || "100%" 30 | : "100%"}; 31 | } 32 | 33 | ${({ stretch }) => 34 | stretch && 35 | ` 36 | display: flex; 37 | align-self: stretch; 38 | `} 39 | `; 40 | 41 | export default Item; 42 | -------------------------------------------------------------------------------- /src/components/app/Launches/styles.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export const Wrapper = styled.div` 4 | padding: 4rem 0; 5 | 6 | h4 { 7 | color: #2462b4; 8 | font-size: 12pt; 9 | margin: unset; 10 | } 11 | 12 | p.description { 13 | line-height: 1.6; 14 | color: #777; 15 | margin-bottom: 4rem; 16 | } 17 | 18 | @media (max-width: 960px) { 19 | text-align: center; 20 | } 21 | ` 22 | 23 | export const Flex = styled.div` 24 | display: flex; 25 | flex-wrap: wrap; 26 | justify-content: space-between; 27 | ` 28 | 29 | export const Item = styled.div` 30 | width: 100%; 31 | max-width: 30%; 32 | display: flex; 33 | ` 34 | 35 | export const Card = styled.div` 36 | width: 100%; 37 | height: 100%; 38 | background: #fff; 39 | box-shadow: 0px 8px 24px #c9d0dc; 40 | display: flex; 41 | flex-direction: column; 42 | justify-content: space-between; 43 | ` 44 | 45 | export const Title = styled.div` 46 | padding: 2rem 1rem; 47 | ` 48 | 49 | export const Video = styled.div` 50 | padding: unset; 51 | ` 52 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | .env.development 57 | 58 | # gatsby files 59 | .cache/ 60 | public 61 | 62 | # Mac files 63 | .DS_Store 64 | 65 | # Yarn 66 | yarn-error.log 67 | .pnp/ 68 | .pnp.js 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gatsby-Apollo-Starter 2 | 3 | [![Netlify Status](https://api.netlify.com/api/v1/badges/e2bfca08-a76e-43ab-864f-751f34592c3a/deploy-status)](https://app.netlify.com/sites/gatsby-apollo-starter/deploys) 4 | 5 | ## Features 6 | 7 | - Apollo provider & Client side routing 8 | - Eslint/Prettier configured 9 | - Easy to customize 10 | - Nice project structure 11 | - Flex Grid components easy to customize 12 | 13 | ## Prerequisites 14 | 15 | [Yarn](https://yarnpkg.com/en/) 16 | 17 | Please create a new file `.env.development` and put this env variable with your GitHub token 18 | 19 | > If you're building locally, you will have to create a new file `.env.production` and put the same env variable 20 | 21 | ```bash 22 | GATSBY_GRAPHQL_API=xxxxxxxxxx 23 | ``` 24 | 25 | Don't forget to edit your site's data on `src/data/index.js` file 26 | 27 | ## Installing 28 | 29 | Installing the dependencies 30 | 31 | ```bash 32 | yarn 33 | ``` 34 | 35 | ## Start the dev server 36 | 37 | ```bash 38 | yarn start 39 | ``` 40 | 41 | ### Clean the cache 42 | 43 | This removes the `.cache/` & `public/` folders 44 | 45 | ```bash 46 | yarn reset 47 | ``` 48 | 49 | ## Built with 50 | 51 | - Gatsby 52 | - React & GraphQL 53 | - Apollo 54 | - VSCode 55 | - And these useful of JavaScript libraries & Gatsby plugins [package.json](package.json) 56 | 57 | ## License 58 | 59 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 60 | 61 | ## Contributors 62 | 63 | - [Myself](https://smakosh.com) 64 | 65 | ## Support 66 | 67 | If you love this Gatsby template and want to support me, you can do so through my Patreon 68 | 69 | [![Support me on Patreon](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/smakosh) 70 | -------------------------------------------------------------------------------- /src/providers/Apollo.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import fetch from 'unfetch' 3 | import { ApolloProvider as Provider } from 'react-apollo' 4 | import { InMemoryCache } from 'apollo-cache-inmemory' 5 | import { ApolloClient } from 'apollo-client' 6 | import { ApolloLink } from 'apollo-link' 7 | import { setContext } from 'apollo-link-context' 8 | import { onError } from 'apollo-link-error' 9 | import { toast } from 'react-toastify' 10 | import { createUploadLink } from 'apollo-upload-client' 11 | 12 | export default ({ children }) => { 13 | const httpLink = createUploadLink({ 14 | fetch, 15 | uri: process.env.GATSBY_GRAPHQL_API, 16 | }) 17 | 18 | const errorLink = onError(({ networkError, graphQLErrors }) => { 19 | if (graphQLErrors) { 20 | toast.error( 21 | 'There was an error while trying to connect to the server, please try again', 22 | { 23 | position: toast.POSITION.TOP_CENTER, 24 | } 25 | ) 26 | graphQLErrors.map(({ message, locations, path }) => 27 | console.log( 28 | `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` 29 | ) 30 | ) 31 | } 32 | if (networkError) { 33 | toast.error(`[Network error]: ${networkError}`, { 34 | position: toast.POSITION.TOP_CENTER, 35 | }) 36 | console.log(`[Network err]: Message: ${networkError}`) 37 | } 38 | }) 39 | 40 | const authLink = setContext((_, { headers }) => ({ 41 | headers: { 42 | ...headers, 43 | }, 44 | })) 45 | 46 | const link = ApolloLink.from([errorLink, authLink.concat(httpLink)]) 47 | 48 | const client = new ApolloClient({ 49 | cache: new InMemoryCache(), 50 | link, 51 | }) 52 | return {children} 53 | } 54 | -------------------------------------------------------------------------------- /src/components/app/Launches/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Container from 'components/common/Container' 3 | import PostLoader from 'components/common/PostLoader' 4 | import Flex from 'components/common/Flex' 5 | import Item from 'components/common/Item' 6 | import { Query } from 'react-apollo' 7 | import GET_LAUNCHES from './getLaunches.graphql' 8 | import { Wrapper, Card, Title, Video } from './styles' 9 | import Layout from 'components/common/Layout' 10 | 11 | export default () => ( 12 | 13 | {({ loading, error, data }) => { 14 | if (error) { 15 | console.log(error) 16 | } 17 | 18 | const { launchesPast } = data 19 | 20 | return ( 21 | 22 | 23 |

Past launches

24 | {loading ? ( 25 | 26 | ) : ( 27 | 28 | {launchesPast.map( 29 | ({ id, mission_name, links: { video_link } }) => ( 30 | 38 | 39 | 40 | <h4>{mission_name}</h4> 41 | 42 |