├── assets ├── scss │ ├── atoms │ │ ├── _module.scss │ │ └── _button.scss │ ├── layouts │ │ ├── _module.scss │ │ └── _wrapper.scss │ ├── base │ │ ├── _module.scss │ │ ├── _base.scss │ │ └── _resetr.scss │ ├── pages │ │ ├── _products.scss │ │ ├── _module.scss │ │ ├── _landing-page.scss │ │ ├── _blog-home.scss │ │ ├── _page-404.scss │ │ ├── _product.scss │ │ ├── _homepage.scss │ │ └── _blog-post.scss │ ├── utils │ │ ├── _module.scss │ │ ├── _fonts.scss │ │ └── _prismic-edit-button.scss │ ├── fragments │ │ ├── _separator.scss │ │ ├── _module.scss │ │ ├── _text-block.scss │ │ ├── _banner-split.scss │ │ ├── _numeroted-items.scss │ │ ├── _products-grid.scss │ │ ├── _product-quote.scss │ │ ├── _footer.scss │ │ ├── _cta-banner.scss │ │ └── _header.scss │ └── main.scss └── js │ └── main.js ├── prismic-configuration.js ├── views ├── partials │ ├── slices │ │ ├── separator.ejs │ │ ├── text-block.ejs │ │ ├── banner-split.ejs │ │ ├── numeroted-items.ejs │ │ ├── cta-banner.ejs │ │ ├── product-quote.ejs │ │ └── products-grid.ejs │ ├── footer.ejs │ └── header.ejs ├── error.ejs ├── page-404.ejs ├── landing-page.ejs ├── blog-home.ejs ├── products.ejs ├── homepage.ejs ├── blog-post.ejs └── product.ejs ├── public └── img │ ├── coffee-bag.png │ ├── footer-background.png │ ├── burger-closed.svg │ └── burger-opened.svg ├── .editorconfig ├── webpack.dev.config.js ├── webpack.prod.config.js ├── README.md ├── link-resolver.js ├── custom_types ├── author.json ├── index.json ├── layout.json ├── blog_home.json ├── products.json ├── blog_post.json ├── product.json ├── landing_page.json └── homepage.json ├── webpack.base.config.js ├── package.json ├── bin └── www ├── .gitignore ├── app.js └── routes └── index.js /assets/scss/atoms/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./button"; 2 | -------------------------------------------------------------------------------- /assets/scss/layouts/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./wrapper"; 2 | -------------------------------------------------------------------------------- /assets/scss/base/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./resetr"; 2 | @import "./base"; 3 | -------------------------------------------------------------------------------- /assets/scss/pages/_products.scss: -------------------------------------------------------------------------------- 1 | .products-section { 2 | padding: 70px 0 130px; 3 | } 4 | -------------------------------------------------------------------------------- /assets/scss/utils/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./fonts"; 2 | @import "./prismic-edit-button"; 3 | -------------------------------------------------------------------------------- /prismic-configuration.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | endpoint: 'https://new-demo.prismic.io/api/v2' 3 | }; 4 | -------------------------------------------------------------------------------- /views/partials/slices/separator.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | -------------------------------------------------------------------------------- /views/error.ejs: -------------------------------------------------------------------------------- 1 |

<%= message %>

2 |

<%= error.status %>

3 |
<%= error.stack %>
4 | -------------------------------------------------------------------------------- /public/img/coffee-bag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/prismic-website-demo/master/public/img/coffee-bag.png -------------------------------------------------------------------------------- /assets/scss/fragments/_separator.scss: -------------------------------------------------------------------------------- 1 | .separator-hr { 2 | border: none; 3 | border-top: 1px solid #d6d6d6; 4 | } 5 | -------------------------------------------------------------------------------- /public/img/footer-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/prismic-website-demo/master/public/img/footer-background.png -------------------------------------------------------------------------------- /assets/scss/base/_base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | color: #121212; 3 | font-family: $font-sans; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | } 7 | -------------------------------------------------------------------------------- /assets/scss/layouts/_wrapper.scss: -------------------------------------------------------------------------------- 1 | .l-wrapper { 2 | max-width: 1190px; 3 | padding-left: 15px; 4 | padding-right: 15px; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /assets/scss/utils/_fonts.scss: -------------------------------------------------------------------------------- 1 | $font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 2 | $font-mono: "PT Mono", monospace; 3 | -------------------------------------------------------------------------------- /assets/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import "./utils/module"; 2 | @import "./base/module"; 3 | @import "./layouts/module"; 4 | @import "./atoms/module"; 5 | @import "./fragments/module"; 6 | @import "./pages/module"; 7 | -------------------------------------------------------------------------------- /assets/scss/pages/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./blog-home"; 2 | @import "./blog-post"; 3 | @import "./homepage"; 4 | @import "./landing-page"; 5 | @import "./page-404"; 6 | @import "./product"; 7 | @import "./products"; 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /webpack.dev.config.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const baseWebpackConfig = require('./webpack.base.config'); 3 | 4 | const devWebpackConfig = merge(baseWebpackConfig, { 5 | mode: 'development' 6 | }); 7 | 8 | module.exports = devWebpackConfig; 9 | -------------------------------------------------------------------------------- /webpack.prod.config.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const baseWebpackConfig = require('./webpack.base.config'); 3 | 4 | const prodWebpackConfig = merge(baseWebpackConfig, { 5 | mode: 'production' 6 | }); 7 | 8 | module.exports = prodWebpackConfig; 9 | -------------------------------------------------------------------------------- /assets/js/main.js: -------------------------------------------------------------------------------- 1 | import "../scss/main.scss"; 2 | 3 | import $ from 'jquery'; 4 | 5 | $(document).ready(function () { 6 | const $header = $('#header'); 7 | 8 | $('#header-burger').on('click', function () { 9 | $header.toggleClass('header--is-nav-opened'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /assets/scss/fragments/_module.scss: -------------------------------------------------------------------------------- 1 | @import "./banner-split"; 2 | @import "./cta-banner"; 3 | @import "./footer"; 4 | @import "./header"; 5 | @import "./numeroted-items"; 6 | @import "./product-quote"; 7 | @import "./products-grid"; 8 | @import "./separator"; 9 | @import "./text-block"; 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prismic Website Demo 2 | 3 | ## Install dependencies 4 | 5 | ``` bash 6 | npm install 7 | ``` 8 | 9 | ## Run in development mode 10 | 11 | ``` bash 12 | npm run dev 13 | ``` 14 | 15 | Then you can access it at [http://localhost:3000](http://localhost:3000). 16 | 17 | ## Run in production mode 18 | 19 | ``` bash 20 | npm start 21 | ``` 22 | -------------------------------------------------------------------------------- /views/partials/slices/text-block.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | <%- richTextAsHtml(slice.primary.title1) %> 6 |
7 |
8 | <%- richTextAsHtml(slice.primary.paragraph) %> 9 |
10 |
11 |
12 |
13 | -------------------------------------------------------------------------------- /assets/scss/pages/_landing-page.scss: -------------------------------------------------------------------------------- 1 | .lp-header { 2 | padding: 90px 15px 0; 3 | } 4 | 5 | .lp-title { 6 | max-width: 764px; 7 | margin: 0 auto; 8 | font-family: $font-mono; 9 | font-size: 28px; 10 | line-height: 1.786; 11 | text-align: center; 12 | } 13 | 14 | .lp-slices-wrapper { 15 | padding: 130px 0 200px; 16 | } 17 | 18 | .lp-slice-wrapper { 19 | &:not(:first-child) { 20 | margin-top: 130px; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /views/partials/slices/banner-split.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /views/partials/slices/numeroted-items.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | <%- richTextAsHtml(slice.primary.title_section) %> 6 |
7 |
8 |
9 |
10 | <% slice.items.forEach(function (item) { %> 11 |
12 | <%- richTextAsHtml(item.description_paragraph) %> 13 |
14 | <% }); %> 15 |
16 |
17 | -------------------------------------------------------------------------------- /views/page-404.ejs: -------------------------------------------------------------------------------- 1 | <%- include('partials/header'); %> 2 | 3 |
4 |
5 |
6 | 7 |
8 | Coffee bag 9 |
10 |

404

11 |

Something is wrong

12 |

The page you are looking for was moved, removed, renamed or might never existed

13 |
14 |
15 | 16 | <%- include('partials/footer'); %> 17 | -------------------------------------------------------------------------------- /link-resolver.js: -------------------------------------------------------------------------------- 1 | const linkResolver = function (doc) { 2 | if (doc.type === 'homepage') { 3 | return '/'; 4 | } 5 | if (doc.type === 'products') { 6 | return '/products'; 7 | } 8 | if (doc.type === 'product') { 9 | return '/products/' + doc.uid; 10 | } 11 | if (doc.type === 'blog_home') { 12 | return '/blog'; 13 | } 14 | if (doc.type === 'blog_post') { 15 | return '/blog/' + doc.uid; 16 | } 17 | if (doc.type === 'landing_page') { 18 | return '/pages/' + doc.uid; 19 | } 20 | return '/'; 21 | }; 22 | 23 | module.exports = linkResolver; 24 | -------------------------------------------------------------------------------- /custom_types/author.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "name" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "paragraph", 7 | "label" : "Name" 8 | } 9 | }, 10 | "bio" : { 11 | "type" : "StructuredText", 12 | "config" : { 13 | "single" : "paragraph", 14 | "label" : "Bio" 15 | } 16 | }, 17 | "picture" : { 18 | "type" : "Image", 19 | "config" : { 20 | "constraint" : { }, 21 | "thumbnails" : [ ], 22 | "label" : "Picture" 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /assets/scss/utils/_prismic-edit-button.scss: -------------------------------------------------------------------------------- 1 | .wio-link { 2 | position: fixed; 3 | bottom: 30px; 4 | right: 30px; 5 | 6 | display: inline-flex; 7 | justify-content: center; 8 | align-items: center; 9 | width: 42px; 10 | height: 42px; 11 | border-radius: 21px; 12 | background-color: #121212; 13 | color: white; 14 | font-family: "Font Awesome 5 Free"; 15 | font-size: 18px; 16 | font-style: normal; 17 | font-variant: normal; 18 | font-weight: 900; 19 | line-height: 1; 20 | text-rendering: auto; 21 | 22 | &::before { 23 | content: "\f303"; 24 | } 25 | 26 | img { 27 | display: none; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/scss/fragments/_text-block.scss: -------------------------------------------------------------------------------- 1 | .text-block-inner { 2 | display: flex; 3 | 4 | @media (max-width: 1190px) { 5 | flex-direction: column; 6 | } 7 | } 8 | 9 | .text-block-title { 10 | max-width: 366px; 11 | width: 100%; 12 | font-family: $font-mono; 13 | font-size: 28px; 14 | font-weight: 700; 15 | line-height: 1.786; 16 | 17 | margin-right: 30px; 18 | 19 | @media (max-width: 1190px) { 20 | margin-right: 0; 21 | margin-bottom: 70px; 22 | } 23 | } 24 | 25 | .text-block-richtext { 26 | font-family: $font-mono; 27 | font-size: 17px; 28 | line-height: 2.353; 29 | 30 | p:not(:first-child) { 31 | margin-top: 40px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /webpack.base.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | 4 | const baseWebpackConfig = { 5 | entry: path.resolve('./assets/js/main.js'), 6 | output: { 7 | path: path.resolve('./public/bundles'), 8 | filename: '[name].js' 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.scss$/, 13 | use: [ 14 | MiniCssExtractPlugin.loader, 15 | 'css-loader', 16 | 'sass-loader' 17 | ] 18 | }] 19 | }, 20 | plugins: [ 21 | new MiniCssExtractPlugin({ 22 | filename: '[name].css' 23 | }) 24 | ] 25 | }; 26 | 27 | module.exports = baseWebpackConfig; 28 | -------------------------------------------------------------------------------- /assets/scss/atoms/_button.scss: -------------------------------------------------------------------------------- 1 | .a-button { 2 | display: inline-flex; 3 | justify-content: center; 4 | align-items: center; 5 | height: 50px; 6 | padding: 0 32px; 7 | border: 1px solid #121212; 8 | border-radius: 2px; 9 | color: #121212; 10 | font-weight: 500; 11 | white-space: nowrap; 12 | transition-property: background-color, color; 13 | transition-duration: 150ms; 14 | outline: none; 15 | 16 | &:hover { 17 | background-color: #121212; 18 | color: white; 19 | } 20 | } 21 | 22 | .a-button--filled { 23 | background-color: #121212; 24 | color: white; 25 | 26 | &:hover { 27 | background-color: white; 28 | color: #121212; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /assets/scss/fragments/_banner-split.scss: -------------------------------------------------------------------------------- 1 | .banner-split-image { 2 | margin-bottom: 70px; 3 | width: 100%; 4 | } 5 | 6 | .banner-split-content-wrapper { 7 | display: flex; 8 | justify-content: space-between; 9 | font-family: $font-mono; 10 | 11 | @media (max-width: 1190px) { 12 | display: block; 13 | text-align: center; 14 | } 15 | } 16 | 17 | .banner-split-title { 18 | max-width: 564px; 19 | font-size: 28px; 20 | font-weight: 700; 21 | line-height: 1.786; 22 | 23 | @media (max-width: 1190px) { 24 | max-width: 764px; 25 | margin: 0 auto; 26 | } 27 | } 28 | 29 | .banner-split-text { 30 | max-width: 564px; 31 | font-size: 17px; 32 | line-height: 2.353; 33 | 34 | @media (max-width: 1190px) { 35 | max-width: 764px; 36 | margin: 30px auto 0; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /views/partials/slices/cta-banner.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%= slice.primary.image_banner.alt %> 4 |
5 |
6 |
7 | <%- richTextAsHtml(slice.primary.banner_title) %> 8 |
9 |
10 | <%- richTextAsHtml(slice.primary.banner_text) %> 11 |
12 |
13 | 18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /public/img/burger-closed.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | burger-close 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /views/partials/slices/product-quote.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | <%- richTextAsHtml(slice.primary.quote_text) %> 7 |
8 |
9 | <%- richTextAsHtml(slice.primary.quote_author) %> 10 |
11 |
12 |
13 | <%- richTextAsHtml(slice.primary.product_description) %> 14 |
15 | <%= slice.primary.product_image.alt %> 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /assets/scss/pages/_blog-home.scss: -------------------------------------------------------------------------------- 1 | .blog-home-section { 2 | padding: 70px 0 130px; 3 | } 4 | 5 | .blog-home-posts-wrapper { 6 | max-width: 794px; 7 | padding-left: 15px; 8 | padding-right: 15px; 9 | margin-left: auto; 10 | margin-right: auto; 11 | } 12 | 13 | .blog-home-post-wrapper { 14 | &:not(:first-child) { 15 | border-top: 1px solid #d6d6d6; 16 | margin-top: 60px; 17 | padding-top: 60px; 18 | } 19 | } 20 | 21 | .blog-home-post-image { 22 | width: 100%; 23 | max-height: 546px; 24 | object-fit: cover; 25 | } 26 | 27 | .blog-home-post-title { 28 | margin-top: 56px; 29 | font-family: $font-mono; 30 | font-size: 28px; 31 | font-weight: 700; 32 | line-height: 1.786; 33 | } 34 | 35 | .blog-home-post-excerpt { 36 | margin-top: 20px; 37 | font-family: $font-mono; 38 | font-size: 17px; 39 | line-height: 2.353; 40 | } 41 | 42 | .blog-home-post-button-wrapper { 43 | margin-top: 20px; 44 | } 45 | -------------------------------------------------------------------------------- /public/img/burger-opened.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | burger-open 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "prismic-website-demo", 3 | "version": "0.3.1", 4 | "scripts": { 5 | "start": "npm run build && node ./bin/www", 6 | "dev": "webpack --config webpack.dev.config.js --watch | cross-env DEBUG=myapp:* nodemon ./bin/www", 7 | "build": "webpack --config webpack.prod.config.js" 8 | }, 9 | "dependencies": { 10 | "cookie-parser": "~1.4.3", 11 | "cross-env": "~5.2.0", 12 | "debug": "~3.1.0", 13 | "ejs": "~2.6.1", 14 | "express": "~4.16.3", 15 | "http-errors": "~1.7.0", 16 | "jquery": "~3.3.1", 17 | "morgan": "~1.9.0", 18 | "prismic-dom": "~2.1.0", 19 | "prismic-javascript": "2.0.0-beta.0" 20 | }, 21 | "devDependencies": { 22 | "css-loader": "~1.0.0", 23 | "mini-css-extract-plugin": "~0.4.2", 24 | "node-sass": "~4.12.0", 25 | "nodemon": "~1.19.1", 26 | "sass-loader": "~7.1.0", 27 | "webpack": "~4.17.2", 28 | "webpack-cli": "~3.1.0", 29 | "webpack-merge": "~4.1.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /assets/scss/pages/_page-404.scss: -------------------------------------------------------------------------------- 1 | .page-404-wrapper { 2 | position: relative; 3 | max-width: 1040px; 4 | padding: 0 15px; 5 | margin: 110px auto 140px; 6 | } 7 | 8 | .page-404-image { 9 | width: 798px; 10 | height: 377px; 11 | 12 | @media (max-width: 980px) { 13 | display: none; 14 | } 15 | } 16 | 17 | .page-404-content { 18 | position: absolute; 19 | top: 0; 20 | right: 15px; 21 | max-width: 400px; 22 | 23 | @media (max-width: 980px) { 24 | position: static; 25 | margin: 0 auto; 26 | text-align: center; 27 | } 28 | } 29 | 30 | .page-404-title { 31 | font-size: 192px; 32 | font-weight: 900; 33 | line-height: 1; 34 | 35 | @media (max-width: 460px) { 36 | font-size: 132px; 37 | } 38 | } 39 | 40 | .page-404-subtitle { 41 | font-size: 40px; 42 | font-weight: 700; 43 | line-height: 1; 44 | 45 | @media (max-width: 460px) { 46 | font-size: 30px; 47 | } 48 | } 49 | 50 | .page-404-paragraph { 51 | margin-top: 15px; 52 | color: #7f7d7c; 53 | font-size: 17px; 54 | line-height: 1.647; 55 | } 56 | -------------------------------------------------------------------------------- /custom_types/index.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "author", 4 | "name": "Author", 5 | "repeatable": true, 6 | "value": "author.json" 7 | }, 8 | { 9 | "id": "blog_home", 10 | "name": "Blog Home Metadata", 11 | "repeatable": false, 12 | "value": "blog_home.json" 13 | }, 14 | { 15 | "id": "blog_post", 16 | "name": "Blog Post", 17 | "repeatable": true, 18 | "value": "blog_post.json" 19 | }, 20 | { 21 | "id": "homepage", 22 | "name": "Homepage", 23 | "repeatable": false, 24 | "value": "homepage.json" 25 | }, 26 | { 27 | "id": "landing_page", 28 | "name": "Landing Page", 29 | "repeatable": true, 30 | "value": "landing_page.json" 31 | }, 32 | { 33 | "id": "layout", 34 | "name": "Layout", 35 | "repeatable": false, 36 | "value": "layout.json" 37 | }, 38 | { 39 | "id": "product", 40 | "name": "Product", 41 | "repeatable": true, 42 | "value": "product.json" 43 | }, 44 | { 45 | "id": "products", 46 | "name": "Products List", 47 | "repeatable": false, 48 | "value": "products.json" 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /assets/scss/fragments/_numeroted-items.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Header 3 | */ 4 | 5 | .numeroted-items-header { 6 | display: flex; 7 | justify-content: center; 8 | } 9 | 10 | .numeroted-items-header-title { 11 | max-width: 592px; 12 | font-family: $font-mono; 13 | font-size: 28px; 14 | font-weight: 700; 15 | line-height: 1.786; 16 | } 17 | 18 | /** 19 | * Items 20 | */ 21 | 22 | .numeroted-items-items-wrapper { 23 | display: flex; 24 | flex-wrap: wrap; 25 | justify-content: center; 26 | max-width: 1190px; 27 | margin-left: auto; 28 | margin-right: auto; 29 | counter-reset: item; 30 | } 31 | 32 | .numeroted-items-item-wrapper { 33 | max-width: 366px; 34 | margin: 70px 15px 0; 35 | 36 | font-family: $font-mono; 37 | font-size: 18px; 38 | line-height: 1.889; 39 | text-align: center; 40 | 41 | &::before { 42 | counter-increment: item; 43 | content: counter(item); 44 | display: inline-block; 45 | width: 82px; 46 | border-bottom: 4px solid #e7e7e7; 47 | padding-bottom: 30px; 48 | margin-bottom: 30px; 49 | font-size: 68px; 50 | font-weight: 700; 51 | line-height: 1; 52 | } 53 | 54 | p { 55 | &:not(:first-child) { 56 | margin-top: 40px; 57 | } 58 | 59 | em { 60 | color: #acacac; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /views/landing-page.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(document.data.meta_title), 5 | description: richTextAsPlain(document.data.meta_description), 6 | social: document.data.social, 7 | canonicalUrl: getCanonicalUrl(document) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | 16 |
17 |
18 | <%- richTextAsHtml(document.data.title) %> 19 |
20 |
21 | 22 |
23 | <% document.data.body.forEach(function (slice) { %> 24 | <% if (slice.slice_type === 'banner_split') { %> 25 |
26 | <%- include('partials/slices/banner-split', { slice }); %> 27 |
28 | <% } else if (slice.slice_type === 'big_bullet_item') { %> 29 |
30 | <%- include('partials/slices/numeroted-items', { slice }); %> 31 |
32 | <% } else if (slice.slice_type === 'product_quote') { %> 33 |
34 | <%- include('partials/slices/product-quote', { slice }); %> 35 |
36 | <% } %> 37 | <% }); %> 38 |
39 | 40 |
41 | 42 | <%- include('partials/footer'); %> 43 | -------------------------------------------------------------------------------- /views/partials/slices/products-grid.ejs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 | <%- richTextAsHtml(slice.primary.section_title) %> 6 |
7 | 12 |
13 |
14 |
15 | <% slice.items.forEach(function (item) { %> 16 | <% if (item.link_to_product.data) { %> 17 | 18 | <%= item.link_to_product.data.product_image.alt %> 23 |

24 | <% const product = item.link_to_product.data.product %> 25 | <%= product ? product.title : '' %> 26 |

27 |

28 | <%= product ? product.country : '' %> 29 |

30 |
31 | <% } %> 32 | <% }); %> 33 |
34 |
35 | -------------------------------------------------------------------------------- /views/blog-home.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(blogHomeDocument.data.meta_title), 5 | description: richTextAsPlain(blogHomeDocument.data.meta_description), 6 | social: blogHomeDocument.data.social, 7 | canonicalUrl: getCanonicalUrl(blogHomeDocument) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | 16 |
17 |
18 | <% blogPostDocuments.forEach(function (document) { %> 19 |
20 |
21 | <%= document.data.image.alt %> 22 |

23 | <%= richTextAsPlain(document.data.title) %> 24 |

25 |

26 | <%= richTextAsPlain(document.data.excerpt).substring(0, 158) %> … 27 |

28 |
29 | 30 | Read post 31 | 32 |
33 |
34 |
35 | <% }); %> 36 |
37 |
38 | 39 |
40 | 41 | <%- include('partials/footer'); %> 42 | -------------------------------------------------------------------------------- /views/partials/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% if (layoutContent.site_name && layoutContent.footer_nav_items.length > 0) { %> 4 | 34 | <% } %> 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /views/products.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(productsDocument.data.meta_title), 5 | description: richTextAsPlain(productsDocument.data.meta_description), 6 | social: productsDocument.data.social, 7 | canonicalUrl: getCanonicalUrl(productsDocument) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 | <%- richTextAsHtml(productsDocument.data.title) %> 21 |
22 |
23 |
24 |
25 | <% productDocuments.forEach(function (document) { %> 26 | 27 | <%= document.data.product_image.alt %> 32 |

33 | <% const product = document.data.product %> 34 | <%= product ? product.title : '' %> 35 |

36 |

37 | <%= product ? product.country : '' %> 38 |

39 |
40 | <% }); %> 41 |
42 |
43 | 44 |
45 | 46 | <%- include('partials/footer'); %> 47 | -------------------------------------------------------------------------------- /assets/scss/fragments/_products-grid.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Header 3 | */ 4 | 5 | .products-grid-header { 6 | display: flex; 7 | justify-content: space-between; 8 | 9 | @media (max-width: 774px) { 10 | flex-direction: column; 11 | justify-content: flex-start; 12 | align-items: flex-start; 13 | } 14 | } 15 | 16 | .products-grid-header-title { 17 | max-width: 592px; 18 | font-family: $font-mono; 19 | font-size: 28px; 20 | font-weight: 700; 21 | line-height: 1.786; 22 | } 23 | 24 | .products-grid-header-button-wrapper { 25 | @media (min-width: 775px) { 26 | margin-left: 30px; 27 | } 28 | 29 | @media (max-width: 774px) { 30 | margin-top: 30px; 31 | } 32 | } 33 | 34 | /** 35 | * Items 36 | */ 37 | 38 | .products-grid-items-wrapper { 39 | display: flex; 40 | flex-wrap: wrap; 41 | max-width: 1190px; 42 | margin-left: auto; 43 | margin-right: auto; 44 | 45 | @media (max-width: 1189px) { 46 | max-width: 792px; 47 | } 48 | 49 | @media (max-width: 791px) { 50 | max-width: 396px; 51 | } 52 | } 53 | 54 | .products-grid-item-wrapper { 55 | max-width: 366px; 56 | margin: 70px 15px 0; 57 | } 58 | 59 | .products-grid-item-image { 60 | width: 100%; 61 | max-height: 320px; 62 | object-fit: cover; 63 | } 64 | 65 | .products-grid-item-title { 66 | margin-top: 30px; 67 | color: #001000; 68 | font-family: $font-mono; 69 | font-size: 18px; 70 | font-weight: 700; 71 | text-align: center; 72 | 73 | &::before { 74 | content: "⇥"; 75 | } 76 | } 77 | 78 | .products-grid-item-country { 79 | margin-top: 10px; 80 | color: #7f7d7c; 81 | text-align: center; 82 | } 83 | -------------------------------------------------------------------------------- /assets/scss/fragments/_product-quote.scss: -------------------------------------------------------------------------------- 1 | .product-quote-inner { 2 | position: relative; 3 | 4 | @media (max-width: 1190px) { 5 | text-align: center; 6 | } 7 | } 8 | 9 | .product-quote-box { 10 | width: 664px; 11 | height: 520px; 12 | padding: 64px 74px; 13 | background: #121212 no-repeat center; 14 | background-size: cover; 15 | color: white; 16 | 17 | .product-quote-inner--reverse & { 18 | margin-left: auto; 19 | } 20 | 21 | @media (max-width: 1190px) { 22 | max-width: 520px; 23 | width: 100%; 24 | height: auto; 25 | margin: 0 auto; 26 | } 27 | 28 | @media (max-width: 550px) { 29 | padding: 30px; 30 | } 31 | } 32 | 33 | .product-quote-box-quote-text { 34 | font-family: $font-mono; 35 | font-size: 28px; 36 | font-weight: 700; 37 | line-height: 1.786; 38 | 39 | @media (max-width: 550px) { 40 | font-size: 22px; 41 | line-height: 1.909; 42 | } 43 | } 44 | 45 | .product-quote-box-quote-author { 46 | margin-top: 20px; 47 | } 48 | 49 | .product-quote-product-description { 50 | margin-top: 114px; 51 | max-width: 520px; 52 | font-family: $font-mono; 53 | font-size: 17px; 54 | line-height: 2.353; 55 | 56 | .product-quote-inner--reverse & { 57 | margin-left: auto; 58 | } 59 | 60 | @media (max-width: 1190px) { 61 | margin: 70px auto 0; 62 | } 63 | } 64 | 65 | .product-quote-product-image { 66 | position: absolute; 67 | bottom: 0; 68 | right: 0; 69 | width: 564px; 70 | height: 564px; 71 | object-fit: cover; 72 | 73 | .product-quote-inner--reverse & { 74 | right: none; 75 | left: 0; 76 | } 77 | 78 | @media (max-width: 1190px) { 79 | display: none; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /assets/scss/fragments/_footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | min-height: 420px; 3 | padding: 90px 0; 4 | background: #f6f6f6 url(/img/footer-background.png) no-repeat center; 5 | 6 | @media (max-width: 1680px) { 7 | background-size: cover; 8 | } 9 | } 10 | 11 | .footer-inner { 12 | display: flex; 13 | justify-content: space-between; 14 | max-width: 1190px; 15 | padding: 0 15px; 16 | margin: 0 auto; 17 | 18 | @media (max-width: 1000px) { 19 | align-items: flex-start; 20 | padding: 0 60px; 21 | } 22 | 23 | @media (max-width: 564px) { 24 | flex-direction: column; 25 | justify-content: flex-start; 26 | } 27 | } 28 | 29 | .footer-name { 30 | font-size: 28px; 31 | font-weight: 700; 32 | } 33 | 34 | .footer-social-items { 35 | display: flex; 36 | flex-wrap: wrap; 37 | margin-top: 30px; 38 | } 39 | 40 | .footer-social-item { 41 | display: inline-block; 42 | 43 | &:not(:last-child) { 44 | margin-right: 20px; 45 | } 46 | 47 | width: 28px; 48 | height: 28px; 49 | 50 | img { 51 | width: 100%; 52 | height: 100%; 53 | } 54 | } 55 | 56 | .footer-nav { 57 | display: flex; 58 | flex-wrap: wrap; 59 | margin-left: 40px; 60 | color: #7f7d7c; 61 | 62 | @media (max-width: 1000px) { 63 | flex-wrap: nowrap; 64 | flex-direction: column; 65 | font-size: 20px; 66 | text-align: right; 67 | } 68 | 69 | @media (max-width: 564px) { 70 | margin-left: 0; 71 | margin-top: 40px; 72 | text-align: left; 73 | } 74 | } 75 | 76 | .footer-nav-link { 77 | &:not(:last-child) { 78 | margin-right: 40px; 79 | 80 | @media (max-width: 1000px) { 81 | margin-right: 0; 82 | margin-bottom: 16px; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /custom_types/layout.json: -------------------------------------------------------------------------------- 1 | { 2 | "Header" : { 3 | "site_name" : { 4 | "type" : "Text", 5 | "config" : { 6 | "label" : "Site name" 7 | } 8 | }, 9 | "header_nav_items" : { 10 | "type" : "Group", 11 | "config" : { 12 | "fields" : { 13 | "text" : { 14 | "type" : "Text", 15 | "config" : { 16 | "label" : "Text" 17 | } 18 | }, 19 | "link" : { 20 | "type" : "Link", 21 | "config" : { 22 | "label" : "Link" 23 | } 24 | } 25 | }, 26 | "label" : "Header navigation items" 27 | } 28 | } 29 | }, 30 | "Footer" : { 31 | "footer_nav_items" : { 32 | "type" : "Group", 33 | "config" : { 34 | "fields" : { 35 | "text" : { 36 | "type" : "Text", 37 | "config" : { 38 | "label" : "Text" 39 | } 40 | }, 41 | "link" : { 42 | "type" : "Link", 43 | "config" : { 44 | "label" : "Link" 45 | } 46 | } 47 | }, 48 | "label" : "Footer navigation items" 49 | } 50 | }, 51 | "footer_social_items" : { 52 | "type" : "Group", 53 | "config" : { 54 | "fields" : { 55 | "icon" : { 56 | "type" : "Image", 57 | "config" : { 58 | "constraint" : { }, 59 | "thumbnails" : [ ], 60 | "label" : "Icon" 61 | } 62 | }, 63 | "link" : { 64 | "type" : "Link", 65 | "config" : { 66 | "allowTargetBlank" : true, 67 | "label" : "Link" 68 | } 69 | } 70 | }, 71 | "label" : "Footer social items" 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /assets/scss/pages/_product.scss: -------------------------------------------------------------------------------- 1 | .product-sections-wrapper { 2 | padding: 70px 0 130px; 3 | } 4 | 5 | .product-separator-wrapper { 6 | margin: 130px 0 70px; 7 | } 8 | 9 | /** 10 | * Hero 11 | */ 12 | 13 | .product-hero-inner { 14 | display: flex; 15 | justify-content: space-between; 16 | 17 | @media (max-width: 1190px) { 18 | flex-direction: column; 19 | justify-content: flex-start; 20 | align-items: center; 21 | } 22 | } 23 | 24 | .product-hero-image { 25 | max-width: 564px; 26 | width: 100%; 27 | max-height: 564px; 28 | height: 100%; 29 | object-fit: cover; 30 | background-color:#f6f6f6; 31 | } 32 | 33 | .product-hero-content { 34 | max-width: 564px; 35 | width: 100%; 36 | 37 | @media (max-width: 1190px) { 38 | margin-top: 30px; 39 | } 40 | } 41 | 42 | .product-hero-title { 43 | font-family: $font-mono; 44 | font-size: 28px; 45 | font-weight: 700; 46 | line-height: 1.786; 47 | } 48 | 49 | .product-hero-subtitle { 50 | margin-top: 20px; 51 | font-family: $font-mono; 52 | font-size: 22px; 53 | font-weight: 700; 54 | line-height: 1.818; 55 | } 56 | 57 | .product-hero-list { 58 | margin-top: 10px; 59 | padding-left: 30px; 60 | font-family: $font-mono; 61 | font-size: 16px; 62 | line-height: 2.5; 63 | } 64 | 65 | .product-hero-paragraph { 66 | margin-top: 10px; 67 | font-family: $font-mono; 68 | font-size: 16px; 69 | line-height: 2.5; 70 | } 71 | 72 | .product-hero-button-wrapper { 73 | margin-top: 40px; 74 | } 75 | 76 | /** 77 | * Description 78 | */ 79 | 80 | .product-description-title { 81 | margin-top: 130px; 82 | font-family: $font-mono; 83 | font-size: 28px; 84 | font-weight: 700; 85 | line-height: 1.786; 86 | } 87 | 88 | .product-description-content { 89 | margin-top: 30px; 90 | font-family: $font-mono; 91 | font-size: 17px; 92 | line-height: 2.353; 93 | 94 | p:not(:first-child) { 95 | margin-top: 20px; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /assets/scss/fragments/_cta-banner.scss: -------------------------------------------------------------------------------- 1 | .cta-banner-inner { 2 | position: relative; 3 | max-width: 1160px; 4 | margin-left: auto; 5 | margin-right: auto; 6 | text-align: right; // Align the image on right 7 | } 8 | 9 | .cta-banner-image { 10 | display: inline-block; // Allow to align the image on right with `text-align: right;` 11 | width: 100%; 12 | max-width: 664px; 13 | height: 100%; 14 | max-height: 664px; 15 | object-fit: cover; 16 | 17 | @media (max-width: 1000px) { 18 | display: block; 19 | margin-left: auto; 20 | margin-right: auto; 21 | max-width: 580px; 22 | } 23 | } 24 | 25 | .cta-banner-content { 26 | position: absolute; 27 | top: 206px; 28 | left: 0; 29 | max-width: 580px; 30 | text-align: left; 31 | 32 | @media (max-width: 1000px) { 33 | position: static; 34 | margin-left: auto; 35 | margin-right: auto; 36 | } 37 | } 38 | 39 | .cta-banner-box { 40 | padding: 80px; 41 | background-color: #121212; 42 | color: white; 43 | font-family: $font-mono; 44 | 45 | @media (max-width: 580px) { 46 | padding: 60px; 47 | } 48 | } 49 | 50 | .cta-banner-title { 51 | font-size: 28px; 52 | line-height: 1.786; 53 | 54 | @media (max-width: 580px) { 55 | font-size: 22px; 56 | line-height: 1.909; 57 | } 58 | } 59 | 60 | .cta-banner-text { 61 | margin-top: 5px; 62 | font-size: 17px; 63 | line-height: 2.353; 64 | 65 | @media (max-width: 580px) { 66 | font-size: 16px; 67 | line-height: 2.25; 68 | } 69 | } 70 | 71 | .cta-banner-link-wrapper { 72 | margin-top: 62px; 73 | 74 | @media (max-width: 1190px) { 75 | padding: 0 15px; 76 | } 77 | 78 | @media (max-width: 1000px) { 79 | text-align: center; 80 | } 81 | } 82 | 83 | .cta-banner-link { 84 | font-family: $font-mono; 85 | font-size: 17px; 86 | font-weight: 700; 87 | 88 | &::before { 89 | content: "[ "; 90 | } 91 | 92 | &::after { 93 | content: " ⇥ ]"; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('prismic-website-demo:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | console.log(`Open your browser to http://localhost:${port}`); 18 | 19 | /** 20 | * Create HTTP server. 21 | */ 22 | 23 | var server = http.createServer(app); 24 | 25 | /** 26 | * Listen on provided port, on all network interfaces. 27 | */ 28 | 29 | server.listen(port); 30 | server.on('error', onError); 31 | server.on('listening', onListening); 32 | 33 | /** 34 | * Normalize a port into a number, string, or false. 35 | */ 36 | 37 | function normalizePort(val) { 38 | var port = parseInt(val, 10); 39 | 40 | if (isNaN(port)) { 41 | // named pipe 42 | return val; 43 | } 44 | 45 | if (port >= 0) { 46 | // port number 47 | return port; 48 | } 49 | 50 | return false; 51 | } 52 | 53 | /** 54 | * Event listener for HTTP server "error" event. 55 | */ 56 | 57 | function onError(error) { 58 | if (error.syscall !== 'listen') { 59 | throw error; 60 | } 61 | 62 | var bind = typeof port === 'string' 63 | ? 'Pipe ' + port 64 | : 'Port ' + port; 65 | 66 | // handle specific listen errors with friendly messages 67 | switch (error.code) { 68 | case 'EACCES': 69 | console.error(bind + ' requires elevated privileges'); 70 | process.exit(1); 71 | break; 72 | case 'EADDRINUSE': 73 | console.error(bind + ' is already in use'); 74 | process.exit(1); 75 | break; 76 | default: 77 | throw error; 78 | } 79 | } 80 | 81 | /** 82 | * Event listener for HTTP server "listening" event. 83 | */ 84 | 85 | function onListening() { 86 | var addr = server.address(); 87 | var bind = typeof addr === 'string' 88 | ? 'pipe ' + addr 89 | : 'port ' + addr.port; 90 | debug('Listening on ' + bind); 91 | } 92 | -------------------------------------------------------------------------------- /views/homepage.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(document.data.meta_title), 5 | description: richTextAsPlain(document.data.meta_description), 6 | social: document.data.social, 7 | canonicalUrl: getCanonicalUrl(document) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | <%- richTextAsHtml(document.data.title) %> 16 |
17 |
18 |
19 | 20 |
21 | <%= document.data.banner_image.alt %> 22 |
23 |
24 | <%- richTextAsHtml(document.data.banner_text) %> 25 |
26 |
27 |
28 | 29 |
30 | <% document.data.body.forEach(function (slice) { %> 31 | <% if (slice.slice_type === 'cta_banner') { %> 32 |
33 | <%- include('partials/slices/cta-banner', { slice }); %> 34 |
35 | <% } else if (slice.slice_type === 'featured_items') { %> 36 |
37 | <%- include('partials/slices/products-grid', { slice }); %> 38 |
39 | <% } else if (slice.slice_type === 'big_bullet_item') { %> 40 |
41 | <%- include('partials/slices/numeroted-items', { slice }); %> 42 |
43 | <% } else if (slice.slice_type === 'separator') { %> 44 |
45 | <%- include('partials/slices/separator'); %> 46 |
47 | <% } else if (slice.slice_type === 'text_block') { %> 48 |
49 | <%- include('partials/slices/text-block', { slice }); %> 50 |
51 | <% } %> 52 | <% }); %> 53 |
54 | 55 |
56 | 57 | <%- include('partials/footer'); %> 58 | -------------------------------------------------------------------------------- /assets/scss/pages/_homepage.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Header 3 | */ 4 | 5 | .homepage-header { 6 | padding: 80px 0 100px; 7 | 8 | @media (max-width: 564px) { 9 | padding: 60px 0; 10 | } 11 | } 12 | 13 | .homepage-header-title { 14 | max-width: 764px; 15 | font-family: $font-mono; 16 | font-size: 28px; 17 | line-height: 1.786; 18 | 19 | @media (max-width: 564px) { 20 | font-size: 22px; 21 | line-height: 1.909; 22 | } 23 | } 24 | 25 | /** 26 | * Banner 27 | */ 28 | 29 | .homepage-banner { 30 | position: relative; 31 | 32 | @media (max-width: 1000px) { 33 | position: static; 34 | overflow: hidden; 35 | font-size: 0; 36 | } 37 | } 38 | 39 | .homepage-banner-image { 40 | width: 100%; 41 | height: 600px; 42 | background-color: #f6f6f6; 43 | object-fit: cover; 44 | object-position: left center; 45 | 46 | @media (max-width: 1000px) { 47 | width: 200%; 48 | height: auto; 49 | } 50 | } 51 | 52 | .homepage-banner-box-wrapper { 53 | position: absolute; 54 | top: 0; 55 | left: 0; 56 | right: 0; 57 | max-width: 1160px; 58 | margin-left: auto; 59 | margin-right: auto; 60 | 61 | @media (max-width: 1000px) { 62 | position: static; 63 | } 64 | } 65 | 66 | .homepage-banner-box { 67 | position: relative; 68 | top: 180px; 69 | width: 100%; 70 | max-width: 564px; 71 | margin-left: auto; 72 | padding: 70px; 73 | background-color: #121212; 74 | color: white; 75 | font-family: $font-mono; 76 | font-size: 17px; 77 | line-height: 2.353; 78 | 79 | @media (max-width: 1000px) { 80 | position: static; 81 | max-width: none; 82 | margin-left: 0; 83 | } 84 | 85 | @media (max-width: 564px) { 86 | padding: 60px; 87 | font-size: 16px; 88 | line-height: 2.25; 89 | } 90 | 91 | p:not(:first-child) { 92 | margin-top: 40px; 93 | 94 | @media (max-width: 564px) { 95 | margin-top: 30px; 96 | } 97 | } 98 | } 99 | 100 | /** 101 | * Slices 102 | */ 103 | 104 | .homepage-slices-wrapper { 105 | padding: 130px 0; 106 | } 107 | 108 | .homepage-slice-wrapper { 109 | &:not(:first-child) { 110 | margin-top: 130px; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /assets/scss/fragments/_header.scss: -------------------------------------------------------------------------------- 1 | .header { 2 | padding: 100px 0 50px; 3 | 4 | @media (max-width: 1000px) { 5 | padding: 30px 0; 6 | } 7 | } 8 | 9 | .header--is-nav-opened { 10 | .header-nav { 11 | opacity: 1; 12 | visibility: visible; 13 | transition: 150ms; 14 | } 15 | 16 | .header-burger-img--closed { 17 | opacity: 0; 18 | visibility: hidden; 19 | } 20 | 21 | .header-burger-img--opened { 22 | opacity: 1; 23 | visibility: visible; 24 | } 25 | } 26 | 27 | .header-inner { 28 | display: flex; 29 | justify-content: space-between; 30 | align-items: center; 31 | max-width: 1190px; 32 | padding: 0 15px; 33 | margin: 0 auto; 34 | } 35 | 36 | .header-name { 37 | flex-shrink: 0; 38 | font-size: 28px; 39 | font-weight: 700; 40 | } 41 | 42 | .header-nav { 43 | display: flex; 44 | flex-wrap: wrap; 45 | margin-left: 40px; 46 | color: #7f7d7c; 47 | 48 | @media (max-width: 1000px) { 49 | flex-wrap: nowrap; 50 | flex-direction: column; 51 | margin-left: 0; 52 | 53 | position: absolute; 54 | z-index: 1; 55 | top: 92px; 56 | left: 0; 57 | right: 0; 58 | min-height: calc(100% - 92px); 59 | background-color: #f6f6f6; 60 | font-size: 30px; 61 | opacity: 0; 62 | visibility: hidden; 63 | } 64 | } 65 | 66 | .header-nav-link { 67 | &:not(:last-child) { 68 | margin-right: 40px; 69 | 70 | @media (max-width: 1000px) { 71 | margin-right: 0; 72 | } 73 | } 74 | 75 | @media (max-width: 1000px) { 76 | border-bottom: 1px solid #d6d6d6; 77 | padding: 30px; 78 | } 79 | } 80 | 81 | .header-burger { 82 | display: none; 83 | 84 | position: relative; 85 | width: 32px; 86 | height: 32px; 87 | cursor: pointer; 88 | 89 | @media (max-width: 1000px) { 90 | display: inline-block; 91 | } 92 | } 93 | 94 | .header-burger-img { 95 | position: absolute; 96 | top: 0; 97 | bottom: 0; 98 | left: 0; 99 | right: 0; 100 | width: 100%; 101 | height: 100%; 102 | transition: 150ms; 103 | } 104 | 105 | .header-burger-img--closed { 106 | opacity: 1; 107 | visibility: visible; 108 | } 109 | 110 | .header-burger-img--opened { 111 | opacity: 0; 112 | visibility: hidden; 113 | } 114 | -------------------------------------------------------------------------------- /views/blog-post.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(document.data.meta_title), 5 | description: richTextAsPlain(document.data.meta_description), 6 | social: document.data.social, 7 | canonicalUrl: getCanonicalUrl(document) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | 16 |
17 |
18 | <% if (document.data.image.url) { %> 19 |
20 | <%= document.data.image.alt %> 21 |
22 | <% } %> 23 |
24 | <%- richTextAsHtml(document.data.title) %> 25 |
26 |
27 | <% document.data.body.forEach(function (slice) { %> 28 | <% if (slice.slice_type === 'text_block') { %> 29 |
30 | <%- richTextAsHtml(slice.primary.text) %> 31 |
32 | <% } else if (slice.slice_type === 'image') { %> 33 |
34 | <%= slice.primary.img.alt %> 35 |
36 | <% } else if (slice.slice_type === 'embed') { %> 37 |
38 | <%- slice.primary.embed.html %> 39 |
40 | <% } %> 41 | <% }); %> 42 |
43 | <% if (document.data.author.data) { %> 44 | 57 | <% } %> 58 |
59 |
60 | 61 |
62 | 63 | <%- include('partials/footer'); %> 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /public/bundles/ 2 | 3 | # Created by https://www.gitignore.io/api/node,macos,visualstudiocode 4 | 5 | ### macOS ### 6 | # General 7 | .DS_Store 8 | .AppleDouble 9 | .LSOverride 10 | 11 | # Icon must end with two \r 12 | Icon 13 | 14 | # Thumbnails 15 | ._* 16 | 17 | # Files that might appear in the root of a volume 18 | .DocumentRevisions-V100 19 | .fseventsd 20 | .Spotlight-V100 21 | .TemporaryItems 22 | .Trashes 23 | .VolumeIcon.icns 24 | .com.apple.timemachine.donotpresent 25 | 26 | # Directories potentially created on remote AFP share 27 | .AppleDB 28 | .AppleDesktop 29 | Network Trash Folder 30 | Temporary Items 31 | .apdisk 32 | 33 | ### Node ### 34 | # Logs 35 | logs 36 | *.log 37 | npm-debug.log* 38 | yarn-debug.log* 39 | yarn-error.log* 40 | 41 | # Runtime data 42 | pids 43 | *.pid 44 | *.seed 45 | *.pid.lock 46 | 47 | # Directory for instrumented libs generated by jscoverage/JSCover 48 | lib-cov 49 | 50 | # Coverage directory used by tools like istanbul 51 | coverage 52 | 53 | # nyc test coverage 54 | .nyc_output 55 | 56 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 57 | .grunt 58 | 59 | # Bower dependency directory (https://bower.io/) 60 | bower_components 61 | 62 | # node-waf configuration 63 | .lock-wscript 64 | 65 | # Compiled binary addons (https://nodejs.org/api/addons.html) 66 | build/Release 67 | 68 | # Dependency directories 69 | node_modules/ 70 | jspm_packages/ 71 | 72 | # TypeScript v1 declaration files 73 | typings/ 74 | 75 | # Optional npm cache directory 76 | .npm 77 | 78 | # Optional eslint cache 79 | .eslintcache 80 | 81 | # Optional REPL history 82 | .node_repl_history 83 | 84 | # Output of 'npm pack' 85 | *.tgz 86 | 87 | # Yarn Integrity file 88 | .yarn-integrity 89 | 90 | # dotenv environment variables file 91 | .env 92 | 93 | # parcel-bundler cache (https://parceljs.org/) 94 | .cache 95 | 96 | # next.js build output 97 | .next 98 | 99 | # nuxt.js build output 100 | .nuxt 101 | 102 | # vuepress build output 103 | .vuepress/dist 104 | 105 | # Serverless directories 106 | .serverless 107 | 108 | ### VisualStudioCode ### 109 | .vscode/* 110 | !.vscode/settings.json 111 | !.vscode/tasks.json 112 | !.vscode/launch.json 113 | !.vscode/extensions.json 114 | 115 | # End of https://www.gitignore.io/api/node,macos,visualstudiocode 116 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const createError = require('http-errors'); 2 | const express = require('express'); 3 | const path = require('path'); 4 | const cookieParser = require('cookie-parser'); 5 | const logger = require('morgan'); 6 | const prismicDOM = require('prismic-dom'); 7 | const prismicJS = require('prismic-javascript'); 8 | 9 | const prismicConfig = require('./prismic-configuration.js'); 10 | const linkResolver = require('./link-resolver'); 11 | const indexRouter = require('./routes/index'); 12 | 13 | const app = express(); 14 | 15 | // view engine setup 16 | app.set('views', path.join(__dirname, 'views')); 17 | app.set('view engine', 'ejs'); 18 | 19 | app.use(logger('dev')); 20 | app.use(express.json()); 21 | app.use(express.urlencoded({ extended: false })); 22 | app.use(cookieParser()); 23 | app.use(express.static(path.join(__dirname, 'public'))); 24 | 25 | // Add getCanonicalUrl function in locals 26 | app.use(function (req, res, next) { 27 | res.locals.getCanonicalUrl = function (document) { 28 | return 'http://' + req.headers.host + linkResolver(document); 29 | }; 30 | next(); 31 | }); 32 | 33 | // Prismic middleware 34 | app.use(function (req, res, next) { 35 | res.locals.prismicEndpoint = prismicConfig.endpoint; 36 | res.locals.linkResolver = linkResolver; 37 | res.locals.linkAsUrl = function (field) { 38 | return prismicDOM.Link.url(field, linkResolver); 39 | }; 40 | res.locals.richTextAsHtml = function (field) { 41 | return prismicDOM.RichText.asHtml(field, linkResolver); 42 | }; 43 | res.locals.richTextAsPlain = function (field) { 44 | return prismicDOM.RichText.asText(field); 45 | }; 46 | 47 | prismicJS.api(prismicConfig.endpoint, { req }) 48 | .then((api) => { 49 | req.prismic = { api }; 50 | next(); 51 | }) 52 | .catch((error) => { 53 | res.status(404).send(error.message); 54 | }); 55 | }); 56 | 57 | // retrieve Prismic layout content 58 | app.use(function (req, res, next) { 59 | req.prismic.api.getSingle('layout') 60 | .then((document) => { 61 | res.locals.layoutContent = document.data; 62 | next(); 63 | }) 64 | .catch((error) => { 65 | next(`Error when retrieving "layout" document from Prismic. ${error.message}`); 66 | }); 67 | }); 68 | 69 | // routes 70 | app.use('/', indexRouter); 71 | 72 | // catch 404 and forward to error handler 73 | app.use(function (req, res, next) { 74 | next(createError(404)); 75 | }); 76 | 77 | // error handler 78 | app.use(function (err, req, res, next) { 79 | // set locals, only providing error in development 80 | res.locals.message = err.message; 81 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 82 | 83 | // render the error page 84 | res.status(err.status || 500); 85 | res.render('error'); 86 | }); 87 | 88 | module.exports = app; 89 | -------------------------------------------------------------------------------- /assets/scss/pages/_blog-post.scss: -------------------------------------------------------------------------------- 1 | .blog-post-article { 2 | padding: 70px 0 130px; 3 | } 4 | 5 | .blog-post-inner { 6 | max-width: 794px; 7 | padding-left: 15px; 8 | padding-right: 15px; 9 | margin-left: auto; 10 | margin-right: auto; 11 | } 12 | 13 | .blog-post-image-wrapper { 14 | margin-bottom: 130px; 15 | font-size: 0; 16 | text-align: center; 17 | } 18 | 19 | .blog-post-image { 20 | width: 100%; 21 | max-height: 564px; 22 | object-fit: cover; 23 | } 24 | 25 | .blog-post-title { 26 | max-width: 554px; 27 | margin: 0 auto; 28 | font-family: $font-mono; 29 | font-size: 28px; 30 | font-weight: 700; 31 | line-height: 1.786; 32 | text-align: center; 33 | } 34 | 35 | .blog-post-slices-wrapper { 36 | margin-top: 45px; 37 | } 38 | 39 | .blog-post-slice-text { 40 | font-family: $font-mono; 41 | font-size: 17px; 42 | line-height: 2.353; 43 | 44 | p { 45 | &:not(:first-child) { 46 | margin-top: 30px; 47 | } 48 | 49 | &:not(:last-child) { 50 | margin-bottom: 30px; 51 | } 52 | } 53 | 54 | h2 { 55 | &:not(:first-child) { 56 | margin-top: 70px; 57 | } 58 | 59 | &:not(:last-child) { 60 | margin-bottom: 70px; 61 | } 62 | 63 | max-width: 554px; 64 | margin-left: auto; 65 | margin-right: auto; 66 | font-size: 28px; 67 | font-weight: 700; 68 | line-height: 1.786; 69 | text-align: center; 70 | } 71 | 72 | a { 73 | text-decoration: underline; 74 | } 75 | } 76 | 77 | .blog-post-slice-img { 78 | &:not(:first-child) { 79 | margin-top: 70px; 80 | } 81 | 82 | &:not(:last-child) { 83 | margin-bottom: 70px; 84 | } 85 | 86 | font-size: 0; 87 | 88 | img { 89 | max-width: 100%; 90 | } 91 | } 92 | 93 | .blog-post-slice-embed { 94 | &:not(:first-child) { 95 | margin-top: 70px; 96 | } 97 | 98 | &:not(:last-child) { 99 | margin-bottom: 70px; 100 | } 101 | 102 | iframe { 103 | display: block; 104 | margin: 0 auto; 105 | max-width: 100%; 106 | } 107 | } 108 | 109 | .blog-post-author-wrapper { 110 | display: flex; 111 | border-top: 1px solid #d6d6d6; 112 | margin-top: 70px; 113 | padding-top: 50px; 114 | 115 | @media (max-width: 564px) { 116 | flex-direction: column; 117 | } 118 | } 119 | 120 | .blog-post-author-picture { 121 | margin-right: 46px; 122 | width: 124px; 123 | height: 124px; 124 | border-radius: 62px; 125 | object-fit: cover; 126 | 127 | @media (max-width: 564px) { 128 | margin-right: 0; 129 | margin-bottom: 30px; 130 | } 131 | } 132 | 133 | .blog-post-author-name { 134 | font-family: $font-mono; 135 | font-size: 18px; 136 | font-weight: 700; 137 | line-height: 1.667; 138 | } 139 | 140 | .blog-post-author-bio { 141 | margin-top: 10px; 142 | font-family: $font-mono; 143 | font-size: 14px; 144 | line-height: 2.286; 145 | } 146 | -------------------------------------------------------------------------------- /views/partials/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <% if (locals.meta && meta.title) { %> 8 | <%= meta.title %> 9 | <% } else { %> 10 | Disrupt Coffee 11 | <% } %> 12 | 13 | 14 | 15 | <% if (locals.meta && meta.description) { %> 16 | 17 | <% } %> 18 | 19 | <% if (locals.meta && meta.social) { %> 20 | <% meta.social.forEach(function (slice) { %> 21 | <% if (slice.slice_type === 'twitter_card') { %> 22 | 23 | 24 | 25 | 26 | <% } else if (slice.slice_type === 'open_graph') { %> 27 | 28 | 29 | 30 | 31 | <% if (meta.canonicalUrl) { %> 32 | 33 | <% } %> 34 | <% } %> 35 | <% }); %> 36 | <% } %> 37 | 38 | 39 | 40 | 41 | 42 | 47 | 48 | 49 | 50 | 51 | <% if (layoutContent.site_name && layoutContent.header_nav_items.length > 0) { %> 52 | 70 | <% } %> 71 | 72 |
73 | -------------------------------------------------------------------------------- /custom_types/blog_home.json: -------------------------------------------------------------------------------- 1 | { 2 | "SEO & Social" : { 3 | "meta_title" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "heading1", 7 | "label" : "Meta title", 8 | "placeholder" : "Meta title" 9 | } 10 | }, 11 | "meta_description" : { 12 | "type" : "StructuredText", 13 | "config" : { 14 | "single" : "paragraph", 15 | "label" : "Meta description", 16 | "placeholder" : "Meta description" 17 | } 18 | }, 19 | "social" : { 20 | "type" : "Slices", 21 | "fieldset" : "Slice zone", 22 | "config" : { 23 | "choices" : { 24 | "twitter_card" : { 25 | "type" : "Slice", 26 | "fieldset" : "Twitter Card", 27 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 28 | "icon" : "credit_card", 29 | "display" : "list", 30 | "non-repeat" : { 31 | "twitter_title" : { 32 | "type" : "StructuredText", 33 | "config" : { 34 | "single" : "paragraph", 35 | "label" : "Title", 36 | "placeholder" : "Title for Twitter Card" 37 | } 38 | }, 39 | "twitter_description" : { 40 | "type" : "StructuredText", 41 | "config" : { 42 | "single" : "paragraph", 43 | "label" : "Description", 44 | "placeholder" : "Description for Twitter Card" 45 | } 46 | }, 47 | "twitter_image" : { 48 | "type" : "Image", 49 | "config" : { 50 | "constraint" : { 51 | "width" : 1200, 52 | "height" : 675 53 | }, 54 | "thumbnails" : [ ], 55 | "label" : "Image" 56 | } 57 | } 58 | }, 59 | "repeat" : { } 60 | }, 61 | "open_graph" : { 62 | "type" : "Slice", 63 | "fieldset" : "Open Graph", 64 | "description" : "Fields to customize Open Graph", 65 | "icon" : "thumb_up", 66 | "display" : "list", 67 | "non-repeat" : { 68 | "og_title" : { 69 | "type" : "StructuredText", 70 | "config" : { 71 | "single" : "paragraph", 72 | "label" : "Title", 73 | "placeholder" : "Title for Open Graph" 74 | } 75 | }, 76 | "og_description" : { 77 | "type" : "StructuredText", 78 | "config" : { 79 | "single" : "paragraph", 80 | "label" : "Description", 81 | "placeholder" : "Description for Open Graph" 82 | } 83 | }, 84 | "og_image" : { 85 | "type" : "Image", 86 | "config" : { 87 | "constraint" : { 88 | "width" : 1200, 89 | "height" : 628 90 | }, 91 | "thumbnails" : [ ], 92 | "label" : "Image" 93 | } 94 | } 95 | }, 96 | "repeat" : { } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /custom_types/products.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "title" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "heading1", 7 | "label" : "Title" 8 | } 9 | } 10 | }, 11 | "SEO & Social" : { 12 | "meta_title" : { 13 | "type" : "StructuredText", 14 | "config" : { 15 | "single" : "heading1", 16 | "label" : "Meta title", 17 | "placeholder" : "Meta title" 18 | } 19 | }, 20 | "meta_description" : { 21 | "type" : "StructuredText", 22 | "config" : { 23 | "single" : "paragraph", 24 | "label" : "Meta description", 25 | "placeholder" : "Meta description" 26 | } 27 | }, 28 | "social" : { 29 | "type" : "Slices", 30 | "fieldset" : "Slice zone", 31 | "config" : { 32 | "choices" : { 33 | "twitter_card" : { 34 | "type" : "Slice", 35 | "fieldset" : "Twitter Card", 36 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 37 | "icon" : "credit_card", 38 | "display" : "list", 39 | "non-repeat" : { 40 | "twitter_title" : { 41 | "type" : "StructuredText", 42 | "config" : { 43 | "single" : "paragraph", 44 | "label" : "Title", 45 | "placeholder" : "Title for Twitter Card" 46 | } 47 | }, 48 | "twitter_description" : { 49 | "type" : "StructuredText", 50 | "config" : { 51 | "single" : "paragraph", 52 | "label" : "Description", 53 | "placeholder" : "Description for Twitter Card" 54 | } 55 | }, 56 | "twitter_image" : { 57 | "type" : "Image", 58 | "config" : { 59 | "constraint" : { 60 | "width" : 1200, 61 | "height" : 675 62 | }, 63 | "thumbnails" : [ ], 64 | "label" : "Image" 65 | } 66 | } 67 | }, 68 | "repeat" : { } 69 | }, 70 | "open_graph" : { 71 | "type" : "Slice", 72 | "fieldset" : "Open Graph", 73 | "description" : "Fields to customize Open Graph", 74 | "icon" : "thumb_up", 75 | "display" : "list", 76 | "non-repeat" : { 77 | "og_title" : { 78 | "type" : "StructuredText", 79 | "config" : { 80 | "single" : "paragraph", 81 | "label" : "Title", 82 | "placeholder" : "Title for Open Graph" 83 | } 84 | }, 85 | "og_description" : { 86 | "type" : "StructuredText", 87 | "config" : { 88 | "single" : "paragraph", 89 | "label" : "Description", 90 | "placeholder" : "Description for Open Graph" 91 | } 92 | }, 93 | "og_image" : { 94 | "type" : "Image", 95 | "config" : { 96 | "constraint" : { 97 | "width" : 1200, 98 | "height" : 628 99 | }, 100 | "thumbnails" : [ ], 101 | "label" : "Image" 102 | } 103 | } 104 | }, 105 | "repeat" : { } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /views/product.ejs: -------------------------------------------------------------------------------- 1 | <%- 2 | include('partials/header', { 3 | meta: { 4 | title: richTextAsPlain(document.data.meta_title), 5 | description: richTextAsPlain(document.data.meta_description), 6 | social: document.data.social, 7 | canonicalUrl: getCanonicalUrl(document) 8 | } 9 | }); 10 | %> 11 | 12 |
13 |
14 |
15 | 16 |
17 | 18 |
19 |
20 |
21 | <%= document.data.product_image.alt %> 26 |
27 |

28 | <% const product = document.data.product %> 29 | <%= product ? product.title : 'Unknown' %> 30 |

31 |

32 | <%= product ? product.country : 'Unknown' %> 33 |

34 |
    35 |
  • 36 | <%= product ? product.price : 'Unknown' %> per <%= product ? product.weight : 'Unknown' %> 37 |
  • 38 |
  • 39 | Taste & Notes: <%= product ? product.taste : 'Unknown' %> 40 |
  • 41 |
  • 42 | Origin: <%= product ? product.origin : 'Unknown' %> 43 |
  • 44 |
  • 45 | Varietal: <%= product ? product.varietal : 'Unknown' %> 46 |
  • 47 |
  • 48 | Process: <%= product ? product.process : 'Unknown' %> 49 |
  • 50 |
51 |

Shipping

52 |

53 | <%= product ? product.shipping : 'Unknown' %> 54 |

55 |
56 | 61 |
62 |
63 |
64 |
65 |
66 | 67 |
68 |
69 |
70 | <%- richTextAsHtml(document.data.title) %> 71 |
72 |
73 | <%- richTextAsHtml(document.data.product_description) %> 74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 |
82 |
83 | 84 |
85 |
86 |
87 |
88 | <%- richTextAsHtml(document.data.related_products_title) %> 89 |
90 |
91 |
92 |
93 | <% document.data.related_products.forEach(function (item) { %> 94 | <% if (item.product1.data) { %> 95 | 96 | <%= item.product1.data.product_image.alt %> 101 |

102 | <% const linkedProduct = item.product1.data.product %> 103 | <%= linkedProduct ? linkedProduct.title : '' %> 104 |

105 |

106 | <%= linkedProduct ? linkedProduct.country : '' %> 107 |

108 |
109 | <% } %> 110 | <% }); %> 111 |
112 |
113 | 114 |
115 | 116 |
117 | 118 | <%- include('partials/footer'); %> 119 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const prismicJS = require('prismic-javascript'); 3 | 4 | const linkResolver = require('../link-resolver'); 5 | 6 | const router = express.Router(); 7 | 8 | /* GET homepage. */ 9 | router.get('/', function (req, res, next) { 10 | const graphQuery = `{ 11 | homepage { 12 | ...homepageFields 13 | body { 14 | ...on featured_items { 15 | non-repeat { 16 | ...non-repeatFields 17 | } 18 | repeat { 19 | ...repeatFields 20 | link_to_product { 21 | product_image 22 | product 23 | } 24 | } 25 | } 26 | ...on cta_banner { 27 | non-repeat { 28 | ...non-repeatFields 29 | } 30 | repeat { 31 | ...repeatFields 32 | } 33 | } 34 | ...on big_bullet_item { 35 | non-repeat { 36 | ...non-repeatFields 37 | } 38 | repeat { 39 | ...repeatFields 40 | } 41 | } 42 | ...on separator { 43 | non-repeat { 44 | ...non-repeatFields 45 | } 46 | repeat { 47 | ...repeatFields 48 | } 49 | } 50 | ...on text_block { 51 | non-repeat { 52 | ...non-repeatFields 53 | } 54 | repeat { 55 | ...repeatFields 56 | } 57 | } 58 | } 59 | } 60 | }`; 61 | 62 | req.prismic.api.getSingle('homepage', { graphQuery }) 63 | .then((document) => { 64 | res.render('homepage', { document }); 65 | }) 66 | .catch((error) => { 67 | next(`Error when retrieving "homepage" document from Prismic. ${error.message}`); 68 | }); 69 | }); 70 | 71 | /* GET products. */ 72 | router.get('/products', function (req, res, next) { 73 | const queryProductsDocument = req.prismic.api.getSingle('products'); 74 | const queryProductDocuments = req.prismic.api.query(prismicJS.Predicates.at('document.type', 'product'), { pageSize: 24 }); 75 | 76 | Promise.all([queryProductsDocument, queryProductDocuments]) 77 | .then((values) => { 78 | const productsDocument = values[0]; 79 | const productDocuments = values[1].results; 80 | res.render('products', { productsDocument, productDocuments }); 81 | }) 82 | .catch((error) => { 83 | next(`Error when retrieving documents from Prismic. ${error.message}`); 84 | }); 85 | }); 86 | 87 | /* GET product. */ 88 | router.get('/products/:uid', function (req, res, next) { 89 | const graphQuery = `{ 90 | product { 91 | ...productFields 92 | related_products { 93 | ...related_productsFields 94 | product1 { 95 | product_image 96 | product 97 | } 98 | } 99 | } 100 | }`; 101 | 102 | req.prismic.api.getByUID('product', req.params.uid, { graphQuery }) 103 | .then((document) => { 104 | if (document) { 105 | res.render('product', { document }); 106 | } 107 | res.render('page-404'); 108 | }) 109 | .catch((error) => { 110 | next(`Error when retrieving "product" document from Prismic. ${error.message}`); 111 | }); 112 | }); 113 | 114 | /* GET blog home. */ 115 | router.get('/blog', function (req, res, next) { 116 | const queryBlogHomeDocument = req.prismic.api.getSingle('blog_home'); 117 | const queryBlogPostDocuments = req.prismic.api.query(prismicJS.Predicates.at('document.type', 'blog_post'), { pageSize: 10 }); 118 | 119 | Promise.all([queryBlogHomeDocument, queryBlogPostDocuments]) 120 | .then((values) => { 121 | const blogHomeDocument = values[0]; 122 | const blogPostDocuments = values[1].results; 123 | res.render('blog-home', { blogHomeDocument, blogPostDocuments }); 124 | }) 125 | .catch((error) => { 126 | next(`Error when retrieving documents from Prismic. ${error.message}`); 127 | }); 128 | }); 129 | 130 | /* GET blog post. */ 131 | router.get('/blog/:uid', function (req, res, next) { 132 | const graphQuery = `{ 133 | blog_post { 134 | ...blog_postFields 135 | author { 136 | name 137 | bio 138 | picture 139 | } 140 | } 141 | }`; 142 | 143 | req.prismic.api.getByUID('blog_post', req.params.uid, { graphQuery }) 144 | .then((document) => { 145 | if (document) { 146 | res.render('blog-post', { document }); 147 | } 148 | res.render('page-404'); 149 | }) 150 | .catch((error) => { 151 | next(`Error when retrieving "blog_post" document from Prismic. ${error.message}`); 152 | }); 153 | }); 154 | 155 | /* GET landing page. */ 156 | router.get('/pages/:uid', function (req, res, next) { 157 | req.prismic.api.getByUID('landing_page', req.params.uid) 158 | .then((document) => { 159 | if (document) { 160 | res.render('landing-page', { document }); 161 | } 162 | res.render('page-404'); 163 | }) 164 | .catch((error) => { 165 | next(`Error when retrieving "landing_page" document from Prismic. ${error.message}`); 166 | }); 167 | }); 168 | 169 | /* In-Website Preview by Prismic. */ 170 | router.get('/preview', function (req, res) { 171 | req.prismic.api.previewSession(req.query.token, linkResolver, '/') 172 | .then((url) => { 173 | res.redirect(302, url); 174 | }); 175 | }); 176 | 177 | router.get('*', function (req, res) { 178 | res.status(404).render('page-404'); 179 | }); 180 | 181 | module.exports = router; 182 | -------------------------------------------------------------------------------- /custom_types/blog_post.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "title" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "heading1", 7 | "label" : "Title" 8 | } 9 | }, 10 | "image" : { 11 | "type" : "Image", 12 | "config" : { 13 | "constraint" : { }, 14 | "thumbnails" : [ ], 15 | "label" : "Image" 16 | } 17 | }, 18 | "excerpt" : { 19 | "type" : "StructuredText", 20 | "config" : { 21 | "single" : "paragraph", 22 | "label" : "Excerpt" 23 | } 24 | }, 25 | "body" : { 26 | "type" : "Slices", 27 | "fieldset" : "Slice zone", 28 | "config" : { 29 | "choices" : { 30 | "text_block" : { 31 | "type" : "Slice", 32 | "fieldset" : "Text Block", 33 | "description" : "Rich Text", 34 | "icon" : "text_fields", 35 | "display" : "list", 36 | "non-repeat" : { 37 | "text" : { 38 | "type" : "StructuredText", 39 | "config" : { 40 | "multi" : "paragraph, heading2, strong, em, hyperlink", 41 | "allowTargetBlank" : true, 42 | "label" : "Text", 43 | "placeholder" : "Type your text here" 44 | } 45 | } 46 | }, 47 | "repeat" : { } 48 | }, 49 | "image" : { 50 | "type" : "Slice", 51 | "fieldset" : "Image", 52 | "description" : "Image", 53 | "icon" : "image", 54 | "display" : "list", 55 | "non-repeat" : { 56 | "img" : { 57 | "type" : "Image", 58 | "config" : { 59 | "constraint" : { }, 60 | "thumbnails" : [ ], 61 | "label" : "Image" 62 | } 63 | } 64 | }, 65 | "repeat" : { } 66 | }, 67 | "embed" : { 68 | "type" : "Slice", 69 | "fieldset" : "Embed", 70 | "description" : "Youtube, Instagram, ...", 71 | "icon" : "cloud", 72 | "display" : "list", 73 | "non-repeat" : { 74 | "embed" : { 75 | "type" : "Embed", 76 | "config" : { 77 | "label" : "Embed" 78 | } 79 | } 80 | }, 81 | "repeat" : { } 82 | } 83 | } 84 | } 85 | } 86 | }, 87 | "SEO & Social" : { 88 | "uid" : { 89 | "type" : "UID", 90 | "config" : { 91 | "label" : "UID" 92 | } 93 | }, 94 | "meta_title" : { 95 | "type" : "StructuredText", 96 | "config" : { 97 | "single" : "heading1", 98 | "label" : "Meta title", 99 | "placeholder" : "Meta title" 100 | } 101 | }, 102 | "meta_description" : { 103 | "type" : "StructuredText", 104 | "config" : { 105 | "single" : "paragraph", 106 | "label" : "Meta description", 107 | "placeholder" : "Meta description" 108 | } 109 | }, 110 | "author" : { 111 | "type" : "Link", 112 | "config" : { 113 | "select" : "document", 114 | "customtypes" : [ "author" ], 115 | "label" : "Author", 116 | "placeholder" : "Johnny McJohn" 117 | } 118 | }, 119 | "social" : { 120 | "type" : "Slices", 121 | "fieldset" : "Slice zone", 122 | "config" : { 123 | "choices" : { 124 | "twitter_card" : { 125 | "type" : "Slice", 126 | "fieldset" : "Twitter Card", 127 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 128 | "icon" : "credit_card", 129 | "display" : "list", 130 | "non-repeat" : { 131 | "twitter_title" : { 132 | "type" : "StructuredText", 133 | "config" : { 134 | "single" : "paragraph", 135 | "label" : "Title", 136 | "placeholder" : "Title for Twitter Card" 137 | } 138 | }, 139 | "twitter_description" : { 140 | "type" : "StructuredText", 141 | "config" : { 142 | "single" : "paragraph", 143 | "label" : "Description", 144 | "placeholder" : "Description for Twitter Card" 145 | } 146 | }, 147 | "twitter_image" : { 148 | "type" : "Image", 149 | "config" : { 150 | "constraint" : { 151 | "width" : 1200, 152 | "height" : 675 153 | }, 154 | "thumbnails" : [ ], 155 | "label" : "Image" 156 | } 157 | } 158 | }, 159 | "repeat" : { } 160 | }, 161 | "open_graph" : { 162 | "type" : "Slice", 163 | "fieldset" : "Open Graph", 164 | "description" : "Fields to customize Open Graph", 165 | "icon" : "thumb_up", 166 | "display" : "list", 167 | "non-repeat" : { 168 | "og_title" : { 169 | "type" : "StructuredText", 170 | "config" : { 171 | "single" : "paragraph", 172 | "label" : "Title", 173 | "placeholder" : "Title for Open Graph" 174 | } 175 | }, 176 | "og_description" : { 177 | "type" : "StructuredText", 178 | "config" : { 179 | "single" : "paragraph", 180 | "label" : "Description", 181 | "placeholder" : "Description for Open Graph" 182 | } 183 | }, 184 | "og_image" : { 185 | "type" : "Image", 186 | "config" : { 187 | "constraint" : { 188 | "width" : 1200, 189 | "height" : 628 190 | }, 191 | "thumbnails" : [ ], 192 | "label" : "Image" 193 | } 194 | } 195 | }, 196 | "repeat" : { } 197 | } 198 | } 199 | } 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /custom_types/product.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "product_image" : { 4 | "type" : "Image", 5 | "config" : { 6 | "constraint" : { }, 7 | "thumbnails" : [ ], 8 | "label" : "Product Image" 9 | } 10 | }, 11 | "product_name" : { 12 | "type" : "StructuredText", 13 | "config" : { 14 | "single" : "heading1", 15 | "label" : "Product Name", 16 | "placeholder" : "Thought Leader's Coffee" 17 | } 18 | }, 19 | "rich_content" : { 20 | "type" : "StructuredText", 21 | "config" : { 22 | "multi" : "paragraph, heading2, list-item", 23 | "label" : "Rich content" 24 | } 25 | }, 26 | "button_label" : { 27 | "type" : "StructuredText", 28 | "config" : { 29 | "single" : "paragraph", 30 | "label" : "Button Label", 31 | "placeholder" : "Add to cart" 32 | } 33 | }, 34 | "sub_title" : { 35 | "type" : "StructuredText", 36 | "config" : { 37 | "single" : "heading2", 38 | "label" : "Sub title", 39 | "placeholder" : "Kenya" 40 | } 41 | }, 42 | "product" : { 43 | "type" : "IntegrationFields", 44 | "config" : { 45 | "catalog" : "new-demo--products_catalog", 46 | "label" : "Product", 47 | "placeholder" : "Map this product page with the Product Catalog data" 48 | } 49 | }, 50 | "product_old" : { 51 | "type" : "IntegrationFields", 52 | "config" : { 53 | "catalog" : "new-demo--disrupt_coffee_catalog_api", 54 | "label" : "Product_old", 55 | "placeholder" : "Map this product page with the Product Catalog data" 56 | } 57 | } 58 | }, 59 | "Product Description" : { 60 | "title" : { 61 | "type" : "StructuredText", 62 | "config" : { 63 | "single" : "heading2", 64 | "label" : "Title", 65 | "placeholder" : "What we like" 66 | } 67 | }, 68 | "product_description" : { 69 | "type" : "StructuredText", 70 | "config" : { 71 | "multi" : "paragraph, heading3, heading4, heading5, strong, em, hyperlink, list-item, o-list-item, o-list-item", 72 | "allowTargetBlank" : true, 73 | "label" : "Product description", 74 | "placeholder" : "This coffee guarantees a rather complex set of flavors" 75 | } 76 | } 77 | }, 78 | "Related Product" : { 79 | "related_products_title" : { 80 | "type" : "StructuredText", 81 | "config" : { 82 | "single" : "heading2", 83 | "label" : "Title" 84 | } 85 | }, 86 | "related_products" : { 87 | "type" : "Group", 88 | "config" : { 89 | "fields" : { 90 | "product1" : { 91 | "type" : "Link", 92 | "config" : { 93 | "select" : "document", 94 | "customtypes" : [ "product" ], 95 | "label" : "Product", 96 | "placeholder" : "Select a product" 97 | } 98 | } 99 | }, 100 | "label" : "Related products" 101 | } 102 | } 103 | }, 104 | "SEO & Social" : { 105 | "uid" : { 106 | "type" : "UID", 107 | "config" : { 108 | "label" : "Slug for url", 109 | "placeholder" : "uid" 110 | } 111 | }, 112 | "meta_title" : { 113 | "type" : "StructuredText", 114 | "config" : { 115 | "single" : "heading1", 116 | "label" : "Meta title", 117 | "placeholder" : "Meta title" 118 | } 119 | }, 120 | "meta_description" : { 121 | "type" : "StructuredText", 122 | "config" : { 123 | "single" : "paragraph", 124 | "label" : "Meta description", 125 | "placeholder" : "Meta description" 126 | } 127 | }, 128 | "social" : { 129 | "type" : "Slices", 130 | "fieldset" : "Slice zone", 131 | "config" : { 132 | "choices" : { 133 | "twitter_card" : { 134 | "type" : "Slice", 135 | "fieldset" : "Twitter Card", 136 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 137 | "icon" : "credit_card", 138 | "display" : "list", 139 | "non-repeat" : { 140 | "twitter_title" : { 141 | "type" : "StructuredText", 142 | "config" : { 143 | "single" : "paragraph", 144 | "label" : "Title", 145 | "placeholder" : "Title for Twitter Card" 146 | } 147 | }, 148 | "twitter_description" : { 149 | "type" : "StructuredText", 150 | "config" : { 151 | "single" : "paragraph", 152 | "label" : "Description", 153 | "placeholder" : "Description for Twitter Card" 154 | } 155 | }, 156 | "twitter_image" : { 157 | "type" : "Image", 158 | "config" : { 159 | "constraint" : { 160 | "width" : 1200, 161 | "height" : 675 162 | }, 163 | "thumbnails" : [ ], 164 | "label" : "Image" 165 | } 166 | } 167 | }, 168 | "repeat" : { } 169 | }, 170 | "open_graph" : { 171 | "type" : "Slice", 172 | "fieldset" : "Open Graph", 173 | "description" : "Fields to customize Open Graph", 174 | "icon" : "thumb_up", 175 | "display" : "list", 176 | "non-repeat" : { 177 | "og_title" : { 178 | "type" : "StructuredText", 179 | "config" : { 180 | "single" : "paragraph", 181 | "label" : "Title", 182 | "placeholder" : "Title for Open Graph" 183 | } 184 | }, 185 | "og_description" : { 186 | "type" : "StructuredText", 187 | "config" : { 188 | "single" : "paragraph", 189 | "label" : "Description", 190 | "placeholder" : "Description for Open Graph" 191 | } 192 | }, 193 | "og_image" : { 194 | "type" : "Image", 195 | "config" : { 196 | "constraint" : { 197 | "width" : 1200, 198 | "height" : 628 199 | }, 200 | "thumbnails" : [ ], 201 | "label" : "Image" 202 | } 203 | } 204 | }, 205 | "repeat" : { } 206 | } 207 | } 208 | } 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /custom_types/landing_page.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "title" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "heading1, strong", 7 | "label" : "Title", 8 | "placeholder" : "Title" 9 | } 10 | }, 11 | "body" : { 12 | "type" : "Slices", 13 | "fieldset" : "Slice zone", 14 | "config" : { 15 | "labels" : { 16 | "product_quote" : [ { 17 | "name" : "normal", 18 | "display" : "Text left - Image right (default)" 19 | }, { 20 | "name" : "reverse", 21 | "display" : "Text right - Image left" 22 | } ] 23 | }, 24 | "choices" : { 25 | "big_bullet_item" : { 26 | "type" : "Slice", 27 | "fieldset" : "Item with numbers", 28 | "description" : "1 number and description in a grid layout", 29 | "icon" : "filter_1", 30 | "display" : "grid", 31 | "non-repeat" : { 32 | "title_section" : { 33 | "type" : "StructuredText", 34 | "config" : { 35 | "single" : "heading2", 36 | "label" : "Title Section", 37 | "placeholder" : "How it works ..." 38 | } 39 | } 40 | }, 41 | "repeat" : { 42 | "description_paragraph" : { 43 | "type" : "StructuredText", 44 | "config" : { 45 | "multi" : "paragraph, strong, em", 46 | "label" : "Description paragraph", 47 | "placeholder" : "Select some amazing coffee" 48 | } 49 | } 50 | } 51 | }, 52 | "banner_split" : { 53 | "type" : "Slice", 54 | "fieldset" : "Banner split", 55 | "description" : "Banner image with splitted text", 56 | "icon" : "image", 57 | "display" : "list", 58 | "non-repeat" : { 59 | "banner_image" : { 60 | "type" : "Image", 61 | "config" : { 62 | "constraint" : { }, 63 | "thumbnails" : [ ], 64 | "label" : "Image" 65 | } 66 | }, 67 | "banner_title" : { 68 | "type" : "StructuredText", 69 | "config" : { 70 | "single" : "heading2", 71 | "label" : "Title" 72 | } 73 | }, 74 | "banner_text" : { 75 | "type" : "StructuredText", 76 | "config" : { 77 | "single" : "paragraph", 78 | "label" : "Text" 79 | } 80 | } 81 | }, 82 | "repeat" : { } 83 | }, 84 | "product_quote" : { 85 | "type" : "Slice", 86 | "fieldset" : "Product + quote", 87 | "description" : "Product + quote", 88 | "icon" : "format_quote", 89 | "display" : "list", 90 | "non-repeat" : { 91 | "quote_background" : { 92 | "type" : "Image", 93 | "config" : { 94 | "constraint" : { }, 95 | "thumbnails" : [ ], 96 | "label" : "Quote background" 97 | } 98 | }, 99 | "quote_text" : { 100 | "type" : "StructuredText", 101 | "config" : { 102 | "single" : "paragraph", 103 | "label" : "Quote text" 104 | } 105 | }, 106 | "quote_author" : { 107 | "type" : "StructuredText", 108 | "config" : { 109 | "single" : "paragraph", 110 | "label" : "Quote author" 111 | } 112 | }, 113 | "product_image" : { 114 | "type" : "Image", 115 | "config" : { 116 | "constraint" : { }, 117 | "thumbnails" : [ ], 118 | "label" : "Product image" 119 | } 120 | }, 121 | "product_description" : { 122 | "type" : "StructuredText", 123 | "config" : { 124 | "single" : "paragraph", 125 | "label" : "Product description" 126 | } 127 | } 128 | }, 129 | "repeat" : { } 130 | } 131 | } 132 | } 133 | } 134 | }, 135 | "SEO & Social" : { 136 | "uid" : { 137 | "type" : "UID", 138 | "config" : { 139 | "label" : "Slug for url", 140 | "placeholder" : "uid" 141 | } 142 | }, 143 | "meta_title" : { 144 | "type" : "StructuredText", 145 | "config" : { 146 | "single" : "heading1", 147 | "label" : "Meta title", 148 | "placeholder" : "Meta title" 149 | } 150 | }, 151 | "meta_description" : { 152 | "type" : "StructuredText", 153 | "config" : { 154 | "single" : "paragraph", 155 | "label" : "Meta description", 156 | "placeholder" : "Meta description" 157 | } 158 | }, 159 | "social" : { 160 | "type" : "Slices", 161 | "fieldset" : "Slice zone", 162 | "config" : { 163 | "choices" : { 164 | "twitter_card" : { 165 | "type" : "Slice", 166 | "fieldset" : "Twitter Card", 167 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 168 | "icon" : "credit_card", 169 | "display" : "list", 170 | "non-repeat" : { 171 | "twitter_title" : { 172 | "type" : "StructuredText", 173 | "config" : { 174 | "single" : "paragraph", 175 | "label" : "Title", 176 | "placeholder" : "Title for Twitter Card" 177 | } 178 | }, 179 | "twitter_description" : { 180 | "type" : "StructuredText", 181 | "config" : { 182 | "single" : "paragraph", 183 | "label" : "Description", 184 | "placeholder" : "Description for Twitter Card" 185 | } 186 | }, 187 | "twitter_image" : { 188 | "type" : "Image", 189 | "config" : { 190 | "constraint" : { 191 | "width" : 1200, 192 | "height" : 675 193 | }, 194 | "thumbnails" : [ ], 195 | "label" : "Image" 196 | } 197 | } 198 | }, 199 | "repeat" : { } 200 | }, 201 | "open_graph" : { 202 | "type" : "Slice", 203 | "fieldset" : "Open Graph", 204 | "description" : "Fields to customize Open Graph", 205 | "icon" : "thumb_up", 206 | "display" : "list", 207 | "non-repeat" : { 208 | "og_title" : { 209 | "type" : "StructuredText", 210 | "config" : { 211 | "single" : "paragraph", 212 | "label" : "Title", 213 | "placeholder" : "Title for Open Graph" 214 | } 215 | }, 216 | "og_description" : { 217 | "type" : "StructuredText", 218 | "config" : { 219 | "single" : "paragraph", 220 | "label" : "Description", 221 | "placeholder" : "Description for Open Graph" 222 | } 223 | }, 224 | "og_image" : { 225 | "type" : "Image", 226 | "config" : { 227 | "constraint" : { 228 | "width" : 1200, 229 | "height" : 628 230 | }, 231 | "thumbnails" : [ ], 232 | "label" : "Image" 233 | } 234 | } 235 | }, 236 | "repeat" : { } 237 | } 238 | } 239 | } 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /assets/scss/base/_resetr.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * resetr.css v3.0.0 3 | * MIT License 4 | * github.com/jbdebiasio/resetr.css 5 | * 6 | * Based on ress.css v1.2.2 and normalize.css v8.0.0 7 | * github.com/filipelinhares/ress 8 | * github.com/necolas/normalize.css 9 | */ 10 | 11 | /* # ================================================================= 12 | # Global selectors 13 | # ================================================================= */ 14 | 15 | html { 16 | box-sizing: border-box; 17 | background: white; 18 | color: black; 19 | font-family: sans-serif; 20 | font-size: 16px; 21 | line-height: 1.15; 22 | -ms-text-size-adjust: 100%; 23 | -webkit-text-size-adjust: 100%; /* iOS 8+ */ 24 | } 25 | 26 | *, 27 | ::before, 28 | ::after { 29 | box-sizing: inherit; 30 | } 31 | 32 | ::before, 33 | ::after { 34 | text-decoration: inherit; /* Inherit text-decoration and vertical align to ::before and ::after pseudo elements */ 35 | vertical-align: inherit; 36 | } 37 | 38 | * { 39 | padding: 0; /* Reset `padding` and `margin` of all elements */ 40 | margin: 0; 41 | font: inherit; 42 | } 43 | 44 | /* # ================================================================= 45 | # General elements 46 | # ================================================================= */ 47 | 48 | /* Add the correct display in iOS 4-7.*/ 49 | audio:not([controls]) { 50 | display: none; 51 | height: 0; 52 | } 53 | 54 | hr { 55 | height: 0; 56 | overflow: visible; /* Show the overflow in Edge and IE */ 57 | } 58 | 59 | /* 60 | * Correct `block` display not defined for any HTML5 element in IE 8/9 61 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 62 | * and Firefox 63 | * Correct `block` display not defined for `main` in IE 11 64 | */ 65 | article, 66 | aside, 67 | details, 68 | figcaption, 69 | figure, 70 | footer, 71 | header, 72 | main, 73 | menu, 74 | nav, 75 | section, 76 | summary { 77 | display: block; 78 | } 79 | 80 | summary { 81 | display: list-item; /* Add the correct display in all browsers */ 82 | } 83 | 84 | small { 85 | font-size: 80%; /* Set font-size to 80% in `small` elements */ 86 | } 87 | 88 | [hidden], 89 | template { 90 | display: none; /* Add the correct display in IE */ 91 | } 92 | 93 | abbr[title] { 94 | border-bottom: none; 95 | text-decoration: underline; 96 | text-decoration: underline dotted; 97 | } 98 | 99 | a { 100 | background-color: transparent; /* Remove the gray background on active links in IE 10 */ 101 | color: inherit; 102 | text-decoration: none; 103 | -webkit-text-decoration-skip: objects; /* Remove gaps in links underline in iOS 8+ and Safari 8+ */ 104 | } 105 | 106 | a:active, 107 | a:hover { 108 | outline-width: 0; /* Remove the outline when hovering in all browsers */ 109 | } 110 | 111 | code, 112 | kbd, 113 | pre, 114 | samp { 115 | font-family: monospace, monospace; /* Specify the font family of code elements */ 116 | } 117 | 118 | /* Correct style set to `bold` in Edge 12+, Safari 6.2+, and Chrome 18+ */ 119 | strong { 120 | font-weight: bolder; 121 | } 122 | 123 | /* Addition */ 124 | em { 125 | font-style: italic; 126 | } 127 | 128 | /* Address styling not present in IE 8/9 */ 129 | mark { 130 | background-color: #ff0; 131 | color: #000; 132 | } 133 | 134 | /* https://gist.github.com/unruthless/413930 */ 135 | sub, 136 | sup { 137 | font-size: 75%; 138 | line-height: 0; 139 | position: relative; 140 | vertical-align: baseline; 141 | } 142 | 143 | sub { 144 | bottom: -0.25em; 145 | } 146 | 147 | sup { 148 | top: -0.5em; 149 | } 150 | 151 | /* # ================================================================= 152 | # Forms 153 | # ================================================================= */ 154 | 155 | input { 156 | border-radius: 0; 157 | } 158 | 159 | /* Apply cursor pointer to button elements */ 160 | button, 161 | [type="button"], 162 | [type="reset"], 163 | [type="submit"], 164 | [role="button"] { 165 | cursor: pointer; 166 | } 167 | 168 | /* Replace pointer cursor in disabled elements */ 169 | [disabled] { 170 | cursor: default; 171 | } 172 | 173 | [type="number"] { 174 | width: auto; /* Firefox 36+ */ 175 | } 176 | 177 | [type="search"]::-webkit-search-cancel-button, 178 | [type="search"]::-webkit-search-decoration { 179 | -webkit-appearance: none; /* Safari 8 */ 180 | } 181 | 182 | textarea { 183 | overflow: auto; /* Internet Explorer 11+ */ 184 | resize: vertical; /* Specify textarea resizability */ 185 | } 186 | 187 | button, 188 | input { 189 | overflow: visible; /* Address `overflow` set to `hidden` in IE 8/9/10/11 */ 190 | } 191 | 192 | /* Remove inner padding and border in Firefox 4+ */ 193 | button::-moz-focus-inner, 194 | [type="button"]::-moz-focus-inner, 195 | [type="reset"]::-moz-focus-inner, 196 | [type="submit"]::-moz-focus-inner { 197 | border-style: 0; 198 | padding: 0; 199 | } 200 | 201 | /* Replace focus style removed in the border reset above */ 202 | button:-moz-focusring, 203 | [type="button"]::-moz-focus-inner, 204 | [type="reset"]::-moz-focus-inner, 205 | [type="submit"]::-moz-focus-inner { 206 | outline: 1px dotted ButtonText; 207 | } 208 | 209 | button, 210 | html [type="button"], /* Prevent a WebKit bug where (2) destroys native `audio` and `video`controls in Android 4 */ 211 | [type="reset"], 212 | [type="submit"] { 213 | -webkit-appearance: button; /* Correct the inability to style clickable types in iOS */ 214 | } 215 | 216 | button, 217 | select { 218 | text-transform: none; /* Firefox 40+, Internet Explorer 11- */ 219 | } 220 | 221 | /* Remove the default button styling in all browsers */ 222 | button, 223 | input, 224 | select, 225 | textarea { 226 | background-color: transparent; 227 | border-style: none; 228 | color: inherit; 229 | } 230 | 231 | /* Correct the cursor style of increment and decrement buttons in Chrome. */ 232 | [type="number"]::-webkit-inner-spin-button, 233 | [type="number"]::-webkit-outer-spin-button { 234 | height: auto; 235 | } 236 | 237 | /* Style select like a standard input */ 238 | select { 239 | -moz-appearance: none; /* Firefox 36+ */ 240 | -webkit-appearance: none; /* Chrome 41+ */ 241 | } 242 | 243 | select::-ms-expand { 244 | display: none; /* Internet Explorer 11+ */ 245 | } 246 | 247 | select::-ms-value { 248 | color: currentColor; /* Internet Explorer 11+ */ 249 | } 250 | 251 | legend { 252 | border: 0; /* Correct `color` not being inherited in IE 8/9/10/11 */ 253 | color: inherit; /* Correct the color inheritance from `fieldset` elements in IE */ 254 | display: table; /* Correct the text wrapping in Edge and IE */ 255 | max-width: 100%; /* Correct the text wrapping in Edge and IE */ 256 | white-space: normal; /* Correct the text wrapping in Edge and IE */ 257 | } 258 | 259 | ::-webkit-file-upload-button { 260 | -webkit-appearance: button; /* Correct the inability to style clickable types in iOS and Safari */ 261 | font: inherit; /* Change font properties to `inherit` in Chrome and Safari */ 262 | } 263 | 264 | [type="search"] { 265 | -webkit-appearance: textfield; /* Correct the odd appearance in Chrome and Safari */ 266 | outline-offset: -2px; /* Correct the outline style in Safari */ 267 | } 268 | 269 | /* # ================================================================= 270 | # Specify media element style 271 | # ================================================================= */ 272 | 273 | img { 274 | border-style: none; /* Remove border when inside `a` element in IE 8/9/10 */ 275 | } 276 | 277 | /* Add the correct vertical alignment in Chrome, Firefox, and Opera */ 278 | progress { 279 | vertical-align: baseline; 280 | } 281 | 282 | svg:not(:root) { 283 | overflow: hidden; /* Internet Explorer 11- */ 284 | } 285 | 286 | img, 287 | svg, 288 | audio, 289 | canvas, 290 | progress, 291 | video { 292 | display: inline-block; /* Internet Explorer 11+, Windows Phone 8.1+ */ 293 | } 294 | 295 | /* # ================================================================= 296 | # Accessibility 297 | # ================================================================= */ 298 | 299 | /* Hide content from screens but not screenreaders */ 300 | @media screen { 301 | [hidden~="screen"] { 302 | display: inherit; 303 | } 304 | [hidden~="screen"]:not(:active):not(:focus):not(:target) { 305 | position: absolute !important; 306 | clip: rect(0 0 0 0) !important; 307 | } 308 | } 309 | 310 | /* Specify the progress cursor of updating elements */ 311 | [aria-busy="true"] { 312 | cursor: progress; 313 | } 314 | 315 | /* Specify the pointer cursor of trigger elements */ 316 | [aria-controls] { 317 | cursor: pointer; 318 | } 319 | 320 | /* Specify the unstyled cursor of disabled, not-editable, or otherwise inoperable elements */ 321 | [aria-disabled] { 322 | cursor: default; 323 | } 324 | 325 | /* # ================================================================= 326 | # Selection 327 | # ================================================================= */ 328 | 329 | /* Specify text selection background color and omit drop shadow */ 330 | 331 | ::-moz-selection { 332 | background-color: #b3d4fc; /* Required when declaring ::selection */ 333 | color: #000; 334 | text-shadow: none; 335 | } 336 | 337 | ::selection { 338 | background-color: #b3d4fc; /* Required when declaring ::selection */ 339 | color: #000; 340 | text-shadow: none; 341 | } 342 | -------------------------------------------------------------------------------- /custom_types/homepage.json: -------------------------------------------------------------------------------- 1 | { 2 | "Main" : { 3 | "title" : { 4 | "type" : "StructuredText", 5 | "config" : { 6 | "single" : "heading1, strong", 7 | "label" : "Title", 8 | "placeholder" : "Title of the homepage" 9 | } 10 | }, 11 | "banner_image" : { 12 | "type" : "Image", 13 | "config" : { 14 | "constraint" : { }, 15 | "thumbnails" : [ ], 16 | "label" : "Banner image" 17 | } 18 | }, 19 | "banner_text" : { 20 | "type" : "StructuredText", 21 | "config" : { 22 | "multi" : "paragraph, strong", 23 | "label" : "Banner text", 24 | "placeholder" : "Coffee, reimagined. Enjoy your coffee like you never did before..." 25 | } 26 | }, 27 | "body" : { 28 | "type" : "Slices", 29 | "fieldset" : "Slice zone", 30 | "config" : { 31 | "choices" : { 32 | "featured_items" : { 33 | "type" : "Slice", 34 | "fieldset" : "Featured items", 35 | "description" : "Set of featured items with illustration, title, description and CTA", 36 | "icon" : "star", 37 | "display" : "grid", 38 | "non-repeat" : { 39 | "section_title" : { 40 | "type" : "StructuredText", 41 | "config" : { 42 | "single" : "heading2", 43 | "label" : "Section title", 44 | "placeholder" : "Our smart algorithms picks ..." 45 | } 46 | }, 47 | "button_label" : { 48 | "type" : "StructuredText", 49 | "config" : { 50 | "single" : "paragraph", 51 | "label" : "Button Label", 52 | "placeholder" : "Visit Shop" 53 | } 54 | }, 55 | "button_link" : { 56 | "type" : "Link", 57 | "config" : { 58 | "label" : "Button Link", 59 | "placeholder" : "Choose your link" 60 | } 61 | } 62 | }, 63 | "repeat" : { 64 | "link_to_product" : { 65 | "type" : "Link", 66 | "config" : { 67 | "select" : "document", 68 | "customtypes" : [ "product" ], 69 | "label" : "Link to product", 70 | "placeholder" : "Select a product" 71 | } 72 | } 73 | } 74 | }, 75 | "cta_banner" : { 76 | "type" : "Slice", 77 | "fieldset" : "CTA Banner", 78 | "description" : "A wide banner with text and button", 79 | "icon" : "chrome_reader_mode", 80 | "display" : "list", 81 | "non-repeat" : { 82 | "image_banner" : { 83 | "type" : "Image", 84 | "config" : { 85 | "constraint" : { }, 86 | "thumbnails" : [ ], 87 | "label" : "Image Banner" 88 | } 89 | }, 90 | "banner_title" : { 91 | "type" : "StructuredText", 92 | "config" : { 93 | "single" : "heading2", 94 | "label" : "Banner title", 95 | "placeholder" : "Our story" 96 | } 97 | }, 98 | "banner_text" : { 99 | "type" : "StructuredText", 100 | "config" : { 101 | "single" : "paragraph", 102 | "label" : "Banner text", 103 | "placeholder" : "It all started in 1999 ..." 104 | } 105 | }, 106 | "cta_label" : { 107 | "type" : "Text", 108 | "config" : { 109 | "label" : "CTA label", 110 | "placeholder" : "You'll never guess ...." 111 | } 112 | }, 113 | "cta_link" : { 114 | "type" : "Link", 115 | "config" : { 116 | "label" : "CTA link", 117 | "placeholder" : "CTA link", 118 | "allowTargetBlank" : true 119 | } 120 | } 121 | }, 122 | "repeat" : { } 123 | }, 124 | "big_bullet_item" : { 125 | "type" : "Slice", 126 | "fieldset" : "Item with numbers", 127 | "description" : "1 number and description in a grid layout", 128 | "icon" : "filter_1", 129 | "display" : "grid", 130 | "non-repeat" : { 131 | "title_section" : { 132 | "type" : "StructuredText", 133 | "config" : { 134 | "single" : "heading2", 135 | "label" : "Title Section", 136 | "placeholder" : "How it works ..." 137 | } 138 | } 139 | }, 140 | "repeat" : { 141 | "description_paragraph" : { 142 | "type" : "StructuredText", 143 | "config" : { 144 | "multi" : "paragraph, strong, em", 145 | "label" : "Description paragraph", 146 | "placeholder" : "Select some amazing coffee" 147 | } 148 | } 149 | } 150 | }, 151 | "text_block" : { 152 | "type" : "Slice", 153 | "fieldset" : "Text block", 154 | "description" : "Text block", 155 | "icon" : "text_fields", 156 | "display" : "list", 157 | "non-repeat" : { 158 | "title1" : { 159 | "type" : "StructuredText", 160 | "config" : { 161 | "single" : "heading2", 162 | "label" : "Title", 163 | "placeholder" : "Philosophy" 164 | } 165 | }, 166 | "paragraph" : { 167 | "type" : "StructuredText", 168 | "config" : { 169 | "multi" : "paragraph", 170 | "label" : "Paragraph", 171 | "placeholder" : "We believe that having a good cup of coffee ..." 172 | } 173 | } 174 | }, 175 | "repeat" : { } 176 | }, 177 | "separator" : { 178 | "type" : "Slice", 179 | "fieldset" : "Separator", 180 | "description" : "Separator", 181 | "icon" : "remove", 182 | "display" : "list", 183 | "non-repeat" : { }, 184 | "repeat" : { } 185 | } 186 | } 187 | } 188 | } 189 | }, 190 | "SEO & Social" : { 191 | "display_name" : { 192 | "type" : "StructuredText", 193 | "config" : { 194 | "useAsTitle" : true, 195 | "single" : "paragraph", 196 | "label" : "Display name", 197 | "placeholder" : "Display name" 198 | } 199 | }, 200 | "meta_title" : { 201 | "type" : "StructuredText", 202 | "config" : { 203 | "single" : "heading1", 204 | "label" : "Meta title", 205 | "placeholder" : "Meta title" 206 | } 207 | }, 208 | "meta_description" : { 209 | "type" : "StructuredText", 210 | "config" : { 211 | "single" : "paragraph", 212 | "label" : "Meta description", 213 | "placeholder" : "Meta description" 214 | } 215 | }, 216 | "social" : { 217 | "type" : "Slices", 218 | "fieldset" : "Slice zone", 219 | "config" : { 220 | "choices" : { 221 | "twitter_card" : { 222 | "type" : "Slice", 223 | "fieldset" : "Twitter Card", 224 | "description" : "Fields to customize Twitter Card (Summary Card with Large Image)", 225 | "icon" : "credit_card", 226 | "display" : "list", 227 | "non-repeat" : { 228 | "twitter_title" : { 229 | "type" : "StructuredText", 230 | "config" : { 231 | "single" : "paragraph", 232 | "label" : "Title", 233 | "placeholder" : "Title for Twitter Card" 234 | } 235 | }, 236 | "twitter_description" : { 237 | "type" : "StructuredText", 238 | "config" : { 239 | "single" : "paragraph", 240 | "label" : "Description", 241 | "placeholder" : "Description for Twitter Card" 242 | } 243 | }, 244 | "twitter_image" : { 245 | "type" : "Image", 246 | "config" : { 247 | "constraint" : { 248 | "width" : 1200, 249 | "height" : 675 250 | }, 251 | "thumbnails" : [ ], 252 | "label" : "Image" 253 | } 254 | } 255 | }, 256 | "repeat" : { } 257 | }, 258 | "open_graph" : { 259 | "type" : "Slice", 260 | "fieldset" : "Open Graph", 261 | "description" : "Fields to customize Open Graph", 262 | "icon" : "thumb_up", 263 | "display" : "list", 264 | "non-repeat" : { 265 | "og_title" : { 266 | "type" : "StructuredText", 267 | "config" : { 268 | "single" : "paragraph", 269 | "label" : "Title", 270 | "placeholder" : "Title for Open Graph" 271 | } 272 | }, 273 | "og_description" : { 274 | "type" : "StructuredText", 275 | "config" : { 276 | "single" : "paragraph", 277 | "label" : "Description", 278 | "placeholder" : "Description for Open Graph" 279 | } 280 | }, 281 | "og_image" : { 282 | "type" : "Image", 283 | "config" : { 284 | "constraint" : { 285 | "width" : 1200, 286 | "height" : 628 287 | }, 288 | "thumbnails" : [ ], 289 | "label" : "Image" 290 | } 291 | } 292 | }, 293 | "repeat" : { } 294 | } 295 | } 296 | } 297 | } 298 | } 299 | } 300 | --------------------------------------------------------------------------------