├── netlify.toml
├── .prettierrc
├── public
├── images
│ ├── 1.jpg
│ ├── 10.jpg
│ ├── 11.jpg
│ ├── 12.jpg
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── 4.jpg
│ ├── 5.jpg
│ ├── 6.jpg
│ ├── 7.jpg
│ ├── 8.jpg
│ ├── 9.jpg
│ ├── about.jpg
│ ├── dolar.png
│ ├── hero.png
│ ├── intro.jpg
│ ├── 10_thumb.jpg
│ ├── 11_thumb.jpg
│ ├── 12_thumb.jpg
│ ├── 1_thumb.jpg
│ ├── 2_thumb.jpg
│ ├── 3_thumb.jpg
│ ├── 4_thumb.jpg
│ ├── 5_thumb.jpg
│ ├── 6_thumb.jpg
│ ├── 7_thumb.jpg
│ ├── 8_thumb.jpg
│ ├── 9_thumb.jpg
│ ├── author.jpg
│ ├── avatar.png
│ ├── favicon.png
│ ├── feature1.png
│ ├── feature2.png
│ ├── feature3.png
│ ├── review1.jpg
│ ├── review2.jpg
│ ├── review3.jpg
│ ├── logo.svg
│ └── logo-alt.svg
└── js
│ └── plugins.js
├── src
├── sass
│ ├── imports
│ │ ├── _menus.scss
│ │ ├── _functions.scss
│ │ ├── _banner.scss
│ │ ├── _custom.scss
│ │ ├── _tables.scss
│ │ ├── _buttons.scss
│ │ ├── _structure.scss
│ │ ├── _palettes.scss
│ │ ├── _helpers.scss
│ │ ├── _variables.scss
│ │ ├── _forms.scss
│ │ ├── _icons.scss
│ │ ├── _posts.scss
│ │ ├── _footer.scss
│ │ ├── _reset.scss
│ │ ├── _general.scss
│ │ └── _header.scss
│ └── main.scss
├── utils
│ ├── attribute.js
│ ├── pathJoin.js
│ ├── markdownify.js
│ ├── getPageUrl.js
│ ├── classNames.js
│ ├── getData.js
│ ├── withPrefix.js
│ ├── index.js
│ ├── getPage.js
│ ├── link.js
│ └── htmlToReact.js
├── pages
│ ├── _app.js
│ ├── [[...slug]].js
│ └── _document.js
├── layouts
│ ├── index.js
│ ├── landing.js
│ ├── page.js
│ ├── post.js
│ └── blog.js
└── components
│ ├── CtaButtons.js
│ ├── ActionLink.js
│ ├── FooterNav.js
│ ├── BlogPostFooter.js
│ ├── FooterText.js
│ ├── SectionCta.js
│ ├── Action.js
│ ├── SectionHero.js
│ ├── index.js
│ ├── SectionContent.js
│ ├── SectionReviews.js
│ ├── FooterForm.js
│ ├── SectionFaq.js
│ ├── SectionPricing.js
│ ├── FormField.js
│ ├── SectionPosts.js
│ ├── SectionFeatures.js
│ ├── SectionContact.js
│ ├── Footer.js
│ ├── Layout.js
│ ├── Header.js
│ └── Icon.js
├── content
├── data
│ ├── authors
│ │ ├── john-doe.yaml
│ │ └── jane-doe.yaml
│ └── config.json
└── pages
│ ├── blog
│ ├── index.md
│ ├── design-team-collaborates.md
│ ├── design-azimuth.md
│ ├── azimuth-improvements.md
│ ├── customer-service-skills-that-every-employee-needs.md
│ ├── sales-as-service.md
│ ├── user-journey-mapping.md
│ ├── set-big-goals.md
│ ├── working-from-home.md
│ └── customer-loyalty.md
│ ├── terms-of-service.md
│ ├── privacy-policy.md
│ ├── contact.md
│ ├── signup.md
│ ├── features.md
│ ├── about.md
│ ├── pricing.md
│ ├── index.md
│ └── style-guide.md
├── MOCK_DATA.js
├── .eslintrc.json
├── next.config.js
├── README.md
├── package.json
├── .gitignore
├── sourcebit.js
└── LICENSE.md
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "out"
3 | command = "npm run build"
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | tabWidth: 4
2 | singleQuote: true
3 | trailingComma: none
4 | printWidth: 160
5 |
--------------------------------------------------------------------------------
/public/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/1.jpg
--------------------------------------------------------------------------------
/public/images/10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/10.jpg
--------------------------------------------------------------------------------
/public/images/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/11.jpg
--------------------------------------------------------------------------------
/public/images/12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/12.jpg
--------------------------------------------------------------------------------
/public/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/2.jpg
--------------------------------------------------------------------------------
/public/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/3.jpg
--------------------------------------------------------------------------------
/public/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/4.jpg
--------------------------------------------------------------------------------
/public/images/5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/5.jpg
--------------------------------------------------------------------------------
/public/images/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/6.jpg
--------------------------------------------------------------------------------
/public/images/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/7.jpg
--------------------------------------------------------------------------------
/public/images/8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/8.jpg
--------------------------------------------------------------------------------
/public/images/9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/9.jpg
--------------------------------------------------------------------------------
/public/images/about.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/about.jpg
--------------------------------------------------------------------------------
/public/images/dolar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/dolar.png
--------------------------------------------------------------------------------
/public/images/hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/hero.png
--------------------------------------------------------------------------------
/public/images/intro.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/intro.jpg
--------------------------------------------------------------------------------
/public/images/10_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/10_thumb.jpg
--------------------------------------------------------------------------------
/public/images/11_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/11_thumb.jpg
--------------------------------------------------------------------------------
/public/images/12_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/12_thumb.jpg
--------------------------------------------------------------------------------
/public/images/1_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/1_thumb.jpg
--------------------------------------------------------------------------------
/public/images/2_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/2_thumb.jpg
--------------------------------------------------------------------------------
/public/images/3_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/3_thumb.jpg
--------------------------------------------------------------------------------
/public/images/4_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/4_thumb.jpg
--------------------------------------------------------------------------------
/public/images/5_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/5_thumb.jpg
--------------------------------------------------------------------------------
/public/images/6_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/6_thumb.jpg
--------------------------------------------------------------------------------
/public/images/7_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/7_thumb.jpg
--------------------------------------------------------------------------------
/public/images/8_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/8_thumb.jpg
--------------------------------------------------------------------------------
/public/images/9_thumb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/9_thumb.jpg
--------------------------------------------------------------------------------
/public/images/author.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/author.jpg
--------------------------------------------------------------------------------
/public/images/avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/avatar.png
--------------------------------------------------------------------------------
/public/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/favicon.png
--------------------------------------------------------------------------------
/public/images/feature1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/feature1.png
--------------------------------------------------------------------------------
/public/images/feature2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/feature2.png
--------------------------------------------------------------------------------
/public/images/feature3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/feature3.png
--------------------------------------------------------------------------------
/public/images/review1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/review1.jpg
--------------------------------------------------------------------------------
/public/images/review2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/review2.jpg
--------------------------------------------------------------------------------
/public/images/review3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Platzi-MasterJam/dinamita/HEAD/public/images/review3.jpg
--------------------------------------------------------------------------------
/src/sass/imports/_menus.scss:
--------------------------------------------------------------------------------
1 | .menu {
2 | list-style: none;
3 | margin: 0;
4 | padding: 0;
5 | }
6 |
7 | .menu-item {
8 | font-size: 0.88889rem;
9 | line-height: 1.5;
10 | }
11 |
--------------------------------------------------------------------------------
/src/sass/imports/_functions.scss:
--------------------------------------------------------------------------------
1 | // Gets a value from a map.
2 | @function map-deep-get($map, $keys...) {
3 | @each $key in $keys {
4 | $map: map-get($map, $key);
5 | }
6 | @return $map;
7 | }
--------------------------------------------------------------------------------
/src/utils/attribute.js:
--------------------------------------------------------------------------------
1 | export default function attribute(name, value, condition) {
2 | if (typeof condition === 'undefined') {
3 | condition = true;
4 | }
5 | return condition ? { [name]: value } : null;
6 | }
7 |
--------------------------------------------------------------------------------
/src/pages/_app.js:
--------------------------------------------------------------------------------
1 | import '../sass/main.scss';
2 |
3 | // This default export is required in a new `pages/_app.js` file.
4 | export default function MyApp({ Component, pageProps }) {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/src/sass/imports/_banner.scss:
--------------------------------------------------------------------------------
1 | body.has-theme-bar {
2 | #page {
3 | top: 60px;
4 |
5 | .site-header {
6 | @media only screen and (min-width: 801px) {
7 | top: 60px;
8 | }
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/pathJoin.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | export default function pathJoin(...pathParts) {
4 | const result = _.compact(pathParts)
5 | .join('/')
6 | .replace(/\/{2,}/g, '/');
7 | return result || '.';
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/markdownify.js:
--------------------------------------------------------------------------------
1 | import marked from 'marked';
2 | import htmlToReact from './htmlToReact';
3 |
4 | export default function markdownify(markdown) {
5 | if (!markdown) {
6 | return null;
7 | }
8 | return htmlToReact(marked(markdown));
9 | }
10 |
--------------------------------------------------------------------------------
/src/layouts/index.js:
--------------------------------------------------------------------------------
1 | import landing from './landing';
2 | import page from './page';
3 | import blog from './blog';
4 | import post from './post';
5 |
6 | export { landing, page, blog, post };
7 |
8 | export default {
9 | landing,
10 | page,
11 | blog,
12 | post
13 | };
14 |
--------------------------------------------------------------------------------
/src/utils/getPageUrl.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | import withPrefix from './withPrefix';
3 |
4 | export default function getPageUrl(post, { withPrefix: addPrefix = false } = {}) {
5 | const urlPath = _.get(post, '__metadata.urlPath');
6 | return addPrefix ? withPrefix(urlPath) : urlPath;
7 | }
8 |
--------------------------------------------------------------------------------
/content/data/authors/john-doe.yaml:
--------------------------------------------------------------------------------
1 | first_name: John
2 | last_name: Doe
3 | bio: >-
4 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
5 | incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
6 | nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
7 | photo: images/review1.jpg
8 |
--------------------------------------------------------------------------------
/src/utils/classNames.js:
--------------------------------------------------------------------------------
1 | import classnames from 'classnames';
2 |
3 | // A simple wrapper around classNames to return null, if no classes were generated
4 | // Otherwise, original classNames returns empty string which causes class="" to be generated
5 | export default function classNames(...args) {
6 | return classnames.call(this, ...args) || null;
7 | }
8 |
--------------------------------------------------------------------------------
/MOCK_DATA.js:
--------------------------------------------------------------------------------
1 | export const json = [
2 | {
3 | "material":1,
4 | "valor":8
5 | },
6 | {
7 | "material":2,
8 | "valor":50
9 | },
10 | {
11 | "material":3,
12 | "valor":0.6
13 | },
14 | {
15 | "material":4,
16 | "valor":9
17 | }
18 | ]
--------------------------------------------------------------------------------
/content/data/authors/jane-doe.yaml:
--------------------------------------------------------------------------------
1 | first_name: Jane
2 | last_name: Doe
3 | bio: >-
4 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
5 | incididunt ut labore et dolore magna aliqua. Risus nullam eget felis eget nunc
6 | lobortis. Sodales ut etiam sit amet nisl purus in mollis nunc. Enim ut tellus
7 | elementum sagittis vitae.
8 | photo: images/review2.jpg
9 |
--------------------------------------------------------------------------------
/src/components/CtaButtons.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import Action from './Action';
5 |
6 | export default class CtaButtons extends React.Component {
7 | render() {
8 | const actions = _.get(this.props, 'actions');
9 | return _.map(actions, (action, actionIdx) => );
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/sass/imports/_custom.scss:
--------------------------------------------------------------------------------
1 | .featureCustom{
2 | &_space{
3 | display: flex!important;
4 | &-img{
5 | width: 50%;
6 | }
7 | &-value{
8 | margin: auto 0px;
9 | font-size: 140px;
10 | color: #2c2f3b;
11 | font-weight: bolder;
12 | & p {
13 | margin: auto 0px;
14 | }
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/src/utils/getData.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | export default function getData(props, dataPath) {
4 | dataPath = _.trim(dataPath, '/');
5 | if (_.startsWith(dataPath, 'content/data/')) {
6 | dataPath = dataPath.replace('content/data/', '');
7 | }
8 | // remove extension
9 | dataPath = dataPath.replace(/\.\w+$/, '');
10 | const path = dataPath.split('/');
11 | return _.get(props, path);
12 | }
13 |
--------------------------------------------------------------------------------
/src/utils/withPrefix.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 | const pathPrefix = require('../../content/data/config.json').path_prefix;
3 |
4 | export default function withPrefix(url) {
5 | if (!url) {
6 | return url;
7 | }
8 |
9 | if (_.startsWith(url, '#') || _.startsWith(url, 'http://') || _.startsWith(url, 'https://')) {
10 | return url;
11 | }
12 | const basePath = _.trim(pathPrefix, '/');
13 | return '/' + _.compact([basePath, _.trimStart(url, '/')]).join('/');
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | export { default as attribute } from './attribute';
2 | export { default as classNames } from './classNames';
3 | export { default as getPage } from './getPage';
4 | export { default as getData } from './getData';
5 | export { default as htmlToReact } from './htmlToReact';
6 | export { default as getPageUrl } from './getPageUrl';
7 | export { default as pathJoin } from './pathJoin';
8 | export { default as markdownify } from './markdownify';
9 | export { default as withPrefix } from './withPrefix';
10 | export { default as Link } from './link';
11 |
--------------------------------------------------------------------------------
/src/sass/main.scss:
--------------------------------------------------------------------------------
1 | @import "imports/functions";
2 | @import "imports/variables";
3 | @import "imports/reset";
4 | @import "imports/general";
5 | @import "imports/helpers";
6 | @import "imports/tables";
7 | @import "imports/forms";
8 | @import "imports/buttons";
9 | @import "imports/icons";
10 | @import "imports/menus";
11 | @import "imports/structure";
12 | @import "imports/header";
13 | @import "imports/posts";
14 | @import "imports/sections";
15 | @import "imports/footer";
16 | @import "imports/palettes";
17 | @import "imports/banner";
18 | @import "imports/custom"
19 |
--------------------------------------------------------------------------------
/src/utils/getPage.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 |
3 | /**
4 | * Get the page at the provided `urlPath`.
5 | *
6 | * @param {Array} pages Array of page objects. All pages must have '__metadata.urlPath' field.
7 | * @param {string} urlPath The url path to find the page by
8 | * @return {Object}
9 | */
10 | export default function getPage(pages, urlPath) {
11 | urlPath = _.trim(urlPath, '/');
12 | return _.find(pages, (page) => {
13 | const pageUrlPath = _.trim(_.get(page, '__metadata.urlPath'), '/');
14 | return urlPath === pageUrlPath;
15 | });
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/link.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import NextLink from 'next/link';
3 |
4 | export default function Link({ children, href, ...other }) {
5 | // Pass Any internal link to Next.js Link, for anything else, use tag
6 | const internal = /^\/(?!\/)/.test(href);
7 | if (internal) {
8 | return (
9 |
10 | {children}
11 |
12 | );
13 | }
14 |
15 | return (
16 |
17 | {children}
18 |
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node" : true,
4 | "es6": true
5 | },
6 | "extends": "eslint:recommended",
7 | "parserOptions": {
8 | "ecmaVersion": 2018
9 | },
10 | "rules": {
11 | "indent": [
12 | "error",
13 | 4
14 | ],
15 | "linebreak-style": [
16 | "error",
17 | "unix"
18 | ],
19 | "quotes": [
20 | "error",
21 | "single"
22 | ],
23 | "semi": [
24 | "error",
25 | "always"
26 | ],
27 | "no-unused-vars": 0
28 | }
29 | }
--------------------------------------------------------------------------------
/next.config.js:
--------------------------------------------------------------------------------
1 | const sourcebit = require('sourcebit');
2 |
3 | const sourcebitConfig = require('./sourcebit.js');
4 |
5 | sourcebit.fetch(sourcebitConfig);
6 |
7 | module.exports = {
8 | trailingSlash: true,
9 | devIndicators: {
10 | autoPrerender: false
11 | },
12 | webpack: (config, { webpack }) => {
13 | // Tell webpack to ignore watching content files in the content folder.
14 | // Otherwise webpack receompiles the app and refreshes the whole page.
15 | // Instead, the src/pages/[...slug].js uses the "withRemoteDataUpdates"
16 | // function to update the content on the page without refreshing the
17 | // whole page
18 | config.plugins.push(new webpack.WatchIgnorePlugin([[/\/content\//]]));
19 | return config;
20 | }
21 | };
22 |
--------------------------------------------------------------------------------
/content/pages/blog/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Blog
3 | seo:
4 | title: Blog
5 | description: This is the blog page
6 | extra:
7 | - name: 'og:type'
8 | value: website
9 | keyName: property
10 | - name: 'og:title'
11 | value: Blog
12 | keyName: property
13 | - name: 'og:description'
14 | value: This is the blog page
15 | keyName: property
16 | - name: 'og:image'
17 | value: images/1.jpg
18 | keyName: property
19 | relativeUrl: true
20 | - name: 'twitter:card'
21 | value: summary_large_image
22 | - name: 'twitter:title'
23 | value: Blog
24 | - name: 'twitter:description'
25 | value: This is the blog page
26 | - name: 'twitter:image'
27 | value: images/1.jpg
28 | relativeUrl: true
29 | layout: blog
30 | ---
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dinamita 💥💥
2 | Project About environment for Platzi MasterJam
3 |
4 |
5 | ## About
6 |
7 | The app is the best for collecting waste in big cities. You as a citizen can earn money saving the world.
8 |
9 | ## How does it work?
10 |
11 | We have people for each city, who will pick up waste or recyclables for you if you need to help with this. You just need to come to our page and request a service.
12 | We pay you for the items. We have warehouses and to make the best recycling
13 |
14 |
15 | ## How run this app
16 |
17 | ### Local Enviroment
18 | 1. execute npm install
19 | 2. writting down npm run dev
20 |
21 | If you want to get online access go to:
22 | https://e-collect.netlify.app/
23 | ## Stack's project in Frontend
24 | - Jamstack
25 | - Git
26 | - SASS
27 | - Next.js
28 | - netlify
29 | ## Stack's project in Backend
30 | - Node.js
31 | - Express.js
32 | - AWS
33 | - PostgreSQL
34 | - BABEL
35 |
--------------------------------------------------------------------------------
/src/components/ActionLink.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Link, withPrefix } from '../utils';
5 |
6 | export default class ActionLink extends React.Component {
7 | render() {
8 | const action = _.get(this.props, 'action');
9 | const url = _.get(action, 'url');
10 | const label = _.get(action, 'label', null);
11 | const newWindow = _.get(action, 'new_window');
12 | const noFollow = _.get(action, 'no_follow');
13 | const attrs = {};
14 | if (newWindow) {
15 | attrs.target = '_blank';
16 | }
17 | if (newWindow || noFollow) {
18 | attrs.rel = [(newWindow ? 'noopener' : '') + (noFollow ? 'nofollow' : '')].join(' ');
19 | }
20 |
21 | return (
22 |
23 | {label}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/sass/imports/_tables.scss:
--------------------------------------------------------------------------------
1 | table {
2 | border-bottom: 1px solid $gray-200;
3 | border-collapse: collapse;
4 | border-spacing: 0;
5 | line-height: 1.5;
6 | margin: 0;
7 | max-width: 100%;
8 | text-align: left;
9 | width: 100%;
10 | }
11 |
12 | caption {
13 | color: $gray-500;
14 | font-size: 0.83333em;
15 | font-style: normal;
16 | margin-bottom: 1em;
17 | text-align: left;
18 | }
19 |
20 | th,
21 | td {
22 | border-top: 1px solid $gray-200;
23 | padding: 0.5em 5px;
24 | }
25 |
26 | th {
27 | color: $gray-700;
28 | font-weight: bold;
29 |
30 | .font-fira-sans & {
31 | font-weight: 600;
32 | }
33 | }
34 |
35 | :not(.responsive-table) > table {
36 | margin: 1.66667em 0;
37 |
38 | &:first-child {
39 | margin-top: 0;
40 | }
41 | }
42 |
43 | .responsive-table {
44 | display: block;
45 | margin: 1.66667em 0;
46 | overflow-x: auto;
47 | width: 100%;
48 |
49 | &:first-child {
50 | margin-top: 0;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/sass/imports/_buttons.scss:
--------------------------------------------------------------------------------
1 | .button {
2 | -ms-flex-align: center;
3 | align-items: center;
4 | background: $color-primary;
5 | border: 2px solid $color-primary;
6 | border-radius: $border-radius;
7 | box-sizing: border-box;
8 | color: #fff;
9 | cursor: pointer;
10 | display: -ms-inline-flexbox;
11 | display: inline-flex;
12 | font-size: 0.88889em;
13 | font-weight: bold;
14 | -ms-flex-pack: center;
15 | justify-content: center;
16 | line-height: 1.5;
17 | padding: 0.5em 1.875em;
18 | text-decoration: none;
19 | -webkit-transition: opacity .15s ease-in-out;
20 | transition: opacity .15s ease-in-out;
21 |
22 | .font-fira-sans & {
23 | font-weight: 600;
24 | }
25 |
26 | &:hover,
27 | &:focus,
28 | &:active {
29 | color: #fff;
30 | opacity: 0.8;
31 | outline: 0;
32 | }
33 |
34 | &.large {
35 | padding: 0.625em 2.5em;
36 | }
37 |
38 | &.secondary {
39 | background: transparent;
40 | color: $color-primary;
41 | }
42 | }
--------------------------------------------------------------------------------
/src/components/FooterNav.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import Action from './Action';
5 |
6 | export default class FooterNav extends React.Component {
7 | render() {
8 | const section = _.get(this.props, 'section');
9 | const title = _.get(section, 'title');
10 | const navLinks = _.get(section, 'nav_links');
11 |
12 | return (
13 |
14 | {title && {title} }
15 | {navLinks && (
16 |
17 | {_.map(navLinks, (action, actionIdx) => (
18 |
19 |
20 |
21 | ))}
22 |
23 | )}
24 |
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "azimuth-nextjs",
3 | "description": "A Stackbit Azimuth theme built with Next.js",
4 | "version": "0.1.0",
5 | "license": "MIT",
6 | "scripts": {
7 | "dev": "next dev",
8 | "develop": "next dev",
9 | "fetch": "sourcebit fetch",
10 | "build": "next build && next export",
11 | "start": "next start"
12 | },
13 | "dependencies": {
14 | "babel-runtime": "^6.26.0",
15 | "classnames": "^2.2.6",
16 | "lodash": "^4.17.21",
17 | "marked": "^2.0.0",
18 | "moment": "^2.29.1",
19 | "moment-strftime": "^0.5.0",
20 | "next": "^10.0.7",
21 | "node-sass": "^5.0.0",
22 | "react": "17.0.1",
23 | "react-dom": "17.0.1",
24 | "react-helmet": "^6.1.0",
25 | "react-html-parser": "^2.0.2",
26 | "react-script-tag": "^1.1.2",
27 | "sourcebit": "^0.11.0",
28 | "sourcebit-source-filesystem": "^0.1.3",
29 | "sourcebit-target-next": "^0.6.2"
30 | },
31 | "devDependencies": {
32 | "prettier": "^2.2.1"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/sass/imports/_structure.scss:
--------------------------------------------------------------------------------
1 | .site {
2 | display: -ms-flexbox;
3 | display: flex;
4 | -ms-flex-direction: column;
5 | flex-direction: column;
6 | min-height: 100vh;
7 | position: relative;
8 | }
9 |
10 | .site-content {
11 | box-sizing: border-box;
12 | -ms-flex-positive: 1;
13 | flex-grow: 1;
14 | width: 100%;
15 | }
16 |
17 | .outer {
18 | padding: 3.33333em $container-padding 2.5em;
19 | }
20 |
21 | @media only screen and (min-width: 601px) {
22 | .outer {
23 | padding-bottom: 3.33333em;
24 | padding-top: 4.16667em;
25 | }
26 | }
27 |
28 | .inner {
29 | margin-left: auto;
30 | margin-right: auto;
31 | max-width: $container;
32 | }
33 |
34 | .inner-large {
35 | margin-left: auto;
36 | margin-right: auto;
37 | max-width: $container-lg;
38 | }
39 |
40 | .inner-medium {
41 | margin-left: auto;
42 | margin-right: auto;
43 | max-width: $container-md;
44 | }
45 |
46 | .inner-small {
47 | margin-left: auto;
48 | margin-right: auto;
49 | max-width: $container-sm;
50 | }
--------------------------------------------------------------------------------
/src/components/BlogPostFooter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import moment from 'moment-strftime';
4 |
5 | import { getData } from '../utils';
6 |
7 | export default class BlogPostFooter extends React.Component {
8 | render() {
9 | const post = _.get(this.props, 'post');
10 | const dateType = _.get(this.props, 'dateType');
11 | const data = _.get(this.props, 'data');
12 | const date = _.get(post, 'date');
13 | const dateTimeAttr = moment(date).strftime('%Y-%m-%d %H:%M');
14 | const formattedDate = dateType === 'short' ? moment(date).strftime('%B %d, %Y') : moment(date).strftime('%A, %B %e, %Y');
15 | const postAuthorRef = _.get(post, 'author');
16 | const author = postAuthorRef ? getData(data, postAuthorRef) : null;
17 | const authorName = author ? _.trim(`${author.first_name} ${author.last_name}`) : null;
18 |
19 | return (
20 |
21 |
22 | {formattedDate}
23 |
24 | {authorName && `, by ${authorName}`}
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/[[...slug]].js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import { sourcebitDataClient } from 'sourcebit-target-next';
4 | import { withRemoteDataUpdates } from 'sourcebit-target-next/with-remote-data-updates';
5 |
6 | import pageLayouts from '../layouts';
7 |
8 | class Page extends React.Component {
9 | render() {
10 | const modelName = _.get(this.props, 'page.__metadata.modelName');
11 | const PageLayout = pageLayouts[modelName];
12 | if (!PageLayout) {
13 | throw new Error(`no page layout matching the page model: ${modelName}`);
14 | }
15 | return ;
16 | }
17 | }
18 |
19 | export async function getStaticPaths() {
20 | console.log('Page [...slug].js getStaticPaths');
21 | const paths = await sourcebitDataClient.getStaticPaths();
22 | return { paths, fallback: false };
23 | }
24 |
25 | export async function getStaticProps({ params }) {
26 | console.log('Page [...slug].js getStaticProps, params: ', params);
27 | const pagePath = '/' + (params.slug ? params.slug.join('/') : '');
28 | const props = await sourcebitDataClient.getStaticPropsForPageAtPath(pagePath);
29 | return { props };
30 | }
31 |
32 | export default withRemoteDataUpdates(Page);
33 |
--------------------------------------------------------------------------------
/src/components/FooterText.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Link, withPrefix, markdownify } from '../utils';
5 |
6 | export default class FooterText extends React.Component {
7 | render() {
8 | const section = _.get(this.props, 'section');
9 | const image = _.get(section, 'image');
10 | const imageUrl = _.get(section, 'image_url');
11 | const imageAlt = _.get(section, 'image_alt');
12 | const title = _.get(section, 'title');
13 | const content = _.get(section, 'content');
14 |
15 | return (
16 |
17 | {image &&
18 | (imageUrl ? (
19 |
20 |
21 |
22 | ) : (
23 |
24 |
25 |
26 | ))}
27 | {title && {title} }
28 | {markdownify(content)}
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/sass/imports/_palettes.scss:
--------------------------------------------------------------------------------
1 | // Color palettes
2 | @each $palette in map-keys($theme-palettes) {
3 | $palette-suffix: "#{$palette}";
4 | $color-primary: map-deep-get($theme-palettes, $palette, "primary");
5 | $color-secondary: map-deep-get($theme-palettes, $palette, "secondary");
6 |
7 | .palette-#{$palette-suffix} {
8 | a:not(.button) {
9 | color: $color-primary;
10 |
11 | &:hover {
12 | color: $gray-600;
13 | }
14 | }
15 |
16 | blockquote,
17 | .underline:after,
18 | .card.highlight {
19 | border-color: $color-primary;
20 | }
21 |
22 | .button {
23 | background: $color-primary;
24 | border-color: $color-primary;
25 |
26 | &.secondary {
27 | background: transparent;
28 | color: $color-primary;
29 | }
30 | }
31 |
32 | .icon-plus {
33 | background: $color-primary;
34 | }
35 |
36 | .review-text {
37 | &:before {
38 | color: $color-primary;
39 | }
40 | }
41 |
42 | .bg-accent {
43 | background: $color-primary;
44 | background: -webkit-gradient(linear, left top, right top, from($color-primary), to($color-secondary));
45 | background: linear-gradient(to right,$color-primary, $color-secondary);
46 |
47 | .button {
48 | color: $color-primary;
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/components/SectionCta.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { htmlToReact } from '../utils';
5 | import CtaButtons from './CtaButtons';
6 |
7 | export default class SectionCta extends React.Component {
8 | render() {
9 | const section = _.get(this.props, 'section');
10 | const sectionId = _.get(section, 'section_id');
11 | const title = _.get(section, 'title');
12 | const subtitle = _.get(section, 'subtitle');
13 | const actions = _.get(section, 'actions');
14 |
15 | return (
16 |
17 |
18 |
19 |
20 | {title &&
{title} }
21 | {subtitle &&
{htmlToReact(subtitle)}
}
22 |
23 | {actions && (
24 |
25 |
26 |
27 | )}
28 |
29 |
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/layouts/landing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import components, { Layout } from '../components/index';
5 | import { getPageUrl } from '../utils';
6 |
7 | export default class Landing extends React.Component {
8 | render() {
9 | const config = _.get(this.props, 'data.config');
10 | const page = _.get(this.props, 'page');
11 | const data = _.get(this.props, 'data');
12 | const posts = _.get(this.props, 'posts');
13 | const sections = _.get(page, 'sections');
14 | const pageUrl = getPageUrl(page);
15 |
16 | return (
17 |
18 | {_.map(sections, (section, index) => {
19 | const sectionType = _.get(section, 'type');
20 | const component = _.upperFirst(_.camelCase(sectionType));
21 | if (!component) {
22 | throw new Error(`page section does not have the 'type' property, page: ${pageUrl}`);
23 | }
24 | const Component = components[component];
25 | if (!Component) {
26 | throw new Error(`no component matching the page section's type: ${sectionType}`);
27 | }
28 | return ;
29 | })}
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/components/Action.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Link, withPrefix, classNames } from '../utils';
5 | import Icon from './Icon';
6 |
7 | export default class Action extends React.Component {
8 | render() {
9 | const action = _.get(this.props, 'action');
10 | const url = _.get(action, 'url');
11 | const label = _.get(action, 'label');
12 | const actionStyle = _.get(action, 'style', 'link');
13 | const hasIcon = _.get(action, 'has_icon');
14 | const actionIcon = _.get(action, 'icon', 'arrow-left');
15 | const actionIconPos = _.get(action, 'icon_position', 'left');
16 | const newWindow = _.get(action, 'new_window');
17 | const noFollow = _.get(action, 'no_follow');
18 | const attrs = {};
19 | if (newWindow) {
20 | attrs.target = '_blank';
21 | }
22 | if (newWindow || noFollow) {
23 | attrs.rel = [(newWindow ? 'noopener' : '') + (noFollow ? 'nofollow' : '')].join(' ');
24 | }
25 |
26 | return (
27 |
36 | {hasIcon && }
37 | {label}
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/utils/htmlToReact.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactHtmlParser, { convertNodeToElement } from 'react-html-parser';
3 | import ScriptTag from 'react-script-tag';
4 | import Link from './link';
5 | import _ from 'lodash';
6 |
7 | const convertChildren = (children, index) => _.map(children, (childNode) => convertNodeToElement(childNode, index, _.noop()));
8 |
9 | export default function htmlToReact(html) {
10 | if (!html) {
11 | return null;
12 | }
13 | return ReactHtmlParser(html, {
14 | transform: (node, index) => {
15 | if (node.type === 'script') {
16 | if (!_.isEmpty(node.children)) {
17 | return (
18 |
19 | {convertChildren(node.children, index)}
20 |
21 | );
22 | } else {
23 | return ;
24 | }
25 | } else if (node.type === 'tag' && node.name === 'a') {
26 | const href = node.attribs.href;
27 | const props = _.omit(node.attribs, 'href');
28 | // use Link only if there are no custom attributes like style, class, and what's not that might break react
29 | if (_.isEmpty(props)) {
30 | return (
31 |
32 | {convertChildren(node.children, index)}
33 |
34 | );
35 | }
36 | }
37 | }
38 | });
39 | }
40 |
--------------------------------------------------------------------------------
/src/sass/imports/_helpers.scss:
--------------------------------------------------------------------------------
1 | // Text for screen readers
2 | .screen-reader-text {
3 | clip: rect(1px, 1px, 1px, 1px);
4 | clip-path: polygon(0px 0px, 0px 0px, 0px 0px, 0px 0px);
5 | height: 1px;
6 | overflow: hidden;
7 | position: absolute !important;
8 | width: 1px;
9 | word-wrap: normal !important;
10 | }
11 |
12 | // Flex order
13 | .order-first {
14 | order: -1;
15 | }
16 |
17 | // Heading decorations
18 | .underline {
19 | position: relative;
20 |
21 | &:after {
22 | border-left: 1.5em solid $color-primary;
23 | display: block;
24 | content: "";
25 | height: 2px;
26 | margin-top: 0.5em;
27 | }
28 | }
29 |
30 | // Responsive videos wrapper
31 | .js-reframe {
32 | margin: 0 0 1.66667em;
33 | }
34 |
35 | // Grid
36 | .grid {
37 | display: -ms-flexbox;
38 | display: flex;
39 | -ms-flex-wrap: wrap;
40 | flex-wrap: wrap;
41 | margin-left: -$grid-gap / 2;
42 | margin-right: -$grid-gap / 2;
43 | }
44 |
45 | .cell {
46 | box-sizing: border-box;
47 | padding-left: $grid-gap / 2;
48 | padding-right: $grid-gap / 2;
49 | position: relative;
50 | width: 100%;
51 | }
52 |
53 | @media only screen and (max-width: 750px) {
54 | .grid {
55 | margin-left: -$container-padding / 2;
56 | margin-right: -$container-padding / 2;
57 | }
58 |
59 | .cell {
60 | padding-left: $container-padding / 2;
61 | padding-right: $container-padding / 2;
62 | }
63 | }
64 |
65 | // Card
66 | .card {
67 | background: #fff;
68 | border: 1px solid $gray-200;
69 | border-radius: $border-radius;
70 | box-shadow: $box-shadow;
71 | box-sizing: border-box;
72 |
73 | &.highlight {
74 | border-color: $color-primary;
75 | border-width: 2px;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/layouts/page.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Layout } from '../components/index';
5 | import { htmlToReact, withPrefix, markdownify } from '../utils';
6 |
7 | export default class Page extends React.Component {
8 | render() {
9 | const page = _.get(this.props, 'page');
10 | const data = _.get(this.props, 'data');
11 | const config = _.get(data, 'config');
12 | const title = _.get(page, 'title');
13 | const subtitle = _.get(page, 'subtitle');
14 | const image = _.get(page, 'image');
15 | const imageAlt = _.get(page, 'image_alt');
16 | const markdownContent = _.get(page, 'markdown_content');
17 |
18 | return (
19 |
20 |
21 |
22 |
23 |
24 | {title}
25 | {subtitle && {htmlToReact(subtitle)}
}
26 |
27 | {image && (
28 |
29 |
30 |
31 | )}
32 | {markdownContent && {markdownify(markdownContent)}
}
33 |
34 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/SectionHero.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { withPrefix, markdownify } from '../utils';
5 | import CtaButtons from './CtaButtons';
6 |
7 | export default class SectionHero extends React.Component {
8 | render() {
9 | const section = _.get(this.props, 'section');
10 | const sectionId = _.get(section, 'section_id');
11 | const image = _.get(section, 'image');
12 | const imageAlt = _.get(section, 'image_alt');
13 | const title = _.get(section, 'title');
14 | const content = _.get(section, 'content');
15 | const actions = _.get(section, 'actions');
16 |
17 | return (
18 |
19 |
20 |
21 | {image && (
22 |
23 |
24 |
25 | )}
26 |
27 | {title &&
{title} }
28 | {content &&
{markdownify(content)}
}
29 | {actions && (
30 |
31 |
32 |
33 | )}
34 |
35 |
36 |
37 |
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/sass/imports/_variables.scss:
--------------------------------------------------------------------------------
1 | // Fonts
2 | $font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace !default;
3 |
4 | // Colors
5 | $color-primary: #0072ff !default;
6 | $color-secondary: #00c6ff !default;
7 |
8 | $gray-100: #f7f9fb !default;
9 | $gray-200: #ebecf0 !default;
10 | $gray-300: #c5c8d4 !default;
11 | $gray-400: #999fb3 !default;
12 | $gray-500: #7b839e !default;
13 | $gray-600: #4c5267 !default;
14 | $gray-700: #2c2f3b !default;
15 |
16 | $yellow-pale: #fcffc4 !default;
17 |
18 | // Border radius
19 | $border-radius: 3px;
20 |
21 | // Box shadow
22 | $box-shadow: 0 3px 10px 0 rgba($gray-600,.1) !default;
23 | $box-shadow-white-bg: 0 3px 10px 0 rgba($gray-600,.15) !default;
24 | $box-shadow-sm: 0 1px 4px 0 rgba($gray-600,.1) !default;
25 |
26 | // Container max width
27 | $container: 1140px !default;
28 | $container-sm: 555px !default;
29 | $container-md: 750px !default;
30 | $container-lg: 945px !default;
31 |
32 | // Container padding
33 | $container-padding: 4vw !default;
34 |
35 | // Grid gap
36 | $grid-gap: 1.66667rem !default;
37 |
38 | // Theme variations
39 | $theme-fonts: (
40 | nunito-sans: ("Nunito Sans", sans-serif),
41 | fira-sans: ("Fira Sans", sans-serif),
42 | system-sans: (-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif)
43 | );
44 |
45 | $theme-palettes: (
46 | cyan: (
47 | primary: #2cb1bc,
48 | secondary: #54d1db
49 | ),
50 | green: (
51 | primary: #37b05d,
52 | secondary: #57cb85
53 | ),
54 | orange: (
55 | primary: #fe8c00,
56 | secondary: #f83600
57 | ),
58 | purple: (
59 | primary: #653cad,
60 | secondary: #8662c7
61 | )
62 | );
63 |
--------------------------------------------------------------------------------
/src/pages/_document.js:
--------------------------------------------------------------------------------
1 | import Document, { Html, Head, Main, NextScript } from 'next/document';
2 | import { Helmet } from 'react-helmet';
3 | import { withPrefix } from '../utils';
4 |
5 | export default class MyDocument extends Document {
6 | static async getInitialProps(ctx) {
7 | const initialProps = await Document.getInitialProps(ctx);
8 | // see https://github.com/nfl/react-helmet#server-usage for more information
9 | // 'head' was occupied by 'renderPage().head', we cannot use it
10 | return { ...initialProps, helmet: Helmet.renderStatic() };
11 | }
12 |
13 | // should render on
14 | get helmetHtmlAttrComponents() {
15 | return this.props.helmet.htmlAttributes.toComponent();
16 | }
17 |
18 | // should render on
19 | get helmetBodyAttrComponents() {
20 | return this.props.helmet.bodyAttributes.toComponent();
21 | }
22 |
23 | // should render on
24 | get helmetHeadComponents() {
25 | return Object.keys(this.props.helmet)
26 | .filter((el) => el !== 'htmlAttributes' && el !== 'bodyAttributes')
27 | .map((el) => this.props.helmet[el].toComponent());
28 | }
29 |
30 | render() {
31 | // if you don't like Helmet but you still want to set properties on body use this
32 | // const pageProps = _.get(this.props, '__NEXT_DATA__.props.pageProps');
33 | return (
34 |
35 | {this.helmetHeadComponents}
36 |
37 |
38 |
39 |
40 |
41 |
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import Action from './Action';
2 | import ActionLink from './ActionLink';
3 | import BlogPostFooter from './BlogPostFooter';
4 | import CtaButtons from './CtaButtons';
5 | import Footer from './Footer';
6 | import FooterForm from './FooterForm';
7 | import FooterNav from './FooterNav';
8 | import FooterText from './FooterText';
9 | import FormField from './FormField';
10 | import Header from './Header';
11 | import Layout from './Layout';
12 | import Icon from './Icon';
13 | import SectionContact from './SectionContact';
14 | import SectionContent from './SectionContent';
15 | import SectionCta from './SectionCta';
16 | import SectionFaq from './SectionFaq';
17 | import SectionFeatures from './SectionFeatures';
18 | import SectionHero from './SectionHero';
19 | import SectionPosts from './SectionPosts';
20 | import SectionPricing from './SectionPricing';
21 | import SectionReviews from './SectionReviews';
22 |
23 | export {
24 | Action,
25 | ActionLink,
26 | BlogPostFooter,
27 | CtaButtons,
28 | Footer,
29 | FooterForm,
30 | FooterNav,
31 | FooterText,
32 | FormField,
33 | Header,
34 | Layout,
35 | Icon,
36 | SectionContact,
37 | SectionContent,
38 | SectionCta,
39 | SectionFaq,
40 | SectionFeatures,
41 | SectionHero,
42 | SectionPosts,
43 | SectionPricing,
44 | SectionReviews
45 | };
46 |
47 | export default {
48 | Action,
49 | ActionLink,
50 | BlogPostFooter,
51 | CtaButtons,
52 | Footer,
53 | FooterForm,
54 | FooterNav,
55 | FooterText,
56 | FormField,
57 | Header,
58 | Layout,
59 | Icon,
60 | SectionContact,
61 | SectionContent,
62 | SectionCta,
63 | SectionFaq,
64 | SectionFeatures,
65 | SectionHero,
66 | SectionPosts,
67 | SectionPricing,
68 | SectionReviews
69 | };
70 |
--------------------------------------------------------------------------------
/src/components/SectionContent.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { withPrefix, markdownify } from '../utils';
5 | import CtaButtons from './CtaButtons';
6 |
7 | export default class SectionContent extends React.Component {
8 | render() {
9 | let section = _.get(this.props, 'section');
10 | const sectionId = _.get(section, 'section_id');
11 | const background = _.get(section, 'background');
12 | const image = _.get(section, 'image');
13 | const imageAlt = _.get(section, 'image_alt');
14 | const title = _.get(section, 'title');
15 | const content = _.get(section, 'content');
16 | const actions = _.get(section, 'actions');
17 |
18 | return (
19 |
20 |
21 |
22 | {image && (
23 |
24 |
25 |
26 | )}
27 |
28 | {title &&
{title} }
29 | {content &&
{markdownify(content)}
}
30 | {actions && (
31 |
32 |
33 |
34 | )}
35 |
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/sass/imports/_forms.scss:
--------------------------------------------------------------------------------
1 | label {
2 | display: block;
3 | color: inherit;
4 | line-height: 1.5;
5 | margin-bottom: 0.25em;
6 | }
7 |
8 | input[type="text"],
9 | input[type="password"],
10 | input[type="email"],
11 | input[type="tel"],
12 | input[type="number"],
13 | input[type="search"],
14 | input[type="url"],
15 | select,
16 | textarea {
17 | background: #fff;
18 | border: 1px solid $gray-200;
19 | border-radius: $border-radius;
20 | box-shadow: none;
21 | box-sizing: border-box;
22 | color: $gray-700;
23 | display: block;
24 | font-size: 1em;
25 | font-weight: normal;
26 | line-height: 1.5;
27 | max-width: 100%;
28 | padding: 0.5em;
29 | width: 100%;
30 |
31 | &:focus {
32 | outline: 0;
33 | }
34 | }
35 |
36 | ::placeholder {
37 | color: $gray-400;
38 | opacity: 1;
39 | }
40 |
41 | .form-row {
42 | margin-bottom: 1em;
43 | }
44 |
45 | .form-submit {
46 | margin-top: 1.66667em;
47 | }
48 |
49 | .form-select {
50 | color: inherit;
51 | font-size: 1em;
52 | position: relative;
53 |
54 | select {
55 | -webkit-appearance: none;
56 | -moz-appearance: none;
57 | padding-right: 25px;
58 | }
59 |
60 | &:before,
61 | &:after {
62 | border: solid transparent;
63 | border-width: 0.3125em;
64 | box-sizing: border-box;
65 | content: "";
66 | position: absolute;
67 | right: 10px;
68 | top: 50%;
69 | z-index: 1;
70 | }
71 |
72 | &:before {
73 | border-top-color: currentColor;
74 | margin-top: 0.125em;
75 | }
76 |
77 | &:after {
78 | border-bottom-color: currentColor;
79 | margin-top: -0.75em;
80 | }
81 | }
82 |
83 | .form-checkbox {
84 | padding-left: 1.5em;
85 | position: relative;
86 |
87 | input[type=checkbox] {
88 | height: 1.5em;
89 | left: 0;
90 | position: absolute;
91 | top: 0;
92 | }
93 | }
94 |
95 | #wasteSubtitle {
96 | display: none;
97 | }
98 |
--------------------------------------------------------------------------------
/content/pages/terms-of-service.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Terms of Service
3 | seo:
4 | title: Terms of Service
5 | description: Terms of service page
6 | extra:
7 | - name: 'og:type'
8 | value: website
9 | keyName: property
10 | - name: 'og:title'
11 | value: Terms of service
12 | keyName: property
13 | - name: 'og:description'
14 | value: Terms of service page
15 | keyName: property
16 | - name: 'twitter:card'
17 | value: summary_large_image
18 | - name: 'twitter:title'
19 | value: Terms of service
20 | - name: 'twitter:description'
21 | value: Terms of service page
22 | layout: page
23 | ---
24 |
25 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a metus quis lorem malesuada luctus. Cras lacinia, eros at dapibus molestie, risus tortor pretium ligula, eu malesuada tortor eros dapibus mi. Proin laoreet efficitur suscipit. Donec molestie volutpat euismod. Nulla gravida ligula in eros facilisis, sed dignissim tellus aliquam. Etiam convallis enim nisi, at suscipit tortor pulvinar at. Nulla a interdum lacus. Sed a porttitor mi. Sed at risus eu orci ultricies mattis sed in tellus. Cras nec neque sed dui vehicula iaculis id vel ex. Phasellus non consectetur augue. Pellentesque condimentum sapien arcu, nec tempus nunc maximus eu. Duis blandit risus nulla. In dolor dui, placerat non finibus sit amet, venenatis pretium tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
26 |
27 | Nunc a lorem tellus. Aenean eu auctor purus. Cras pulvinar, nunc at sagittis dignissim, orci elit auctor leo, et consectetur est turpis a nunc. Vivamus in faucibus felis. Aenean rutrum magna at ex auctor, congue efficitur ligula feugiat. Proin a egestas arcu. Etiam feugiat turpis quis mollis pellentesque. Sed posuere luctus tortor, a eleifend augue varius sit amet. Integer ultrices neque sed quam dictum, quis vestibulum justo volutpat. Nam vitae tempus leo, ut mattis mi.
28 |
--------------------------------------------------------------------------------
/src/layouts/post.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Layout } from '../components/index';
5 | import { htmlToReact, withPrefix, markdownify } from '../utils';
6 | import BlogPostFooter from '../components/BlogPostFooter';
7 |
8 | export default class Post extends React.Component {
9 | render() {
10 | const page = _.get(this.props, 'page');
11 | const data = _.get(this.props, 'data');
12 | const config = _.get(data, 'config');
13 | const title = _.get(page, 'title');
14 | const subtitle = _.get(page, 'subtitle');
15 | const image = _.get(page, 'image');
16 | const imageAlt = _.get(page, 'image_alt');
17 | const markdownContent = _.get(page, 'markdown_content');
18 |
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | {title}
26 | {subtitle && {htmlToReact(subtitle)}
}
27 |
28 | {image && (
29 |
30 |
31 |
32 | )}
33 | {markdownContent && {markdownify(markdownContent)}
}
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/content/pages/privacy-policy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Privacy Policy
3 | seo:
4 | title: Privacy Policy
5 | description: This is the privacy policy page
6 | extra:
7 | - name: 'og:type'
8 | value: website
9 | keyName: property
10 | - name: 'og:title'
11 | value: Privacy Policy
12 | keyName: property
13 | - name: 'og:description'
14 | value: This is the privacy policy page
15 | keyName: property
16 | - name: 'twitter:card'
17 | value: summary_large_image
18 | - name: 'twitter:title'
19 | value: Privacy Policy
20 | - name: 'twitter:description'
21 | value: This is the privacy policy page
22 | layout: page
23 | ---
24 |
25 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a metus quis lorem malesuada luctus. Cras lacinia, eros at dapibus molestie, risus tortor pretium ligula, eu malesuada tortor eros dapibus mi. Proin laoreet efficitur suscipit. Donec molestie volutpat euismod. Nulla gravida ligula in eros facilisis, sed dignissim tellus aliquam. Etiam convallis enim nisi, at suscipit tortor pulvinar at. Nulla a interdum lacus. Sed a porttitor mi. Sed at risus eu orci ultricies mattis sed in tellus. Cras nec neque sed dui vehicula iaculis id vel ex. Phasellus non consectetur augue. Pellentesque condimentum sapien arcu, nec tempus nunc maximus eu. Duis blandit risus nulla. In dolor dui, placerat non finibus sit amet, venenatis pretium tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
26 |
27 | Nunc a lorem tellus. Aenean eu auctor purus. Cras pulvinar, nunc at sagittis dignissim, orci elit auctor leo, et consectetur est turpis a nunc. Vivamus in faucibus felis. Aenean rutrum magna at ex auctor, congue efficitur ligula feugiat. Proin a egestas arcu. Etiam feugiat turpis quis mollis pellentesque. Sed posuere luctus tortor, a eleifend augue varius sit amet. Integer ultrices neque sed quam dictum, quis vestibulum justo volutpat. Nam vitae tempus leo, ut mattis mi.
28 |
--------------------------------------------------------------------------------
/content/pages/contact.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Contacto
3 | sections:
4 | - section_id: contact
5 | type: section_contact
6 | background: gray
7 | title: Contacto
8 | content: >-
9 | Déjanos saber que tipo de residuos aprovechables deseas suministrar y muy pronto pasaremos a recogerlos.
10 | form_id: contactForm
11 | form_fields:
12 | - input_type: text
13 | name: name
14 | label: Nombre
15 | is_required: true
16 | - input_type: email
17 | name: email
18 | label: Correo electrónico
19 | is_required: true
20 | - input_type: text
21 | name: address
22 | label: Dirección
23 | is_required: true
24 | - input_type: text
25 | name: wasteSubtitle
26 | label: Selecciona el tipo de residuo que posees
27 | - input_type: checkbox
28 | name: paper
29 | label: Papel
30 | - input_type: checkbox
31 | name: glass
32 | label: Vidrio
33 | - input_type: checkbox
34 | name: metal
35 | label: Metal
36 | - input_type: checkbox
37 | name: plastico
38 | label: Plástico
39 | - input_type: textarea
40 | name: message
41 | label: Observaciones
42 | - input_type: checkbox
43 | name: consent
44 | label: >-
45 | Estoy de acuerdo con la política de tratamiento de datos personales.
46 | is_required: true
47 | submit_label: Enviar
48 | seo:
49 | title: Contacto
50 | description: This is the contact page
51 | extra:
52 | - name: 'og:type'
53 | value: website
54 | keyName: property
55 | - name: 'og:title'
56 | value: Contacto
57 | keyName: property
58 | - name: 'og:description'
59 | value: This is the contact page
60 | keyName: property
61 | - name: 'twitter:card'
62 | value: summary_large_image
63 | - name: 'twitter:title'
64 | value: Contact
65 | - name: 'twitter:description'
66 | value: This is the contact page
67 | layout: landing
68 | ---
69 |
--------------------------------------------------------------------------------
/content/pages/signup.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sign Up
3 | subtitle: >-
4 | This is an optional subtitle. It can be used to describe what this page is
5 | about.
6 | image: images/11.jpg
7 | image_alt: Office desk top view
8 | seo:
9 | title: Sign Up
10 | description: This is the sign up page
11 | extra:
12 | - name: 'og:type'
13 | value: website
14 | keyName: property
15 | - name: 'og:title'
16 | value: Sign Up
17 | keyName: property
18 | - name: 'og:description'
19 | value: This is the sign up page
20 | keyName: property
21 | - name: 'twitter:card'
22 | value: summary_large_image
23 | - name: 'twitter:title'
24 | value: Sign Up
25 | - name: 'twitter:description'
26 | value: This is the sign up page
27 | layout: page
28 | ---
29 |
30 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a metus quis lorem malesuada luctus. Cras lacinia, eros at dapibus molestie, risus tortor pretium ligula, eu malesuada tortor eros dapibus mi. Proin laoreet efficitur suscipit. Donec molestie volutpat euismod. Nulla gravida ligula in eros facilisis, sed dignissim tellus aliquam. Etiam convallis enim nisi, at suscipit tortor pulvinar at. Nulla a interdum lacus. Sed a porttitor mi. Sed at risus eu orci ultricies mattis sed in tellus. Cras nec neque sed dui vehicula iaculis id vel ex. Phasellus non consectetur augue. Pellentesque condimentum sapien arcu, nec tempus nunc maximus eu. Duis blandit risus nulla. In dolor dui, placerat non finibus sit amet, venenatis pretium tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
31 |
32 | Nunc a lorem tellus. Aenean eu auctor purus. Cras pulvinar, nunc at sagittis dignissim, orci elit auctor leo, et consectetur est turpis a nunc. Vivamus in faucibus felis. Aenean rutrum magna at ex auctor, congue efficitur ligula feugiat. Proin a egestas arcu. Etiam feugiat turpis quis mollis pellentesque. Sed posuere luctus tortor, a eleifend augue varius sit amet. Integer ultrices neque sed quam dictum, quis vestibulum justo volutpat. Nam vitae tempus leo, ut mattis mi.
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # Snowpack dependency directory (https://snowpack.dev/)
45 | web_modules/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 | .parcel-cache
78 |
79 | # Next.js build output
80 | .next
81 | out
82 |
83 | # Serverless directories
84 | .serverless/
85 |
86 | # Stores VSCode versions used for testing VSCode extensions
87 | .vscode-test
88 |
89 | # yarn v2
90 | .yarn/cache
91 | .yarn/unplugged
92 | .yarn/build-state.yml
93 | .yarn/install-state.gz
94 | .pnp.*
95 |
96 | .sourcebit-nextjs-cache.json
97 | .DS_Store
98 | .idea
99 |
100 | # package json
101 | package-lock.json
102 |
--------------------------------------------------------------------------------
/sourcebit.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | const isDev = process.env.NODE_ENV === 'development';
4 |
5 |
6 | module.exports = {
7 | plugins: [
8 | {
9 | module: require('sourcebit-source-filesystem'),
10 | options: {
11 | watch: isDev
12 | }
13 | },
14 | // flatten all frontmatter and markdown data
15 | ({ data }) => {
16 | const objects = data.objects.map(object => {
17 | if (_.has(object, 'frontmatter')) {
18 | return {
19 | __metadata: object.__metadata,
20 | ...object.frontmatter,
21 | markdown_content: object.markdown || null
22 | }
23 | }
24 | return object;
25 | });
26 |
27 | return {
28 | ...data,
29 | objects
30 | };
31 | },
32 | {
33 | module: require('sourcebit-target-next'),
34 | options: {
35 | liveUpdate: isDev,
36 | flattenAssetUrls: true,
37 | pages: [
38 | { path: '/{__metadata.urlPath}', predicate: _.matchesProperty('__metadata.modelName', 'landing') },
39 | { path: '/{__metadata.urlPath}', predicate: _.matchesProperty('__metadata.modelName', 'page') },
40 | { path: '/{__metadata.urlPath}', predicate: _.matchesProperty('__metadata.modelName', 'blog') },
41 | { path: '/{__metadata.urlPath}', predicate: _.matchesProperty('__metadata.modelName', 'post') }
42 | ],
43 | commonProps: {
44 | pages: { predicate: _.matchesProperty('__metadata.modelType', 'page') },
45 | posts: { predicate: _.matchesProperty('__metadata.modelName', 'post') },
46 | data: { single: true, predicate: _.matchesProperty('__metadata.id', 'sourcebit-source-filesystem:data') }
47 | }
48 | }
49 | }
50 | ]
51 | };
52 |
--------------------------------------------------------------------------------
/content/pages/features.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Features
3 | sections:
4 | - section_id: features
5 | type: section_content
6 | background: gray
7 | image: images/feature1.png
8 | image_alt: App preview on a phone and tablet
9 | title: The Best Features of Your Services
10 | content: >-
11 | Nam pulvinar ante eu ultricies volutpat. Sed nulla nibh, dapibus sit amet
12 | cursus quis, fringilla nec sapien. Vestibulum imperdiet nunc bibendum
13 | consectetur lobortis.
14 |
15 |
16 | * Lorem ipsum dolor sit amet, consectetur adipiscing elit.
17 |
18 | * Ut eu nunc at diam fringilla fringilla eu ut massa.
19 |
20 | * Phasellus ut enim non lorem venenatis rutrum.
21 |
22 |
23 | Mollis eget congue quis, venenatis sit amet metus. Etiam sit amet tortor
24 | sed justo tempor condimentum.
25 | actions:
26 | - label: Free Trial
27 | url: /signup
28 | style: primary
29 | - label: View Demo
30 | url: '#'
31 | style: secondary
32 | - section_id: call-to-action
33 | type: section_cta
34 | title: This Is Call to Action Block!
35 | subtitle: This is an optional description for the call to action block.
36 | actions:
37 | - label: Get Started
38 | url: '#'
39 | style: secondary
40 | seo:
41 | title: Features
42 | description: This is the features page
43 | extra:
44 | - name: 'og:type'
45 | value: website
46 | keyName: property
47 | - name: 'og:title'
48 | value: Features
49 | keyName: property
50 | - name: 'og:description'
51 | value: This is the features page
52 | keyName: property
53 | - name: 'og:image'
54 | value: images/feature1.png
55 | keyName: property
56 | relativeUrl: true
57 | - name: 'twitter:card'
58 | value: summary_large_image
59 | - name: 'twitter:title'
60 | value: Features
61 | - name: 'twitter:description'
62 | value: This is the features page
63 | - name: 'twitter:image'
64 | value: images/feature1.png
65 | relativeUrl: true
66 | layout: landing
67 | ---
68 |
--------------------------------------------------------------------------------
/src/components/SectionReviews.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { htmlToReact, withPrefix } from '../utils';
5 |
6 | export default class SectionReviews extends React.Component {
7 | renderReview(review, index) {
8 | const content = _.get(review, 'content');
9 | const avatar = _.get(review, 'avatar');
10 | const avatarAlt = _.get(review, 'avatar_alt');
11 | const author = _.get(review, 'author');
12 |
13 | return (
14 |
15 |
16 |
{htmlToReact(content)}
17 |
18 | {avatar && }
19 | {author && {author} }
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | render() {
27 | const section = _.get(this.props, 'section');
28 | const sectionId = _.get(section, 'section_id');
29 | const background = _.get(section, 'background');
30 | const title = _.get(section, 'title');
31 | const subtitle = _.get(section, 'subtitle');
32 | const reviews = _.get(section, 'reviews');
33 |
34 | return (
35 |
36 |
37 | {title &&
{title} }
38 | {subtitle &&
{htmlToReact(subtitle)}
}
39 |
40 | {reviews && (
41 |
42 |
{_.map(reviews, (review, index) => this.renderReview(review, index))}
43 |
44 | )}
45 |
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/content/pages/about.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: About Us
3 | subtitle: >-
4 | This is an optional subtitle. It can be used to describe what this page is
5 | about.
6 | image: images/about.jpg
7 | image_alt: Team members in a conference room
8 | seo:
9 | title: About Us
10 | description: This is the about page
11 | extra:
12 | - name: 'og:type'
13 | value: website
14 | keyName: property
15 | - name: 'og:title'
16 | value: About Us
17 | keyName: property
18 | - name: 'og:description'
19 | value: This is the about page
20 | keyName: property
21 | - name: 'og:image'
22 | value: images/about.jpg
23 | keyName: property
24 | relativeUrl: true
25 | - name: 'twitter:card'
26 | value: summary_large_image
27 | - name: 'twitter:title'
28 | value: About Us
29 | - name: 'twitter:description'
30 | value: This is the about page
31 | - name: 'twitter:image'
32 | value: images/about.jpg
33 | relativeUrl: true
34 | layout: page
35 | ---
36 |
37 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a metus quis lorem malesuada luctus. Cras lacinia, eros at dapibus molestie, risus tortor pretium ligula, eu malesuada tortor eros dapibus mi. Proin laoreet efficitur suscipit. Donec molestie volutpat euismod. Nulla gravida ligula in eros facilisis, sed dignissim tellus aliquam. Etiam convallis enim nisi, at suscipit tortor pulvinar at. Nulla a interdum lacus. Sed a porttitor mi. Sed at risus eu orci ultricies mattis sed in tellus. Cras nec neque sed dui vehicula iaculis id vel ex. Phasellus non consectetur augue. Pellentesque condimentum sapien arcu, nec tempus nunc maximus eu. Duis blandit risus nulla. In dolor dui, placerat non finibus sit amet, venenatis pretium tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
38 |
39 | Nunc a lorem tellus. Aenean eu auctor purus. Cras pulvinar, nunc at sagittis dignissim, orci elit auctor leo, et consectetur est turpis a nunc. Vivamus in faucibus felis. Aenean rutrum magna at ex auctor, congue efficitur ligula feugiat. Proin a egestas arcu. Etiam feugiat turpis quis mollis pellentesque. Sed posuere luctus tortor, a eleifend augue varius sit amet. Integer ultrices neque sed quam dictum, quis vestibulum justo volutpat. Nam vitae tempus leo, ut mattis mi.
40 |
--------------------------------------------------------------------------------
/src/sass/imports/_icons.scss:
--------------------------------------------------------------------------------
1 | // SVG icons
2 | .icon {
3 | color: inherit;
4 | fill: currentColor;
5 | flex-shrink: 0;
6 | height: 1em;
7 | line-height: 1;
8 | width: 1em;
9 | }
10 |
11 | .has-icon {
12 | -ms-flex-align: center;
13 | align-items: center;
14 | display: -ms-inline-flexbox;
15 | display: inline-flex;
16 | -ms-flex-pack: center;
17 | justify-content: center;
18 | vertical-align: middle;
19 |
20 | .icon {
21 | & + .order-first {
22 | margin-right: 0.5em;
23 | }
24 |
25 | & + :not(.order-first) {
26 | margin-left: 0.5em;
27 | }
28 | }
29 | }
30 |
31 | // CSS icons
32 | .icon-menu,
33 | .icon-close {
34 | background: currentColor;
35 | border-radius: 1px;
36 | color: inherit;
37 | height: 2px;
38 | left: 50%;
39 | position: absolute;
40 | top: 50%;
41 | -webkit-transform: translate(-50%,-50%);
42 | transform: translate(-50%,-50%);
43 | width: 28px;
44 |
45 | &:before,
46 | &:after {
47 | background: currentColor;
48 | border-radius: 1px;
49 | content: "";
50 | height: 100%;
51 | left: 0;
52 | position: absolute;
53 | width: 100%;
54 | }
55 | }
56 |
57 | .icon-menu {
58 | &:before {
59 | top: -8px;
60 | }
61 |
62 | &:after {
63 | bottom: -8px;
64 | }
65 | }
66 |
67 | .icon-close {
68 | background: 0;
69 | width: 30px;
70 |
71 | &:before {
72 | top: 0;
73 | -webkit-transform: rotate(45deg);
74 | transform: rotate(45deg);
75 | }
76 |
77 | &:after {
78 | top: 0;
79 | -webkit-transform: rotate(-45deg);
80 | transform: rotate(-45deg);
81 | }
82 | }
83 |
84 | .icon-plus {
85 | background: $color-primary;
86 | border-radius: 50%;
87 | color: #fff;
88 | height: 24px;
89 | position: relative;
90 | width: 24px;
91 |
92 | &:before,
93 | &:after {
94 | background: currentColor;
95 | border-radius: 1px;
96 | content: "";
97 | height: 2px;
98 | left: 50%;
99 | margin-top: -1px;
100 | margin-left: -8px;
101 | position: absolute;
102 | top: 50%;
103 | width: 16px;
104 | }
105 |
106 | &:after {
107 | -webkit-transform: rotate(-90deg);
108 | transform: rotate(-90deg);
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/layouts/blog.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { Layout } from '../components';
5 | import { Link, getPageUrl, withPrefix } from '../utils';
6 | import BlogPostFooter from '../components/BlogPostFooter';
7 |
8 | export default class Blog extends React.Component {
9 | renderPost(post, index, data) {
10 | const title = _.get(post, 'title');
11 | const thumbImage = _.get(post, 'thumb_image');
12 | const thumbImageAlt = _.get(post, 'thumb_image_alt');
13 | const excerpt = _.get(post, 'excerpt');
14 | const postUrl = getPageUrl(post, { withPrefix: true });
15 |
16 | return (
17 |
18 |
19 | {thumbImage && (
20 |
21 |
22 |
23 | )}
24 |
25 |
26 |
27 | {title}
28 |
29 |
30 | {excerpt && (
31 |
34 | )}
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
42 | render() {
43 | const page = _.get(this.props, 'page');
44 | const data = _.get(this.props, 'data');
45 | const config = _.get(this.props, 'data.config');
46 | const posts = _.orderBy(_.get(this.props, 'posts', []), 'date', 'desc');
47 | return (
48 |
49 |
50 |
51 |
{_.map(posts, (post, index) => this.renderPost(post, index, data))}
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/FooterForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { markdownify } from '../utils';
5 | import FormField from './FormField';
6 |
7 | export default class FooterForm extends React.Component {
8 | render() {
9 | const section = _.get(this.props, 'section');
10 | const title = _.get(section, 'title');
11 | const hideLabels = _.get(section, 'hide_labels');
12 | const content = _.get(section, 'content');
13 | const formId = _.get(section, 'form_id');
14 | const formAction = _.get(section, 'form_action');
15 | const formFields = _.get(section, 'form_fields');
16 | const submitLabel = _.get(section, 'submit_label');
17 |
18 | return (
19 |
20 | {title && {title} }
21 | {markdownify(content)}
22 |
50 |
51 | );
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/sass/imports/_posts.scss:
--------------------------------------------------------------------------------
1 | .post {
2 | margin-bottom: 1.66667em;
3 | }
4 |
5 | .post-title {
6 | a {
7 | color: inherit !important;
8 | text-decoration: none;
9 | }
10 | }
11 |
12 | .post-meta {
13 | color: $gray-500;
14 | line-height: 1.5;
15 | }
16 |
17 | .post-image,
18 | .post-content {
19 | img {
20 | border-radius: $border-radius;
21 | }
22 | }
23 |
24 | // Single post
25 | .post-full {
26 | .post-header {
27 | margin-bottom: 2.5em;
28 | text-align: center;
29 | }
30 |
31 | .post-title {
32 | margin-bottom: 0.15em;
33 | }
34 |
35 | .post-meta {
36 | font-size: 0.88889em;
37 | margin-top: 1.875em;
38 | }
39 | }
40 |
41 | .post-subtitle {
42 | color: $gray-500;
43 | font-size: 1.11111em;
44 | line-height: 1.4;
45 | }
46 |
47 | .post-image {
48 | display: block;
49 | margin-bottom: 2.5em;
50 | }
51 |
52 | @media only screen and (min-width: 601px) {
53 | .post-full {
54 | margin-bottom: 3.33333em;
55 | }
56 |
57 | .post-subtitle {
58 | font-size: 1.22222em;
59 | }
60 | }
61 |
62 | // Post feed
63 | .post-feed {
64 | margin-bottom: 1.66667em;
65 |
66 | .card {
67 | height: 100%;
68 | }
69 |
70 | .post-title {
71 | font-size: 1.33333em;
72 | }
73 |
74 | .post-meta {
75 | font-size: 0.77778em;
76 | margin-bottom: 0.25em;
77 | }
78 | }
79 |
80 | .post-thumbnail {
81 | border-radius: $border-radius $border-radius 0 0;
82 | display: block;
83 | margin: 0;
84 | position: relative;
85 | width: 100%;
86 |
87 | &:before {
88 | content: "";
89 | display: block;
90 | padding-top: 66.666%;
91 | }
92 |
93 | img {
94 | border-radius: $border-radius $border-radius 0 0;
95 | height: 100%;
96 | left: 0;
97 | object-fit: cover;
98 | position: absolute;
99 | top: 0;
100 | width: 100%;
101 | }
102 | }
103 |
104 | .post-body {
105 | padding: 1.33333em;
106 | }
107 |
108 | .post-excerpt {
109 | font-size: 0.88889em;
110 | margin-bottom: 1.25em;
111 | }
112 |
113 | @media only screen and (min-width: 601px) {
114 | .post-feed {
115 | .cell {
116 | -ms-flex: 0 0 50%;
117 | flex: 0 0 50%;
118 | margin-bottom: 1.66667em;
119 | max-width: 50%;
120 | }
121 | }
122 | }
123 |
124 | @media only screen and (min-width: 901px) {
125 | .post-feed {
126 | .cell {
127 | -ms-flex: 0 0 33.333%;
128 | flex: 0 0 33.333%;
129 | max-width: 33.333%;
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/src/components/SectionFaq.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { htmlToReact, markdownify } from '../utils';
5 |
6 | export default class SectionFaq extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.handorgelRef = React.createRef();
10 | }
11 |
12 | componentDidMount() {
13 | const handorgelElm = _.get(this.handorgelRef, 'current');
14 | if (handorgelElm) {
15 | new handorgel(handorgelElm, {
16 | multiSelectable: true
17 | });
18 | }
19 | }
20 |
21 | renderFaqItem(faqItem, index) {
22 | const question = _.get(faqItem, 'question');
23 | const answer = _.get(faqItem, 'answer');
24 |
25 | return (
26 |
27 |
28 |
29 | {question}
30 |
31 |
32 |
33 |
34 |
{markdownify(answer)}
35 |
36 |
37 | );
38 | }
39 |
40 | render() {
41 | const section = _.get(this.props, 'section');
42 | const sectionId = _.get(section, 'section_id');
43 | const background = _.get(section, 'background');
44 | const title = _.get(section, 'title');
45 | const subtitle = _.get(section, 'subtitle');
46 | const faqItems = _.get(section, 'faq_items');
47 |
48 | return (
49 |
50 |
51 |
52 | {title &&
{title} }
53 | {subtitle &&
{htmlToReact(subtitle)}
}
54 |
55 | {faqItems && (
56 |
57 | {_.map(faqItems, (faqItem, index) => this.renderFaqItem(faqItem, index))}
58 |
59 | )}
60 |
61 |
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/components/SectionPricing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { htmlToReact, classNames, markdownify } from '../utils';
5 | import CtaButtons from './CtaButtons';
6 |
7 | export default class SectionPricing extends React.Component {
8 | renderPricingPlan(plan, index) {
9 | const highlight = _.get(plan, 'highlight');
10 | const title = _.get(plan, 'title');
11 | const subtitle = _.get(plan, 'subtitle');
12 | const price = _.get(plan, 'price');
13 | const details = _.get(plan, 'details');
14 | const actions = _.get(plan, 'actions');
15 |
16 | return (
17 |
18 |
19 |
20 | {title &&
{title} }
21 | {subtitle &&
{subtitle}
}
22 | {price &&
{price}
}
23 |
24 | {details &&
{markdownify(details)}
}
25 | {actions && (
26 |
27 |
28 |
29 | )}
30 |
31 |
32 | );
33 | }
34 |
35 | render() {
36 | const section = _.get(this.props, 'section');
37 | const sectionId = _.get(section, 'section_id');
38 | const background = _.get(section, 'background');
39 | const title = _.get(section, 'title');
40 | const subtitle = _.get(section, 'subtitle');
41 | const pricingPlans = _.get(section, 'pricing_plans');
42 |
43 | return (
44 |
45 |
46 | {title &&
{title} }
47 | {subtitle &&
{htmlToReact(subtitle)}
}
48 |
49 | {pricingPlans && (
50 |
51 |
{_.map(pricingPlans, (plan, index) => this.renderPricingPlan(plan, index))}
52 |
53 | )}
54 |
55 | );
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/components/FormField.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { classNames } from '../utils';
5 |
6 | export default class FormField extends React.Component {
7 | render() {
8 | const field = _.get(this.props, 'field');
9 | const hideLabels = _.get(this.props, 'hideLabels');
10 | const inputType = _.get(field, 'input_type');
11 | const label = _.get(field, 'label');
12 | const name = _.get(field, 'name');
13 | const defaultValue = _.get(field, 'default_value');
14 | const options = _.get(field, 'options');
15 | const required = _.get(field, 'is_required');
16 | const attr = {};
17 | const nameLabel = `${name}-label`;
18 | if (label) {
19 | attr['aria-labelledby'] = nameLabel;
20 | }
21 | if (required) {
22 | attr.required = true;
23 | }
24 |
25 | return (
26 |
27 | {inputType !== 'checkbox' && label && (
28 |
29 | {label}
30 |
31 | )}
32 | {inputType === 'checkbox' ? (
33 |
34 |
35 | {label && (
36 |
37 | {label}
38 |
39 | )}
40 |
41 | ) : inputType === 'select' ? (
42 |
43 |
44 | {defaultValue && {defaultValue} }
45 | {_.map(options, (option, optionIdx) => (
46 |
47 | {option}
48 |
49 | ))}
50 |
51 |
52 | ) : inputType === 'textarea' ? (
53 |
54 | ) : (
55 |
56 | )}
57 |
58 | );
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/sass/imports/_footer.scss:
--------------------------------------------------------------------------------
1 | #colophon {
2 | background: $gray-700;
3 | color: $gray-400;
4 |
5 | h1,
6 | h2,
7 | h3,
8 | h4,
9 | h5,
10 | h6 {
11 | color: $gray-200;
12 | }
13 |
14 | a {
15 | &:not(.button) {
16 | color: inherit;
17 |
18 | &:hover {
19 | color: $gray-200;
20 | }
21 | }
22 | }
23 | }
24 |
25 | .footer-top {
26 | border-bottom: 1px solid rgba($gray-600,.4);
27 | padding-bottom: 1.11111em;
28 | padding-top: 3.33333em;
29 | }
30 |
31 | .footer-bottom {
32 | padding-bottom: 1.66667em;
33 | padding-top: 1.66667em;
34 | text-align: center;
35 | }
36 |
37 | .widget {
38 | font-size: 0.88889em;
39 | line-height: 1.5;
40 | margin-bottom: 2.5em;
41 | }
42 |
43 | .widget-image {
44 | display: block;
45 | margin-bottom: 0.75em;
46 | }
47 |
48 | .widget-title {
49 | font-size: 1.125em;
50 | margin: 0 0 1.2em;
51 | }
52 |
53 | .widget-nav,
54 | .footer-nav {
55 | a {
56 | &:not(.button) {
57 | text-decoration: none;
58 | }
59 | }
60 | }
61 |
62 | .widget-nav {
63 | .menu-item {
64 | margin-bottom: 0.75em;
65 | }
66 |
67 | .icon {
68 | & + :not(.order-first) {
69 | margin-left: 0.75em;
70 | }
71 | }
72 | }
73 |
74 | .footer-nav {
75 | .menu-item {
76 | display: inline-block;
77 | margin: 0 0.75em 0.25em;
78 | }
79 | }
80 |
81 | .site-info {
82 | font-size: 0.77778em;
83 | line-height: 1.5;
84 |
85 | &:not(:first-child) {
86 | margin-top: 1em;
87 | }
88 | }
89 |
90 | @media only screen and (min-width: 481px) {
91 | .footer-top {
92 | .cell {
93 | -ms-flex: 0 0 50%;
94 | flex: 0 0 50%;
95 | max-width: 50%;
96 | }
97 |
98 | .widget-text {
99 | &:first-child {
100 | -ms-flex: 0 0 100%;
101 | flex: 0 0 100%;
102 | max-width: 100%;
103 | }
104 | }
105 | img {
106 | height: 40px;
107 | }
108 | }
109 | }
110 |
111 | @media only screen and (min-width: 701px) {
112 | .footer-top {
113 | .widget-text {
114 | &:first-child {
115 | & ~ .cell {
116 | -ms-flex: 0 0 33.333%;
117 | flex: 0 0 33.333%;
118 | max-width: 33.333%;
119 | }
120 | }
121 | }
122 | }
123 | }
124 |
125 | @media only screen and (min-width: 901px) {
126 | .footer-top {
127 | .grid {
128 | -ms-flex-pack: center;
129 | justify-content: center;
130 | }
131 |
132 | .cell,
133 | .widget-text:first-child,
134 | .widget-text:first-child ~ .cell {
135 | -ms-flex: 0 0 25%;
136 | flex: 0 0 25%;
137 | max-width: 25%;
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/components/SectionPosts.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { getPageUrl, htmlToReact, Link, withPrefix } from '../utils';
5 | import BlogPostFooter from './BlogPostFooter';
6 |
7 | export default class SectionPosts extends React.Component {
8 | renderRecentPost(post, index, data) {
9 | const title = _.get(post, 'title');
10 | const postUrl = getPageUrl(post, { withPrefix: true });
11 | const thumbImage = _.get(post, 'thumb_image');
12 | const thumbImageAlt = _.get(post, 'thumb_image_alt');
13 | const excerpt = _.get(post, 'excerpt');
14 |
15 | return (
16 |
17 |
18 | {thumbImage && (
19 |
20 |
21 |
22 | )}
23 |
24 |
25 |
26 | {title}
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 |
39 | render() {
40 | const section = _.get(this.props, 'section');
41 | const data = _.get(this.props, 'data');
42 | const posts = _.orderBy(_.get(this.props, 'posts', []), 'date', 'desc');
43 | const recentPosts = posts.slice(0, 3);
44 | const sectionId = _.get(section, 'section_id');
45 | const background = _.get(section, 'background');
46 | const title = _.get(section, 'title');
47 | const subtitle = _.get(section, 'subtitle');
48 |
49 | return (
50 |
51 |
52 | {title &&
{title} }
53 | {subtitle &&
{htmlToReact(subtitle)}
}
54 |
55 |
56 |
{_.map(recentPosts, (post, index) => this.renderRecentPost(post, index, data))}
57 |
58 |
59 | );
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/public/images/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/images/logo-alt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/SectionFeatures.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 | import {json} from '../../MOCK_DATA'
4 |
5 | import { htmlToReact, withPrefix, markdownify } from '../utils';
6 | import CtaButtons from './CtaButtons';
7 |
8 | export default class SectionFeatures extends React.Component {
9 | /* constructor(props) {
10 | super(props);
11 | this.state = {
12 |
13 | };
14 | } */
15 | renderFeature(feature, index) {
16 | const image = _.get(feature, 'image');
17 | const imageAlt = _.get(feature, 'image_alt');
18 | const title = _.get(feature, 'title');
19 | const content = _.get(feature, 'content');
20 | const actions = _.get(feature, 'actions');
21 | const valueElement = _.get(feature, 'valueElement')
22 |
23 | return (
24 |
25 |
26 | {image && (
27 |
28 |
29 |
{markdownify(valueElement)}
30 |
31 | )}
32 |
33 |
{title}
34 |
{markdownify(content)}
35 | {actions && (
36 |
37 |
38 |
39 | )}
40 |
41 |
42 |
43 | );
44 | }
45 |
46 | componentDidMount() {
47 | let nodo = document.querySelectorAll('.featureCustom_space-value')
48 | let arrayNodo = [...nodo]
49 | arrayNodo.forEach((e, index) => {
50 | e.firstChild.textContent = json[index].valor
51 | })
52 | }
53 |
54 |
55 | render() {
56 | const section = _.get(this.props, 'section');
57 | const sectionId = _.get(section, 'section_id');
58 | const background = _.get(section, 'background');
59 | const title = _.get(section, 'title');
60 | const subtitle = _.get(section, 'subtitle');
61 | const features = _.get(section, 'features');
62 |
63 | return (
64 |
65 |
66 | {title &&
{title} }
67 | {subtitle &&
{htmlToReact(subtitle)}
}
68 |
69 | {features && {_.map(features, (feature, index) => this.renderFeature(feature, index))}
}
70 |
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/content/pages/blog/design-team-collaborates.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: How Our Design Team Collaborates
3 | excerpt: >-
4 | Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan blandit accumsan
5 | sapien blandit ac amet faucibus aliquet placerat commodo.
6 | author: content/data/authors/jane-doe.yaml
7 | date: '2019-03-24'
8 | thumb_image: images/11_thumb.jpg
9 | image: images/11.jpg
10 | seo:
11 | title: How Our Design Team Collaborates
12 | description: Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan.
13 | extra:
14 | - name: 'og:type'
15 | value: article
16 | keyName: property
17 | - name: 'og:title'
18 | value: How Our Design Team Collaborates
19 | keyName: property
20 | - name: 'og:description'
21 | value: Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan.
22 | keyName: property
23 | - name: 'og:image'
24 | value: images/11.jpg
25 | keyName: property
26 | relativeUrl: true
27 | - name: 'twitter:card'
28 | value: summary_large_image
29 | - name: 'twitter:title'
30 | value: How Our Design Team Collaborates
31 | - name: 'twitter:description'
32 | value: Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan.
33 | - name: 'twitter:image'
34 | value: images/11.jpg
35 | relativeUrl: true
36 | layout: post
37 | ---
38 |
39 | Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan blandit accumsan sapien blandit ac amet faucibus aliquet placerat commodo. Interdum ante aliquet commodo accumsan vis phasellus adipiscing. Ornare a in lacinia. Vestibulum accumsan ac metus massa tempor. Accumsan in lacinia ornare massa amet. Ac interdum ac non praesent. Cubilia lacinia interdum massa faucibus blandit nullam. Accumsan phasellus nunc integer. Accumsan euismod nunc adipiscing lacinia erat ut sit. Arcu amet. Id massa aliquet arcu accumsan lorem amet accumsan.
40 |
41 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa massa primis. Tempus condimentum tempus non ac varius cubilia adipiscing placerat lorem turpis at. Aliquet lorem porttitor interdum. Amet lacus. Aliquam lobortis faucibus blandit ac phasellus. In amet magna non interdum volutpat porttitor metus a ante ac neque. Nisi turpis. Commodo col. Interdum adipiscing mollis ut aliquam id ante adipiscing commodo integer arcu amet Ac interdum ac non praesent. Cubilia lacinia interdum massa faucibus blandit nullam. Accumsan phasellus nunc integer. Accumsan euismod nunc adipiscing lacinia erat ut sit. Arcu amet. Id massa aliquet arcu accumsan lorem amet accumsan commodo odio cubilia ac eu interdum placerat placerat arcu commodo lobortis adipiscing semper ornare pellentesque.
42 |
43 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa massa primis. Tempus condimentum tempus non ac varius cubilia adipiscing placerat lorem turpis at. Aliquet lorem porttitor interdum. Amet lacus. Aliquam lobortis faucibus blandit ac phasellus. In amet magna non interdum volutpat porttitor metus a ante ac neque. Nisi turpis. Commodo col. Interdum adipiscing mollis ut aliquam id ante adipiscing commodo integer arcu amet blandit adipiscing arcu ante.
44 |
--------------------------------------------------------------------------------
/src/components/SectionContact.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import { htmlToReact, markdownify } from '../utils';
5 | import FormField from './FormField';
6 |
7 | export default class SectionContact extends React.Component {
8 | render() {
9 | const section = _.get(this.props, 'section');
10 | const sectionId = _.get(section, 'section_id');
11 | const background = _.get(section, 'background');
12 | const hideLabels = _.get(section, 'hide_labels');
13 | const title = _.get(section, 'title');
14 | const subtitle = _.get(section, 'subtitle');
15 | const content = _.get(section, 'content');
16 | const formAction = _.get(section, 'form_action');
17 | const formFields = _.get(section, 'form_fields');
18 | const submitLabel = _.get(section, 'submit_label');
19 | const formId = _.get(section, 'form_id');
20 | const formHoneypotInputId = formId + '-honeypot';
21 | const formHoneypotLabelId = formId + '-honeypot-label';
22 | const formHoneypotName = formId + '-bot-field';
23 |
24 | return (
25 |
26 |
27 | {title &&
{title} }
28 | {subtitle &&
{htmlToReact(subtitle)}
}
29 |
30 |
31 | {markdownify(content)}
32 |
58 |
59 |
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/sass/imports/_reset.scss:
--------------------------------------------------------------------------------
1 | // normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css
2 | html {
3 | line-height: 1.15;
4 | -webkit-text-size-adjust: 100%;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | }
10 |
11 | main {
12 | display: block;
13 | }
14 |
15 | hr {
16 | box-sizing: content-box;
17 | height: 0;
18 | overflow: visible;
19 | }
20 |
21 | a {
22 | background-color: transparent;
23 | }
24 |
25 | abbr[title] {
26 | border-bottom: none;
27 | text-decoration: underline;
28 | text-decoration: underline dotted;
29 | }
30 |
31 | b,
32 | strong {
33 | font-weight: bold;
34 |
35 | .font-fira-sans & {
36 | font-weight: 600;
37 | }
38 | }
39 |
40 | pre,
41 | code,
42 | kbd,
43 | samp {
44 | font-family: $font-monospace;
45 | font-size: 1em;
46 | }
47 |
48 | small {
49 | font-size: 80%;
50 | }
51 |
52 | sub,
53 | sup {
54 | font-size: 75%;
55 | line-height: 0;
56 | position: relative;
57 | vertical-align: baseline;
58 | }
59 |
60 | sub {
61 | bottom: -0.25em;
62 | }
63 |
64 | sup {
65 | top: -0.5em;
66 | }
67 |
68 | img {
69 | border-style: none;
70 | vertical-align: middle;
71 | }
72 |
73 | button,
74 | input,
75 | optgroup,
76 | select,
77 | textarea {
78 | font-family: inherit;
79 | font-size: 100%;
80 | line-height: 1.15;
81 | margin: 0;
82 | }
83 |
84 | button,
85 | input {
86 | overflow: visible;
87 | }
88 |
89 | button,
90 | select {
91 | text-transform: none;
92 | }
93 |
94 | button,
95 | [type="button"],
96 | [type="reset"],
97 | [type="submit"] {
98 | -webkit-appearance: button;
99 | }
100 |
101 | button::-moz-focus-inner,
102 | [type="button"]::-moz-focus-inner,
103 | [type="reset"]::-moz-focus-inner,
104 | [type="submit"]::-moz-focus-inner {
105 | border-style: none;
106 | padding: 0;
107 | }
108 |
109 | button:-moz-focusring,
110 | [type="button"]:-moz-focusring,
111 | [type="reset"]:-moz-focusring,
112 | [type="submit"]:-moz-focusring {
113 | outline: 1px dotted ButtonText;
114 | }
115 |
116 | fieldset {
117 | padding: 0.35em 0.75em 0.625em;
118 | }
119 |
120 | legend {
121 | box-sizing: border-box;
122 | color: inherit;
123 | display: table;
124 | max-width: 100%;
125 | padding: 0;
126 | white-space: normal;
127 | }
128 |
129 | progress {
130 | vertical-align: baseline;
131 | }
132 |
133 | textarea {
134 | overflow: auto;
135 | }
136 |
137 | [type="checkbox"],
138 | [type="radio"] {
139 | box-sizing: border-box;
140 | padding: 0;
141 | }
142 |
143 | [type="number"]::-webkit-inner-spin-button,
144 | [type="number"]::-webkit-outer-spin-button {
145 | height: auto;
146 | }
147 |
148 | [type="search"] {
149 | -webkit-appearance: textfield;
150 | outline-offset: -2px;
151 | }
152 |
153 | [type="search"]::-webkit-search-decoration {
154 | -webkit-appearance: none;
155 | }
156 |
157 | ::-webkit-file-upload-button {
158 | -webkit-appearance: button;
159 | font: inherit;
160 | }
161 |
162 | details {
163 | display: block;
164 | }
165 |
166 | summary {
167 | display: list-item;
168 | }
169 |
170 | template {
171 | display: none;
172 | }
173 |
174 | [hidden] {
175 | display: none;
176 | }
--------------------------------------------------------------------------------
/content/pages/blog/design-azimuth.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Behind the Scenes - The Design of Azimuth
3 | excerpt: >-
4 | Quisque ultrices metus sed libero ultricies condimentum. Suspendisse ut
5 | faucibus purus. Mauris at pharetra risus.
6 | author: content/data/authors/jane-doe.yaml
7 | date: '2018-01-09'
8 | thumb_image: images/6_thumb.jpg
9 | image: images/6.jpg
10 | seo:
11 | title: Behind the Scenes - The Design of Azimuth
12 | description: Quisque ultrices metus sed libero ultricies condimentum.
13 | extra:
14 | - name: 'og:type'
15 | value: article
16 | keyName: property
17 | - name: 'og:title'
18 | value: Behind the Scenes - The Design of Azimuth
19 | keyName: property
20 | - name: 'og:description'
21 | value: Quisque ultrices metus sed libero ultricies condimentum.
22 | keyName: property
23 | - name: 'og:image'
24 | value: images/6.jpg
25 | keyName: property
26 | relativeUrl: true
27 | - name: 'twitter:card'
28 | value: summary_large_image
29 | - name: 'twitter:title'
30 | value: Behind the Scenes - The Design of Azimuth
31 | - name: 'twitter:description'
32 | value: Quisque ultrices metus sed libero ultricies condimentum.
33 | - name: 'twitter:image'
34 | value: images/6.jpg
35 | relativeUrl: true
36 | layout: post
37 | ---
38 |
39 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas sagittis convallis bibendum. Aenean ac massa vitae lectus semper iaculis. Pellentesque urna nibh, volutpat ac accumsan a, malesuada non arcu. Ut mi eros, facilisis eget dictum quis, semper ut velit. Phasellus vulputate, odio eu consequat sollicitudin, arcu nulla auctor elit, vitae placerat elit elit sit amet ipsum. Curabitur pulvinar leo ac laoreet semper. Integer ut libero dui. Ut id nunc ornare, ornare tellus eu, rutrum ipsum. Donec molestie iaculis tristique. Quisque euismod commodo leo ac ultrices.
40 |
41 | Morbi ut odio interdum, vestibulum neque eu, dictum massa. Maecenas fermentum, metus ut maximus pellentesque, nibh sem venenatis purus, eget ultricies elit lorem finibus justo. Nullam a faucibus diam. Mauris nisi ligula, fringilla a arcu eu, commodo euismod tellus. Sed blandit massa vel ligula ullamcorper fermentum. Praesent ex justo, ultrices ac imperdiet id, auctor quis nulla. Nunc eu blandit nulla. In faucibus pellentesque libero. Sed facilisis lectus id tellus tempus vestibulum eget eget felis. Nulla facilisi. Sed sed sem tristique, pellentesque diam eu, sollicitudin massa.
42 |
43 | Ut lacus ante, venenatis placerat pulvinar eu, molestie in ipsum. Phasellus suscipit ipsum in pulvinar ultricies. Pellentesque tempus lorem massa, non venenatis nisl facilisis a. Curabitur nec elit sapien. In eu commodo sem. Mauris in magna aliquet, vestibulum libero et, mollis velit. Curabitur ut nisi id est accumsan consectetur. Aliquam sit amet magna quis nisi cursus egestas. Maecenas quis vulputate nisi, sit amet tincidunt lectus. Duis sit amet ipsum ac eros congue sodales. Mauris est purus, tempus eget odio sed, auctor eleifend ante. Curabitur vitae ipsum varius, ultricies ipsum at, fermentum orci. Fusce suscipit fermentum tellus ut euismod. Nullam vestibulum auctor sagittis. Aenean et nisl vulputate justo porta aliquet.
44 |
--------------------------------------------------------------------------------
/src/components/Footer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | import components from './index';
5 | import ActionLink from './ActionLink';
6 | import { htmlToReact } from '../utils';
7 |
8 | export default class Footer extends React.Component {
9 | render() {
10 | const config = _.get(this.props, 'config');
11 | const footer = _.get(config, 'footer');
12 | const footerSections = _.get(footer, 'sections');
13 | const hasNav = _.get(footer, 'has_nav');
14 | const navLinks = _.get(footer, 'nav_links');
15 | const footerContent = _.get(footer, 'content');
16 | const links = _.get(footer, 'links');
17 |
18 | return (
19 |
20 | {footerSections && !_.isEmpty(footerSections) && (
21 |
22 |
23 |
24 | {_.map(footerSections, (section, sectionIdx) => {
25 | const sectionType = _.get(section, 'type');
26 | const component = _.upperFirst(_.camelCase(sectionType));
27 | if (!component) {
28 | throw new Error(`footer section does not have the 'type' property`);
29 | }
30 | const Component = components[component];
31 | if (!Component) {
32 | throw new Error(`no component matching the footer section's type: ${sectionType}`);
33 | }
34 | return ;
35 | })}
36 |
37 |
38 |
39 | )}
40 |
41 |
42 | {hasNav && navLinks && (
43 |
44 |
45 | {_.map(navLinks, (action, actionIdx) => (
46 |
47 |
48 |
49 | ))}
50 |
51 |
52 | )}
53 |
54 | {htmlToReact(footerContent)}
55 |
56 | {_.map(links, (action, actionIdx) => (
57 |
58 | ))}
59 |
60 |
61 |
62 |
63 | );
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/sass/imports/_general.scss:
--------------------------------------------------------------------------------
1 | html {
2 | font-size: 112.5%;
3 | }
4 |
5 | body {
6 | background: $gray-100;
7 | color: $gray-600;
8 | line-height: 1.66667;
9 | -webkit-font-smoothing: antialiased;
10 | -moz-osx-font-smoothing: grayscale;
11 | }
12 |
13 | @each $font, $stack in $theme-fonts {
14 | $font-suffix: "#{$font}";
15 |
16 | .font-#{$font-suffix} {
17 | font-family: $stack;
18 | }
19 | }
20 |
21 | a {
22 | color: $color-primary;
23 | text-decoration: underline;
24 | text-decoration-thickness: 1px;
25 | text-underline-offset: 0.125em;
26 | -webkit-transition: color .15s ease;
27 | transition: color .15s ease;
28 |
29 | &:hover {
30 | color: $gray-600;
31 | }
32 | }
33 |
34 | h1,
35 | h2,
36 | h3,
37 | h4,
38 | h5,
39 | h6 {
40 | color: $gray-700;
41 | font-weight: bold;
42 | line-height: 1.16667;
43 | margin: 1.25em 0 0.5em;
44 | text-rendering: optimizeLegibility;
45 |
46 | &:first-child {
47 | margin-top: 0;
48 | }
49 |
50 | .font-fira-sans & {
51 | font-weight: 600;
52 | }
53 | }
54 |
55 | h1 {
56 | font-size: 2em;
57 | }
58 |
59 | h2 {
60 | font-size: 1.77778em;
61 | }
62 |
63 | h3 {
64 | font-size: 1.55556em;
65 | }
66 |
67 | h4 {
68 | font-size: 1.33333em;
69 | }
70 |
71 | h5 {
72 | font-size: 1.11111em;
73 | }
74 |
75 | h6 {
76 | font-size: 1em;
77 | }
78 |
79 | @media only screen and (min-width: 601px) {
80 | h1 {
81 | font-size: 2.44444em;
82 | }
83 |
84 | h2 {
85 | font-size: 2em;
86 | }
87 |
88 | h3 {
89 | font-size: 1.66667em;
90 | }
91 | }
92 |
93 | p {
94 | margin: 0 0 1em;
95 | }
96 |
97 | mark,
98 | ins {
99 | background: $yellow-pale;
100 | color: $gray-700;
101 | padding: 0 3px;
102 | text-decoration: none;
103 | }
104 |
105 | pre {
106 | background: $gray-700;
107 | border-radius: $border-radius;
108 | color: $gray-200;
109 | font-size: 0.83333em;
110 | margin: 0 0 2em;
111 | overflow: auto;
112 | padding: 1.5em;
113 | white-space: pre;
114 | }
115 |
116 | blockquote {
117 | border-left: 3px solid $color-primary;
118 | color: $gray-700;
119 | font-size: 1.33333em;
120 | line-height: 1.3;
121 | margin: 1.25em 0;
122 | padding: 0 0 0 1.25em;
123 |
124 | &:first-child {
125 | margin-top: 0;
126 | }
127 |
128 | p {
129 | margin-bottom: 0.5em;
130 | }
131 |
132 | small,
133 | cite {
134 | color: $gray-500;
135 | display: block;
136 | font-size: 0.83333em;
137 | font-style: normal;
138 | font-weight: normal;
139 | margin-top: 0.6em;
140 | }
141 | }
142 |
143 | dl {
144 | margin: 0;
145 | }
146 |
147 | dt {
148 | font-weight: bold;
149 |
150 | .font-fira-sans & {
151 | font-weight: 600;
152 | }
153 | }
154 |
155 | ul,
156 | ol,
157 | dd {
158 | margin: 0 0 1em;
159 | }
160 |
161 | ul {
162 | list-style: disc;
163 | padding: 0 0 0 1.125em;
164 | }
165 |
166 | ol {
167 | list-style: decimal;
168 | padding: 0 0 0 1.5em;
169 | }
170 |
171 | li > ul,
172 | li > ol {
173 | margin-bottom: 0;
174 | }
175 |
176 | hr {
177 | background-color: $gray-200;
178 | border: 0;
179 | height: 1px;
180 | margin: 1.66667em 0;
181 |
182 | &:first-child {
183 | margin-top: 0;
184 | }
185 | }
186 |
187 | embed,
188 | iframe,
189 | object,
190 | video {
191 | max-width: 100%;
192 | }
193 |
194 | img {
195 | height: auto;
196 | max-width: 100%;
197 | }
--------------------------------------------------------------------------------
/content/pages/blog/azimuth-improvements.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Release Notes - Azimuth Improvements and New Integrations
3 | subtitle: >-
4 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa
5 | massa primis.
6 | author: content/data/authors/john-doe.yaml
7 | excerpt: >-
8 | Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan blandit accumsan
9 | sapien blandit ac amet faucibus aliquet placerat commodo.
10 | date: '2017-03-26'
11 | thumb_image: images/1_thumb.jpg
12 | seo:
13 | title: Release Notes - Azimuth Improvements and New Integrations
14 | description: >-
15 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa
16 | massa primis.
17 | extra:
18 | - name: 'og:type'
19 | value: article
20 | keyName: property
21 | - name: 'og:title'
22 | value: Release Notes - Azimuth Improvements and New Integrations
23 | keyName: property
24 | - name: 'og:description'
25 | value: >-
26 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum
27 | massa massa primis.
28 | keyName: property
29 | - name: 'og:image'
30 | value: images/1.jpg
31 | keyName: property
32 | relativeUrl: true
33 | - name: 'twitter:card'
34 | value: summary_large_image
35 | - name: 'twitter:title'
36 | value: Release Notes - Azimuth Improvements and New Integrations
37 | - name: 'twitter:description'
38 | value: >-
39 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum
40 | massa massa primis.
41 | - name: 'twitter:image'
42 | value: images/1.jpg
43 | relativeUrl: true
44 | layout: post
45 | ---
46 |
47 | Vis accumsan feugiat adipiscing nisl amet adipiscing accumsan blandit accumsan sapien blandit ac amet faucibus aliquet placerat commodo. Interdum ante aliquet commodo accumsan vis phasellus adipiscing. Ornare a in lacinia. Vestibulum accumsan ac metus massa tempor. Accumsan in lacinia ornare massa amet. Ac interdum ac non praesent. Cubilia lacinia interdum massa faucibus blandit nullam. Accumsan phasellus nunc integer. Accumsan euismod nunc adipiscing lacinia erat ut sit. Arcu amet. Id massa aliquet arcu accumsan lorem amet accumsan.
48 |
49 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa massa primis. Tempus condimentum tempus non ac varius cubilia adipiscing placerat lorem turpis at. Aliquet lorem porttitor interdum. Amet lacus. Aliquam lobortis faucibus blandit ac phasellus. In amet magna non interdum volutpat porttitor metus a ante ac neque. Nisi turpis. Commodo col. Interdum adipiscing mollis ut aliquam id ante adipiscing commodo integer arcu amet Ac interdum ac non praesent. Cubilia lacinia interdum massa faucibus blandit nullam. Accumsan phasellus nunc integer. Accumsan euismod nunc adipiscing lacinia erat ut sit. Arcu amet. Id massa aliquet arcu accumsan lorem amet accumsan commodo odio cubilia ac eu interdum placerat placerat arcu commodo lobortis adipiscing semper ornare pellentesque.
50 |
51 | Amet nibh adipiscing adipiscing. Commodo ante vis placerat interdum massa massa primis. Tempus condimentum tempus non ac varius cubilia adipiscing placerat lorem turpis at. Aliquet lorem porttitor interdum. Amet lacus. Aliquam lobortis faucibus blandit ac phasellus. In amet magna non interdum volutpat porttitor metus a ante ac neque. Nisi turpis. Commodo col. Interdum adipiscing mollis ut aliquam id ante adipiscing commodo integer arcu amet blandit adipiscing arcu ante.
52 |
--------------------------------------------------------------------------------
/content/pages/pricing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Pricing
3 | sections:
4 | - section_id: pricing
5 | type: section_pricing
6 | background: gray
7 | title: Pricing Plans
8 | subtitle: You can have a separate pricing page or list everything on the home page.
9 | pricing_plans:
10 | - title: Basic
11 | subtitle: For small businesses
12 | price: $5/m
13 | details: |-
14 | * Lorem ipsum dolor sit amet
15 | * Mauris a mi tincidunt
16 | * Suspendisse ut lacus
17 | * Etiam eget dui a augue
18 | actions:
19 | - label: Order Now
20 | url: /signup
21 | style: secondary
22 | - title: Professional
23 | subtitle: For medium-sized businesses
24 | price: $49/m
25 | details: |-
26 | * Curabitur non nunc mollis
27 | * Duis a purus nec ligula pellentesque dolor
28 | * Pellentesque sit amet
29 | * Fusce tempus mi vitae luctus
30 | * Nullam sollicitudin ante
31 | highlight: true
32 | actions:
33 | - label: Order Now
34 | url: /signup
35 | style: primary
36 | - title: Enterprise
37 | subtitle: For very large businesses
38 | price: $149/m
39 | details: |-
40 | * Vestibulum non eros quis
41 | * Aenean iaculis lorem
42 | * Mauris eleifend sapien
43 | * Phasellus lobortis risus laoreet quam
44 | actions:
45 | - label: Order Now
46 | url: /signup
47 | style: secondary
48 | - section_id: faq
49 | type: section_faq
50 | background: gray
51 | title: Frequently Asked Questions
52 | subtitle: 'Phasellus luctus laoreet arcu, vel porta metus imperdiet sit amet.'
53 | faq_items:
54 | - question: Mauris ut tellus id arcu sagittis lacinia quis vel justo?
55 | answer: >-
56 | Ut cursus, nunc vitae hendrerit viverra, massa ipsum congue quam, sed
57 | tempus mauris lacus sit amet nibh. Curabitur laoreet est maximus
58 | mollis feugiat. Praesent nibh libero, placerat et justo at, luctus
59 | tristique enim. Pellentesque habitant morbi tristique senectus et
60 | netus et malesuada fames ac turpis egestas.
61 | - question: Aliquam eget purus ante?
62 | answer: >-
63 | Nunc sollicitudin libero tincidunt felis pretium, consectetur aliquam
64 | eros placerat. Sed neque neque, bibendum a pulvinar id, pellentesque
65 | eget velit.
66 | - question: Sed scelerisque in ipsum eu sollicitudin?
67 | answer: >-
68 | Nullam quis ultrices ipsum. Integer eleifend laoreet quam, ac
69 | dignissim nisi mollis eget. Ut vitae nisi sit amet nisi suscipit
70 | dictum faucibus eget magna. Vivamus in hendrerit magna, non
71 | pellentesque metus. Morbi orci odio, dictum at efficitur sit amet,
72 | luctus in ipsum. Nunc pellentesque mi vel dui vulputate, a lobortis
73 | lacus venenatis. Phasellus pellentesque dolor id feugiat faucibus.
74 | Etiam vehicula nunc velit, in consequat nisl feugiat nec.
75 | seo:
76 | title: Pricing
77 | description: This is the pricing page
78 | extra:
79 | - name: 'og:type'
80 | value: website
81 | keyName: property
82 | - name: 'og:title'
83 | value: Pricing
84 | keyName: property
85 | - name: 'og:description'
86 | value: This is the pricing page
87 | keyName: property
88 | - name: 'twitter:card'
89 | value: summary_large_image
90 | - name: 'twitter:title'
91 | value: Pricing
92 | - name: 'twitter:description'
93 | value: This is the pricing page
94 | layout: landing
95 | ---
96 |
--------------------------------------------------------------------------------
/content/pages/blog/customer-service-skills-that-every-employee-needs.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 5 Customer Service Skills that Every Employee Needs
3 | subtitle: 'Apparently, there are 5 Service Skills that Every Employee Needs'
4 | author: content/data/authors/john-doe.yaml
5 | excerpt: >-
6 | Sed nec metus dignissim quam finibus aliquet. Cras luctus, nibh id consequat
7 | interdum, massa massa tempor ante.
8 | date: '2018-01-11'
9 | thumb_image: images/5_thumb.jpg
10 | image: images/5.jpg
11 | seo:
12 | title: 5 Customer Service Skills that Every Employee Needs
13 | description: 'Apparently, there are 5 Service Skills that Every Employee Needs'
14 | extra:
15 | - name: 'og:type'
16 | value: article
17 | keyName: property
18 | - name: 'og:title'
19 | value: 5 Customer Service Skills that Every Employee Needs
20 | keyName: property
21 | - name: 'og:description'
22 | value: 'Apparently, there are 5 Service Skills that Every Employee Needs'
23 | keyName: property
24 | - name: 'og:image'
25 | value: images/5.jpg
26 | keyName: property
27 | relativeUrl: true
28 | - name: 'twitter:card'
29 | value: summary_large_image
30 | - name: 'twitter:title'
31 | value: 5 Customer Service Skills that Every Employee Needs
32 | - name: 'twitter:description'
33 | value: 'Apparently, there are 5 Service Skills that Every Employee Needs'
34 | - name: 'twitter:image'
35 | value: images/5.jpg
36 | relativeUrl: true
37 | layout: post
38 | ---
39 |
40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. In dapibus est a dolor iaculis vulputate. Mauris libero nulla, commodo sit amet tempus quis, finibus cursus tellus. Duis non velit vel velit euismod elementum. Aliquam porta et nisl id mattis. Fusce vitae massa orci. Ut euismod ornare orci ac interdum. Morbi vulputate ullamcorper purus eu dictum. Vestibulum ac neque faucibus lectus egestas volutpat in vitae velit. Morbi elementum nibh libero, ac ultricies metus laoreet ac. Nam tempus ligula a nulla tincidunt, sit amet semper sapien condimentum.
41 |
42 | Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque aliquet ante sed odio pellentesque malesuada at id turpis. Nulla porta ipsum ac augue vulputate varius. Aenean tempor risus rhoncus congue egestas. Donec laoreet tempus tempus. Sed erat erat, elementum ut feugiat at, facilisis ut massa. Duis ultricies ex a mauris sodales euismod. Donec placerat bibendum arcu non rutrum. Praesent quis risus enim. Morbi efficitur lectus at diam cursus ultrices. Integer ut erat eget erat posuere interdum. Ut risus nunc, hendrerit a sagittis id, scelerisque sed ipsum.
43 |
44 | Sed nec metus dignissim quam finibus aliquet. Cras luctus, nibh id consequat interdum, massa massa tempor ante, in gravida dui quam at nibh. Nullam egestas purus nulla, vitae posuere turpis egestas nec. Nam at porttitor massa, sed luctus nibh. Vestibulum varius accumsan orci sed finibus. Quisque suscipit est nisl, et feugiat nunc dictum in. Maecenas pellentesque nulla vel sodales cursus. Nulla venenatis sem a dui sagittis vehicula.
45 |
46 | Etiam interdum finibus neque, vel bibendum diam volutpat et. Nunc volutpat ante at nibh tempus malesuada. Proin pretium sed tellus eget porttitor. Praesent convallis varius magna in pharetra. Nunc quis venenatis massa. In euismod dictum porta. Donec aliquam mauris dignissim odio auctor dictum.
47 |
48 | Suspendisse a dui auctor purus accumsan ullamcorper. In maximus nunc nec fermentum posuere. Cras id ipsum in elit consectetur elementum. Mauris mollis mollis orci non rutrum. Phasellus facilisis convallis hendrerit. Curabitur at erat id odio tincidunt placerat. Sed efficitur, lacus nec viverra dapibus, ligula libero commodo eros, eu aliquam nunc risus in nisi. Curabitur sed malesuada metus. Ut fringilla, arcu non bibendum ornare, justo erat condimentum neque, ut pulvinar leo leo interdum mauris. Integer nulla augue, rutrum vitae nulla quis, cursus mollis justo.
49 |
--------------------------------------------------------------------------------
/content/data/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "E-collect",
3 | "path_prefix": "/",
4 | "base_font": "nunito-sans",
5 | "palette": "blue",
6 | "header": {
7 | "logo_img": "images/logo.svg",
8 | "logo_img_alt": "Logo",
9 | "has_nav": true,
10 | "nav_links": [
11 | {
12 | "label": "Home",
13 | "url": "/",
14 | "style": "link"
15 | },
16 | {
17 | "label": "Solicita tu servicio",
18 | "url": "/contact",
19 | "style": "primary"
20 | }
21 | ]
22 | },
23 | "footer": {
24 | "sections": [
25 | {
26 | "type": "footer_text",
27 | "image": "images/logo-alt.svg",
28 | "image_url": "/",
29 | "image_alt": "Footer logo"
30 | },
31 | {
32 | "type": "footer_nav",
33 | "title": "Nosotros",
34 | "nav_links": [
35 | {
36 | "label": "About Us",
37 | "url": "/about",
38 | "style": "link"
39 | },
40 | {
41 | "label": "Solicita Servicio",
42 | "url": "/contact",
43 | "style": "link"
44 | }
45 | ]
46 | },
47 | {
48 | "type": "footer_nav",
49 | "title": "Community",
50 | "nav_links": [
51 | {
52 | "label": "Twitter",
53 | "url": "https://twitter.com/",
54 | "style": "link",
55 | "has_icon": true,
56 | "icon": "twitter",
57 | "icon_position": "left"
58 | },
59 | {
60 | "label": "LinkedIn",
61 | "url": "https://www.linkedin.com/",
62 | "style": "link",
63 | "has_icon": true,
64 | "icon": "linkedin",
65 | "icon_position": "left"
66 | },
67 | {
68 | "label": "GitHub",
69 | "url": "https://github.com/",
70 | "style": "link",
71 | "has_icon": true,
72 | "icon": "github",
73 | "icon_position": "left"
74 | }
75 | ]
76 | },
77 | {
78 | "type": "footer_form",
79 | "title": "Subscribe",
80 | "content": "Actualizate con nosotros",
81 | "form_id": "contactForm",
82 | "hide_labels": true,
83 | "form_fields": [
84 | {
85 | "input_type": "email",
86 | "name": "email",
87 | "label": "Email",
88 | "default_value": "Enter email address",
89 | "is_required": true
90 | }
91 | ],
92 | "submit_label": "Subscribir"
93 | }
94 | ],
95 | "has_nav": true,
96 | "nav_links": [
97 | {
98 | "label": "Terms of Service",
99 | "url": "/terms-of-service",
100 | "style": "link"
101 | },
102 | {
103 | "label": "Privacy Policy",
104 | "url": "/privacy-policy",
105 | "style": "link"
106 | }
107 | ],
108 | "content": "© E-collect. All rights reserved. This Jamstack site was created with 💚 and 🍕"
109 | }
110 | }
--------------------------------------------------------------------------------
/content/pages/blog/sales-as-service.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Sales as a Service
3 | subtitle: A interesting tale about Sales
4 | excerpt: >-
5 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elementum
6 | purus.
7 | author: content/data/authors/jane-doe.yaml
8 | date: '2018-01-15'
9 | thumb_image: images/4_thumb.jpg
10 | image: images/4.jpg
11 | seo:
12 | title: Sales as a Service
13 | description: A interesting tale about Sales
14 | extra:
15 | - name: 'og:type'
16 | value: article
17 | keyName: property
18 | - name: 'og:title'
19 | value: Sales as a Service
20 | keyName: property
21 | - name: 'og:description'
22 | value: A interesting tale about Sales
23 | keyName: property
24 | - name: 'og:image'
25 | value: images/4.jpg
26 | keyName: property
27 | relativeUrl: true
28 | - name: 'twitter:card'
29 | value: summary_large_image
30 | - name: 'twitter:title'
31 | value: Sales as a Service
32 | - name: 'twitter:description'
33 | value: A interesting tale about Sales
34 | - name: 'twitter:image'
35 | value: images/4.jpg
36 | relativeUrl: true
37 | layout: post
38 | ---
39 |
40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ut elementum purus. Aliquam mauris est, posuere vitae ornare quis, volutpat eget felis. Sed rhoncus hendrerit dapibus. Vestibulum sed turpis a turpis ultrices vehicula. Morbi vulputate eros eu vulputate maximus. Donec aliquam, nulla eget vestibulum luctus, nisi mi porttitor sem, ut varius ipsum nunc vel augue. Nam ante magna, tempor non sapien id, rhoncus vestibulum ipsum. Sed placerat quam sed rutrum efficitur. Duis diam purus, molestie viverra lectus eu, facilisis fringilla quam. Vivamus ut lectus id neque ullamcorper sollicitudin non sagittis massa. Quisque bibendum tincidunt dolor at interdum. Suspendisse vehicula quis sem et tincidunt.
41 |
42 | Donec tempor quis sapien sit amet tempor. Phasellus at erat erat. Vestibulum elementum venenatis porta. Proin non leo in ante dictum dictum. Integer suscipit euismod elit. Phasellus vel libero ante. Nunc varius felis in ex convallis, id luctus nulla feugiat. Proin imperdiet dictum erat, sed egestas augue elementum at. Nunc vel feugiat dolor. Cras et laoreet lorem. Aenean elementum tempor malesuada. Morbi quis commodo augue. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce ac pellentesque velit.
43 |
44 | Mauris a rhoncus purus, ac tincidunt dui. Phasellus lobortis rhoncus dolor, egestas hendrerit lorem lobortis nec. Duis eu condimentum felis. In eros mi, accumsan vitae nisl non, ultricies luctus risus. Proin vitae libero lacus. Nullam ut efficitur magna. Praesent quis eros ac augue blandit ultrices eu et leo. Sed molestie enim ipsum, et auctor diam suscipit vitae. Curabitur sed nisi sit amet lorem feugiat sodales. Etiam elementum ornare nisl eget porta. Donec nec facilisis lorem. Duis luctus elit eu purus fermentum, id pharetra nibh porttitor. Phasellus vel libero non erat mattis viverra.
45 |
46 | Donec et eros euismod tellus congue bibendum vitae sit amet lacus. Nam tempus at nunc eget elementum. Quisque tincidunt diam nulla, eget finibus risus dignissim ut. Fusce eget tincidunt mi, sit amet sollicitudin neque. Cras facilisis ex at massa pretium, ut sollicitudin neque rutrum. Quisque tincidunt purus congue, auctor augue quis, aliquet dui. Nullam orci risus, congue non faucibus in, blandit et leo. Suspendisse eu purus blandit, ultricies orci non, accumsan velit. Suspendisse convallis nisi et vehicula congue. Etiam iaculis nisi mauris, vel ultricies erat egestas quis. Vivamus eros urna, lacinia nec elit euismod, auctor cursus elit. Nunc lobortis hendrerit efficitur. Vivamus ultricies, metus et semper aliquet, ligula elit pulvinar nisi, non ultricies eros velit id felis. Phasellus blandit felis quam, id accumsan arcu luctus non.
47 |
48 | Aliquam blandit facilisis ultricies. Ut hendrerit tellus id nunc interdum vehicula. Proin feugiat arcu a mi mattis, in semper lectus sagittis. Mauris rhoncus vestibulum magna, nec vestibulum orci porta quis. Vivamus at ante ullamcorper, commodo risus vel, facilisis diam. Vivamus nec dui bibendum mauris consectetur hendrerit. Morbi a lacus in risus convallis cursus et ut leo. Aliquam vitae aliquam justo. Curabitur efficitur sapien vel dolor mollis interdum dignissim eget lorem. Maecenas aliquam molestie felis vel sollicitudin. Nulla auctor nisl mattis sapien pulvinar, vel sollicitudin eros pellentesque. Nullam bibendum at metus ac mollis.
49 |
50 |
51 |
--------------------------------------------------------------------------------
/content/pages/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Home
3 | sections:
4 | - section_id: hero
5 | type: section_hero
6 | image: images/hero.png
7 | image_alt: App preview
8 | title: E-collect
9 | content: >-
10 | Es el servicio delivery para reciclar y salvar el planeta.
11 | Gana dinero con nosotros. 💰
12 | actions:
13 | - label: Solicitar servicio
14 | url: /contact
15 | style: primary
16 | - section_id: VALUES FOR PROCUCT
17 | type: section_features
18 | background: gray
19 | title: Ven y miras cuanto cuesta tu "Basura"
20 | features:
21 | - title: Precio del Papel 📰
22 | image: images/dolar.png
23 | image_alt: App preview on a phone and tablet
24 | material: papel
25 | valueElement: >-
26 | 5
27 | content: >-
28 | Es el material más sencillo para reciclar, con él se hacen periodicos, cuadernos, carteles y papel, nuevamente.
29 | Este se puede demorar en desintregrarse 365 días
30 | - title: Precio del Metal 🔧
31 | image: images/dolar.png
32 | image_alt: App preview on a phone and tablet
33 | material: metal
34 | valueElement: >-
35 | 5
36 | content: >-
37 | El reciclaje de los metales contribuye significativamente a no empeorar el entorno medioambiental actual. Al reciclar chatarra, se reduce significativamente la contaminación de agua, aire y los desechos de la minería en un 70 por ciento
38 | - title: Precio del Vidrio 🧪
39 | image: images/dolar.png
40 | image_alt: App preview on a phone and tablet
41 | material: vidrio
42 | valueElement: >-
43 | 5
44 | content: >-
45 | Mediante el reciclaje se pueden convertir desechos de vidrio en materiales que servirán para la creación de nuevos productos útiles para la vida cotidiana
46 | - title: Precio del Plastico 🎮
47 | image: images/dolar.png
48 | image_alt: App preview on a phone and tablet
49 | material: plastico
50 | valueElement: >-
51 | 3
52 | content: >-
53 | Todos los plásticos son reciclables, siendo importante su separación por tipo de resina. Existen 7 categorías distintas: PET, PEAD, PVC, PEBD, PP, PS
54 | - section_id: reviews
55 | type: section_reviews
56 | background: white
57 | title: Tus vecinos ya están ganando
58 | subtitle: >-
59 | Algunos testimonios de personas que están teniendo ganancias con nosotros, ayudando al planeta 🌎
60 | reviews:
61 | - author: Mauricio Fajardo
62 | avatar: images/review1.jpg
63 | avatar_alt: Eric Widget's photo
64 | content: >-
65 | Llevo meses con ellos, super cumplidos y todo a tiempo. Me alegra estar salvando el planeta con ellos.
66 | - author: Melinda Arevalo
67 | avatar: images/review2.jpg
68 | avatar_alt: Parsley Montana's photo
69 | content: >-
70 | Antes hechaba todo con el recolector de mi ciudad, ahora gano dinero extra con este hermoso proyecto.
71 | - author: Jonquil Von
72 | avatar: images/review3.jpg
73 | avatar_alt: Jonquil Von Haggerston's photo
74 | content: >-
75 | Esto es maravilloso, las personas que trabajan en este proyecto son muy profesionales.
76 | - section_id: call-to-action
77 | type: section_cta
78 | title: Solicita tu servicio
79 | subtitle: Salva el planeta ganando dinero.
80 | actions:
81 | - label: Tengo material para reciclar
82 | url: /contact
83 | style: primary
84 | seo:
85 | title: E-collect
86 | description: Una empresa de reciclaje para el futuro
87 | extra:
88 | - name: 'og:type'
89 | value: website
90 | keyName: property
91 | - name: 'og:title'
92 | value: E-collect
93 | keyName: property
94 | - name: 'og:description'
95 | value: Una empresa de reciclaje para el futuro
96 | keyName: property
97 | - name: 'og:image'
98 | value: images/logo.svg
99 | keyName: property
100 | relativeUrl: true
101 | - name: 'twitter:card'
102 | value: summary_large_image
103 | - name: 'twitter:title'
104 | value: E-collect
105 | - name: 'twitter:description'
106 | value: Una empresa de reciclaje para el futuro
107 | - name: 'twitter:image'
108 | value: images/logo.svg
109 | relativeUrl: true
110 | layout: landing
111 | ---
112 |
--------------------------------------------------------------------------------
/content/pages/blog/user-journey-mapping.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: A Guide To User Journey Mapping
3 | subtitle: >-
4 | Praesent ut cursus enim, sit amet dictum turpis. Etiam justo orci, consectetur
5 | aliquet rhoncus sed, hendrerit vel odio.
6 | excerpt: >-
7 | Praesent ut cursus enim, sit amet dictum turpis. Etiam justo orci, consectetur
8 | aliquet rhoncus sed, hendrerit vel odio.
9 | author: content/data/authors/jane-doe.yaml
10 | date: '2019-03-27'
11 | thumb_image: images/10_thumb.jpg
12 | thumb_image_alt: Business people in a meeting
13 | image: images/10.jpg
14 | image_alt: Business people in a meeting
15 | seo:
16 | title: A Guide To User Journey Mapping
17 | description: A tale about Journey Mapping
18 | extra:
19 | - name: 'og:type'
20 | value: article
21 | keyName: property
22 | - name: 'og:title'
23 | value: A Guide To User Journey Mapping
24 | keyName: property
25 | - name: 'og:description'
26 | value: A tale about Journey Mapping
27 | keyName: property
28 | - name: 'og:image'
29 | value: images/10.jpg
30 | keyName: property
31 | relativeUrl: true
32 | - name: 'twitter:card'
33 | value: summary_large_image
34 | - name: 'twitter:title'
35 | value: A Guide To User Journey Mapping
36 | - name: 'twitter:description'
37 | value: A tale about Journey Mapping
38 | - name: 'twitter:image'
39 | value: images/10.jpg
40 | relativeUrl: true
41 | layout: post
42 | ---
43 |
44 | Curabitur sed consectetur nisi. Integer sit amet commodo massa. Cras posuere justo magna, id placerat ligula vulputate malesuada. Aenean a ipsum quis neque ornare placerat eu eu orci. Nullam feugiat sed ante in euismod. Pellentesque a nibh dolor. Donec ultrices lacus eget orci commodo ultricies. Morbi placerat purus non varius egestas. Ut tempus ligula quis lorem suscipit, sed vulputate dolor placerat. Aliquam ut massa placerat, vehicula erat non, mattis leo. Pellentesque egestas velit sit amet lectus lobortis, sit amet pharetra ipsum porta. Nullam massa nulla, tincidunt vel volutpat vel, commodo id leo. Curabitur id volutpat lacus, sed commodo velit. Quisque facilisis consectetur nisl vitae vulputate. Proin porttitor ipsum ut diam faucibus, scelerisque posuere ex euismod. Aenean posuere bibendum egestas.
45 |
46 | Praesent ut cursus enim, sit amet dictum turpis. Etiam justo orci, consectetur aliquet rhoncus sed, hendrerit vel odio. Etiam pharetra neque vel gravida tincidunt. Etiam consequat commodo elit id eleifend. Nullam eu justo eu odio pretium feugiat. Sed non neque dui. Fusce leo erat, imperdiet quis pulvinar vitae, consequat quis dolor. Curabitur eu quam et odio vehicula auctor convallis nec ipsum. Nam vitae dui sapien. Pellentesque vitae lorem id ipsum lacinia consectetur id a erat. Nulla semper ut erat vel vulputate. Nulla sagittis dui ut dapibus euismod. Phasellus et dui posuere, lobortis erat a, pretium nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas molestie ut tellus in convallis. Cras luctus urna quis velit volutpat, semper venenatis mauris auctor.
47 |
48 | Aenean dui sem, sollicitudin non venenatis eget, gravida rutrum risus. Proin massa leo, convallis id orci at, convallis dignissim mi. Integer et arcu arcu. Sed tristique diam id elit iaculis accumsan. Donec vehicula libero nunc, quis dictum orci pharetra nec. Proin blandit pellentesque sapien et sodales. Phasellus convallis sapien venenatis semper iaculis. Curabitur commodo iaculis mi, nec gravida nunc pellentesque ac. Nullam ac felis est. Donec gravida arcu ipsum, ut pulvinar est scelerisque id. Duis lobortis ante eu ante volutpat, quis pharetra sapien mattis. Sed ex enim, accumsan ut volutpat a, consectetur iaculis urna. Donec tempus enim sed porta euismod.
49 |
50 | Nam mauris leo, mattis in finibus sit amet, mattis vitae libero. In sed leo purus. Fusce ac suscipit nisl. Vestibulum tristique neque nec lacus finibus porta. In erat libero, pellentesque non sodales quis, mollis a elit. Vestibulum viverra dui ut ornare maximus. Aliquam at odio quis magna convallis euismod.
51 |
52 | Integer nisi nisi, hendrerit a ultrices ut, facilisis at odio. Suspendisse aliquet sed magna in bibendum. Praesent sit amet tincidunt purus. Cras sollicitudin at ante semper feugiat. Sed sem sem, dignissim id aliquet ac, interdum fringilla ipsum. Proin laoreet metus leo, et tempor felis aliquam at. Cras eget urna vehicula, elementum tellus a, tempor odio. Morbi pretium augue erat, et suscipit metus varius non. Quisque vitae lectus id mi consequat laoreet. Nam non molestie elit. Proin iaculis vel ex non rhoncus. Donec metus velit, blandit quis arcu quis, venenatis sodales velit.
53 |
--------------------------------------------------------------------------------
/content/pages/blog/set-big-goals.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Why You Should Set Big Goals
3 | excerpt: >-
4 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
5 | turpis egestas.
6 | author: content/data/authors/jane-doe.yaml
7 | date: '2019-03-10'
8 | thumb_image: images/12_thumb.jpg
9 | image: images/12.jpg
10 | seo:
11 | title: Why You Should Set Big Goals
12 | description: A interesting tale about Big Goals
13 | extra:
14 | - name: 'og:type'
15 | value: article
16 | keyName: property
17 | - name: 'og:title'
18 | value: Why You Should Set Big Goals
19 | keyName: property
20 | - name: 'og:description'
21 | value: A interesting tale about Big Goals
22 | keyName: property
23 | - name: 'og:image'
24 | value: images/12.jpg
25 | keyName: property
26 | relativeUrl: true
27 | - name: 'twitter:card'
28 | value: summary_large_image
29 | - name: 'twitter:title'
30 | value: Why You Should Set Big Goals
31 | - name: 'twitter:description'
32 | value: A interesting tale about Big Goals
33 | - name: 'twitter:image'
34 | value: images/12.jpg
35 | relativeUrl: true
36 | layout: post
37 | ---
38 |
39 | Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam maximus mauris sagittis, iaculis diam ac, ultrices risus. Aliquam finibus, ipsum eget ultricies imperdiet, arcu diam suscipit urna, eu bibendum tortor tellus vel risus. Praesent quis scelerisque velit. Curabitur varius erat non dignissim porta. Duis viverra sapien a metus semper, et porttitor dolor convallis. Nulla eu dolor volutpat, mollis arcu ut, semper ex. Morbi ultricies, quam et ullamcorper mattis, elit dolor facilisis dui, non consectetur erat elit eu sapien. Duis scelerisque ante iaculis, accumsan mi vel, tempus libero. Fusce quis ipsum in sapien consequat tempor. Duis varius blandit neque quis tempor. Sed sollicitudin ante vitae lectus feugiat tempus. Ut mauris ex, venenatis a vestibulum nec, ullamcorper a erat. Vivamus leo ipsum, porta in iaculis sit amet, euismod non mi.
40 |
41 | Curabitur sed tellus eu felis convallis cursus at vitae neque. Phasellus sem nulla, ornare sit amet augue quis, consectetur lobortis diam. Etiam in egestas orci. Curabitur scelerisque id ligula id rutrum. Maecenas pharetra sapien et hendrerit facilisis. Vestibulum finibus mauris et ultricies porta. Praesent laoreet mauris elit, a semper risus euismod at. Pellentesque ullamcorper augue augue, eget porta nisl volutpat nec. Mauris porttitor commodo tortor eu tincidunt. Ut ut enim iaculis, aliquam augue ut, cursus tortor.
42 |
43 | Cras interdum commodo commodo. Nunc condimentum, eros id consectetur tincidunt, metus ligula venenatis urna, sit amet pharetra dui purus sed tellus. Suspendisse finibus gravida risus, vel sodales nisl fringilla consequat. Aliquam sit amet mollis lorem. Suspendisse dignissim mi tortor, quis iaculis nulla fermentum ut. Nunc laoreet augue vitae aliquet aliquet. Praesent dapibus at dui sit amet interdum. Fusce finibus risus in nibh ultricies, a bibendum lacus pulvinar.
44 |
45 | Proin viverra, ex ut ullamcorper finibus, purus odio porttitor neque, in blandit lectus massa vel massa. Etiam vel mauris ligula. Sed dignissim tellus vel ex tincidunt, eget tempus metus lobortis. In ex felis, fermentum ut ultrices in, consequat ut justo. Etiam ullamcorper, risus nec facilisis porta, ex quam mattis nisi, id consequat turpis massa non dolor. Vestibulum lectus ante, scelerisque quis tempor et, mattis eu justo. Sed ante orci, feugiat aliquet malesuada sed, efficitur ac ex. Morbi ex nisi, tempor eu congue quis, ultrices id justo. Etiam urna libero, porttitor at imperdiet at, ultricies ac erat. Pellentesque est nibh, volutpat nec tempus et, luctus vel urna. Cras faucibus dolor feugiat velit convallis, sit amet consectetur eros tempor. Integer mi elit, semper sed facilisis vel, convallis ut turpis.
46 |
47 | Curabitur sed consectetur nisi. Integer sit amet commodo massa. Cras posuere justo magna, id placerat ligula vulputate malesuada. Aenean a ipsum quis neque ornare placerat eu eu orci. Nullam feugiat sed ante in euismod. Pellentesque a nibh dolor. Donec ultrices lacus eget orci commodo ultricies. Morbi placerat purus non varius egestas. Ut tempus ligula quis lorem suscipit, sed vulputate dolor placerat. Aliquam ut massa placerat, vehicula erat non, mattis leo. Pellentesque egestas velit sit amet lectus lobortis, sit amet pharetra ipsum porta. Nullam massa nulla, tincidunt vel volutpat vel, commodo id leo. Curabitur id volutpat lacus, sed commodo velit. Quisque facilisis consectetur nisl vitae vulputate. Proin porttitor ipsum ut diam faucibus, scelerisque posuere ex euismod. Aenean posuere bibendum egestas.
48 |
--------------------------------------------------------------------------------
/content/pages/blog/working-from-home.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: The Advantages and Disadvantages of Working from Home
3 | excerpt: >-
4 | Work at home parent is an entrepreneur who works from home and integrates
5 | parenting into his or her business activities.
6 | author: content/data/authors/jane-doe.yaml
7 | date: '2020-04-22'
8 | thumb_image: images/9_thumb.jpg
9 | thumb_image_alt: People in a conference room
10 | image: images/9.jpg
11 | image_alt: People in a conference room
12 | seo:
13 | title: The Advantages and Disadvantages of Working from Home
14 | description: A tale about advantages and disadvantages of working from home
15 | extra:
16 | - name: 'og:type'
17 | value: article
18 | keyName: property
19 | - name: 'og:title'
20 | value: The Advantages and Disadvantages of Working from Home
21 | keyName: property
22 | - name: 'og:description'
23 | value: A tale about advantages and disadvantages of working from home
24 | keyName: property
25 | - name: 'og:image'
26 | value: images/9.jpg
27 | keyName: property
28 | relativeUrl: true
29 | - name: 'twitter:card'
30 | value: summary_large_image
31 | - name: 'twitter:title'
32 | value: The Advantages and Disadvantages of Working from Home
33 | - name: 'twitter:description'
34 | value: A tale about advantages and disadvantages of working from home
35 | - name: 'twitter:image'
36 | value: images/9.jpg
37 | relativeUrl: true
38 | layout: post
39 | ---
40 |
41 | **Working from home** convallis aenean et tortor at risus viverra adipiscing at in. Maecenas accumsan lacus vel facilisis volutpat est. Nisl suscipit adipiscing bibendum est ultricies. Nulla facilisi cras fermentum odio eu feugiat pretium. Donec ac odio tempor orci dapibus. Eget velit aliquet sagittis id. Morbi non arcu risus quis varius quam quisque id diam. Facilisis gravida neque convallis a cras semper auctor neque vitae. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla aliquet. Aliquam vestibulum morbi blandit cursus risus. Eget mauris pharetra et ultrices neque ornare.
42 |
43 | ## Advantages and Disadvantages
44 |
45 | Dignissim diam quis enim lobortis scelerisque. Vitae elementum curabitur vitae nunc. Ultrices neque ornare aenean euismod elementum nisi quis eleifend quam. Et ligula ullamcorper malesuada proin libero nunc consequat interdum. Quam lacus suspendisse faucibus interdum posuere. Bibendum arcu vitae elementum curabitur vitae nunc. Ullamcorper malesuada proin libero nunc. Sit amet risus nullam eget felis eget nunc lobortis. Elementum curabitur vitae nunc sed velit dignissim sodales. Turpis in eu mi bibendum neque egestas congue quisque egestas.
46 |
47 | > Success is no accident. It is hard work, perseverance, learning, studying, sacrifice and most of all, love of what you are doing or learning to do. - Pele
48 |
49 | Fermentum iaculis eu non diam. Lorem sed risus ultricies tristique nulla aliquet enim tortor. Viverra nam libero justo laoreet sit amet cursus. Interdum consectetur libero id faucibus nisl tincidunt eget nullam. Aliquet sagittis id consectetur purus ut. Iaculis eu non diam phasellus. Ipsum dolor sit amet consectetur adipiscing elit duis. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec. Dictum sit amet justo donec enim diam. Ultrices eros in cursus turpis massa tincidunt dui. Adipiscing elit ut aliquam purus sit.
50 |
51 | ## Types Of Work
52 |
53 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Felis donec et odio pellentesque diam volutpat. A diam maecenas sed enim ut sem viverra aliquet. Felis eget nunc lobortis mattis aliquam faucibus. Urna cursus eget nunc scelerisque viverra mauris. Pellentesque elit ullamcorper dignissim cras tincidunt lobortis. Ac tincidunt vitae semper quis lectus nulla at volutpat diam. Sapien faucibus et molestie ac feugiat sed lectus vestibulum. Ac turpis egestas sed tempus urna et pharetra pharetra massa. Vitae semper quis lectus nulla. Velit sed ullamcorper morbi tincidunt ornare. A arcu cursus vitae congue mauris. Amet nulla facilisi morbi tempus iaculis urna.
54 |
55 | Fermentum iaculis eu non diam. Lorem sed risus ultricies tristique nulla aliquet enim tortor. Viverra nam libero justo laoreet sit amet cursus. Interdum consectetur libero id faucibus nisl tincidunt eget nullam. Aliquet sagittis id consectetur purus ut. Iaculis eu non diam phasellus. Ipsum dolor sit amet consectetur adipiscing elit duis. Fringilla phasellus faucibus scelerisque eleifend donec pretium vulputate sapien nec. Dictum sit amet justo donec enim diam. Ultrices eros in cursus turpis massa tincidunt dui. Adipiscing elit ut aliquam purus sit.
56 |
--------------------------------------------------------------------------------
/content/pages/style-guide.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Style Guide
3 | subtitle: >-
4 | The style guide provides you with a blueprint of default post and page styles.
5 | The style guide is also a great reference for suggested typographic treatment
6 | and styles for your content.
7 | seo:
8 | title: Style Guide
9 | description: This is the style guide page
10 | extra:
11 | - name: 'og:type'
12 | value: website
13 | keyName: property
14 | - name: 'og:title'
15 | value: Style Guide
16 | keyName: property
17 | - name: 'og:description'
18 | value: This is the style guide page
19 | keyName: property
20 | - name: 'twitter:card'
21 | value: summary_large_image
22 | - name: 'twitter:title'
23 | value: Style Guide
24 | - name: 'twitter:description'
25 | value: This is the style guide page
26 | layout: page
27 | ---
28 |
29 | **This is a paragraph**. Pellentesque habitant morbi *tristique senectus et netus et malesuada* fames ac turpis egestas. Vestibulum [tortor quam](https://www.google.com), feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi.
30 |
31 | # This is an H1
32 |
33 | Quisque facilisis erat a dui. Nam malesuada ornare dolor. Cras gravida, this is marked text ornare, erat elit consectetuer erat, id egestas pede nibh eget odio. Proin tincidunt, velit vel porta elementum, magna diam molestie sapien, non aliquet massa pede eu diam. Aliquam iaculis. Fusce et ipsum et nulla tristique facilisis.
34 |
35 | ## This is an H2
36 |
37 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. Nulla libero.
38 |
39 | ### This is an H3
40 |
41 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. Nulla libero.
42 |
43 | #### This is an H4
44 |
45 | Quisque facilisis erat a dui. Nam malesuada ornare dolor. Cras gravida, diam sit amet rhoncus ornare, erat elit consectetuer erat, id egestas pede nibh eget odio. Proin tincidunt, velit vel porta elementum, magna diam molestie sapien, non aliquet massa pede eu diam. Aliquam iaculis.
46 |
47 | ## Quoting
48 |
49 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. Nulla libero.
50 |
51 | >“Creativity is allowing yourself to make mistakes. Design is knowing which ones to keep.”
52 |
53 | Nunc a lorem tellus. Aenean eu auctor purus. Cras pulvinar, nunc at sagittis dignissim, orci elit auctor leo, et consectetur est turpis a nunc. Vivamus in faucibus felis. Aenean rutrum magna at ex auctor, congue efficitur ligula feugiat. Proin a egestas arcu.
54 |
55 |
56 |
57 | ## Unordered Lists
58 |
59 | + Donec non tortor in arcu mollis feugiat
60 | + Lorem ipsum dolor sit amet, consectetuer adipiscing elit
61 | + Donec id eros eget quam aliquam gravida
62 | + Vivamus convallis urna id felis
63 | + Nulla porta tempus sapien
64 |
65 | ## Ordered Lists
66 |
67 | 1. Donec non tortor in arcu mollis feugiat
68 | 2. Lorem ipsum dolor sit amet, consectetuer adipiscing elit
69 | 3. Donec id eros eget quam aliquam gravida
70 | 4. Vivamus convallis urna id felis
71 | 5. Nulla porta tempus sapien
72 |
73 | ## Code Blocks
74 |
75 | Blocks of code are either fenced by lines with three back-ticks, or are indented with four spaces.
76 |
77 | ```
78 |
79 | body {
80 | color:red;
81 | }
82 | ```
83 |
84 | ## Tables
85 |
86 |
87 | Table with thead, tfoot, and tbody
88 |
89 |
90 | Header content 1
91 | Header content 2
92 |
93 |
94 |
95 |
96 | Body content 1
97 | Body content 2
98 |
99 |
100 |
101 |
102 | Footer content 1
103 | Footer content 2
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/content/pages/blog/customer-loyalty.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Customer Loyalty Programs That Stick
3 | subtitle: A story about customer loyalty
4 | author: content/data/authors/jane-doe.yaml
5 | excerpt: >-
6 | A story about customer loyalty curabitur sed consectetur nisi. Integer sit
7 | amet commodo massa.
8 | date: '2021-01-03'
9 | thumb_image: images/3_thumb.jpg
10 | thumb_image_alt: A group of people working in a cafe
11 | image: images/3.jpg
12 | image_alt: A group of people working in a cafe
13 | seo:
14 | title: Customer Loyalty Programs That Stick
15 | description: >-
16 | A story about customer loyalty curabitur sed consectetur nisi. Integer sit
17 | amet commodo massa.
18 | extra:
19 | - name: 'og:type'
20 | value: article
21 | keyName: property
22 | - name: 'og:title'
23 | value: Customer Loyalty Programs That Stick
24 | keyName: property
25 | - name: 'og:description'
26 | value: >-
27 | A story about customer loyalty curabitur sed consectetur nisi. Integer
28 | sit amet commodo massa.
29 | keyName: property
30 | - name: 'og:image'
31 | value: images/3.jpg
32 | keyName: property
33 | relativeUrl: true
34 | - name: 'twitter:card'
35 | value: summary_large_image
36 | - name: 'twitter:title'
37 | value: Customer Loyalty Programs That Stick
38 | - name: 'twitter:description'
39 | value: >-
40 | A story about customer loyalty curabitur sed consectetur nisi. Integer
41 | sit amet commodo massa.
42 | - name: 'twitter:image'
43 | value: images/3.jpg
44 | relativeUrl: true
45 | layout: post
46 | ---
47 |
48 | **Loyalty** curabitur sed consectetur nisi. Integer sit amet commodo massa. Cras posuere justo magna, id placerat ligula vulputate malesuada. Aenean a ipsum quis neque ornare placerat eu eu orci. Nullam feugiat sed ante in euismod. Pellentesque a nibh dolor. Donec ultrices lacus eget orci commodo ultricies. Morbi placerat purus non varius egestas. Ut tempus ligula quis lorem suscipit, sed vulputate dolor placerat. Aliquam ut massa placerat, vehicula erat non, mattis leo. Pellentesque egestas velit sit amet lectus lobortis, sit amet pharetra ipsum porta. Nullam massa nulla, tincidunt vel volutpat vel, commodo id leo. Curabitur id volutpat lacus, sed commodo velit. Quisque facilisis consectetur nisl vitae vulputate. Proin porttitor ipsum ut diam faucibus, scelerisque posuere ex euismod. Aenean posuere bibendum egestas.
49 |
50 | ## Customer
51 |
52 | Praesent ut cursus enim, sit amet dictum turpis. Etiam justo orci, consectetur aliquet rhoncus sed, hendrerit vel odio. Etiam pharetra neque vel gravida tincidunt. Etiam consequat commodo elit id eleifend. Nullam eu justo eu odio pretium feugiat. Sed non neque dui. Fusce leo erat, imperdiet quis pulvinar vitae, consequat quis dolor. Curabitur eu quam et odio vehicula auctor convallis nec ipsum. Nam vitae dui sapien. Pellentesque vitae lorem id ipsum lacinia consectetur id a erat. Nulla semper ut erat vel vulputate. Nulla sagittis dui ut dapibus euismod. Phasellus et dui posuere, lobortis erat a, pretium nunc. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas molestie ut tellus in convallis. Cras luctus urna quis velit volutpat, semper venenatis mauris auctor.
53 |
54 | ## Loyalty Programs
55 |
56 | Aenean dui sem, sollicitudin non venenatis eget, gravida rutrum risus. Proin massa leo, convallis id orci at, convallis dignissim mi. Integer et arcu arcu. Sed tristique diam id elit iaculis accumsan. Donec vehicula libero nunc, quis dictum orci pharetra nec. Proin blandit pellentesque sapien et sodales. Phasellus convallis sapien venenatis semper iaculis. Curabitur commodo iaculis mi, nec gravida nunc pellentesque ac. Nullam ac felis est. Donec gravida arcu ipsum, ut pulvinar est scelerisque id. Duis lobortis ante eu ante volutpat, quis pharetra sapien mattis. Sed ex enim, accumsan ut volutpat a, consectetur iaculis urna. Donec tempus enim sed porta euismod.
57 |
58 | > The strength of brand loyalty begins with how your product makes people feel. - Jay Samit
59 |
60 | Nam mauris leo, mattis in finibus sit amet, mattis vitae libero. In sed leo purus. Fusce ac suscipit nisl. Vestibulum tristique neque nec lacus finibus porta. In erat libero, pellentesque non sodales quis, mollis a elit. Vestibulum viverra dui ut ornare maximus. Aliquam at odio quis magna convallis euismod.
61 |
62 | Integer nisi nisi, hendrerit a ultrices ut, facilisis at odio. Suspendisse aliquet sed magna in bibendum. Praesent sit amet tincidunt purus. Cras sollicitudin at ante semper feugiat. Sed sem sem, dignissim id aliquet ac, interdum fringilla ipsum. Proin laoreet metus leo, et tempor felis aliquam at. Cras eget urna vehicula, elementum tellus a, tempor odio. Morbi pretium augue erat, et suscipit metus varius non. Quisque vitae lectus id mi consequat laoreet. Nam non molestie elit. Proin iaculis vel ex non rhoncus. Donec metus velit, blandit quis arcu quis, venenatis sodales velit.
63 |
--------------------------------------------------------------------------------
/src/components/Layout.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Helmet } from 'react-helmet';
3 | import Router from 'next/router';
4 | import _ from 'lodash';
5 |
6 | import { withPrefix, classNames } from '../utils';
7 | import Header from './Header';
8 | import Footer from './Footer';
9 |
10 | export default class Body extends React.Component {
11 | constructor(props) {
12 | super(props);
13 | this.handleRouteChange = this.handleRouteChange.bind(this);
14 | }
15 |
16 | componentDidMount() {
17 | // Sticky header
18 | let offsetY = 0;
19 | let ticking = false;
20 |
21 | window.addEventListener('scroll', function (e) {
22 | offsetY = window.scrollY;
23 | if (!ticking) {
24 | window.requestAnimationFrame(function () {
25 | handleHeader(offsetY);
26 | ticking = false;
27 | });
28 | ticking = true;
29 | }
30 | });
31 |
32 | function handleHeader(scrollPos) {
33 | if (scrollPos > 0) {
34 | document.body.classList.add('has--scrolled');
35 | } else {
36 | document.body.classList.remove('has--scrolled');
37 | }
38 | }
39 |
40 | Router.events.on('routeChangeStart', this.handleRouteChange);
41 | }
42 |
43 | componentWillUnmount() {
44 | Router.events.off('routeChangeStart', this.handleRouteChange);
45 | }
46 |
47 | handleRouteChange() {
48 | // Responsive video embeds
49 | const videoEmbeds = ['iframe[src*="youtube.com"]', 'iframe[src*="vimeo.com"]'];
50 | reframe(videoEmbeds.join(','));
51 | }
52 |
53 | render() {
54 | const page = _.get(this.props, 'page');
55 | const config = _.get(this.props, 'config');
56 | const font = _.get(config, 'base_font', 'nunito-sans');
57 | const favIcon = _.get(config, 'favicon');
58 | const palette = _.get(config, 'palette', 'blue');
59 | const domain = _.trim(_.get(config, 'domain', ''), '/');
60 | const configTitle = _.get(config, 'title');
61 | const pageTitle = _.get(page, 'title');
62 | const seo = _.get(page, 'seo');
63 | const seoTitle = _.get(seo, 'title');
64 | const title = seoTitle ? seoTitle : [pageTitle, configTitle].join(' | ');
65 | const seoDescription = _.get(seo, 'description');
66 | const seoRobots = _.get(seo, 'robots', []).join(',');
67 | const seoExtra = _.get(seo, 'extra', []).map((meta, metaIdx) => {
68 | const keyName = _.get(meta, 'keyName', 'name');
69 | const name = _.get(meta, 'name');
70 | if (!name) {
71 | return null;
72 | }
73 | const nameAttr = { [keyName]: name };
74 | const relativeUrl = _.get(meta, 'relativeUrl');
75 | let value = _.get(meta, 'value');
76 | if (!value) {
77 | return null;
78 | }
79 | if (relativeUrl) {
80 | value = domain + withPrefix(value);
81 | }
82 | return ;
83 | });
84 |
85 | return (
86 |
87 |
88 | {title}
89 |
90 |
91 |
92 | {seoDescription && }
93 | {!_.isEmpty(seoRobots) && }
94 | {seoExtra}
95 | {font !== 'system-sans' && }
96 | {font === 'nunito-sans' && (
97 |
98 | )}
99 | {font === 'fira-sans' && (
100 |
101 | )}
102 | {favIcon && }
103 |
104 |
105 |
106 |
107 |
108 | {this.props.children}
109 |
110 |
111 |
112 |
113 | );
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/sass/imports/_header.scss:
--------------------------------------------------------------------------------
1 | .site-header {
2 | background: #fff;
3 | color: $gray-700;
4 | padding-bottom: 1em;
5 | padding-top: 1em;
6 |
7 | a {
8 | text-decoration: none;
9 | }
10 | }
11 |
12 | .site-header-inside {
13 | -ms-flex-align: center;
14 | align-items: center;
15 | display: -ms-flexbox;
16 | display: flex;
17 | }
18 |
19 | .site-branding {
20 | -ms-flex: 0 0 auto;
21 | flex: 0 0 auto;
22 | }
23 |
24 | .site-title {
25 | color: $gray-700;
26 | font-size: 1.33333em;
27 | font-weight: bold;
28 | line-height: 1.2;
29 | margin: 0;
30 |
31 | .font-fira-sans & {
32 | font-weight: 600;
33 | }
34 | }
35 |
36 | .site-logo {
37 | margin: 0;
38 |
39 | img {
40 | max-height: 40px;
41 | height: 40px;
42 | }
43 | }
44 |
45 | .site-navigation {
46 | .button {
47 | font-size: 1em;
48 | }
49 | }
50 |
51 | #masthead {
52 | .site-branding {
53 | a {
54 | color: inherit;
55 | }
56 | }
57 |
58 | .site-navigation {
59 | .current-menu-item {
60 | color: $gray-500;
61 | }
62 |
63 | a:not(.button) {
64 | color: inherit;
65 |
66 | &:hover {
67 | color: $gray-500;
68 | }
69 | }
70 | }
71 | }
72 |
73 | @media only screen and (min-width: 801px) {
74 | .menu-toggle {
75 | display: none;
76 | }
77 |
78 | .site-navigation {
79 | margin-left: auto;
80 |
81 | .menu-item {
82 | display: inline-block;
83 | margin: 0 0 0 1.875em;
84 | }
85 |
86 | .button {
87 | padding: 0.25em 0.9375em;
88 | }
89 |
90 | .menu-button + .menu-button {
91 | margin-left: 0.9375em;
92 | }
93 | }
94 |
95 | @supports (position: sticky) or (position: -webkit-sticky) {
96 | .site-header {
97 | background: #fff;
98 | position: -webkit-sticky;
99 | position: sticky;
100 | top:0;
101 | z-index: 999;
102 |
103 | .has--scrolled & {
104 | box-shadow: $box-shadow-sm;
105 | }
106 | }
107 | }
108 | }
109 |
110 | @media only screen and (max-width: 800px) {
111 | .site {
112 | overflow: hidden;
113 | position: relative;
114 | }
115 |
116 | .site-header {
117 | &:before {
118 | background: rgba($gray-100, .75);
119 | content: "";
120 | height: 100vh;
121 | left: 0;
122 | opacity: 0;
123 | position: absolute;
124 | top: 0;
125 | -webkit-transition: opacity .15s ease-in-out,visibility 0s ease-in-out .15s;
126 | transition: opacity .15s ease-in-out,visibility 0s ease-in-out .15s;
127 | visibility: hidden;
128 | width: 100%;
129 | z-index: 998;
130 | }
131 | }
132 |
133 | .menu-toggle {
134 | background: 0;
135 | border: 0;
136 | box-shadow: none;
137 | color: inherit;
138 | display: block;
139 | cursor: pointer;
140 | font-size: inherit;
141 | height: 1.66667rem;
142 | padding: 0;
143 | position: relative;
144 | width: 1.66667rem;
145 |
146 | &:hover,
147 | &:focus,
148 | &:active {
149 | outline: 0;
150 | }
151 | }
152 |
153 | #menu-open {
154 | margin-left: auto;
155 | }
156 |
157 | #menu-close {
158 | position: absolute;
159 | right: 1rem;
160 | top: 1rem;
161 | }
162 |
163 | .site-navigation {
164 | background: #fff;
165 | box-sizing: border-box;
166 | height: 100vh;
167 | -webkit-overflow-scrolling: touch;
168 | position: absolute;
169 | right: -400px;
170 | top: 0;
171 | -webkit-transition: right .3s ease-in-out, visibility 0s .3s ease-in-out;
172 | transition: right .3s ease-in-out, visibility 0s .3s ease-in-out;
173 | visibility: hidden;
174 | width: 400px;
175 | z-index: 999;
176 |
177 | .menu {
178 | padding: 3.66667em $container-padding 2.5em;
179 | }
180 |
181 | .menu-item {
182 | &:not(.menu-button) {
183 | border-bottom: 1px solid $gray-200;
184 |
185 | &:first-child {
186 | border-top: 1px solid $gray-200;
187 | }
188 | }
189 |
190 | &.menu-button {
191 | margin-top: 1.66667em;
192 | }
193 | }
194 |
195 | a {
196 | &:not(.button) {
197 | display: block;
198 | padding: 0.75em 0;
199 | }
200 | }
201 |
202 | .button {
203 | width: 100%;
204 | }
205 | }
206 |
207 | .site-nav-inside {
208 | height: 100%;
209 | overflow: auto;
210 | -webkit-overflow-scrolling: touch;
211 | position: relative;
212 | }
213 |
214 | .menu--opened {
215 | .site {
216 | height: 100%;
217 | left: 0;
218 | overflow: hidden;
219 | position: fixed;
220 | top: 0;
221 | -webkit-transform: translate3d(0, 0, 0);
222 | transform: translate3d(0, 0, 0);
223 | width: 100%;
224 | z-index: 997;
225 | }
226 |
227 | .site-navigation {
228 | right: 0;
229 | -webkit-transition: right .3s ease-in-out;
230 | transition: right .3s ease-in-out;
231 | visibility: visible;
232 | }
233 |
234 | .site-header {
235 | &:before {
236 | opacity: 1;
237 | -webkit-transition-delay: 0s;
238 | transition-delay: 0s;
239 | visibility: visible;
240 | }
241 | }
242 | }
243 | }
244 |
245 | @media only screen and (max-width: 400px) {
246 | .site-navigation {
247 | width: 100%;
248 | }
249 |
250 | #menu-close {
251 | right: $container-padding;
252 | top: $container-padding;
253 | }
254 | }
255 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Router from 'next/router';
3 | import _ from 'lodash';
4 |
5 | import { Link, withPrefix, classNames, getPageUrl } from '../utils';
6 | import Action from './Action';
7 |
8 | export default class Header extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.handleWindowResize = this.handleWindowResize.bind(this);
12 | this.handleRouteChange = this.handleRouteChange.bind(this);
13 | this.menuOpenRef = React.createRef();
14 | }
15 |
16 | componentDidMount() {
17 | window.addEventListener('resize', this.handleWindowResize, true);
18 | Router.events.on('routeChangeStart', this.handleRouteChange);
19 | }
20 |
21 | componentWillUnmount() {
22 | window.removeEventListener('resize', this.handleWindowResize, true);
23 | Router.events.off('routeChangeStart', this.handleRouteChange);
24 | }
25 |
26 | handleWindowResize() {
27 | const menuOpenElm = _.get(this.menuOpenRef, 'current.offsetParent');
28 | if (menuOpenElm === null) {
29 | document.body.classList.remove('menu--opened');
30 | }
31 | }
32 |
33 | handleRouteChange() {
34 | document.body.classList.remove('menu--opened');
35 | }
36 |
37 | handleMenuOpen(event) {
38 | event.preventDefault();
39 | document.body.classList.add('menu--opened');
40 | }
41 |
42 | handleMenuClose(event) {
43 | event.preventDefault();
44 | document.body.classList.remove('menu--opened');
45 | }
46 |
47 | renderNavLinks(navLinks, pageUrl) {
48 | return (
49 |
50 |
51 |
52 |
56 |
57 | {_.map(navLinks, (action, actionIdx) => {
58 | const actionUrl = _.trim(_.get(action, 'url'), '/');
59 | const actionStyle = _.get(action, 'style', 'link');
60 | return (
61 |
68 |
69 |
70 | );
71 | })}
72 |
73 |
74 |
75 |
79 |
80 | );
81 | }
82 |
83 | render() {
84 | const config = _.get(this.props, 'config');
85 | const page = _.get(this.props, 'page');
86 | const configTitle = _.get(config, 'title');
87 | const header = _.get(config, 'header');
88 | const hasNav = _.get(header, 'has_nav');
89 | const navLinks = _.get(header, 'nav_links');
90 | const logoImage = _.get(header, 'logo_img');
91 | const logoImageAlt = _.get(header, 'logo_img_alt');
92 | const pageTemplate = _.get(page, 'template');
93 | const pageUrl = _.trim(getPageUrl(page), '/');
94 |
95 | return (
96 |
121 | );
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/components/Icon.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import _ from 'lodash';
3 |
4 | export default class Icon extends React.Component {
5 | render() {
6 | const icon = _.get(this.props, 'icon');
7 | return (
8 |
9 | {icon === 'arrow-left' ? (
10 |
11 | ) : icon === 'arrow-right' ? (
12 |
13 | ) : icon === 'envelope' ? (
14 |
15 | ) : icon === 'facebook' ? (
16 |
17 | ) : icon === 'github' ? (
18 |
19 | ) : icon === 'instagram' ? (
20 |
21 | ) : icon === 'linkedin' ? (
22 |
23 | ) : icon === 'twitter' ? (
24 |
25 | ) : icon === 'youtube' ? (
26 |
27 | ) : (
28 | icon === 'vimeo' && (
29 |
30 | )
31 | )}
32 |
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # License Agreement
2 | ##### Version 1.02 (02/14/2019)
3 |
4 | This Single Project License Agreement (**“Agreement”**) is between you and Stackbit Inc., a Delaware corporation (“Stackbit”) and governs Your right to use the website project including website theme and other media content (the "Project") obtained from or generated using our services available at www.stackbit.com (the "Services"). By clicking on the “Create Account” button (or any similar button) that is presented to you at the time of sign-up or by using the Site to generate a Project, you indicate that you agree to the terms and conditions of this Agreement. If You are accepting this Agreement on behalf of Your employer or other organization, You are agreeing to these terms for the entity and You represent and warrant that You have authority to bind such entity (party bound to this Agreement is referred to as “You”).
5 |
6 | 1. **Definitions**. The capitalized terms shall have the meaning given in the relevant paragraph where such term is defined. In addition, the following terms shall have the meaning set forth below.
7 |
8 | **“Client"** means the person or entity whose website you are designing if you are a web developer, web designer, agency or a marketing agent.
9 |
10 | **“Theme”** means the website theme made available on the Site and generated using the Services, in HTML/JS/CSS electronic source code format together with any related developer documentation.
11 |
12 | **“Project”** means any work that includes a Theme or that is derived from or is a ‘derivative work’ of a Theme, as such terms are used under the United States Copyright Act of 1976, as amended.
13 |
14 | 2. **License**. Subject to the terms and conditions of this Agreement, Stackbit hereby grants you a perpetual, non-exclusive, non-transferable, non-sublicensable limited license to use, modify, and display the Theme only as incorporated in a single Project as set forth in Section 3 below. All rights not granted herein are expressly reserved by Stackbit.
15 |
16 | 3. **Permitted Use**
17 |
18 | You may use the Theme as it is incorporated into a single Project, either your own Project or the Project of your Client, and You may make modifications to the Theme necessary to fit the requirements of the Project provided that the Project and the use of the Project by You or the Client remains subject to this Agreement. You will own the Project you create, but Stackbit retains all right, title and interest in and to the Theme and other media content that are incorporated in your Project. You must retain and include all copyright notices and the terms of this License without modification in the files of the Project. You and Client must use the Project in compliance with all applicable federal, state and local laws, rules and regulations.
19 |
20 | 4. **Prohibited Uses**
21 |
22 | You may not, and shall not permit anyone else to, use the Project or do anything with the Project that is not expressly permitted by this Agreement, including, but not limited to, the following strictly prohibited uses:
23 |
24 | 1. resell, sublicense or other transfer the Project or the Theme or other components thereof or your rights to use the Theme as set forth herein or otherwise make available or allows a person to access or reproduce the Theme as an electronic file, except in connection with the single Project and subject to Section 3 above;
25 |
26 | 2. Use, reproduce or display the Theme or Project in any manner that competitive with the Services or our business (e.g. inclusion as part of an online website builder service, or distribution outside the Services such as on a Theme/themes marketplace or a "freebies" website);
27 |
28 | 3. Use, reproduce or display of the Theme in a fashion that we consider as, or under applicable law is considered, pornographic, obscene, immoral, infringing, defamatory or libelous; and
29 |
30 | 4. Use or display of the Theme in an electronic format that enables it to be downloaded or distributed in any file sharing arrangement.
31 |
32 | 5. **Ownership**. Stackbit shall retain and own all right, title and interest, including but not limited to copyright, patent, trade secret and all other intellectual property rights, in and to the Themes. You shall own all right, title and interest, including but not limited to copyright, patent, trade secret and all other intellectual property rights, in and to the Project, subject to Stackbit’s ownership of the Theme and the terms of this license agreement.
33 |
34 | 6. **Term and Termination**. This Agreement shall commence on the deployment of a Project through Stackbit’s Services to a repository (such as for example to Github) and continue indefinitely until it is terminated in accordance with Section 6. Stackbit may terminate this Agreement if You breach the Agreement and such breach remains uncured for 15 days following Your receipt of written notice from Stackbit. You may terminate this Agreement for convenience and without cause at any time immediately upon written notice to Stackbit. Upon termination of this Agreement for any reason, You and your Client shall a) cease all use of the Theme and the Project b) destroy or delete all copies and archives of the Theme, Projects, and accompanying materials, and c) if requested, confirm to Stackbit in writing that you have complied with these requirements. Any provisions of this Agreement which expressly or by implication are intended to survive its termination will survive and continue to bind the parties.
35 |
36 | 7. **Warranty and Disclaimer**. THE SERVICES, SITE, THEME, PROJECT AND ALL CONTENT AVAILABLE THROUGH THE SITE ARE OFFERED “AS IS” AND WITHOUT WARRANTY, AND STACKBIT MAKES NO REPRESENTATION OR WARRANTY OF ANY KIND, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY DISCLAIMS ALL WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE.
37 |
38 | 8. **Limitation of Liability**. Stackbit’s aggregate liability for all claims, losses, liabilities or damages in connection with this Services, Theme, Project or this Agreement or its subject matter, whether as a result of breach of contract, tort (including negligence) or otherwise, regardless of the theory of liability asserted, is limited to no more than the total amount of fees paid to Stackbit under this Agreement, or $100, whichever is greater. In addition, Stackbit will not be liable in any event for lost profits, consequential, indirect, punitive, exemplary or special damages.
39 |
40 | 9. **General**. This Agreement shall be governed by the law of the State of California, without reference to conflict of laws principles. The United Nations Convention on contracts for the International Sales of Goods shall not apply. This Agreement, together with the Stackbit Terms of Service at www.stackbit.com/tos/ represents the entire agreement between the parties with regard to the subject matter thereof and supersedes any prior understandings, proposals or agreements concerning the same subject matter. If any provision of this Agreement is found to be unenforceable or invalid, the remainder of such provision shall be enforced to the maximum extent permitted by law. No amendment or modification of this Agreement shall be valid or binding unless in a writing signed by representatives of both parties. You may not assign this Agreement without Stackbit’s prior written consent. Any attempted assignment in violation of this shall be null and void. This Agreement shall be binding upon and inure to the benefit of the parties hereto and their respective permitted successors and assigns. Any notice required or permitted to be given by either party under this Agreement shall be in writing and may be sent via an active Services account dashboard or shall be personally delivered or sent by commercial courier service, or by first class mail (certified or registered if available), or by telecopy confirmed by first class mail (registered or certified if available), to the other party at its address set forth below, or such new address as may from time-to-time be supplied hereunder by the parties hereto.
41 |
--------------------------------------------------------------------------------
/public/js/plugins.js:
--------------------------------------------------------------------------------
1 | /*
2 | * reframe.js - Reframe.js: responsive iframes for embedded content
3 | * @version v3.0.2
4 | * @link https://github.com/yowainwright/reframe.ts#readme
5 | * @author Jeff Wainwright (http://jeffry.in)
6 | * @license MIT
7 | */
8 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).reframe=t()}(this,function(){"use strict";function t(){for(var e=0,t=0,n=arguments.length;t0&&void 0!==arguments[0])||arguments[0];if(!this.expanded)if(this.handorgel.emitEvent("fold:open",[this]),this.expanded=!0,this.handorgel.options.collapsible||this.disable(),this._updateAria("button","aria-expanded"),this.header.classList.add(this.handorgel.options.headerOpenClass),this.content.classList.add(this.handorgel.options.contentOpenClass),t){var e=this.content.firstElementChild.offsetHeight;this.content.style.height="".concat(e,"px")}else this._opened()}},{key:"close",value:function(){var t=this,e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];if(this.expanded)if(this.handorgel.emitEvent("fold:close",[this]),this.expanded=!1,this.handorgel.options.collapsible||this.enable(),this._updateAria("button","aria-expanded"),this.header.classList.remove(this.handorgel.options.headerOpenedClass),this.content.classList.remove(this.handorgel.options.contentOpenedClass),e){var n=this.content.firstElementChild.offsetHeight;this.content.style.height="".concat(n,"px"),a(function(){t.content.style.height="0px"})}else this._closed()}},{key:"disable",value:function(){this.disabled=!0,this._updateAria("button","aria-disabled"),this.header.classList.add(this.handorgel.options.headerDisabledClass),this.content.classList.add(this.handorgel.options.contentDisabledClass)}},{key:"enable",value:function(){this.disabled=!1,this._updateAria("button","aria-disabled"),this.header.classList.remove(this.handorgel.options.headerDisabledClass),this.content.classList.remove(this.handorgel.options.contentDisabledClass)}},{key:"focus",value:function(){this.button.focus()}},{key:"blur",value:function(){this.button.blur()}},{key:"toggle",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.expanded?this.close(t):this.open(t)}},{key:"destroy",value:function(){this._unbindEvents(),this._cleanAria(),this.header.classList.remove(this.handorgel.options.headerOpenClass),this.header.classList.remove(this.handorgel.options.headerOpenedClass),this.header.classList.remove(this.handorgel.options.headerFocusClass),this.content.classList.remove(this.handorgel.options.contentOpenClass),this.content.classList.remove(this.handorgel.options.contentOpenedClass),this.content.classList.remove(this.handorgel.options.contentFocusClass),this.content.style.height="0px",this.header.handorgelFold=null,this.content.handorgelFold=null,this.header.removeAttribute("id"),this.content.removeAttribute("id"),this.handorgel=null}},{key:"_opened",value:function(){this.content.style.height="auto",this.header.classList.add(this.handorgel.options.headerOpenedClass),this.content.classList.add(this.handorgel.options.contentOpenedClass),this.handorgel.emitEvent("fold:opened",[this])}},{key:"_closed",value:function(){this.header.classList.remove(this.handorgel.options.headerOpenClass),this.content.classList.remove(this.handorgel.options.contentOpenClass),this.handorgel.emitEvent("fold:closed",[this])}},{key:"_initialOpen",value:function(){var t=this;null===this.header.getAttribute(this.handorgel.options.initialOpenAttribute)&&null===this.content.getAttribute(this.handorgel.options.initialOpenAttribute)||(this.handorgel.options.initialOpenTransition?window.setTimeout(function(){t.open()},this.handorgel.options.initialOpenTransitionDelay):this.open(!1))}},{key:"_initialFocus",value:function(){null!==this.button.getAttribute("autofocus")&&this._handleFocus()}},{key:"_initAria",value:function(){this._updateAria("button"),this._updateAria("content")}},{key:"_cleanAria",value:function(){this._updateAria("button",null,!0),this._updateAria("content",null,!0)}},{key:"_updateAria",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];if(this.handorgel.options.ariaEnabled)if(e){var i=d[t][e].call(this);this[t].setAttribute(e,i)}else for(var s in d[t])if(d[t].hasOwnProperty(s))if(n)this[t].removeAttribute(s);else{var o=d[t][s].call(this);this[t].setAttribute(s,o)}}},{key:"_handleContentTransitionEnd",value:function(t){t.target===t.currentTarget&&"height"===t.propertyName&&(this.expanded?this._opened():this._closed())}},{key:"_handleFocus",value:function(){this.focused=!0,this.header.classList.add(this.handorgel.options.headerFocusClass),this.content.classList.add(this.handorgel.options.contentFocusClass),this.handorgel.emitEvent("fold:focus",[this])}},{key:"_handleBlur",value:function(){this.focused=!1,this.header.classList.remove(this.handorgel.options.headerFocusClass),this.content.classList.remove(this.handorgel.options.contentFocusClass),this.handorgel.emitEvent("fold:blur",[this])}},{key:"_handleButtonClick",value:function(t){this.focus(),this.disabled||this.toggle()}},{key:"_handleButtonKeydown",value:function(t){if(this.handorgel.options.keyboardInteraction){var e=null;switch(t.which){case c:e="next";break;case u:e="prev";break;case b:e="first";break;case v:e="last";break;case p:t.ctrlKey&&(e="next");break;case f:t.ctrlKey&&(e="prev")}e&&(t.preventDefault(),this.handorgel.focus(e))}}},{key:"_handleContentKeydown",value:function(t){if(this.handorgel.options.keyboardInteraction&&t.ctrlKey){var e=null;switch(t.which){case p:e="next";break;case f:e="prev"}e&&(t.preventDefault(),this.handorgel.focus(e))}}},{key:"_bindEvents",value:function(){for(var t in this._listeners={bFocus:["focus",this.button,this._handleFocus.bind(this)],bBlur:["blur",this.button,this._handleBlur.bind(this)],bClick:["click",this.button,this._handleButtonClick.bind(this)],bKeydown:["keydown",this.button,this._handleButtonKeydown.bind(this)],cKeydown:["keydown",this.content,this._handleContentKeydown.bind(this)],cTransition:["transitionend",this.content,this._handleContentTransitionEnd.bind(this)]},this._listeners)if(this._listeners.hasOwnProperty(t)){var e=this._listeners[t];e[1].addEventListener(e[0],e[2])}}},{key:"_unbindEvents",value:function(){for(var t in this._listeners)if(this._listeners.hasOwnProperty(t)){var e=this._listeners[t];e[1].removeEventListener(e[0],e[2])}}}]),e}(),_=0,y=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};t(this,e),n.handorgel||(this.element=n,this.element.handorgel=this,this.id="handorgel".concat(++_),this.element.setAttribute("id",this.id),this.folds=[],this.options=h({},e.defaultOptions,i),this._listeners={},this._bindEvents(),this._initAria(),this.update())}return n(e,[{key:"update",value:function(){this.folds=[];for(var t=this.element.children,e=0,n=t.length;e