├── .eslintignore ├── .gitignore ├── .env.example ├── static ├── css │ ├── custom.css │ └── nprogress.css └── js │ ├── nprogress.js │ └── jquery.min.js ├── screenshots └── medical-professional.png ├── routes.js ├── app.json ├── components ├── widgets │ └── Meta │ │ └── index.js └── views │ ├── page.js │ ├── about-us.js │ ├── faq.js │ ├── search.js │ ├── partials │ ├── footer.js │ └── header.js │ ├── contact.js │ ├── home.js │ └── blog.js ├── config └── index.js ├── .babelrc ├── server.js ├── LICENSE ├── pages ├── _document.js ├── faqs.js ├── generic.js ├── index.js ├── about-us.js ├── blog.js ├── search.js └── contact.js ├── .eslintrc ├── utils ├── helperFuncs.js └── request.js ├── package.json ├── README.md └── bucket.json /.eslintignore: -------------------------------------------------------------------------------- 1 | /.next 2 | /public/* 3 | /__tests__ 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /npm-debug.log 3 | /.next 4 | /coverage 5 | .env -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | COSMIC_BUCKET= 2 | COSMIC_READ_KEY= 3 | COSMIC_WRITE_KEY= 4 | PORT= -------------------------------------------------------------------------------- /static/css/custom.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Roboto,sans-serif; 3 | font-size: 15px; 4 | line-height: 2; 5 | color: #666; 6 | } -------------------------------------------------------------------------------- /screenshots/medical-professional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cosmicjs/react-website-boilerplate/HEAD/screenshots/medical-professional.png -------------------------------------------------------------------------------- /routes.js: -------------------------------------------------------------------------------- 1 | const nextRoutes = require('next-routes') 2 | const routes = module.exports = nextRoutes() 3 | 4 | routes.add('blog', '/blog/:slug?') 5 | routes.add('generic', '/:pagename') -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Next.js Website Boilerplate", 3 | "description": "A website boilerplate built using Next.js and Cosmic JS", 4 | "repository": "https://github.com/cosmicjs/nextjs-website-boilerplate", 5 | "logo": "https://cosmicjs.com/images/logo.svg", 6 | "keywords": ["react", "next.js", "website"] 7 | } 8 | -------------------------------------------------------------------------------- /components/widgets/Meta/index.js: -------------------------------------------------------------------------------- 1 | import NProgress from 'nprogress'; 2 | import Router from 'next/router'; 3 | 4 | Router.onRouteChangeStart = () => NProgress.start() 5 | Router.onRouteChangeComplete = () => NProgress.done() 6 | Router.onRouteChangeError = () => NProgress.done() 7 | 8 | export default (props) => ( 9 |
10 | {props.children} 11 |
12 | ) 13 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bucket: { 3 | slug: process.env.COSMIC_BUCKET || 'nextjs-medical-website', 4 | read_key: process.env.COSMIC_READ_KEY, 5 | write_key: process.env.COSMIC_WRITE_KEY 6 | }, 7 | env: { 8 | SENDGRID_FUNCTION_ENDPOINT: process.env.SENDGRID_FUNCTION_ENDPOINT || 'your-sendgrid-email-function-url' 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "development": { 4 | "presets": ["next/babel"], 5 | "plugins": [ 6 | ["module-resolver", { "root": ["./"] }], 7 | ["inline-dotenv"] 8 | ] 9 | }, 10 | "production": { 11 | "presets": ["next/babel"], 12 | "plugins": [ 13 | ["module-resolver", { "root": ["./"] }], 14 | ["inline-dotenv"] 15 | ] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /components/views/page.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | class Page extends React.Component { 3 | render() { 4 | const { page } = this.props; 5 | return ( 6 |
7 |
8 |

{page.title}

9 |
10 |
11 |
12 | ); 13 | } 14 | } 15 | 16 | export default Page; -------------------------------------------------------------------------------- /components/views/about-us.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | class AboutUs extends React.Component { 3 | render() { 4 | const { aboutUs } = this.props; 5 | return ( 6 |
7 |
8 |

{aboutUs.title}

9 |
10 |
11 |
12 | ); 13 | } 14 | } 15 | 16 | export default AboutUs; 17 | -------------------------------------------------------------------------------- /components/views/faq.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | class Faq extends React.Component { 3 | render() { 4 | const { faq } = this.props; 5 | return ( 6 |
7 |

{faq.title}

8 | { 9 | !!faq.faqs && faq.faqs.map((f, index) => 10 |
11 |

{f.title}

12 |

{f.value}

13 |
14 | ) 15 | } 16 |
17 | ); 18 | } 19 | } 20 | 21 | export default Faq; 22 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import next from 'next'; 3 | import compression from 'compression'; 4 | import routes from 'routes'; 5 | const port = parseInt(process.env.PORT, 10) || 3000 6 | const dev = process.env.NODE_ENV !== 'production' 7 | import bodyParser from 'body-parser'; 8 | const app = next({ dev }) 9 | const handle = routes.getRequestHandler(app) 10 | 11 | app.prepare() 12 | .then(() => { 13 | const server = express(); 14 | server.use(compression()); 15 | server.use(bodyParser.urlencoded({ extended: false })); 16 | server.use(bodyParser.json()); 17 | server.get('*', (req, res) => handle(req, res)) 18 | // server 19 | server.use(handle).listen(port, (err) => { 20 | if (err) throw err 21 | console.log(`> Ready on http://localhost:${port}`) 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /static/css/nprogress.css: -------------------------------------------------------------------------------- 1 | #nprogress{pointer-events:none;}#nprogress .bar{background:#29d;position:fixed;z-index:1031;top:0;left:0;width:100%;height:2px;}#nprogress .peg{display:block;position:absolute;right:0px;width:100px;height:100%;box-shadow:0 0 10px #29d,0 0 5px #29d;opacity:1.0;-webkit-transform:rotate(3deg) translate(0px,-4px);-ms-transform:rotate(3deg) translate(0px,-4px);transform:rotate(3deg) translate(0px,-4px);}#nprogress .spinner{display:block;position:fixed;z-index:1031;top:15px;right:15px;}#nprogress .spinner-icon{width:18px;height:18px;box-sizing:border-box;border:solid 2px transparent;border-top-color:#29d;border-left-color:#29d;border-radius:50%;-webkit-animation:nprogress-spinner 400ms linear infinite;animation:nprogress-spinner 400ms linear infinite;}.nprogress-custom-parent{overflow:hidden;position:relative;}.nprogress-custom-parent #nprogress .spinner,.nprogress-custom-parent #nprogress .bar{position:absolute;}@-webkit-keyframes nprogress-spinner{0%{-webkit-transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);}}@keyframes nprogress-spinner{0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}} -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Cosmic JS 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 | -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | import Document, { Head, Main, NextScript } from 'next/document'; 2 | 3 | export default class MyDocument extends Document { 4 | 5 | render () { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | {/* CSS Files */} 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | ) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "plugins": [ 4 | "react" 5 | ], 6 | "parserOptions": { 7 | "ecmaVersion": 6, 8 | "sourceType": "module", 9 | "ecmaFeatures": { 10 | "jsx": true 11 | } 12 | }, 13 | "env": { 14 | "browser": true, 15 | "amd": true, 16 | "es6": true, 17 | "node": true, 18 | "mocha": true 19 | }, 20 | "extends": [ 21 | "airbnb", 22 | "eslint:recommended", 23 | "plugin:import/errors", 24 | "plugin:import/warnings" 25 | ], 26 | "rules": { 27 | "quotes": [ 1, "single" ], 28 | "no-undef": 1, 29 | "no-extra-semi": 1, 30 | "no-console": 1, 31 | "no-unused-vars": 1, 32 | "no-trailing-spaces": [1, { "skipBlankLines": true }], 33 | "no-unreachable": 1, 34 | "react/jsx-uses-react": 1, 35 | "react/jsx-uses-vars": 1, 36 | "react/jsx-filename-extension": 0, 37 | "react/prop-types": 0, 38 | "import/no-unresolved": [0, {"commonjs": true, "amd": true}], 39 | "import/named": 1, 40 | "import/namespace": 1, 41 | "import/default": 1, 42 | "import/export": 1, 43 | "import/no-extraneous-dependencies": 0, 44 | "import/extensions": 0 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /utils/helperFuncs.js: -------------------------------------------------------------------------------- 1 | 2 | import { assign } from 'lodash'; 3 | 4 | export const mapGlobals = (globals) => { 5 | var response = {}; 6 | globals.map((global) => { 7 | switch(global.slug){ 8 | case 'contact-form': 9 | response.contact_form = global; 10 | break; 11 | case 'header': 12 | response.header = global; 13 | break; 14 | case 'nav': 15 | response.nav = global; 16 | break; 17 | case 'social': 18 | response.social = global; 19 | break; 20 | case 'contact-info': 21 | response.contact_info = global; 22 | break; 23 | case 'footer': 24 | response.footer = global; 25 | break; 26 | } 27 | }) 28 | return response; 29 | }; 30 | 31 | export const mapHome = (data) => { 32 | const home = {}; 33 | data.metafields.map((obj) => { 34 | if(obj.key == 'carousel' || obj.key == 'blurbs'){ 35 | home[obj.key] = obj.children 36 | } 37 | else 38 | home[obj.key] = obj; 39 | }); 40 | return home; 41 | } 42 | 43 | export const mapFaqs = (data) => { 44 | const faqs = {}; 45 | faqs.title = 'FAQs' 46 | data.metafields.map((obj) => { 47 | faqs[obj.key] = obj.children 48 | }); 49 | return faqs; 50 | } -------------------------------------------------------------------------------- /components/views/search.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from 'next/link'; 3 | class Search extends React.Component { 4 | render() { 5 | const { searchResult, searchField, handleChange } = this.props; 6 | return ( 7 |
8 |
9 |
10 |

Search

11 |
12 | 13 |
14 |
15 | { 16 | !!searchResult && searchResult.map((s, index) => 17 |
18 |

19 | {s.title} 20 |

21 |

22 | {s.teaser} 23 |

24 |
25 | Read more 26 |
27 |
28 | ) 29 | } 30 |
31 |
32 | ); 33 | } 34 | } 35 | 36 | export default Search; 37 | -------------------------------------------------------------------------------- /pages/faqs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Router from 'next/router'; 3 | 4 | import { mapGlobals, mapFaqs } from 'utils/helperFuncs'; 5 | import Head from 'next/head'; 6 | import Meta from 'components/widgets/Meta'; 7 | import Faq from 'components/views/faq' 8 | import Header from 'components/views/partials/header' 9 | import Footer from 'components/views/partials/footer' 10 | import Request from 'utils/request'; 11 | 12 | class FaqPage extends React.Component { 13 | 14 | static async getInitialProps({ req, query }) { 15 | const Response = await Request.getGlobals(); 16 | const faqResponse = await Request.getObject('faqs'); 17 | const faq = mapFaqs(faqResponse.object); 18 | const globals = mapGlobals(Response.objects); 19 | return { globals, faq }; 20 | } 21 | 22 | constructor(props){ 23 | super(props); 24 | this.state = { 25 | header: props.globals.header, 26 | contact_form: props.globals.contact_form, 27 | nav: props.globals.nav, 28 | social: props.globals.social, 29 | contactInfo: props.globals.contact_info.metadata, 30 | footer: props.globals.footer, 31 | faq: props.faq 32 | } 33 | } 34 | 35 | render() { 36 | return ( 37 | 38 | 39 | Medical Professional ~ Cosmic JS Next Js App 40 | 41 | 42 | 43 | 44 |
45 | 46 |