├── .browserslistrc ├── .codeclimate.yml ├── .eslintignore ├── .eslintrc.json ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md ├── .gitignore ├── .stylelintrc ├── LICENSE ├── README.md ├── gatsby-config.js ├── gatsby-node.js ├── netlify.toml ├── package-lock.json ├── package.json ├── renovate.json ├── src ├── components │ ├── Content.js │ ├── Features.js │ ├── Layout.js │ ├── Navbar.js │ ├── Pagination.js │ ├── PostList.js │ ├── Pricing.js │ ├── Testimonials.js │ └── all.sass ├── img │ ├── github-icon.svg │ └── logo.svg ├── pages │ └── 404.js └── templates │ ├── author.js │ ├── blog.js │ ├── category.js │ ├── page.js │ ├── post.js │ └── tag.js ├── static └── img │ ├── chemex.jpg │ ├── coffee-gear.png │ ├── coffee.png │ ├── flavor_wheel.jpg │ ├── jumbotron.jpg │ ├── meeting-space.png │ ├── products-full-width.jpg │ ├── products-grid1.jpg │ ├── products-grid2.jpg │ ├── products-grid3.jpg │ └── tutorials.png └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | Last 2 versions 2 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | eslint: 3 | enabled: true 4 | stylelint: 5 | enabled: true 6 | duplication: 7 | enabled: true 8 | config: 9 | languages: 10 | javascript: 11 | mass_threshold: 70 12 | 13 | ratings: 14 | paths: 15 | - "**.js" 16 | - "**.jsx" 17 | - "**.css" 18 | 19 | exclude_paths: 20 | - static/**/* 21 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | public 2 | static 3 | .cache 4 | content -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier"], 3 | "plugins": ["react", "jsx-a11y", "import"], 4 | "rules": { 5 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 6 | "react/prefer-stateless-function": "off", 7 | "react/require-default-props": "off", 8 | "react/prop-types": "off", 9 | "react/no-danger": "off" 10 | }, 11 | "settings": { 12 | "import/core-modules": [] 13 | }, 14 | "env": { 15 | "browser": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Support request 4 | url: https://stackoverflow.com/questions/tagged/gatsby 5 | about: Please ask and answer support requests on stack overflow 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 3 | node_modules 4 | .cache/ 5 | # Build directory 6 | public/ 7 | static/admin/*.bundle.* 8 | .DS_Store 9 | yarn-error.log 10 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules": { 4 | "indentation": 4 5 | } 6 | } -------------------------------------------------------------------------------- /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 | # Gatsby v2 WordPress Starter 2 | 3 | This starter is forked from the 4 | [gatsby-starter-netlify-cms](https://github.com/netlify-templates/gatsby-starter-netlify-cms) 5 | and modified to use WordPress instead of netlify-cms, using the [gatsby-source-wordpress](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-wordpress) plugin as the data connector. 6 | 7 | Demo: https://gatsby-starter-wordpress.netlify.com/ 8 | 9 | > **Looking for maintainer**: If you're interested in taking over the maintenance of this starter, please reach out in an issue. We're not working with Gatsby any more (it got way too complicated, hello nextjs), and so we're not maintaining this. 10 | 11 | ## Use It Now 12 | 13 | gatsby new NAME https://github.com/GatsbyCentral/gatsby-starter-wordpress 14 | 15 | * Edit `gatsby-config.js`, change `baseUrl` 16 | - Make sure you have at least 1 post and 1 page on your WordPress site 17 | - Make sure at least 1 post has at least 1 tag 18 | * Ensure the permalink structure in your WordPress installation is set to `Post Name` instead of the deafult `Plain`, or else the `gatsby-source-wordpress` plugin won't be able to communicate with WordPress 19 | * Rejoice 20 | - For more information on the source plugin, check out the [gatsby-source-wordpress](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-wordpress) repository page 21 | - File any [issues here](https://github.com/GatsbyCentral/gatsby-starter-wordpress/issues) 22 | 23 | ### Known Limitations 24 | 25 | * This is based on the [netlify starter](https://github.com/netlify-templates/gatsby-starter-netlify-cms) which uses [bulma](https://bulma.io). This adds 150KB to every built page. 26 | * Your WordPress site must have at least 1 post with 1 tag, or the starter will crash 27 | * Nested pages / categories will not render with nested pages 28 | - A WordPress page like `/about/team/` will render on Gatsby as `/team/` 29 | - Likewise for categories 30 | - Discussion here https://github.com/GatsbyCentral/gatsby-starter-wordpress/issues/24 31 | 32 | ## CSS Processing 33 | 34 | This plugin uses [gatsby-plugin-purgecss](https://www.gatsbyjs.org/packages/gatsby-plugin-purgecss/) and [bulma](https://bulma.io/). The bulma build would otherwise be ~170K which adds 170K to each of your built HTML pages. However, with purgecss this is reduced 90%. 35 | 36 | ## WordPress Setup 37 | 38 | Check the [gatsby-source-wordpress](https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-wordpress) plugin for more information. If you want to copy the demo content, you can grab the [WordPress XML export here](https://wpdemo.gatsbycentral.com/gatsbystarterwordpress.WordPress.2019-09-12.xml) and import it into your WordPress site as a starting point. 39 | 40 | ## Support 41 | 42 | Please post support questions on StackOverflow or other similar sites. Please only post issues here if you have a bug to report with a reproduction. Unfortunately we're not able to provide support here. 43 | 44 | ## Contributors 45 | 46 | This starter was forked from the netlify starter by the 47 | [GatsbyCentral](https://www.gatsbycentral.com/) crew. Additional contributions 48 | were gratefully received from the following folks: 49 | 50 | * https://github.com/tomByrer 51 | * https://github.com/dajocarter 52 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: 'Gatsby + WordPress Starter', 4 | }, 5 | plugins: [ 6 | 'gatsby-plugin-react-helmet', 7 | 'gatsby-plugin-sass', 8 | { 9 | resolve: 'gatsby-source-wordpress', 10 | options: { 11 | // The base url to your WP site. 12 | baseUrl: 'wpdemo.gatsbycentral.chm.ac', 13 | // WP.com sites set to true, WP.org set to false 14 | hostingWPCOM: false, 15 | // The protocol. This can be http or https. 16 | protocol: 'https', 17 | // Use 'Advanced Custom Fields' Wordpress plugin 18 | useACF: false, 19 | auth: {}, 20 | // Set to true to debug endpoints on 'gatsby build' 21 | verboseOutput: false, 22 | }, 23 | }, 24 | 'gatsby-plugin-sharp', 25 | 'gatsby-transformer-sharp', 26 | { 27 | // Removes unused css rules 28 | resolve:'gatsby-plugin-purgecss', 29 | options: { 30 | // Activates purging in gatsby develop 31 | develop: true, 32 | // Purge only the main css file 33 | purgeOnly: ['/all.sass'], 34 | }, 35 | }, // must be after other CSS plugins 36 | 'gatsby-plugin-netlify', // make sure to keep it last in the array 37 | ], 38 | } 39 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const _ = require('lodash') 2 | const path = require('path') 3 | const { createFilePath } = require('gatsby-source-filesystem') 4 | const { paginate } = require('gatsby-awesome-pagination') 5 | 6 | const getOnlyPublished = edges => 7 | _.filter(edges, ({ node }) => node.status === 'publish') 8 | 9 | exports.createPages = ({ actions, graphql }) => { 10 | const { createPage } = actions 11 | 12 | return graphql(` 13 | { 14 | allWordpressPage { 15 | edges { 16 | node { 17 | id 18 | slug 19 | status 20 | } 21 | } 22 | } 23 | } 24 | `) 25 | .then(result => { 26 | if (result.errors) { 27 | result.errors.forEach(e => console.error(e.toString())) 28 | return Promise.reject(result.errors) 29 | } 30 | 31 | const pageTemplate = path.resolve(`./src/templates/page.js`) 32 | 33 | // Only publish pages with a `status === 'publish'` in production. This 34 | // excludes drafts, future posts, etc. They will appear in development, 35 | // but not in a production build. 36 | 37 | const allPages = result.data.allWordpressPage.edges 38 | const pages = 39 | process.env.NODE_ENV === 'production' 40 | ? getOnlyPublished(allPages) 41 | : allPages 42 | 43 | // Call `createPage()` once per WordPress page 44 | _.each(pages, ({ node: page }) => { 45 | createPage({ 46 | path: `/${page.slug}/`, 47 | component: pageTemplate, 48 | context: { 49 | id: page.id, 50 | }, 51 | }) 52 | }) 53 | }) 54 | .then(() => { 55 | return graphql(` 56 | { 57 | allWordpressPost { 58 | edges { 59 | node { 60 | id 61 | slug 62 | status 63 | } 64 | } 65 | } 66 | } 67 | `) 68 | }) 69 | .then(result => { 70 | if (result.errors) { 71 | result.errors.forEach(e => console.error(e.toString())) 72 | return Promise.reject(result.errors) 73 | } 74 | 75 | const postTemplate = path.resolve(`./src/templates/post.js`) 76 | const blogTemplate = path.resolve(`./src/templates/blog.js`) 77 | 78 | // In production builds, filter for only published posts. 79 | const allPosts = result.data.allWordpressPost.edges 80 | const posts = 81 | process.env.NODE_ENV === 'production' 82 | ? getOnlyPublished(allPosts) 83 | : allPosts 84 | 85 | // Iterate over the array of posts 86 | _.each(posts, ({ node: post }) => { 87 | // Create the Gatsby page for this WordPress post 88 | createPage({ 89 | path: `/${post.slug}/`, 90 | component: postTemplate, 91 | context: { 92 | id: post.id, 93 | }, 94 | }) 95 | }) 96 | 97 | // Create a paginated blog, e.g., /, /page/2, /page/3 98 | paginate({ 99 | createPage, 100 | items: posts, 101 | itemsPerPage: 10, 102 | pathPrefix: ({ pageNumber }) => (pageNumber === 0 ? `/` : `/page`), 103 | component: blogTemplate, 104 | }) 105 | }) 106 | .then(() => { 107 | return graphql(` 108 | { 109 | allWordpressCategory(filter: { count: { gt: 0 } }) { 110 | edges { 111 | node { 112 | id 113 | name 114 | slug 115 | } 116 | } 117 | } 118 | } 119 | `) 120 | }) 121 | .then(result => { 122 | if (result.errors) { 123 | result.errors.forEach(e => console.error(e.toString())) 124 | return Promise.reject(result.errors) 125 | } 126 | 127 | const categoriesTemplate = path.resolve(`./src/templates/category.js`) 128 | 129 | // Create a Gatsby page for each WordPress Category 130 | _.each(result.data.allWordpressCategory.edges, ({ node: cat }) => { 131 | createPage({ 132 | path: `/categories/${cat.slug}/`, 133 | component: categoriesTemplate, 134 | context: { 135 | name: cat.name, 136 | slug: cat.slug, 137 | }, 138 | }) 139 | }) 140 | }) 141 | .then(() => { 142 | return graphql(` 143 | { 144 | allWordpressTag(filter: { count: { gt: 0 } }) { 145 | edges { 146 | node { 147 | id 148 | name 149 | slug 150 | } 151 | } 152 | } 153 | } 154 | `) 155 | }) 156 | 157 | .then(result => { 158 | if (result.errors) { 159 | result.errors.forEach(e => console.error(e.toString())) 160 | return Promise.reject(result.errors) 161 | } 162 | 163 | const tagsTemplate = path.resolve(`./src/templates/tag.js`) 164 | 165 | // Create a Gatsby page for each WordPress tag 166 | _.each(result.data.allWordpressTag.edges, ({ node: tag }) => { 167 | createPage({ 168 | path: `/tags/${tag.slug}/`, 169 | component: tagsTemplate, 170 | context: { 171 | name: tag.name, 172 | slug: tag.slug, 173 | }, 174 | }) 175 | }) 176 | }) 177 | .then(() => { 178 | return graphql(` 179 | { 180 | allWordpressWpUsers { 181 | edges { 182 | node { 183 | id 184 | slug 185 | } 186 | } 187 | } 188 | } 189 | `) 190 | }) 191 | .then(result => { 192 | if (result.errors) { 193 | result.errors.forEach(e => console.error(e.toString())) 194 | return Promise.reject(result.errors) 195 | } 196 | 197 | const authorTemplate = path.resolve(`./src/templates/author.js`) 198 | 199 | _.each(result.data.allWordpressWpUsers.edges, ({ node: author }) => { 200 | createPage({ 201 | path: `/author/${author.slug}`, 202 | component: authorTemplate, 203 | context: { 204 | id: author.id, 205 | }, 206 | }) 207 | }) 208 | }) 209 | } 210 | 211 | exports.onCreateNode = ({ node, actions, getNode }) => { 212 | const { createNodeField } = actions 213 | 214 | if (node.internal.type === `MarkdownRemark`) { 215 | const value = createFilePath({ node, getNode }) 216 | createNodeField({ 217 | name: `slug`, 218 | node, 219 | value, 220 | }) 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "public" 3 | command = "npm run build" 4 | [build.environment] 5 | YARN_VERSION = "1.3.2" 6 | YARN_FLAGS = "--no-ignore-optional" 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-wordpress", 3 | "description": "Gatsby v2 starter for WordPress", 4 | "version": "0.1.0", 5 | "author": "GatsbyCentral.com", 6 | "dependencies": { 7 | "bulma": "^0.7.5", 8 | "gatsby": "^2.18.1", 9 | "gatsby-awesome-pagination": "^0.3.3", 10 | "gatsby-plugin-lodash": "^3.1.7", 11 | "gatsby-plugin-netlify": "^2.1.12", 12 | "gatsby-plugin-purgecss": "^4.0.1", 13 | "gatsby-plugin-react-helmet": "^3.1.7", 14 | "gatsby-plugin-sass": "^2.1.14", 15 | "gatsby-plugin-sharp": "^2.2.21", 16 | "gatsby-remark-images": "^3.1.21", 17 | "gatsby-source-filesystem": "^2.1.22", 18 | "gatsby-source-wordpress": "^3.1.31", 19 | "gatsby-transformer-remark": "^2.6.22", 20 | "gatsby-transformer-sharp": "^2.2.14", 21 | "lodash": "^4.17.5", 22 | "node-sass": "^4.12.0", 23 | "parcel-bundler": "^1.12.3", 24 | "prop-types": "^15.6.0", 25 | "react": "^16.9.0", 26 | "react-dom": "^16.9.0", 27 | "react-helmet": "^5.2.1", 28 | "uuid": "^3.3.3" 29 | }, 30 | "keywords": [ 31 | "gatsby" 32 | ], 33 | "license": "MIT", 34 | "main": "n/a", 35 | "scripts": { 36 | "start": "npm run develop", 37 | "clean": "rimraf .cache public", 38 | "build": "npm run clean && gatsby build", 39 | "develop": "npm run clean && gatsby develop", 40 | "serve": "gatsby serve", 41 | "format": "prettier --trailing-comma es5 --no-semi --single-quote --write \"{gatsby-*.js,src/**/*.js}\"", 42 | "test": "echo \"Error: no test specified\" && exit 1" 43 | }, 44 | "devDependencies": { 45 | "eslint-config-airbnb": "^18.0.1", 46 | "eslint-config-prettier": "^6.3.0", 47 | "prettier": "^1.18.2", 48 | "rimraf": "^3.0.0" 49 | }, 50 | "prettier": { 51 | "trailingComma": "es5", 52 | "semi": false, 53 | "singleQuote": true 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "rangeStrategy": "replace", 6 | "lockFileMaintenance": { 7 | "enabled": true, 8 | "extends": "schedule:weekly" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Content.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | export const HTMLContent = ({ content, className }) => ( 5 |
6 | ) 7 | 8 | const Content = ({ content, className }) => ( 9 |
{content}
10 | ) 11 | 12 | Content.propTypes = { 13 | content: PropTypes.node, 14 | className: PropTypes.string, 15 | } 16 | 17 | HTMLContent.propTypes = Content.propTypes 18 | 19 | export default Content 20 | -------------------------------------------------------------------------------- /src/components/Features.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const FeatureGrid = ({ gridItems }) => ( 5 |
6 | {gridItems.map(item => ( 7 |
8 |
9 |

10 | 11 |

12 |

{item.text}

13 |
14 |
15 | ))} 16 |
17 | ) 18 | 19 | FeatureGrid.propTypes = { 20 | gridItems: PropTypes.arrayOf( 21 | PropTypes.shape({ 22 | image: PropTypes.string, 23 | text: PropTypes.string, 24 | }) 25 | ), 26 | } 27 | 28 | export default FeatureGrid 29 | -------------------------------------------------------------------------------- /src/components/Layout.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Helmet from 'react-helmet' 3 | 4 | import Navbar from './Navbar' 5 | import './all.sass' 6 | 7 | const TemplateWrapper = ({ children }) => ( 8 |
9 | 10 | 11 |
{children}
12 |
13 | ) 14 | 15 | export default TemplateWrapper 16 | -------------------------------------------------------------------------------- /src/components/Navbar.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link, StaticQuery, graphql } from 'gatsby' 3 | import github from '../img/github-icon.svg' 4 | import logo from '../img/logo.svg' 5 | 6 | const Navbar = () => ( 7 | ( 21 | 55 | )} 56 | /> 57 | ) 58 | 59 | export default Navbar 60 | -------------------------------------------------------------------------------- /src/components/Pagination.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'gatsby' 3 | 4 | const Pagination = ({ pageContext, pathPrefix }) => { 5 | const { previousPagePath, nextPagePath } = pageContext 6 | 7 | return ( 8 | 26 | ) 27 | } 28 | 29 | export default Pagination 30 | -------------------------------------------------------------------------------- /src/components/PostList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { Link, graphql } from 'gatsby' 4 | 5 | export default class IndexPage extends React.Component { 6 | render() { 7 | const { posts, title } = this.props 8 | 9 | return ( 10 |
11 |
12 |
13 |

{title}

14 |
15 | {posts.map(({ node: post }) => ( 16 |
21 |

22 | 23 | {post.title} 24 | 25 | 26 | 27 | {post.date} - posted by{' '} 28 | 29 | {post.author.name} 30 | 31 | 32 |

33 |
34 | 43 |
44 | ))} 45 |
46 |
47 | ) 48 | } 49 | } 50 | 51 | IndexPage.propTypes = { 52 | posts: PropTypes.arrayOf(PropTypes.object), 53 | title: PropTypes.string, 54 | } 55 | 56 | export const pageQuery = graphql` 57 | fragment PostListFields on wordpress__POST { 58 | id 59 | title 60 | excerpt 61 | author { 62 | name 63 | slug 64 | avatar_urls { 65 | wordpress_48 66 | } 67 | } 68 | date(formatString: "MMMM DD, YYYY") 69 | slug 70 | } 71 | ` 72 | -------------------------------------------------------------------------------- /src/components/Pricing.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | 4 | const Pricing = ({ data }) => ( 5 |
6 | {data.map(price => ( 7 |
8 |
9 |

10 | {price.plan} 11 |

12 |

13 | ${price.price} 14 |

15 |

{price.description}

16 |
    17 | {price.items.map(item => ( 18 |
  • 19 | {item} 20 |
  • 21 | ))} 22 |
23 |
24 |
25 | ))} 26 |
27 | ) 28 | 29 | Pricing.propTypes = { 30 | data: PropTypes.arrayOf( 31 | PropTypes.shape({ 32 | plan: PropTypes.string, 33 | price: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 34 | description: PropTypes.string, 35 | items: PropTypes.array, 36 | }) 37 | ), 38 | } 39 | 40 | export default Pricing 41 | -------------------------------------------------------------------------------- /src/components/Testimonials.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { v4 } from 'uuid' 4 | 5 | const Testimonials = ({ testimonials }) => ( 6 |
7 | {testimonials.map(testimonial => ( 8 |
9 |
10 | {testimonial.quote} 11 |
12 | – {testimonial.author} 13 |
14 |
15 | ))} 16 |
17 | ) 18 | 19 | Testimonials.propTypes = { 20 | testimonials: PropTypes.arrayOf( 21 | PropTypes.shape({ 22 | quote: PropTypes.string, 23 | author: PropTypes.string, 24 | }) 25 | ), 26 | } 27 | 28 | export default Testimonials 29 | -------------------------------------------------------------------------------- /src/components/all.sass: -------------------------------------------------------------------------------- 1 | @import "~bulma/sass/utilities/initial-variables" 2 | 3 | // Config vars 4 | $kaldi-red: #FD461E 5 | $kaldi-red-invert: #fff 6 | 7 | $primary: $kaldi-red 8 | $primary-invert: $kaldi-red-invert 9 | 10 | .content .taglist 11 | list-style: none 12 | margin-bottom: 0 13 | margin-left: 0 14 | margin-right: 1.5rem 15 | margin-top: 1.5rem 16 | display: flex 17 | flex-wrap: wrap 18 | justify-content: left 19 | align-items: center 20 | li 21 | padding: 0 2rem 1rem 0 22 | margin-bottom: 1.5rem 23 | margin-top: 0 24 | 25 | .pagination .navbar 26 | justify-content: center 27 | 28 | // Helper Classes 29 | .full-width-image-container 30 | width: 100vw 31 | height: 400px 32 | position: relative 33 | left: 50% 34 | right: 50% 35 | margin: 5em -50vw 36 | background-size: cover 37 | background-position: bottom 38 | display: flex 39 | justify-content: center 40 | align-items: center 41 | 42 | .margin-top-0 43 | margin-top: 0 !important 44 | 45 | @import "~bulma" 46 | -------------------------------------------------------------------------------- /src/img/github-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |