├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── App.css ├── App.js ├── App.test.js ├── assets ├── images │ ├── cta-illustration.svg │ ├── feature-tile-icon-01.svg │ ├── feature-tile-icon-02.svg │ ├── feature-tile-icon-03.svg │ ├── feature-tile-icon-04.svg │ ├── feature-tile-icon-05.svg │ ├── feature-tile-icon-06.svg │ ├── features-split-image-01.png │ ├── features-split-image-02.png │ ├── features-split-image-03.png │ ├── illustration-section-01.svg │ ├── illustration-section-02.svg │ ├── logo.svg │ └── video-placeholder.jpg └── scss │ ├── core │ ├── _normalize.scss │ ├── abstracts │ │ ├── _functions.scss │ │ ├── _include-media.scss │ │ └── _mixins.scss │ ├── base │ │ ├── _base.scss │ │ ├── _fonts.scss │ │ ├── _helpers.scss │ │ ├── _scroll-reveal.scss │ │ └── _typography.scss │ ├── elements │ │ ├── _buttons.scss │ │ ├── _containers.scss │ │ ├── _forms.scss │ │ ├── _hamburger.scss │ │ └── _modal.scss │ ├── layout │ │ ├── _footer.scss │ │ ├── _header.scss │ │ └── _main.scss │ ├── patterns │ │ ├── _split.scss │ │ └── _tiles.scss │ └── sections │ │ ├── _cta.scss │ │ ├── _features-split.scss │ │ ├── _features-tiles.scss │ │ ├── _hero.scss │ │ ├── _section.scss │ │ └── _testimonial.scss │ ├── settings │ ├── _settings.scss │ ├── base │ │ ├── _colors.scss │ │ ├── _links.scss │ │ ├── _misc.scss │ │ ├── _scroll-reveal.scss │ │ ├── _typography.scss │ │ └── _widths-and-spacing.scss │ ├── elements │ │ ├── _buttons-and-forms.scss │ │ └── _modal.scss │ ├── layout │ │ ├── _footer.scss │ │ └── _header.scss │ ├── patterns │ │ ├── _split.scss │ │ └── _tiles.scss │ └── sections │ │ ├── _cta.scss │ │ ├── _features-split.scss │ │ ├── _features-tiles.scss │ │ ├── _hero.scss │ │ └── _testimonial.scss │ ├── style.scss │ └── theme │ ├── _theme.scss │ ├── base │ ├── _base.scss │ ├── _fonts.scss │ ├── _scroll-reveal.scss │ └── _typography.scss │ ├── elements │ ├── _buttons.scss │ ├── _containers.scss │ ├── _forms.scss │ ├── _hamburger.scss │ └── _modal.scss │ ├── illustrations │ └── _illustrations.scss │ ├── layout │ ├── _footer.scss │ ├── _header.scss │ └── _main.scss │ ├── patterns │ ├── _split.scss │ └── _tiles.scss │ └── sections │ ├── _cta.scss │ ├── _features-split.scss │ ├── _features-tiles.scss │ ├── _hero.scss │ ├── _section.scss │ └── _testimonial.scss ├── components ├── elements │ ├── Button.js │ ├── ButtonGroup.js │ ├── Checkbox.js │ ├── FormHint.js │ ├── FormLabel.js │ ├── Image.js │ ├── Input.js │ ├── Modal.js │ ├── Radio.js │ ├── Select.js │ ├── SmoothScroll.js │ └── Switch.js ├── layout │ ├── Footer.js │ ├── Header.js │ └── partials │ │ ├── FooterNav.js │ │ ├── FooterSocial.js │ │ └── Logo.js └── sections │ ├── Cta.js │ ├── FeaturesSplit.js │ ├── FeaturesTiles.js │ ├── GenericSection.js │ ├── Hero.js │ ├── Testimonial.js │ └── partials │ └── SectionHeader.js ├── index.js ├── layouts └── LayoutDefault.js ├── serviceWorker.js ├── utils ├── AppRoute.js ├── ScrollReveal.js └── SectionProps.js └── views └── Home.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Free React landing page template 2 | 3 | ![Open React template preview](https://user-images.githubusercontent.com/2683512/78789364-545e7100-79ad-11ea-9e3c-9528c99cda8e.png) 4 | 5 | **Open** is a **free React landing page template designed** for developers/makers who want to create a quick and professional landing page for their open source projects, SaaS products, online services, and more. 6 | 7 | Use it for whatever you want, and be sure to reach us out on [Twitter](https://twitter.com/Cruip_com) if you build anything cool/useful with it. 8 | 9 | Created and maintained with ❤️ by [Cruip.com](https://cruip.com). 10 | 11 | ## Live demo 12 | 13 | Check the live demo here 👉️ [https://open.cruip.com/](https://open.cruip.com/) 14 | 15 | ## Open PRO 16 | 17 | Looking for more pages and components? Have a look at the **premium version** here 👉️ [https://cruip.com/demos/open-pro/](https://cruip.com/demos/open-pro/) 18 | 19 | *The premium template is built on-the-top of [Tailwind CSS](https://tailwindcss.com/), and React components have been re-built from scratch.* 20 | 21 | ## Table of contents 22 | 23 | * [Usage](#usage) 24 | * [Available Scripts](#available-scripts) 25 | * [npm start](#npm-start) 26 | * [npm test](#npm-test) 27 | * [npm run build](#npm-run-build) 28 | * [npm run eject](#npm-run-eject) 29 | * [Learn More](#learn-more) 30 | * [Code Splitting](#code-splitting) 31 | * [Analyzing the Bundle Size](#analyzing-the-bundle-size) 32 | * [Making a Progressive Web App](#making-a-progressive-web-app) 33 | * [Advanced Configuration](#advanced-configuration) 34 | * [Deployment](#deployment) 35 | * [npm run build fails to minify](#npm-run-build-fails-to-minify) 36 | * [Google Analytics Setup](#google-analytics-setup) 37 | * [Credits](#credits) 38 | * [Terms and License](#terms-and-license) 39 | * [About Us](#about-us) 40 | * [Stay in the loop](#stay-in-the-loop) 41 | 42 | ## Usage 43 | 44 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 45 | 46 | ### Available Scripts 47 | 48 | In the project directory, you can run: 49 | 50 | #### `npm install` 51 | To install the dependencies package. 52 | 53 | #### `npm start` 54 | 55 | Runs the app in the development mode.
56 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 57 | 58 | The page will reload if you make edits.
59 | You will also see any lint errors in the console. 60 | 61 | #### `npm test` 62 | 63 | Launches the test runner in the interactive watch mode.
64 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 65 | 66 | #### `npm run build` 67 | 68 | Builds the app for production to the `build` folder.
69 | It correctly bundles React in production mode and optimizes the build for the best performance. 70 | 71 | The build is minified and the filenames include the hashes.
72 | Your app is ready to be deployed! 73 | 74 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 75 | 76 | #### `npm run eject` 77 | 78 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 79 | 80 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 81 | 82 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 83 | 84 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 85 | 86 | ### Learn More 87 | 88 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 89 | 90 | To learn React, check out the [React documentation](https://reactjs.org/). 91 | 92 | #### Code Splitting 93 | 94 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 95 | 96 | #### Analyzing the Bundle Size 97 | 98 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 99 | 100 | #### Making a Progressive Web App 101 | 102 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 103 | 104 | #### Advanced Configuration 105 | 106 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 107 | 108 | #### Deployment 109 | 110 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 111 | 112 | #### `npm run build` fails to minify 113 | 114 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 115 | 116 | ### Google Analytics Setup 117 | 118 | This template uses the [React Google Analytics Module](https://github.com/react-ga/react-ga). 119 | 120 | In order to track visitors, you need to set an [environment variable](https://create-react-app.dev/docs/adding-custom-environment-variables/) called `REACT_APP_GA_CODE` storing your [GA Tracking ID](https://support.google.com/analytics/answer/7372977). 121 | 122 | ## Credits 123 | 124 | - [Nucleo](https://nucleoapp.com/) 125 | - [Unsplash](https://unsplash.com/) 126 | 127 | ## Terms and License 128 | 129 | - Released under the [GPL](https://www.gnu.org/licenses/gpl-3.0.html). 130 | - Copyright 2020 [Cruip](https://cruip.com/). 131 | - Use it for personal and commercial projects, but please don’t republish, redistribute, or resell the template. 132 | - Attribution is not required, although it is really appreciated. 133 | 134 | ## About Us 135 | 136 | We're an Italian developer/designer duo creating high-quality design/code resources for developers, makers, and startups. 137 | 138 | ## Stay in the loop 139 | 140 | If you would like to know when we release new resources, you can follow us on [Twitter](https://twitter.com/Cruip_com), or you can subscribe to our monthly [newsletter](https://cruip.com/#subscribe). 141 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "open-react-template", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "classnames": "^2.2.6", 7 | "lodash": "^4.17.15", 8 | "node-sass": "^4.13.1", 9 | "react": "^16.13.1", 10 | "react-dom": "^16.13.1", 11 | "react-ga": "^2.7.0", 12 | "react-router-dom": "^5.1.2", 13 | "react-scripts": "^3.4.1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/cruip/open-react-template.git" 18 | }, 19 | "scripts": { 20 | "start": "react-scripts start", 21 | "build": "react-scripts build", 22 | "test": "react-scripts test", 23 | "eject": "react-scripts eject" 24 | }, 25 | "eslintConfig": { 26 | "extends": "react-app" 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | }, 40 | "devDependencies": {} 41 | } 42 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | Open - React Template 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/App.css -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { useRef, useEffect } from 'react'; 2 | import { useLocation, Switch } from 'react-router-dom'; 3 | import AppRoute from './utils/AppRoute'; 4 | import ScrollReveal from './utils/ScrollReveal'; 5 | import ReactGA from 'react-ga'; 6 | 7 | // Layouts 8 | import LayoutDefault from './layouts/LayoutDefault'; 9 | 10 | // Views 11 | import Home from './views/Home'; 12 | 13 | // Initialize Google Analytics 14 | ReactGA.initialize(process.env.REACT_APP_GA_CODE); 15 | 16 | const trackPage = page => { 17 | ReactGA.set({ page }); 18 | ReactGA.pageview(page); 19 | }; 20 | 21 | const App = () => { 22 | 23 | const childRef = useRef(); 24 | let location = useLocation(); 25 | 26 | useEffect(() => { 27 | const page = location.pathname; 28 | document.body.classList.add('is-loaded') 29 | childRef.current.init(); 30 | trackPage(page); 31 | // eslint-disable-next-line react-hooks/exhaustive-deps 32 | }, [location]); 33 | 34 | return ( 35 | ( 38 | 39 | 40 | 41 | )} /> 42 | ); 43 | } 44 | 45 | export default App; -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Router } from 'react-router-dom'; 4 | import { createMemoryHistory } from 'history' 5 | import App from './App'; 6 | 7 | const history = createMemoryHistory(); 8 | 9 | it('renders without crashing', () => { 10 | const div = document.createElement('div'); 11 | ReactDOM.render( 12 | 13 | 14 | , 15 | div 16 | ); 17 | ReactDOM.unmountComponentAtNode(div); 18 | }); 19 | -------------------------------------------------------------------------------- /src/assets/images/cta-illustration.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-01.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-02.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-03.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-04.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-05.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/feature-tile-icon-06.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/features-split-image-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/images/features-split-image-01.png -------------------------------------------------------------------------------- /src/assets/images/features-split-image-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/images/features-split-image-02.png -------------------------------------------------------------------------------- /src/assets/images/features-split-image-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/images/features-split-image-03.png -------------------------------------------------------------------------------- /src/assets/images/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/images/video-placeholder.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/images/video-placeholder.jpg -------------------------------------------------------------------------------- /src/assets/scss/core/_normalize.scss: -------------------------------------------------------------------------------- 1 | html { 2 | line-height: 1.15; 3 | -ms-text-size-adjust: 100%; 4 | -webkit-text-size-adjust: 100%; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | } 10 | 11 | article, 12 | aside, 13 | footer, 14 | header, 15 | nav, 16 | section { 17 | display: block; 18 | } 19 | 20 | h1 { 21 | font-size: 2em; 22 | margin: 0.67em 0; 23 | } 24 | 25 | figcaption, 26 | figure, 27 | main { 28 | display: block; 29 | } 30 | 31 | figure { 32 | margin: 1em 40px; 33 | } 34 | 35 | hr { 36 | box-sizing: content-box; 37 | height: 0; 38 | overflow: visible; 39 | } 40 | 41 | pre { 42 | font-family: monospace, monospace; 43 | font-size: 1em; 44 | } 45 | 46 | a { 47 | background-color: transparent; 48 | -webkit-text-decoration-skip: objects; 49 | } 50 | 51 | abbr[title] { 52 | border-bottom: none; 53 | text-decoration: underline; 54 | text-decoration: underline dotted; 55 | } 56 | 57 | b, 58 | strong { 59 | font-weight: inherit; 60 | } 61 | 62 | b, 63 | strong { 64 | font-weight: bolder; 65 | } 66 | 67 | code, 68 | kbd, 69 | samp { 70 | font-family: monospace, monospace; 71 | font-size: 1em; 72 | } 73 | 74 | dfn { 75 | font-style: italic; 76 | } 77 | 78 | mark { 79 | background-color: #ff0; 80 | color: #000; 81 | } 82 | 83 | small { 84 | font-size: 80%; 85 | } 86 | 87 | sub, 88 | sup { 89 | font-size: 75%; 90 | line-height: 0; 91 | position: relative; 92 | vertical-align: baseline; 93 | } 94 | 95 | sub { 96 | bottom: -0.25em; 97 | } 98 | 99 | sup { 100 | top: -0.5em; 101 | } 102 | 103 | audio, 104 | video { 105 | display: inline-block; 106 | } 107 | 108 | audio:not([controls]) { 109 | display: none; 110 | height: 0; 111 | } 112 | 113 | img { 114 | border-style: none; 115 | } 116 | 117 | svg:not(:root) { 118 | overflow: hidden; 119 | } 120 | 121 | button, 122 | input, 123 | optgroup, 124 | select, 125 | textarea { 126 | font-family: sans-serif; 127 | font-size: 100%; 128 | line-height: 1.15; 129 | margin: 0; 130 | } 131 | 132 | button, 133 | input { 134 | overflow: visible; 135 | } 136 | 137 | button, 138 | select { 139 | text-transform: none; 140 | } 141 | 142 | button, 143 | html [type="button"], 144 | [type="reset"], 145 | [type="submit"] { 146 | -webkit-appearance: button; 147 | } 148 | 149 | button::-moz-focus-inner, 150 | [type="button"]::-moz-focus-inner, 151 | [type="reset"]::-moz-focus-inner, 152 | [type="submit"]::-moz-focus-inner { 153 | border-style: none; 154 | padding: 0; 155 | } 156 | 157 | button:-moz-focusring, 158 | [type="button"]:-moz-focusring, 159 | [type="reset"]:-moz-focusring, 160 | [type="submit"]:-moz-focusring { 161 | outline: 1px dotted ButtonText; 162 | } 163 | 164 | fieldset { 165 | padding: 0.35em 0.75em 0.625em; 166 | } 167 | 168 | legend { 169 | box-sizing: border-box; 170 | color: inherit; 171 | display: table; 172 | max-width: 100%; 173 | padding: 0; 174 | white-space: normal; 175 | } 176 | 177 | progress { 178 | display: inline-block; 179 | vertical-align: baseline; 180 | } 181 | 182 | textarea { 183 | overflow: auto; 184 | } 185 | 186 | [type="checkbox"], 187 | [type="radio"] { 188 | box-sizing: border-box; 189 | padding: 0; 190 | } 191 | 192 | [type="number"]::-webkit-inner-spin-button, 193 | [type="number"]::-webkit-outer-spin-button { 194 | height: auto; 195 | } 196 | 197 | [type="search"] { 198 | -webkit-appearance: textfield; 199 | outline-offset: -2px; 200 | } 201 | 202 | [type="search"]::-webkit-search-cancel-button, 203 | [type="search"]::-webkit-search-decoration { 204 | -webkit-appearance: none; 205 | } 206 | 207 | ::-webkit-file-upload-button { 208 | -webkit-appearance: button; 209 | font: inherit; 210 | } 211 | 212 | details, 213 | menu { 214 | display: block; 215 | } 216 | 217 | summary { 218 | display: list-item; 219 | } 220 | 221 | canvas { 222 | display: inline-block; 223 | } 224 | 225 | template { 226 | display: none; 227 | } 228 | 229 | [hidden] { 230 | display: none; 231 | } 232 | -------------------------------------------------------------------------------- /src/assets/scss/core/abstracts/_functions.scss: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------- 2 | // Recursive map merge function -------------------------------------- 3 | // Used in _variables.scss -------------------------------------------- 4 | // -------------------------------------------------------------------- 5 | @function map-push($parent-map, $child-map) { 6 | $result: $parent-map; 7 | @each $key, $value in $child-map { 8 | @if (not map-has-key($result, $key)) or (type-of(map-get($result, $key)) != type-of($value)) or (not (type-of(map-get($result, $key)) == map and type-of($value) == map)) { 9 | $result: map-merge($result, ($key: $value)); 10 | } 11 | @else { 12 | $result: map-merge($result, ($key: map-push(map-get($result, $key), $value))); 13 | } 14 | } 15 | @return $result; 16 | } 17 | 18 | // -------------------------------------------------------------------- 19 | // Retrieve Font Family ----------------------------------------------- 20 | // Used in _mixins.scss [@mixin font-family] -------------------------- 21 | // -------------------------------------------------------------------- 22 | @function get-font-family($elem) { 23 | @return map-get($font--family, $elem); 24 | } 25 | 26 | // -------------------------------------------------------------------- 27 | // Retrieve Font Size ------------------------------------------------- 28 | // Used in _mixins.scss [@mixin font-family] -------------------------- 29 | // -------------------------------------------------------------------- 30 | @function get-font-size($elem) { 31 | @if ( map-get($font--size, $elem) ) { 32 | @return nth(map-get($font--scale, map-get($font--size, $elem)), 1); 33 | } @else { 34 | @return null; 35 | } 36 | } 37 | 38 | // -------------------------------------------------------------------- 39 | // Retrieve Line Height ----------------------------------------------- 40 | // Used in _mixins.scss [@mixin font-size] ---------------------------- 41 | // -------------------------------------------------------------------- 42 | @function get-line-height($elem) { 43 | @if ( map-get($font--size, $elem) ) { 44 | @return nth(map-get($font--scale, map-get($font--size, $elem)), 2); 45 | } @else { 46 | @return null; 47 | } 48 | } 49 | 50 | // -------------------------------------------------------------------- 51 | // Retrieve Kerning --------------------------------------------------- 52 | // Used in _mixins.scss [@mixin font-size] ---------------------------- 53 | // -------------------------------------------------------------------- 54 | @function get-kerning($elem) { 55 | @if ( map-get($font--size, $elem) ) { 56 | @return nth(map-get($font--scale, map-get($font--size, $elem)), 3); 57 | } @else { 58 | @return null; 59 | } 60 | } 61 | 62 | // -------------------------------------------------------------------- 63 | // Retrieve Font Weight ----------------------------------------------- 64 | // Used in _mixins.scss [@mixin font-weight] -------------------------- 65 | // -------------------------------------------------------------------- 66 | @function get-font-weight($elem) { 67 | @return map-get($font--weight, $elem); 68 | } 69 | 70 | // -------------------------------------------------------------------- 71 | // Retrieve Colors ---------------------------------------------------- 72 | // Usage: get-color(dark, 1) ------------------------------------------ 73 | // -------------------------------------------------------------------- 74 | @function get-color($elem, $variant) { 75 | @return map-get(map-get($palette, $elem), $variant); 76 | } 77 | 78 | // -------------------------------------------------------------------- 79 | // Output Color ------------------------------------------------------- 80 | // Usage: color(heading) ----------------------------------------- 81 | // -------------------------------------------------------------------- 82 | @function color($elem) { 83 | @return map-get($color, $elem); 84 | } 85 | 86 | // -------------------------------------------------------------------- 87 | // Output Borders Color ----------------------------------------------- 88 | // Usage: color-border(divider) --------------------------------------- 89 | // -------------------------------------------------------------------- 90 | @function color-border($elem) { 91 | @return map-get($border--color, $elem); 92 | } 93 | 94 | // -------------------------------------------------------------------- 95 | // Output Bg Color ---------------------------------------------------- 96 | // Usage: color-bg(code) ---------------------------------------------- 97 | // -------------------------------------------------------------------- 98 | @function color-bg($elem) { 99 | @return map-get($bg--color, $elem); 100 | } 101 | 102 | // -------------------------------------------------------------------- 103 | // Output Icon Color -------------------------------------------------- 104 | // Usage: color-icon(hamburger) --------------------------------------- 105 | // -------------------------------------------------------------------- 106 | @function color-icon($elem) { 107 | @return map-get($icon--color, $elem); 108 | } 109 | 110 | // -------------------------------------------------------------------- 111 | // urlencode the svg string ------------------------------------------- 112 | // -------------------------------------------------------------------- 113 | @function str-replace($string, $search, $replace: '') { 114 | $index: str-index($string, $search); 115 | @if $index { 116 | @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); 117 | } 118 | @return $string; 119 | } 120 | 121 | @function url-encode($string) { 122 | $map: ( 123 | "%": "%25", 124 | "<": "%3C", 125 | ">": "%3E", 126 | " ": "%20", 127 | "!": "%21", 128 | "*": "%2A", 129 | "'": "%27", 130 | '"': "%22", 131 | "(": "%28", 132 | ")": "%29", 133 | ";": "%3B", 134 | ":": "%3A", 135 | "@": "%40", 136 | "&": "%26", 137 | "=": "%3D", 138 | "+": "%2B", 139 | "$": "%24", 140 | ",": "%2C", 141 | "/": "%2F", 142 | "?": "%3F", 143 | "#": "%23", 144 | "[": "%5B", 145 | "]": "%5D" 146 | ); 147 | $new: $string; 148 | @each $search, $replace in $map { 149 | $new: str-replace($new, $search, $replace); 150 | } 151 | @return $new; 152 | } 153 | 154 | @function inline-svg($string) { 155 | @return url('data:image/svg+xml;charset=US-ASCII,#{url-encode($string)}'); 156 | } 157 | -------------------------------------------------------------------------------- /src/assets/scss/core/abstracts/_mixins.scss: -------------------------------------------------------------------------------- 1 | // Font Family 2 | @mixin font-family($elem) { 3 | font-family: unquote(get-font-family($elem)); 4 | } 5 | 6 | // Font-size + Line-height + Kerning 7 | @mixin font-size($elem) { 8 | font-size: get-font-size($elem); 9 | line-height: get-line-height($elem); 10 | letter-spacing: get-kerning($elem); 11 | } 12 | 13 | // Font Weight 14 | @mixin font-weight($elem) { 15 | font-weight: get-font-weight($elem); 16 | } 17 | 18 | // Anchor aspect 19 | @mixin anchor-aspect($type: 'main', $layout: false) { 20 | @if ( $type == 'main' ) { // Base 21 | @if ( $layout == 'inverse' ) { 22 | color: color(link-inverse); 23 | } @else { 24 | color: color(link); 25 | } 26 | text-decoration: $link-main--decoration; 27 | 28 | &:hover, 29 | &:active { 30 | @if ( $layout == 'inverse' ) { 31 | color: color(link-hover-inverse); 32 | } @else { 33 | color: color(link-hover); 34 | } 35 | outline: 0; 36 | text-decoration: $link-main--decoration-hover; 37 | } 38 | } @else if ($type == 'header') { 39 | @if ( $layout == 'inverse' ) { 40 | color: color(header-link-inverse); 41 | } @else { 42 | color: color(header-link); 43 | } 44 | text-decoration: $link-header--decoration; 45 | 46 | &:hover, 47 | &:active { 48 | @if ( $layout == 'inverse' ) { 49 | color: color(header-link-hover-inverse); 50 | } @else { 51 | color: color(header-link-hover); 52 | } 53 | text-decoration: $link-header--decoration-hover; 54 | } 55 | } @else if ($type == 'header-mobile') { 56 | color: color(header-link-mobile); 57 | 58 | &:hover, 59 | &:active { 60 | color: color(header-link-mobile-hover); 61 | } 62 | } @else if ($type == 'footer') { 63 | @if ( $layout == 'inverse' ) { 64 | color: color(footer-link-inverse); 65 | } @else { 66 | color: color(footer-link); 67 | } 68 | text-decoration: $link-footer--decoration; 69 | 70 | &:hover, 71 | &:active { 72 | @if ( $layout == 'inverse' ) { 73 | color: color(footer-link-hover-inverse); 74 | } @else { 75 | color: color(footer-link-hover); 76 | } 77 | text-decoration: $link-footer--decoration-hover; 78 | } 79 | } @else if ($type == 'footer-block') { 80 | @if ( $layout == 'inverse' ) { 81 | color: color(footer-block-link-inverse); 82 | } @else { 83 | color: color(footer-block-link); 84 | } 85 | text-decoration: $link-footer-block--decoration; 86 | 87 | &:hover, 88 | &:active { 89 | @if ( $layout == 'inverse' ) { 90 | color: color(footer-block-link-hover-inverse); 91 | } @else { 92 | color: color(footer-block-link-hover); 93 | } 94 | text-decoration: $link-footer-block--decoration-hover; 95 | } 96 | } @else if ($type == 'button-link') { 97 | @if ( $layout == 'inverse' ) { 98 | color: color(button-link-inverse); 99 | } @else { 100 | color: color(button-link); 101 | } 102 | text-decoration: $link-button--decoration; 103 | 104 | &:hover, 105 | &:active { 106 | @if ( $layout == 'inverse' ) { 107 | color: color(button-link-hover-inverse); 108 | } @else { 109 | color: color(button-link-hover); 110 | } 111 | text-decoration: $link-button--decoration-hover; 112 | } 113 | } @else if ($type == 'func-link') { 114 | @if ( $layout == 'inverse' ) { 115 | color: color(func-link-inverse); 116 | } @else { 117 | color: color(func-link); 118 | } 119 | text-decoration: $link-func--decoration; 120 | 121 | &:hover, 122 | &:active { 123 | @if ( $layout == 'inverse' ) { 124 | color: color(func-link-hover-inverse); 125 | } @else { 126 | color: color(func-link-hover); 127 | } 128 | text-decoration: $link-func--decoration-hover; 129 | } 130 | } 131 | } 132 | 133 | @mixin divider-mix($layout: false) { 134 | display: block; 135 | height: 1px; 136 | @if ( $layout == 'inverse' ) { 137 | background: color-border(divider-inverse); 138 | } @else { 139 | background: color-border(divider); 140 | } 141 | } 142 | 143 | @mixin divider($type: false, $layout: false) { 144 | @if ( $type == 'before' ) { 145 | position: relative; 146 | 147 | &::before { 148 | content: ''; 149 | position: absolute; 150 | top: 0; 151 | left: 0; 152 | width: 100%; 153 | @include divider-mix($layout); 154 | } 155 | } @else if ($type == 'after') { 156 | position: relative; 157 | 158 | &::after { 159 | content: ''; 160 | position: absolute; 161 | bottom: 0; 162 | left: 0; 163 | width: 100%; 164 | @include divider-mix($layout); 165 | } 166 | } @else { 167 | @include divider-mix($layout); 168 | } 169 | } 170 | 171 | // Handles a scalabale background image related to a specific elements 172 | // $file: name of file (e.g. illustration-element-01.svg) 173 | // $width: (in %) illustration width as a percent of related element width 174 | // $height: (in % or px) illustration height as a percent of related element width (scaling) or illustration height in px 175 | // $vpos: illustration is centered by default, allowed values: top or bottom 176 | // $hoffset: horizontal offset 177 | // $voffset: vertical offset 178 | @mixin illustration($file, $width, $height, $vpos: null, $hoffset: null, $voffset: null) { 179 | content: ''; 180 | position: absolute; 181 | width: $width; 182 | max-width: $width; 183 | height: $height; 184 | background-image: url(../../../images/#{$file}); 185 | background-repeat: no-repeat; 186 | @if( unit( $height ) == '%' ) { 187 | background-size: contain; 188 | } @else { 189 | background-size: auto; 190 | } 191 | @if ( $hoffset ) { 192 | left: calc(50% + #{$hoffset}); 193 | } @else { 194 | left: 50%; 195 | } 196 | @if ( $vpos == 'top' ) { 197 | @if ( $voffset ) { 198 | top: #{$voffset}; 199 | } @else { 200 | top: 0; 201 | } 202 | background-position: center top; 203 | transform: translate(-50%); 204 | } @else if ( $vpos == 'bottom' ) { 205 | @if ( $voffset ) { 206 | bottom: #{$voffset}; 207 | } @else { 208 | bottom: 0; 209 | } 210 | background-position: center bottom; 211 | transform: translate(-50%); 212 | } @else { 213 | background-position: center; 214 | @if ( $voffset ) { 215 | top: calc(50% + #{$voffset}); 216 | } @else { 217 | top: 50%; 218 | } 219 | transform: translate(-50%, -50%); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/assets/scss/core/base/_base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | } 4 | 5 | *, 6 | *:before, 7 | *:after { /* Inherit box-sizing to make it easier to change the property for components that leverage other behavior; see http://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/ */ 8 | box-sizing: inherit; 9 | } 10 | 11 | body { 12 | background: color-bg(body); /* Fallback for when there is no custom background color defined. */ 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-font-smoothing: antialiased; 15 | } 16 | 17 | hr { 18 | border: 0; 19 | @include divider(); 20 | margin-top: $spacing--shared-v; 21 | margin-bottom: $spacing--shared-v; 22 | } 23 | 24 | ul, ol { 25 | margin-top: 0; 26 | padding-left: $spacing--shared-h; 27 | 28 | &:not(:last-child) { 29 | margin-bottom: $spacing--shared-v; 30 | } 31 | } 32 | 33 | ul { 34 | list-style: disc; 35 | } 36 | 37 | ol { 38 | list-style: decimal; 39 | } 40 | 41 | li { 42 | 43 | &:not(:last-child) { 44 | margin-bottom: $spacing--shared-v / 2; 45 | } 46 | } 47 | 48 | li > ul, 49 | li > ol { 50 | margin-top: $spacing--shared-v / 2; 51 | margin-bottom: 0; 52 | } 53 | 54 | dl { 55 | margin-top: 0; 56 | margin-bottom: $spacing--shared-v; 57 | } 58 | 59 | dt { 60 | @include font-weight(strong); 61 | } 62 | 63 | dd { 64 | margin-left: $spacing--shared-h; 65 | margin-bottom: $spacing--shared-v; 66 | } 67 | 68 | img { 69 | border-radius: $img-radius; 70 | } 71 | 72 | img, 73 | svg, 74 | video { 75 | display: block; 76 | height: auto; /* Make sure images are scaled correctly. */ 77 | max-width: 100%; /* Adhere to container width. */ 78 | } 79 | 80 | figure { 81 | margin: $spacing--figure-v $spacing--figure-h; /* Extra wide images within figure tags don't overflow the content area. */ 82 | } 83 | 84 | figcaption { 85 | padding: $spacing--figcaption-v $spacing--figcaption-h; 86 | } 87 | 88 | // tables 89 | table { 90 | @include font-size(table); 91 | border-collapse: collapse; 92 | margin-bottom: $spacing--shared-v; 93 | width: 100%; 94 | } 95 | 96 | tr { 97 | border-bottom: 1px solid color-border(divider); 98 | } 99 | 100 | th { 101 | @include font-weight(strong); 102 | text-align: left; 103 | } 104 | 105 | th, 106 | td { 107 | padding: $spacing--table-cell-v $spacing--table-cell-h; 108 | 109 | &:first-child { 110 | padding-left: 0; 111 | } 112 | 113 | &:last-child { 114 | padding-right: 0; 115 | } 116 | } 117 | 118 | .invert-color { 119 | 120 | hr { 121 | @include divider(false, inverse); 122 | } 123 | 124 | tr { 125 | border-bottom: 1px solid color-border(divider-inverse); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/assets/scss/core/base/_fonts.scss: -------------------------------------------------------------------------------- 1 | @if ( $font--provider == 'Google Fonts' ) { 2 | @import url('https://fonts.googleapis.com/css?family=#{$font--import}&display=swap'); 3 | } -------------------------------------------------------------------------------- /src/assets/scss/core/base/_helpers.scss: -------------------------------------------------------------------------------- 1 | // Hide elements, for screen readers only 2 | .screen-reader { 3 | position: absolute; 4 | width: 1px; 5 | height: 1px; 6 | padding: 0; 7 | overflow: hidden; 8 | clip: rect(0,0,0,0); 9 | white-space: nowrap; 10 | border: 0; 11 | } 12 | 13 | // Reset lists style 14 | .list-reset { 15 | list-style: none; 16 | padding: 0; 17 | 18 | li { 19 | margin: 0; 20 | } 21 | } 22 | 23 | // Text alignment 24 | .ta-l { 25 | text-align: left; 26 | } 27 | 28 | .ta-c { 29 | text-align: center; 30 | } 31 | 32 | .ta-r { 33 | text-align: right; 34 | } 35 | 36 | // Font weight 37 | .fw-400 { 38 | font-weight: 400; 39 | } 40 | 41 | .fw-500 { 42 | font-weight: 500; 43 | } 44 | 45 | .fw-600 { 46 | font-weight: 600; 47 | } 48 | 49 | .fw-700 { 50 | font-weight: 700; 51 | } 52 | 53 | // Text color 54 | .text-color-high { 55 | color: color(high-contrast); 56 | } 57 | 58 | .text-color-mid { 59 | color: color(mid-contrast); 60 | } 61 | 62 | .text-color-low { 63 | color: color(low-contrast); 64 | } 65 | 66 | .text-color-primary { 67 | color: color(primary); 68 | } 69 | 70 | .text-color-secondary { 71 | color: color(secondary); 72 | } 73 | 74 | .text-color-error { 75 | color: color(error); 76 | } 77 | 78 | .text-color-warning { 79 | color: color(warning); 80 | } 81 | 82 | .text-color-success { 83 | color: color(success); 84 | } 85 | 86 | .invert-color { 87 | 88 | .text-color-high { 89 | color: color(high-contrast-inverse); 90 | } 91 | 92 | .text-color-mid { 93 | color: color(mid-contrast-inverse); 94 | } 95 | 96 | .text-color-low { 97 | color: color(low-contrast-inverse); 98 | } 99 | } 100 | 101 | // Text transform 102 | .tt-u { 103 | text-transform: uppercase; 104 | } 105 | 106 | // Images 107 | .image-full { 108 | width: 100%; 109 | } 110 | 111 | .image-larger { 112 | position: relative; 113 | left: 50%; 114 | transform: translateX(-50%); 115 | width: calc(100% + #{$image-larger--extra-width * 2}); 116 | max-width: 100vw; 117 | } 118 | 119 | // Helper class for coloured bg 120 | .has-bg-color { 121 | position: relative; 122 | background-color: color-bg(bg-color); 123 | z-index: 0; 124 | } 125 | 126 | // Helper class for box shadow 127 | .has-shadow { 128 | box-shadow: color-bg(shadow); 129 | } 130 | 131 | img.has-shadow { 132 | border-radius: $img-radius; 133 | } 134 | 135 | // Dividers 136 | .has-top-divider { 137 | @include divider(before); 138 | } 139 | 140 | .has-bottom-divider { 141 | @include divider(after); 142 | } 143 | 144 | .invert-color { 145 | 146 | .has-top-divider { 147 | @include divider(before, inverse); 148 | } 149 | 150 | .has-bottom-divider { 151 | @include divider(after, inverse); 152 | } 153 | } 154 | 155 | // For centering content 156 | .center-content { 157 | text-align: center; 158 | 159 | img, 160 | svg, 161 | video { 162 | margin-left: auto; 163 | margin-right: auto; 164 | } 165 | 166 | .button-group { 167 | justify-content: center; 168 | } 169 | } 170 | 171 | // Responsive video 172 | .responsive-video { 173 | position: relative; 174 | padding-bottom: 56.25%; // 16:9 175 | height: 0; 176 | 177 | &.is-4-3 { 178 | padding-bottom: 75%; // 4:3 179 | } 180 | 181 | iframe { 182 | position: absolute; 183 | top: 0; 184 | left: 0; 185 | width: 100%; 186 | height: 100%; 187 | } 188 | } 189 | 190 | // Spacing, margin 191 | .m-0 { 192 | margin: 0; 193 | } 194 | 195 | .mt-0 { 196 | margin-top: 0; 197 | } 198 | 199 | .mr-0 { 200 | margin-right: 0; 201 | } 202 | 203 | .mb-0 { 204 | margin-bottom: 0; 205 | } 206 | 207 | .ml-0 { 208 | margin-left: 0; 209 | } 210 | 211 | .m-4 { 212 | margin: 4px; 213 | } 214 | 215 | .mt-4 { 216 | margin-top: 4px; 217 | } 218 | 219 | .mr-4 { 220 | margin-right: 4px; 221 | } 222 | 223 | .mb-4 { 224 | margin-bottom: 4px; 225 | } 226 | 227 | .ml-4 { 228 | margin-left: 4px; 229 | } 230 | 231 | .m-8 { 232 | margin: 8px; 233 | } 234 | 235 | .mt-8 { 236 | margin-top: 8px; 237 | } 238 | 239 | .mr-8 { 240 | margin-right: 8px; 241 | } 242 | 243 | .mb-8 { 244 | margin-bottom: 8px; 245 | } 246 | 247 | .ml-8 { 248 | margin-left: 8px; 249 | } 250 | 251 | .m-12 { 252 | margin: 12px; 253 | } 254 | 255 | .mt-12 { 256 | margin-top: 12px; 257 | } 258 | 259 | .mr-12 { 260 | margin-right: 12px; 261 | } 262 | 263 | .mb-12 { 264 | margin-bottom: 12px; 265 | } 266 | 267 | .ml-12 { 268 | margin-left: 12px; 269 | } 270 | 271 | .m-16 { 272 | margin: 16px; 273 | } 274 | 275 | .mt-16 { 276 | margin-top: 16px; 277 | } 278 | 279 | .mr-16 { 280 | margin-right: 16px; 281 | } 282 | 283 | .mb-16 { 284 | margin-bottom: 16px; 285 | } 286 | 287 | .ml-16 { 288 | margin-left: 16px; 289 | } 290 | 291 | .m-24 { 292 | margin: 24px; 293 | } 294 | 295 | .mt-24 { 296 | margin-top: 24px; 297 | } 298 | 299 | .mr-24 { 300 | margin-right: 24px; 301 | } 302 | 303 | .mb-24 { 304 | margin-bottom: 24px; 305 | } 306 | 307 | .ml-24 { 308 | margin-left: 24px; 309 | } 310 | 311 | .m-32 { 312 | margin: 32px; 313 | } 314 | 315 | .mt-32 { 316 | margin-top: 32px; 317 | } 318 | 319 | .mr-32 { 320 | margin-right: 32px; 321 | } 322 | 323 | .mb-32 { 324 | margin-bottom: 32px; 325 | } 326 | 327 | .ml-32 { 328 | margin-left: 32px; 329 | } 330 | 331 | // Spacing, padding 332 | .p-0 { 333 | padding: 0; 334 | } 335 | 336 | .pt-0 { 337 | padding-top: 0; 338 | } 339 | 340 | .pr-0 { 341 | padding-right: 0; 342 | } 343 | 344 | .pb-0 { 345 | padding-bottom: 0; 346 | } 347 | 348 | .pl-0 { 349 | padding-left: 0; 350 | } 351 | 352 | .p-4 { 353 | padding: 4px; 354 | } 355 | 356 | .pt-4 { 357 | padding-top: 4px; 358 | } 359 | 360 | .pr-4 { 361 | padding-right: 4px; 362 | } 363 | 364 | .pb-4 { 365 | padding-bottom: 4px; 366 | } 367 | 368 | .pl-4 { 369 | padding-left: 4px; 370 | } 371 | 372 | .p-8 { 373 | padding: 8px; 374 | } 375 | 376 | .pt-8 { 377 | padding-top: 8px; 378 | } 379 | 380 | .pr-8 { 381 | padding-right: 8px; 382 | } 383 | 384 | .pb-8 { 385 | padding-bottom: 8px; 386 | } 387 | 388 | .pl-8 { 389 | padding-left: 8px; 390 | } 391 | 392 | .p-12 { 393 | padding: 12px; 394 | } 395 | 396 | .pt-12 { 397 | padding-top: 12px; 398 | } 399 | 400 | .pr-12 { 401 | padding-right: 12px; 402 | } 403 | 404 | .pb-12 { 405 | padding-bottom: 12px; 406 | } 407 | 408 | .pl-12 { 409 | padding-left: 12px; 410 | } 411 | 412 | .p-16 { 413 | padding: 16px; 414 | } 415 | 416 | .pt-16 { 417 | padding-top: 16px; 418 | } 419 | 420 | .pr-16 { 421 | padding-right: 16px; 422 | } 423 | 424 | .pb-16 { 425 | padding-bottom: 16px; 426 | } 427 | 428 | .pl-16 { 429 | padding-left: 16px; 430 | } 431 | 432 | .p-24 { 433 | padding: 24px; 434 | } 435 | 436 | .pt-24 { 437 | padding-top: 24px; 438 | } 439 | 440 | .pr-24 { 441 | padding-right: 24px; 442 | } 443 | 444 | .pb-24 { 445 | padding-bottom: 24px; 446 | } 447 | 448 | .pl-24 { 449 | padding-left: 24px; 450 | } 451 | 452 | .p-32 { 453 | padding: 32px; 454 | } 455 | 456 | .pt-32 { 457 | padding-top: 32px; 458 | } 459 | 460 | .pr-32 { 461 | padding-right: 32px; 462 | } 463 | 464 | .pb-32 { 465 | padding-bottom: 32px; 466 | } 467 | 468 | .pl-32 { 469 | padding-left: 32px; 470 | } 471 | 472 | // Spacing, spacers 473 | .spacer-4 { 474 | padding-top: 4px; 475 | } 476 | 477 | .spacer-8 { 478 | padding-top: 8px; 479 | } 480 | 481 | .spacer-12 { 482 | padding-top: 12px; 483 | } 484 | 485 | .spacer-16 { 486 | padding-top: 16px; 487 | } 488 | 489 | .spacer-24 { 490 | padding-top: 24px; 491 | } 492 | 493 | .spacer-32 { 494 | padding-top: 32px; 495 | } 496 | 497 | .spacer-48 { 498 | padding-top: 48px; 499 | } 500 | 501 | .spacer-64 { 502 | padding-top: 64px; 503 | } 504 | 505 | @include media( '<=medium' ) { 506 | 507 | .ta-l-mobile { 508 | text-align: left; 509 | } 510 | 511 | .ta-c-mobile { 512 | text-align: center; 513 | } 514 | 515 | .ta-r-mobile { 516 | text-align: right; 517 | } 518 | 519 | .center-content-mobile { 520 | text-align: center; 521 | 522 | img, 523 | svg, 524 | video { 525 | margin-left: auto; 526 | margin-right: auto; 527 | } 528 | 529 | .button-group { 530 | justify-content: center; 531 | } 532 | } 533 | 534 | // Spacing, spacers 535 | .spacer-4-mobile { 536 | padding-top: 4px; 537 | } 538 | 539 | .spacer-8-mobile { 540 | padding-top: 8px; 541 | } 542 | 543 | .spacer-12-mobile { 544 | padding-top: 12px; 545 | } 546 | 547 | .spacer-16-mobile { 548 | padding-top: 16px; 549 | } 550 | 551 | .spacer-24-mobile { 552 | padding-top: 24px; 553 | } 554 | 555 | .spacer-32-mobile { 556 | padding-top: 32px; 557 | } 558 | 559 | .spacer-48-mobile { 560 | padding-top: 48px; 561 | } 562 | 563 | .spacer-64-mobile { 564 | padding-top: 64px; 565 | } 566 | } 567 | 568 | @include media( '>medium' ) { 569 | 570 | .ta-l-desktop { 571 | text-align: left; 572 | } 573 | 574 | .ta-c-desktop { 575 | text-align: center; 576 | } 577 | 578 | .ta-r-desktop { 579 | text-align: right; 580 | } 581 | 582 | .center-content-desktop { 583 | text-align: center; 584 | 585 | img, 586 | svg, 587 | video { 588 | margin-left: auto; 589 | margin-right: auto; 590 | } 591 | 592 | .button-group { 593 | justify-content: center; 594 | } 595 | } 596 | } 597 | -------------------------------------------------------------------------------- /src/assets/scss/core/base/_scroll-reveal.scss: -------------------------------------------------------------------------------- 1 | @include media( '>medium' ) { 2 | 3 | .has-animations { 4 | 5 | [class*=reveal-] { 6 | opacity: 0; 7 | will-change: opacity, transform; 8 | } 9 | 10 | .reveal-from-top { 11 | transform: translateY($scroll-reveal--from-top-amount); 12 | } 13 | 14 | .reveal-from-bottom { 15 | transform: translateY($scroll-reveal--from-bottom-amount); 16 | } 17 | 18 | .reveal-from-left { 19 | transform: translateX($scroll-reveal--from-left-amount); 20 | } 21 | 22 | .reveal-from-right { 23 | transform: translateX($scroll-reveal--from-right-amount); 24 | } 25 | 26 | .reveal-scale-up { 27 | transform: scale($scroll-reveal--scale-up-amount); 28 | } 29 | 30 | .reveal-scale-down { 31 | transform: scale($scroll-reveal--scale-down-amount); 32 | } 33 | 34 | .reveal-rotate-from-left { 35 | transform: perspective(1000px) rotateY($scroll-reveal--rotate-from-left-amount); 36 | } 37 | 38 | .reveal-rotate-from-right { 39 | transform: perspective(1000px) rotateY($scroll-reveal--rotate-from-right-amount); 40 | } 41 | 42 | &.is-loaded { 43 | 44 | [class*=reveal-] { 45 | transition: opacity $scroll-reveal--transition-duration $scroll-reveal--transition-timing, transform $scroll-reveal--transition-duration $scroll-reveal--transition-timing; 46 | 47 | &.is-revealed { 48 | opacity: 1; 49 | transform: translate(0); 50 | } 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/assets/scss/core/base/_typography.scss: -------------------------------------------------------------------------------- 1 | html { 2 | @include font-size(base); 3 | } 4 | 5 | body { 6 | color: color(base); 7 | font-size: 1rem; 8 | } 9 | 10 | body, 11 | button, 12 | input, 13 | select, 14 | textarea { 15 | @include font-family(base); 16 | @include font-weight(base); 17 | } 18 | 19 | h1, h2, h3, h4, h5, h6, 20 | .h1, .h2, .h3, .h4, .h5, .h6 { 21 | @include font-family(heading); 22 | @include font-weight(heading); 23 | clear: both; 24 | color: color(heading); 25 | word-wrap: break-word; 26 | overflow-wrap: break-word; 27 | } 28 | 29 | h1, 30 | .h1 { 31 | @include font-size(h1); 32 | } 33 | 34 | h2, 35 | .h2 { 36 | @include font-size(h2); 37 | } 38 | 39 | h3, 40 | .h3 { 41 | @include font-size(h3); 42 | } 43 | 44 | h4, 45 | .h4 { 46 | @include font-size(h4); 47 | } 48 | 49 | h5, 50 | .h5 { 51 | @include font-size(base); 52 | } 53 | 54 | h6, 55 | .h6, 56 | small, 57 | .text-sm { 58 | @include font-size(sm); 59 | } 60 | 61 | .text-xs { 62 | @include font-size(xs); 63 | } 64 | 65 | .text-xxs { 66 | @include font-size(xxs); 67 | } 68 | 69 | figcaption { 70 | @include font-size(figcap); 71 | @include font-weight(figcap); 72 | } 73 | 74 | a { 75 | 76 | &:not(.button) { 77 | @include anchor-aspect(main); 78 | @include font-weight(link); 79 | } 80 | 81 | &.button-link { 82 | @include anchor-aspect(button-link); 83 | @include font-weight(button-link); 84 | text-transform: $link-button--transform; 85 | } 86 | 87 | &.func-link { 88 | @include anchor-aspect(func-link); 89 | @include font-weight(func-link); 90 | text-transform: $link-func--transform; 91 | } 92 | } 93 | 94 | h1, 95 | .h1 { 96 | margin-top: $spacing--h1-t; 97 | margin-bottom: $spacing--h1-b; 98 | } 99 | 100 | h2, 101 | .h2 { 102 | margin-top: $spacing--h2-t; 103 | margin-bottom: $spacing--h2-b; 104 | } 105 | 106 | h3, 107 | .h3 { 108 | margin-top: $spacing--h3-t; 109 | margin-bottom: $spacing--h3-b; 110 | } 111 | 112 | h4, h5, h6, 113 | .h4, .h5, .h6 { 114 | margin-top: $spacing--hx-t; 115 | margin-bottom: $spacing--hx-b; 116 | } 117 | 118 | p { 119 | margin-top: 0; 120 | margin-bottom: $spacing--shared-v; 121 | } 122 | 123 | dfn, cite, em, i { 124 | font-style: italic; 125 | } 126 | 127 | blockquote { 128 | @include font-size(bquote); 129 | margin-top: $spacing--shared-v; 130 | margin-bottom: $spacing--shared-v; 131 | margin-left: $spacing--shared-h; 132 | 133 | &::before { 134 | content: "\201C"; 135 | } 136 | 137 | &::after { 138 | content: "\201D"; 139 | } 140 | 141 | p { 142 | display: inline; 143 | } 144 | } 145 | 146 | address { 147 | border-width: 1px 0; 148 | border-style: solid; 149 | border-color: color-border(divider); 150 | padding: $spacing--shared-v 0; 151 | margin: 0 0 $spacing--shared-v; 152 | } 153 | 154 | pre, 155 | pre h1, 156 | pre h2, 157 | pre h3, 158 | pre h4, 159 | pre h5, 160 | pre h6, 161 | pre .h1, 162 | pre .h2, 163 | pre .h3, 164 | pre .h4, 165 | pre .h5, 166 | pre .h6 { 167 | @include font-family(pre); 168 | } 169 | 170 | pre, code, kbd, tt, var { 171 | background: color-bg(code); 172 | } 173 | 174 | pre { 175 | @include font-size(pre); 176 | max-width: 100%; 177 | overflow: auto; 178 | padding: $spacing--shared-v $spacing--shared-h; 179 | margin-top: $spacing--shared-v; 180 | margin-bottom: $spacing--shared-v; 181 | } 182 | 183 | code, kbd, tt, var { 184 | @include font-family(code); 185 | @include font-size(code); 186 | padding: $spacing--code-v $spacing--code-h; 187 | } 188 | 189 | abbr, acronym { 190 | cursor: help; 191 | } 192 | 193 | mark, ins { 194 | text-decoration: none; 195 | } 196 | 197 | b, 198 | strong { 199 | @include font-weight(strong); 200 | } 201 | 202 | .invert-color { 203 | color: color(base-inverse); 204 | 205 | a { 206 | 207 | &:not(.button) { 208 | @include anchor-aspect(main, inverse); 209 | } 210 | 211 | &.button-link { 212 | @include anchor-aspect(button-link, inverse); 213 | } 214 | 215 | &.func-link { 216 | @include anchor-aspect(func-link, inverse); 217 | } 218 | } 219 | 220 | h1, h2, h3, h4, h5, h6, 221 | .h1, .h2, .h3, .h4, .h5, .h6 { 222 | color: color(heading-inverse); 223 | } 224 | 225 | address { 226 | border-color: color-border(divider-inverse); 227 | } 228 | 229 | pre, code, kbd, tt, var { 230 | background: color-bg(code-inverse); 231 | } 232 | } 233 | 234 | @include media( '<=medium' ) { 235 | 236 | .h1-mobile { 237 | @include font-size(h1); 238 | } 239 | 240 | .h2-mobile { 241 | @include font-size(h2); 242 | } 243 | 244 | .h3-mobile { 245 | @include font-size(h3); 246 | } 247 | 248 | .h4-mobile { 249 | @include font-size(h4); 250 | } 251 | 252 | .h5-mobile { 253 | @include font-size(base); 254 | } 255 | 256 | .h6-mobile { 257 | @include font-size(sm); 258 | } 259 | } 260 | 261 | @include media( '>medium' ) { 262 | 263 | html { 264 | @include font-size(base-desktop); 265 | } 266 | 267 | h1, 268 | .h1 { 269 | @include font-size(h1-desktop); 270 | } 271 | 272 | h2, 273 | .h2 { 274 | @include font-size(h2-desktop); 275 | } 276 | 277 | h3, 278 | .h3 { 279 | @include font-size(h3-desktop); 280 | } 281 | 282 | h4, 283 | .h4 { 284 | @include font-size(h4-desktop); 285 | } 286 | 287 | h5, 288 | .h5 { 289 | @include font-size(base-desktop); 290 | } 291 | 292 | h6, 293 | .h6, 294 | small, 295 | .text-sm { 296 | @include font-size(sm-desktop); 297 | } 298 | 299 | .text-xs { 300 | @include font-size(xs-desktop); 301 | } 302 | 303 | .text-xxs { 304 | @include font-size(xxs-desktop); 305 | } 306 | 307 | figcaption { 308 | @include font-size(figcap-desktop); 309 | } 310 | 311 | blockquote { 312 | @include font-size(bquote-desktop); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/assets/scss/core/elements/_buttons.scss: -------------------------------------------------------------------------------- 1 | .button { 2 | display: inline-flex; 3 | @include font-size(button); 4 | @include font-weight(button); 5 | padding: (($button-form--height - get-line-height(button) - ($button-form--border-width * 2)) / 2) ($button--padding-h - $button-form--border-width); 6 | height: $button-form--height; 7 | text-decoration: none !important; 8 | text-transform: $button--transform; 9 | color: color(button-light); 10 | background-color: color-bg(button-light); 11 | border-width: $button-form--border-width; 12 | border-style: $button-form--border-style; 13 | border-color: color-border(button-light); 14 | border-radius: $button--radius; 15 | cursor: pointer; 16 | justify-content: center; 17 | text-align: center; 18 | letter-spacing: inherit; 19 | white-space: nowrap; 20 | transition: background .15s ease; 21 | 22 | &:active { 23 | outline: 0; 24 | } 25 | 26 | &:hover { 27 | background-color: color-bg(button-light-hover); 28 | border-color: color-border(button-light-hover); 29 | } 30 | 31 | &.is-loading { 32 | position: relative; 33 | color: transparent!important; 34 | pointer-events: none; 35 | 36 | &::after { 37 | content: ''; 38 | display: block; 39 | position: absolute; 40 | width: get-line-height(button); 41 | height: get-line-height(button); 42 | margin-left: -(get-line-height(button) / 2); 43 | margin-top: -(get-line-height(button) / 2); 44 | top: 50%; 45 | left: 50%; 46 | border: $button-loading--thickness solid color(button-light); 47 | border-radius: 50%; 48 | border-right-color: transparent !important; 49 | border-top-color: transparent !important; 50 | z-index: 1; 51 | animation: button-loading .6s infinite linear; 52 | } 53 | } 54 | 55 | &[disabled] { 56 | cursor: not-allowed; 57 | color: color(button-disabled); 58 | background-color: color-bg(button-disabled) !important; 59 | border-color: color-border(button-disabled); 60 | 61 | &.is-loading { 62 | 63 | &::after { 64 | border-color: color(button-disabled); 65 | } 66 | } 67 | } 68 | } 69 | 70 | .button-sm { 71 | padding: (($button-form-sm--height - get-line-height(button) - ($button-form--border-width * 2)) / 2) ($button-sm--padding-h - $button-form--border-width); 72 | height: $button-form-sm--height; 73 | } 74 | 75 | .button-dark { 76 | color: color(button-dark); 77 | background-color: color-bg(button-dark); 78 | border-color: color-border(button-dark); 79 | 80 | &:hover { 81 | background-color: color-bg(button-dark-hover); 82 | border-color: color-border(button-dark-hover); 83 | } 84 | 85 | &.is-loading { 86 | 87 | &::after { 88 | border-color: color(button-dark); 89 | } 90 | } 91 | } 92 | 93 | .button-primary { 94 | color: color(button-primary); 95 | background-color: color-bg(button-primary); 96 | border-color: color-border(button-primary); 97 | 98 | &:hover { 99 | background-color: color-bg(button-primary-hover); 100 | border-color: color-border(button-primary-hover); 101 | } 102 | 103 | &.is-loading { 104 | 105 | &::after { 106 | border-color: color(button-primary); 107 | } 108 | } 109 | } 110 | 111 | .button-secondary { 112 | color: color(button-secondary); 113 | background-color: color-bg(button-secondary); 114 | border-color: color-border(button-secondary); 115 | 116 | &:hover { 117 | background-color: color-bg(button-secondary-hover); 118 | border-color: color-border(button-secondary-hover); 119 | } 120 | 121 | &.is-loading { 122 | 123 | &::after { 124 | border-color: color(button-secondary); 125 | } 126 | } 127 | } 128 | 129 | .button-block { 130 | display: flex; 131 | width: 100%; 132 | } 133 | 134 | .button-group { 135 | display: flex; 136 | flex-wrap: wrap; 137 | align-items: center; 138 | margin-right: -($button-group-padding / 2); 139 | margin-left: -($button-group-padding / 2); 140 | margin-top: -($button-group-padding / 2); 141 | 142 | &:last-of-type { 143 | margin-bottom: -($button-group-padding / 2); 144 | } 145 | 146 | &:not(:last-of-type) { 147 | margin-bottom: ($button-group-padding / 2); 148 | } 149 | 150 | > [class*=button] { 151 | margin: $button-group-padding / 2; 152 | } 153 | } 154 | 155 | @include media( '<=medium' ) { 156 | 157 | .button-wide-mobile { 158 | width: 100%; 159 | max-width: $button--max-size-mobile; 160 | } 161 | } 162 | 163 | @keyframes button-loading { 164 | 0% { 165 | transform: rotate(0); 166 | } 167 | 168 | 100% { 169 | transform: rotate(360deg); 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/assets/scss/core/elements/_containers.scss: -------------------------------------------------------------------------------- 1 | .container, 2 | .container-sm, 3 | .container-xs { 4 | width: 100%; 5 | margin: 0 auto; 6 | padding-left: $container--padding__mobile; 7 | padding-right: $container--padding__mobile; 8 | 9 | @include media( '>small' ) { 10 | padding-left: $container--padding__desktop; 11 | padding-right: $container--padding__desktop; 12 | } 13 | } 14 | 15 | .container { 16 | max-width: $container--width + ( $container--padding__desktop * 2 ); 17 | } 18 | 19 | .container-sm { 20 | max-width: $container--width-sm + ( $container--padding__desktop * 2 ); 21 | } 22 | 23 | .container-xs { 24 | max-width: $container--width-xs + ( $container--padding__desktop * 2 ); 25 | } 26 | 27 | [class*=container] { 28 | 29 | [class*=container] { 30 | padding-left: 0; 31 | padding-right: 0; 32 | } 33 | 34 | .container-sm { 35 | max-width: $container--width-sm; 36 | } 37 | 38 | .container-xs { 39 | max-width: $container--width-xs; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/assets/scss/core/elements/_hamburger.scss: -------------------------------------------------------------------------------- 1 | .header-nav-toggle { 2 | background: transparent; 3 | border: 0; 4 | outline: 0; 5 | padding: 0; 6 | cursor: pointer; 7 | } 8 | 9 | .hamburger, 10 | .hamburger-inner { 11 | display: block; 12 | pointer-events: none; 13 | } 14 | 15 | .hamburger { 16 | position: relative; 17 | width: $header-hamburger--size; 18 | height: $header-hamburger--size; 19 | } 20 | 21 | .hamburger-inner, 22 | .hamburger-inner::before, 23 | .hamburger-inner::after { 24 | width: $header-hamburger--size; 25 | height: $header-hamburger--thickness; 26 | position: absolute; 27 | background: color-icon(hamburger); 28 | border-radius: $header-hamburger--radius; 29 | 30 | .invert-color & { 31 | background: color-icon(hamburger-inverse); 32 | } 33 | } 34 | 35 | .hamburger-inner { 36 | top: 50%; 37 | margin-top: -($header-hamburger--thickness / 2); 38 | transition-duration: 0.22s; 39 | transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); 40 | 41 | &::before, 42 | &::after { 43 | content: ''; 44 | display: block; 45 | } 46 | 47 | &::before { 48 | top: -$header-hamburger--distance; 49 | transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in; 50 | } 51 | 52 | &::after { 53 | bottom: -$header-hamburger--distance; 54 | transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), width 0.1s 0.25s ease-in; 55 | } 56 | 57 | .off-nav-is-active & { 58 | transform: rotate(225deg); 59 | transition-delay: 0.12s; 60 | transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); 61 | 62 | &::before { 63 | top: 0; 64 | opacity: 0; 65 | transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; 66 | } 67 | 68 | &::after { 69 | width: $header-hamburger--size; 70 | bottom: 0; 71 | transform: rotate(-90deg); 72 | transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1), width 0.1s ease-out; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/assets/scss/core/elements/_modal.scss: -------------------------------------------------------------------------------- 1 | .modal, 2 | .modal::before { 3 | bottom: 0; 4 | left: 0; 5 | right: 0; 6 | top: 0 7 | } 8 | 9 | .modal { 10 | display: none; 11 | align-items: center; 12 | flex-direction: column; 13 | justify-content: center; 14 | overflow: hidden; 15 | position: fixed; 16 | z-index: 40; 17 | 18 | &.modal-video { 19 | 20 | .modal-inner { 21 | padding: 0; 22 | max-width: $modal-video--max-width; 23 | } 24 | } 25 | 26 | &::before, 27 | .modal-inner { 28 | display: none; 29 | } 30 | 31 | &::before { 32 | content: ''; 33 | position: absolute; 34 | background-color: color-bg(modal-outer); 35 | } 36 | 37 | &.is-active { 38 | display: flex; 39 | 40 | &::before, 41 | .modal-inner { 42 | display: block; 43 | } 44 | 45 | .modal-inner { 46 | animation: slideUpInModal .15s ease-in-out both; 47 | } 48 | 49 | &::before { 50 | animation: slideUpInModalBg .15s ease-in-out both; 51 | } 52 | } 53 | } 54 | 55 | .modal-inner { 56 | max-height: calc(100vh - #{$modal--outer-padding-v__mobile} * 2); 57 | overflow: auto; 58 | position: relative; 59 | width: calc(100% - ( #{$container--padding__mobile} * 2 )); 60 | min-width: $modal--min-width; 61 | max-width: $modal--max-width; 62 | margin-left: $container--padding__mobile; 63 | margin-right: $container--padding__mobile; 64 | background: color-bg(modal); 65 | } 66 | 67 | .modal-content { 68 | padding: $modal--inner-padding-v__mobile $modal--inner-padding-h__mobile; 69 | } 70 | 71 | .modal-close { 72 | background: transparent; 73 | border: 0; 74 | outline: 0; 75 | padding: 0; 76 | cursor: pointer; 77 | position: absolute; 78 | right: $modal-close-position; 79 | top: $modal-close-position; 80 | width: $modal-close-icon--size; 81 | height: $modal-close-icon--size; 82 | 83 | &::before, 84 | &::after { 85 | content: ''; 86 | display: block; 87 | position: absolute; 88 | top: 50%; 89 | left: 50%; 90 | margin-top: -($modal-close-icon--thickness / 2); 91 | margin-left: -($modal-close-icon--size / 2); 92 | width: $modal-close-icon--size; 93 | height: $modal-close-icon--thickness; 94 | background: color-icon(modal); 95 | border-radius: $modal-close-icon--radius; 96 | } 97 | 98 | &::before { 99 | transform: rotate(225deg); 100 | } 101 | 102 | &::after { 103 | transform: rotate(-45deg); 104 | } 105 | 106 | &:hover { 107 | 108 | &::before, 109 | &::after { 110 | background: color-icon(modal-hover); 111 | } 112 | } 113 | } 114 | 115 | @include media( '>medium' ) { 116 | 117 | .modal-inner { 118 | margin: 0 auto; 119 | max-height: calc(100vh - #{$modal--outer-padding-v__desktop} * 2); 120 | } 121 | 122 | .modal-content { 123 | padding-top: $modal--inner-padding-v__desktop; 124 | padding-bottom: $modal--inner-padding-v__desktop; 125 | padding-left: $modal--inner-padding-h__desktop; 126 | padding-right: $modal--inner-padding-h__desktop; 127 | } 128 | } 129 | 130 | @keyframes slideUpInModal { 131 | 0% { 132 | opacity: 0; 133 | transform: translateY(-24px); 134 | } 135 | 136 | to { 137 | opacity: 1; 138 | transform: translateY(0); 139 | } 140 | } 141 | 142 | @keyframes slideUpInModalBg { 143 | 0% { 144 | opacity: 0; 145 | } 146 | 147 | to { 148 | opacity: 1; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/assets/scss/core/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | .site-footer { 2 | position: relative; 3 | 4 | &::before { 5 | content: ''; 6 | position: absolute; 7 | bottom: 0; 8 | left: 0; 9 | width: 100%; 10 | height: 100%; 11 | background: color-bg(footer); 12 | z-index: -3; 13 | } 14 | } 15 | 16 | .site-footer-inner { 17 | padding: $footer--padding__mobile 0; 18 | } 19 | 20 | .footer-top { 21 | padding-bottom: $footer-inner--padding-v / 2; 22 | } 23 | 24 | .footer-bottom { 25 | padding-top: $footer-inner--padding-v / 2; 26 | } 27 | 28 | .footer-blocks { 29 | display: flex; 30 | flex-wrap: wrap; 31 | margin-right: -($footer-block--padding_h / 2); 32 | margin-left: -($footer-block--padding_h / 2); 33 | margin-top: -($footer-block--padding_v / 2); 34 | 35 | &:last-of-type { 36 | margin-bottom: -($footer-block--padding_v / 2) + $footer-blocks--padding; 37 | } 38 | 39 | &:not(:last-of-type) { 40 | margin-bottom: ($footer-block--padding_v / 2); 41 | } 42 | } 43 | 44 | .footer-block { 45 | flex-grow: 1; 46 | flex-basis: $footer-block--min-width; 47 | box-sizing: content-box; 48 | padding: $footer-block--padding_v / 2 $footer-block--padding_h / 2; 49 | 50 | * { 51 | box-sizing: border-box; 52 | } 53 | 54 | ul li { 55 | 56 | &:not(:last-child) { 57 | margin-bottom: $footer-block-list-padding; 58 | } 59 | } 60 | 61 | a { 62 | @include anchor-aspect(footer-block); 63 | @include font-weight(footer-block-link); 64 | text-transform: $link-footer-block--transform; 65 | 66 | .invert-color & { 67 | @include anchor-aspect(footer-block, inverse); 68 | } 69 | } 70 | } 71 | 72 | .footer-block-title { 73 | @include font-size(block-title); 74 | @include font-weight(block-title); 75 | color: color(block-title); 76 | text-transform: $footer-block-title--transform; 77 | margin-bottom: $footer-block-title-padding; 78 | 79 | .invert-color & { 80 | color: color(block-title-inverse); 81 | } 82 | } 83 | 84 | .footer-social, 85 | .footer-nav { 86 | 87 | a { 88 | display: flex; 89 | } 90 | 91 | ul { 92 | display: flex; 93 | flex-wrap: wrap; 94 | justify-content: center; 95 | align-items: center; 96 | white-space: nowrap; 97 | margin-bottom: 0; 98 | } 99 | } 100 | 101 | .footer-social { 102 | 103 | ul { 104 | margin-right: -($footer-social--inner-padding + $footer-social--outer-padding-h); 105 | margin-left: -($footer-social--inner-padding + $footer-social--outer-padding-h); 106 | } 107 | 108 | li { 109 | padding: 0 $footer-social--outer-padding-h; 110 | } 111 | 112 | a { 113 | padding: $footer-social--inner-padding; 114 | 115 | svg { 116 | fill: color-icon(social); 117 | transition: fill .15s ease; 118 | 119 | .invert-color & { 120 | fill: color-icon(social-inverse); 121 | } 122 | } 123 | 124 | &:hover { 125 | 126 | svg { 127 | fill: color-icon(social-hover); 128 | 129 | .invert-color & { 130 | fill: color-icon(social-hover-inverse); 131 | } 132 | } 133 | } 134 | } 135 | } 136 | 137 | .footer-nav { 138 | margin-right: -$footer-nav--padding-h; 139 | margin-left: -$footer-nav--padding-h; 140 | 141 | a { 142 | @include anchor-aspect(footer); 143 | @include font-weight(footer-link); 144 | text-transform: $link-footer--transform; 145 | padding: 0 $footer-nav--padding-h; 146 | 147 | .invert-color & { 148 | @include anchor-aspect(footer, inverse); 149 | } 150 | } 151 | } 152 | 153 | @include media( '<=medium' ) { 154 | 155 | .footer-top, 156 | .footer-bottom { 157 | 158 | > *:not(:last-child) { 159 | margin-bottom: $footer-inner--padding-v; 160 | } 161 | } 162 | } 163 | 164 | @include media( '>medium' ) { 165 | 166 | @if ( $footer--padding__mobile != $footer--padding__desktop ) { 167 | 168 | .site-footer-inner { 169 | padding: $footer--padding__desktop 0; 170 | } 171 | } 172 | 173 | .footer-top, 174 | .footer-bottom { 175 | 176 | &.space-between { 177 | display: flex; 178 | justify-content: space-between; 179 | align-items: center; 180 | } 181 | } 182 | 183 | .footer-top, 184 | .footer-bottom { 185 | 186 | &.invert-order-desktop { 187 | 188 | > *:first-child { 189 | order: 1; 190 | } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/assets/scss/core/layout/_header.scss: -------------------------------------------------------------------------------- 1 | .site-header { 2 | position: absolute !important; 3 | top: 0; 4 | width: 100%; 5 | z-index: 10 !important; 6 | background: color-bg(header); 7 | 8 | + .site-content { 9 | 10 | .section:first-of-type { 11 | padding-top: $header-height__mobile; 12 | } 13 | } 14 | 15 | .brand { 16 | margin-right: $header-nav--padding-h; 17 | } 18 | } 19 | 20 | .site-header-inner { 21 | display: flex; 22 | justify-content: space-between; 23 | align-items: center; 24 | height: $header-height__mobile; 25 | } 26 | 27 | .header-nav { 28 | flex-grow: 1; 29 | 30 | .header-nav-inner { 31 | display: flex; 32 | flex-grow: 1; 33 | } 34 | 35 | ul { 36 | display: flex; 37 | align-items: center; 38 | flex-grow: 1; 39 | white-space: nowrap; 40 | margin-bottom: 0; 41 | 42 | &:first-of-type { 43 | flex-wrap: wrap; 44 | } 45 | } 46 | 47 | li { 48 | 49 | + .header-button { 50 | margin-left: $header-nav--padding-h; 51 | } 52 | } 53 | 54 | a:not(.button) { 55 | display: block; 56 | @include anchor-aspect(header); 57 | @include font-weight(header-link); 58 | text-transform: $link-header--transform; 59 | padding: 0 $header-nav--padding-h; 60 | 61 | .invert-color & { 62 | @include anchor-aspect(header, inverse); 63 | } 64 | } 65 | 66 | a.button { 67 | margin-left: $header-nav--padding-h; 68 | } 69 | } 70 | 71 | .header-nav-center:first-of-type { 72 | flex-grow: 1; 73 | justify-content: flex-end; 74 | } 75 | 76 | .header-nav-right { 77 | justify-content: flex-end; 78 | 79 | + .header-nav-right { 80 | flex-grow: 0; 81 | } 82 | } 83 | 84 | .header-nav-toggle { 85 | display: none; 86 | } 87 | 88 | @include media( '<=medium' ) { 89 | 90 | .header-nav-toggle { 91 | display: block; 92 | 93 | // Header navigation when the hamburger is a previous sibling 94 | + .header-nav { 95 | flex-direction: column; 96 | position: absolute; 97 | left: 0; 98 | right: 0; 99 | top: 100%; 100 | z-index: 9999; 101 | background: color-bg(menu-mobile); 102 | max-height: 0; 103 | opacity: 0; 104 | overflow: hidden; 105 | transition: max-height .25s ease-in-out, opacity .15s; 106 | 107 | &.is-active { 108 | opacity: 1; 109 | } 110 | 111 | .header-nav-inner { 112 | flex-direction: column; 113 | padding: $header-nav--padding-v__mobile; 114 | } 115 | 116 | ul { 117 | display: block; 118 | text-align: center; 119 | 120 | a:not(.button) { 121 | display: inline-flex; 122 | @include anchor-aspect(header-mobile); 123 | padding-top: $header-nav--padding-v__mobile / 2; 124 | padding-bottom: $header-nav--padding-v__mobile / 2; 125 | } 126 | } 127 | 128 | a.button { 129 | margin-left: 0; 130 | margin-top: $header-nav--padding-v__mobile / 2; 131 | margin-bottom: $header-nav--padding-v__mobile / 2; 132 | } 133 | } 134 | } 135 | } 136 | 137 | @include media( '>medium' ) { 138 | 139 | .site-header { 140 | 141 | + .site-content { 142 | 143 | .section:first-of-type { 144 | padding-top: $header-height__desktop; 145 | } 146 | } 147 | } 148 | 149 | .site-header-inner { 150 | height: $header-height__desktop; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/assets/scss/core/layout/_main.scss: -------------------------------------------------------------------------------- 1 | .is-boxed { 2 | background: color-bg(body-outer); 3 | 4 | .body-wrap { 5 | max-width: $container--width-boxed; 6 | margin: 0 auto; 7 | box-shadow: color-bg(body-shadow); 8 | 9 | &::before { 10 | content: ''; 11 | position: absolute; 12 | top: 0; 13 | left: 0; 14 | width: 100%; 15 | height: 100%; 16 | background: color-bg(body); 17 | z-index: -10; 18 | } 19 | } 20 | } 21 | 22 | .body-wrap { 23 | position: relative; 24 | overflow: hidden; 25 | // Sticky footer 26 | display: flex; 27 | flex-direction: column; 28 | min-height: 100vh; 29 | } 30 | 31 | .site-content { 32 | flex: 1 0 auto; 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/scss/core/patterns/_split.scss: -------------------------------------------------------------------------------- 1 | .split-wrap { 2 | margin-top: -($split-item--padding-v__mobile / 2); 3 | 4 | &:last-of-type { 5 | margin-bottom: -($split-item--padding-v__mobile / 2); 6 | } 7 | 8 | &:not(:last-of-type) { 9 | margin-bottom: $split-item--padding-v__mobile / 2; 10 | } 11 | 12 | .split-item { 13 | padding-top: $split-item--padding-v__mobile / 2; 14 | padding-bottom: $split-item--padding-v__mobile / 2; 15 | display: flex; 16 | flex-direction: column; 17 | 18 | .split-item-image { 19 | position: relative; 20 | width: 100%; 21 | 22 | img, 23 | svg, 24 | video { 25 | width: auto; 26 | height: auto; 27 | max-width: 100%; 28 | overflow: visible; 29 | } 30 | 31 | &.split-item-image-fill { 32 | 33 | img, 34 | svg, 35 | video { 36 | width: 100%; 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | @include media( '<=medium' ) { 44 | 45 | .split-wrap { 46 | 47 | .split-item { 48 | 49 | .split-item-content { 50 | margin-bottom: $split-item--inner-padding-v_mobile; 51 | } 52 | } 53 | 54 | &.invert-mobile { 55 | 56 | .split-item { 57 | 58 | .split-item-content { 59 | order: 1; 60 | margin-bottom: 0 !important; 61 | } 62 | 63 | .split-item-image { 64 | margin-bottom: $split-item--inner-padding-v_mobile; 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | @include media( '>medium' ) { 72 | 73 | .split-wrap { 74 | margin-top: -($split-item--padding-v__desktop / 2); 75 | 76 | &:last-of-type { 77 | margin-bottom: -($split-item--padding-v__desktop / 2); 78 | } 79 | 80 | &:not(:last-of-type) { 81 | margin-bottom: $split-item--padding-v__desktop / 2; 82 | } 83 | 84 | .split-item { 85 | padding-top: $split-item--padding-v__desktop / 2; 86 | padding-bottom: $split-item--padding-v__desktop / 2; 87 | flex-direction: row; 88 | flex-wrap: nowrap; 89 | align-items: center; 90 | justify-content: flex-start; 91 | 92 | .split-item-content { 93 | flex-shrink: 0; 94 | width: ($container--width-sm / 2) - $split-item-content--padding-h; 95 | margin-bottom: 0; 96 | margin-right: $split-item--inner-padding-h; 97 | } 98 | 99 | .split-item-image { 100 | min-width: ($container--width-sm / 2) - $split-item-image--padding-h; 101 | } 102 | } 103 | 104 | &:not(.invert-desktop) .split-item:nth-child(even), 105 | &.invert-desktop .split-item:nth-child(odd) { 106 | justify-content: flex-end; 107 | 108 | .split-item-content { 109 | order: 1; 110 | margin-left: $split-item--inner-padding-h; 111 | margin-right: 0; 112 | } 113 | } 114 | 115 | &:not(.invert-desktop) .split-item:nth-child(odd), 116 | &.invert-desktop .split-item:nth-child(even) { 117 | 118 | .split-item-image { 119 | 120 | img, 121 | svg, 122 | video { 123 | margin-left: auto; 124 | } 125 | } 126 | } 127 | 128 | &.align-top { 129 | 130 | .split-item { 131 | align-items: flex-start; 132 | } 133 | } 134 | } 135 | } 136 | 137 | @include media( '>large' ) { 138 | 139 | .container { 140 | 141 | .split-wrap { 142 | 143 | .split-item { 144 | 145 | .split-item-content { 146 | width: ($container--width / 2) - $split-item-content--padding-h; 147 | } 148 | 149 | .split-item-image { 150 | min-width: ($container--width / 2) - $split-item-image--padding-h; 151 | } 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/assets/scss/core/patterns/_tiles.scss: -------------------------------------------------------------------------------- 1 | .tiles-wrap { 2 | display: flex; 3 | flex-wrap: wrap; 4 | justify-content: center; 5 | margin-right: -($tiles-items--padding__mobile / 2); 6 | margin-left: -($tiles-items--padding__mobile / 2); 7 | margin-top: -($tiles-items--padding__mobile / 2); 8 | 9 | &:last-of-type { 10 | margin-bottom: -($tiles-items--padding__mobile / 2); 11 | } 12 | 13 | &:not(:last-of-type) { 14 | margin-bottom: ($tiles-items--padding__mobile / 2); 15 | } 16 | 17 | &.push-left { 18 | 19 | &::after { 20 | content: ''; 21 | flex-basis: $tiles-item--width; 22 | max-width: $tiles-item--width; 23 | box-sizing: content-box; 24 | padding-left: $tiles-items--padding__mobile / 2; 25 | padding-right: $tiles-items--padding__mobile / 2; 26 | height: 0; 27 | } 28 | } 29 | } 30 | 31 | .tiles-item { 32 | flex-basis: $tiles-item--width; 33 | max-width: $tiles-item--width; 34 | box-sizing: content-box; 35 | padding: $tiles-items--padding__mobile / 2; 36 | 37 | * { 38 | box-sizing: border-box; 39 | } 40 | } 41 | 42 | .tiles-item-inner { 43 | display: flex; 44 | flex-wrap: wrap; 45 | flex-direction: column; 46 | height: 100%; 47 | padding: $tiles-item--inner-padding-v $tiles-item--inner-padding-h; 48 | } 49 | 50 | @if ( $tiles-items--padding__desktop != null ) { 51 | 52 | @include media( '>medium' ) { 53 | 54 | .tiles-wrap { 55 | margin-right: -($tiles-items--padding__desktop / 2); 56 | margin-left: -($tiles-items--padding__desktop / 2); 57 | margin-top: -($tiles-items--padding__desktop / 2); 58 | 59 | &:last-of-type { 60 | margin-bottom: -($tiles-items--padding__desktop / 2); 61 | } 62 | 63 | &:not(:last-of-type) { 64 | margin-bottom: ($tiles-items--padding__desktop / 2); 65 | } 66 | 67 | &.push-left { 68 | 69 | &::after { 70 | padding-left: $tiles-items--padding__desktop / 2; 71 | padding-right: $tiles-items--padding__desktop / 2; 72 | } 73 | } 74 | } 75 | 76 | .tiles-item { 77 | padding: $tiles-items--padding__desktop / 2; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_cta.scss: -------------------------------------------------------------------------------- 1 | .cta { 2 | 3 | .section-inner { 4 | padding-top: $cta--padding-t__mobile; 5 | padding-bottom: $cta--padding-b__mobile; 6 | } 7 | } 8 | 9 | .cta-slogan { 10 | margin-bottom: $cta-slogan--padding-v__mobile; 11 | } 12 | 13 | @include media( '>medium' ) { 14 | 15 | .cta { 16 | 17 | .section-inner { 18 | padding-top: $cta--padding-t__desktop; 19 | padding-bottom: $cta--padding-b__desktop; 20 | } 21 | } 22 | 23 | .cta-split { 24 | display: flex; 25 | justify-content: space-between; 26 | align-items: center; 27 | } 28 | 29 | .cta-slogan { 30 | margin-bottom: $cta-slogan--padding-v__desktop; 31 | 32 | .cta-split & { 33 | margin-bottom: 0; 34 | margin-right: $cta-slogan--padding-h__desktop; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_features-split.scss: -------------------------------------------------------------------------------- 1 | .features-split { 2 | 3 | .section-inner { 4 | padding-top: $features-split--padding-t__mobile; 5 | padding-bottom: $features-split--padding-b__mobile; 6 | } 7 | 8 | .section-header { 9 | padding-bottom: $features-split-header--padding__mobile; 10 | } 11 | } 12 | 13 | @include media( '>medium' ) { 14 | 15 | .features-split { 16 | 17 | .section-inner { 18 | padding-top: $features-split--padding-t__desktop; 19 | padding-bottom: $features-split--padding-b__desktop; 20 | } 21 | 22 | .section-header { 23 | padding-bottom: $features-split-header--padding__desktop; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_features-tiles.scss: -------------------------------------------------------------------------------- 1 | .features-tiles { 2 | 3 | .section-inner { 4 | padding-top: $features-tiles--padding-t__mobile; 5 | padding-bottom: $features-tiles--padding-b__mobile; 6 | } 7 | 8 | .section-header { 9 | padding-bottom: $features-tiles-header--padding__mobile; 10 | } 11 | 12 | .tiles-wrap { 13 | @if ( $features-tiles-items--padding__mobile != null ) { 14 | margin-right: -($features-tiles-items--padding__mobile / 2); 15 | margin-left: -($features-tiles-items--padding__mobile / 2); 16 | margin-top: -($features-tiles-items--padding__mobile / 2); 17 | 18 | &:last-of-type { 19 | margin-bottom: -($features-tiles-items--padding__mobile / 2); 20 | } 21 | 22 | &:not(:last-of-type) { 23 | margin-bottom: ($features-tiles-items--padding__mobile / 2); 24 | } 25 | } 26 | 27 | &.push-left { 28 | 29 | &::after { 30 | flex-basis: $features-tiles-item--width; 31 | max-width: $features-tiles-item--width; 32 | @if ( $features-tiles-items--padding__mobile != null ) { 33 | padding-left: $features-tiles-items--padding__mobile / 2; 34 | padding-right: $features-tiles-items--padding__mobile / 2; 35 | } 36 | } 37 | } 38 | } 39 | 40 | .tiles-item { 41 | flex-basis: $features-tiles-item--width; 42 | max-width: $features-tiles-item--width; 43 | @if ( $features-tiles-items--padding__mobile != null ) { 44 | padding: $features-tiles-items--padding__mobile / 2; 45 | } 46 | } 47 | 48 | .tiles-item-inner { 49 | padding-top: $features-tiles-item--inner-padding-v; 50 | padding-bottom: $features-tiles-item--inner-padding-v; 51 | padding-left: $features-tiles-item--inner-padding-h; 52 | padding-right: $features-tiles-item--inner-padding-h; 53 | } 54 | } 55 | 56 | @include media( '>medium' ) { 57 | 58 | .features-tiles { 59 | 60 | .section-inner { 61 | padding-top: $features-tiles--padding-t__desktop; 62 | padding-bottom: $features-tiles--padding-b__desktop; 63 | } 64 | 65 | .section-header { 66 | padding-bottom: $features-tiles-header--padding__desktop; 67 | } 68 | 69 | @if ( $features-tiles-items--padding__desktop != null ) { 70 | 71 | .tiles-wrap { 72 | margin-right: -($features-tiles-items--padding__desktop / 2); 73 | margin-left: -($features-tiles-items--padding__desktop / 2); 74 | margin-top: -($features-tiles-items--padding__desktop / 2); 75 | 76 | &:last-of-type { 77 | margin-bottom: -($features-tiles-items--padding__desktop / 2); 78 | } 79 | 80 | &:not(:last-of-type) { 81 | margin-bottom: ($features-tiles-items--padding__desktop / 2); 82 | } 83 | 84 | &.push-left { 85 | 86 | &::after { 87 | padding-left: $features-tiles-items--padding__desktop / 2; 88 | padding-right: $features-tiles-items--padding__desktop / 2; 89 | } 90 | } 91 | } 92 | 93 | .tiles-item { 94 | padding: $features-tiles-items--padding__desktop / 2; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_hero.scss: -------------------------------------------------------------------------------- 1 | .hero { 2 | 3 | .section-inner { 4 | padding-top: $hero--padding-t__mobile; 5 | padding-bottom: $hero--padding-b__mobile; 6 | } 7 | } 8 | 9 | .hero-inner { 10 | 11 | // Affects only hero full 12 | > .hero-content + .hero-figure, 13 | > .hero-figure + .hero-content { 14 | margin-top: $hero--inner-padding-v_mobile; 15 | } 16 | 17 | > .hero-figure { 18 | 19 | > a { 20 | display: inline-flex; 21 | // prevents stretching 22 | align-items: center; 23 | vertical-align: top; 24 | } 25 | } 26 | } 27 | 28 | @include media( '<=medium' ) { 29 | 30 | .hero { 31 | 32 | .split-wrap { 33 | 34 | .split-item { 35 | 36 | .split-item-content { 37 | margin-bottom: $hero--inner-padding-v_mobile; 38 | } 39 | } 40 | 41 | &.invert-mobile { 42 | 43 | .split-item { 44 | 45 | .split-item-image { 46 | margin-bottom: $hero--inner-padding-v_mobile; 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | 54 | @include media( '>medium' ) { 55 | 56 | .hero { 57 | 58 | .section-inner { 59 | padding-top: $hero--padding-t__desktop; 60 | padding-bottom: $hero--padding-b__desktop; 61 | } 62 | } 63 | 64 | .hero-inner { 65 | 66 | // Affects only hero full 67 | > .hero-content + .hero-figure, 68 | > .hero-figure + .hero-content { 69 | margin-top: $hero--inner-padding-v_desktop; 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_section.scss: -------------------------------------------------------------------------------- 1 | .section-inner { 2 | position: relative; // To always display inner elements above pseudo decorative stuff 3 | padding-top: $section--padding__mobile; 4 | padding-bottom: $section--padding__mobile; 5 | } 6 | 7 | .section-header { 8 | padding-bottom: $section-header--padding__mobile; 9 | } 10 | 11 | @include media( '>medium' ) { 12 | 13 | .section-inner { 14 | padding-top: $section--padding__desktop; 15 | padding-bottom: $section--padding__desktop; 16 | } 17 | 18 | .section-header { 19 | padding-bottom: $section-header--padding__desktop; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/scss/core/sections/_testimonial.scss: -------------------------------------------------------------------------------- 1 | .testimonial { 2 | 3 | .section-inner { 4 | padding-top: $testimonial--padding-t__mobile; 5 | padding-bottom: $testimonial--padding-b__mobile; 6 | } 7 | 8 | .section-header { 9 | padding-bottom: $testimonial-header--padding__mobile; 10 | } 11 | 12 | .tiles-wrap { 13 | @if ( $testimonial-items--padding__mobile != null ) { 14 | margin-right: -($testimonial-items--padding__mobile / 2); 15 | margin-left: -($testimonial-items--padding__mobile / 2); 16 | margin-top: -($testimonial-items--padding__mobile / 2); 17 | 18 | &:last-of-type { 19 | margin-bottom: -($testimonial-items--padding__mobile / 2); 20 | } 21 | 22 | &:not(:last-of-type) { 23 | margin-bottom: ($testimonial-items--padding__mobile / 2); 24 | } 25 | } 26 | 27 | &.push-left { 28 | 29 | &::after { 30 | flex-basis: $testimonial-item--width; 31 | max-width: $testimonial-item--width; 32 | @if ( $testimonial-items--padding__mobile != null ) { 33 | padding-left: $testimonial-items--padding__mobile / 2; 34 | padding-right: $testimonial-items--padding__mobile / 2; 35 | } 36 | } 37 | } 38 | } 39 | 40 | .tiles-item { 41 | flex-basis: $testimonial-item--width; 42 | max-width: $testimonial-item--width; 43 | @if ( $testimonial-items--padding__mobile != null ) { 44 | padding: $testimonial-items--padding__mobile / 2; 45 | } 46 | } 47 | 48 | .tiles-item-inner { 49 | padding-top: $testimonial-item--inner-padding-v; 50 | padding-bottom: $testimonial-item--inner-padding-v; 51 | padding-left: $testimonial-item--inner-padding-h; 52 | padding-right: $testimonial-item--inner-padding-h; 53 | } 54 | } 55 | 56 | .testimonial-item-content { 57 | flex-grow: 1; 58 | } 59 | 60 | .testimonial-item-source { 61 | display: inline-flex; // to allow centering when using .content-center on a parent tag 62 | flex-wrap: wrap; 63 | align-items: center; 64 | } 65 | 66 | @include media( '>medium' ) { 67 | 68 | .testimonial { 69 | 70 | .section-inner { 71 | padding-top: $testimonial--padding-t__desktop; 72 | padding-bottom: $testimonial--padding-b__desktop; 73 | } 74 | 75 | .section-header { 76 | padding-bottom: $testimonial-header--padding__desktop; 77 | } 78 | 79 | @if ( $testimonial-items--padding__desktop != null ) { 80 | 81 | .tiles-wrap { 82 | margin-right: -($testimonial-items--padding__desktop / 2); 83 | margin-left: -($testimonial-items--padding__desktop / 2); 84 | margin-top: -($testimonial-items--padding__desktop / 2); 85 | 86 | &:last-of-type { 87 | margin-bottom: -($testimonial-items--padding__desktop / 2); 88 | } 89 | 90 | &:not(:last-of-type) { 91 | margin-bottom: ($testimonial-items--padding__desktop / 2); 92 | } 93 | 94 | &.push-left { 95 | 96 | &::after { 97 | padding-left: $testimonial-items--padding__desktop / 2; 98 | padding-right: $testimonial-items--padding__desktop / 2; 99 | } 100 | } 101 | } 102 | 103 | .tiles-item { 104 | padding: $testimonial-items--padding__desktop / 2; 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/assets/scss/settings/_settings.scss: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------- 2 | # Scroll reveal 3 | --------------------------------------------------------------*/ 4 | @import "base/scroll-reveal"; 5 | 6 | /*-------------------------------------------------------------- 7 | # Colors 8 | --------------------------------------------------------------*/ 9 | @import "base/colors"; 10 | 11 | /*-------------------------------------------------------------- 12 | # Typography 13 | --------------------------------------------------------------*/ 14 | @import "base/typography"; 15 | 16 | /*-------------------------------------------------------------- 17 | # Widths and spacing 18 | --------------------------------------------------------------*/ 19 | @import "base/widths-and-spacing"; 20 | 21 | /*-------------------------------------------------------------- 22 | # Links 23 | --------------------------------------------------------------*/ 24 | @import "base/links"; 25 | 26 | /*-------------------------------------------------------------- 27 | # Other settings 28 | --------------------------------------------------------------*/ 29 | @import "base/misc"; 30 | 31 | /*-------------------------------------------------------------- 32 | # Buttons and forms 33 | --------------------------------------------------------------*/ 34 | @import "elements/buttons-and-forms"; 35 | 36 | /*-------------------------------------------------------------- 37 | # Buttons and forms 38 | --------------------------------------------------------------*/ 39 | @import "elements/buttons-and-forms"; 40 | 41 | /*-------------------------------------------------------------- 42 | # Modal 43 | --------------------------------------------------------------*/ 44 | @import "elements/modal"; 45 | 46 | /*-------------------------------------------------------------- 47 | # Split pattern 48 | --------------------------------------------------------------*/ 49 | @import "patterns/split"; 50 | 51 | /*-------------------------------------------------------------- 52 | # Tiles pattern 53 | --------------------------------------------------------------*/ 54 | @import "patterns/tiles"; 55 | 56 | /*-------------------------------------------------------------- 57 | # Header 58 | --------------------------------------------------------------*/ 59 | @import "layout/header"; 60 | 61 | /*-------------------------------------------------------------- 62 | # Footer 63 | --------------------------------------------------------------*/ 64 | @import "layout/footer"; 65 | 66 | /*-------------------------------------------------------------- 67 | # Hero 68 | --------------------------------------------------------------*/ 69 | @import "sections/hero"; 70 | 71 | /*-------------------------------------------------------------- 72 | # Features split 73 | --------------------------------------------------------------*/ 74 | @import "sections/features-split"; 75 | 76 | /*-------------------------------------------------------------- 77 | # Features tiles 78 | --------------------------------------------------------------*/ 79 | @import "sections/features-tiles"; 80 | 81 | /*-------------------------------------------------------------- 82 | # Testimonial 83 | --------------------------------------------------------------*/ 84 | @import "sections/testimonial"; 85 | 86 | /*-------------------------------------------------------------- 87 | # Call to action 88 | --------------------------------------------------------------*/ 89 | @import "sections/cta"; 90 | -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_colors.scss: -------------------------------------------------------------------------------- 1 | // Colors 2 | 3 | // The color palette 4 | $palette: ( 5 | light: ( 6 | 1: #ECEDED, 7 | 2: #9CA9B3, 8 | 3: #717D86 9 | ), 10 | dark: ( 11 | 1: #151719, 12 | 2: #25282C, 13 | 3: #33363A 14 | ), 15 | primary: ( 16 | 1: #6163FF, 17 | 2: #ACADFF, 18 | 3: #5658DD, 19 | 4: #E9E9FF 20 | ), 21 | secondary: ( 22 | 1: #24E5AF, 23 | 2: #73EFCC, 24 | 3: #1CB68B, 25 | 4: #D2F9EE 26 | ), 27 | alert: ( 28 | error: #FF6171, 29 | warning: #FFA173, 30 | success: #24E5AF 31 | ) 32 | ); 33 | 34 | // Base typography: color 35 | $color: ( 36 | heading: get-color(light, 1), 37 | base: get-color(light, 2), 38 | high-contrast: get-color(light, 1), 39 | mid-contrast: get-color(light, 2), 40 | low-contrast: get-color(light, 3), 41 | primary: get-color(primary, 3), 42 | secondary: get-color(secondary, 1), 43 | error: get-color(alert, error), 44 | warning: get-color(alert, warning), 45 | success: get-color(alert, success), 46 | // ↓ Inverted colors 47 | heading-inverse: get-color(dark, 1), 48 | base-inverse: get-color(light, 3), 49 | high-contrast-inverse: get-color(dark, 1), 50 | mid-contrast-inverse: get-color(dark, 2), 51 | low-contrast-inverse: get-color(light, 3) 52 | ); 53 | 54 | // Borders and dividers: color 55 | $border--color: ( 56 | divider: get-color(dark, 2), 57 | divider-inverse: get-color(light, 1) 58 | ); 59 | 60 | // Icons: fill color 61 | $icon--color: ( 62 | hamburger: get-color(light, 2), // hamburger icon 63 | accordion: get-color(primary, 1), // accordion icon 64 | social: get-color(primary, 1), // social icons 65 | social-hover: get-color(primary, 2), // social icons (:hover) 66 | modal: get-color(light, 3), // modal icon 67 | modal-hover: get-color(light, 2), // modal icon (:hover) 68 | news-more: get-color(primary, 2), // news - read more link arrow 69 | // ↓ Inverted colors 70 | hamburger-inverse: get-color(dark, 2), // hamburger icon 71 | accordion-inverse: get-color(primary, 1), // accordion icon 72 | social-inverse: null, // social icons 73 | social-hover-inverse: null // social icons (:hover) 74 | ); 75 | 76 | // Misc elements: background color 77 | $bg--color: ( 78 | body: get-color(dark, 1), 79 | body-shadow: 0 20px 48px rgba(get-color(dark, 1), .8), // body shadow when a boxed layout is used (set to null if don't want a shadow) 80 | body-outer: lighten(get-color(dark, 1), 2%), // outer bg color when a boxed layout is used 81 | bg-color: lighten(get-color(light, 1), 9%), // .has-bg-color helper class 82 | shadow: 0 24px 64px rgba(get-color(dark, 1), .64), // .has-shadow helper class 83 | code: darken(get-color(dark, 1), 3%), 84 | code-inverse: darken(get-color(dark, 1), 3%) 85 | ); 86 | -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_links.scss: -------------------------------------------------------------------------------- 1 | // Links 2 | 3 | // Color 4 | $link--color: ( 5 | link: get-color(light, 1), 6 | link-hover: null, 7 | header-link: get-color(light, 2), 8 | header-link-hover: get-color(light, 1), 9 | header-link-mobile: get-color(light, 1), 10 | header-link-mobile-hover: null, 11 | footer-link: get-color(light, 2), 12 | footer-link-hover: get-color(light, 1), 13 | footer-block-link: get-color(light, 2), 14 | footer-block-link-hover: get-color(light, 1), 15 | button-link: get-color(light, 2), 16 | button-link-hover: get-color(light, 1), 17 | func-link: null, 18 | func-link-hover: null, 19 | // ↓ Inverted colors 20 | link-inverse: get-color(light, 3), 21 | link-hover-inverse: null, 22 | header-link-inverse: get-color(dark, 3), 23 | header-link-hover-inverse: get-color(primary, 1), 24 | footer-link-inverse: null, 25 | footer-link-hover-inverse: null, 26 | footer-block-link-inverse: null, 27 | footer-block-link-hover-inverse: null, 28 | button-link-inverse: null, 29 | button-link-hover-inverse: get-color(primary, 1), 30 | func-link-inverse: null, 31 | func-link-hover-inverse: get-color(primary, 1) 32 | ); 33 | 34 | // Font-weight 35 | $link--weight: ( 36 | link: null, 37 | header-link: 500, 38 | footer-link: null, 39 | footer-block-link: null, 40 | button-link: null 41 | ); 42 | 43 | // Text decoration 44 | $link-main--decoration: none; 45 | $link-main--decoration-hover: null; 46 | $link-header--decoration: null; 47 | $link-header--decoration-hover: null; 48 | $link-footer--decoration: null; 49 | $link-footer--decoration-hover: null; 50 | $link-footer-block--decoration: null; 51 | $link-footer-block--decoration-hover: null; 52 | $link-button--decoration: null; 53 | $link-button--decoration-hover: null; 54 | $link-func--decoration: null; 55 | $link-func--decoration-hover: null; 56 | 57 | // Text transform 58 | $link-header--transform: null; 59 | $link-footer--transform: null; 60 | $link-footer-block--transform: null; 61 | $link-button--transform: null; 62 | $link-func--transform: null; 63 | 64 | // Don't change lines below! 65 | $color: map-push($color, $link--color); 66 | $font--weight: map-push($font--weight, $link--weight); -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_misc.scss: -------------------------------------------------------------------------------- 1 | // Larger images, extra width 2 | $image-larger--extra-width: 48px; // left and right exceeding pixels (.image-larger) 3 | 4 | // img radius 5 | $img-radius: 2px; 6 | -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_scroll-reveal.scss: -------------------------------------------------------------------------------- 1 | $scroll-reveal--transition-duration: 0.8s; 2 | $scroll-reveal--transition-timing: cubic-bezier(0.39, 0.575, 0.565, 1); 3 | $scroll-reveal--from-top-amount: -10px; 4 | $scroll-reveal--from-bottom-amount: 10px; 5 | $scroll-reveal--from-left-amount: -10px; 6 | $scroll-reveal--from-right-amount: 10px; 7 | $scroll-reveal--scale-up-amount: 0.95; 8 | $scroll-reveal--scale-down-amount: 1.05; 9 | $scroll-reveal--rotate-from-left-amount: -45deg; 10 | $scroll-reveal--rotate-from-right-amount: 45deg; 11 | -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_typography.scss: -------------------------------------------------------------------------------- 1 | // Typography 2 | 3 | $font--provider: 'Google Fonts'; 4 | $font--import: 'Inter:400,500,600,700,800'; 5 | 6 | // The font set 7 | $font--family: ( 8 | heading: null, 9 | base: '"Inter", sans-serif', 10 | code: 'Monaco, Consolas, "Andale Mono", "DejaVu Sans Mono", monospace', 11 | pre: '"Courier 10 Pitch", Courier, monospace' 12 | ); 13 | 14 | // The typographic scale 15 | $font--scale: ( 16 | // key // font-size, line-height, kerning 17 | alpha: ( 52px, 62px, -0.3px ), 18 | beta: ( 44px, 54px, -0.3px ), 19 | gamma: ( 32px, 42px, -0.3px ), 20 | delta: ( 24px, 34px, -0.1px ), 21 | epsilon: ( 20px, 30px, -0.1px ), 22 | zeta: ( 18px, 28px, -0.1px ), 23 | eta: ( 16px, 24px, -0.1px ), 24 | theta: ( 14px, 22px, null ) 25 | ); 26 | 27 | // Base elements: font size 28 | $font--size: ( 29 | // ↓ Mobile // key in $font--scale 30 | h1: 'beta', 31 | h2: 'gamma', 32 | h3: 'delta', 33 | h4: 'delta', 34 | base: 'epsilon', 35 | sm: 'zeta', 36 | xs: 'eta', 37 | xxs: 'theta', 38 | bquote: 'epsilon', 39 | figcap: 'theta', 40 | code: 'eta', 41 | pre: 'eta', 42 | table: 'eta', 43 | // ↓ Desktop (set to null if font size won't change on desktop) 44 | h1-desktop: 'alpha', 45 | h2-desktop: 'beta', 46 | h3-desktop: 'gamma', 47 | h4-desktop: null, 48 | base-desktop: null, 49 | sm-desktop: null, 50 | xs-desktop: null, 51 | xxs-desktop: null, 52 | bquote-desktop: null, 53 | figcap-desktop: null, 54 | code-desktop: null, 55 | pre-desktop: null, 56 | table-desktop: null 57 | ); 58 | 59 | // Base elements: font weight 60 | $font--weight: ( 61 | heading: 800, 62 | base: 400, 63 | strong: 700, 64 | bquote: 600, 65 | figcap: null, 66 | ); 67 | -------------------------------------------------------------------------------- /src/assets/scss/settings/base/_widths-and-spacing.scss: -------------------------------------------------------------------------------- 1 | // Widths and spacing 2 | 3 | // Breakpoints 4 | $breakpoints: ( 5 | small: 480px, 6 | medium: 640px, 7 | large: 820px 8 | ); 9 | 10 | // Containers widths 11 | $container--width-boxed: 1440px; // boxed container width 12 | $container--width: 1080px; // container width 13 | $container--width-sm: 896px; // container sm width 14 | $container--width-xs: 620px; // container xs width 15 | $container--padding__mobile: 16px; // container, left and right padding (mobile) 16 | $container--padding__desktop: 24px; // container, left and right padding (desktop) 17 | 18 | // Global spacing 19 | $spacing--shared-v: 24px; // used on many different elements (e.g. hr, ul, ol and more) 20 | $spacing--shared-h: 24px; 21 | $spacing--h1-t: 48px; 22 | $spacing--h1-b: 32px; 23 | $spacing--h2-t: 48px; 24 | $spacing--h2-b: 32px; 25 | $spacing--h3-t: 36px; 26 | $spacing--h3-b: 24px; 27 | $spacing--hx-t: 24px; 28 | $spacing--hx-b: 24px; 29 | $spacing--figure-v: 48px; 30 | $spacing--figure-h: 0; 31 | $spacing--figcaption-v: 8px; 32 | $spacing--figcaption-h: 0; 33 | $spacing--table-cell-v: 8px; 34 | $spacing--table-cell-h: 16px; 35 | $spacing--code-v: 2px; 36 | $spacing--code-h: 4px; 37 | 38 | // Sections spacing 39 | $section--padding__mobile: 48px; // section, top and bottom padding (mobile) 40 | $section--padding__desktop: 80px; // section, top and bottom padding (desktop) 41 | $section-header--padding__mobile: 48px; // section header, bottom padding (mobile) 42 | $section-header--padding__desktop: 80px; // section header, bottom padding (desktop) 43 | -------------------------------------------------------------------------------- /src/assets/scss/settings/elements/_buttons-and-forms.scss: -------------------------------------------------------------------------------- 1 | // Buttons and Forms (shared settings) 2 | $button-form--height: 48px; // height of buttons and forms 3 | $button-form-sm--height: 36px; // height of buttons and forms (small) 4 | $button-form--border-width: 1px; // border width (if you wish not to display any border, just set colors to null instead of changing this value) 5 | $button-form--border-style: solid; // border style 6 | $button-form--group-padding: 12px; // padding separating input from button in a form group (.form-group). Prefer null over 0 7 | 8 | // Buttons: text color 9 | $button--color: ( 10 | button-light: get-color(dark, 2), 11 | button-dark: get-color(light, 1), 12 | button-primary: get-color(light, 1), 13 | button-secondary: get-color(light, 1), 14 | button-disabled: get-color(dark, 3) 15 | ); 16 | 17 | // Buttons: background color 18 | $button--bg: ( 19 | button-light: get-color(light, 1), 20 | button-light-hover: darken(get-color(light, 1), 5%), 21 | button-dark: get-color(dark, 2), 22 | button-dark-hover: lighten(get-color(dark, 2), 2%), 23 | button-primary: get-color(primary, 1), 24 | button-primary-hover: lighten(get-color(primary, 1), 2%), 25 | button-secondary: get-color(secondary, 1), 26 | button-secondary-hover: lighten(get-color(secondary, 1), 2%), 27 | button-disabled: get-color(light, 3) 28 | ); 29 | 30 | // Buttons: border color 31 | $button--border: ( 32 | button-light: transparent, // button-light is default (.button), so if it's transparent you can set all other values to null 33 | button-light-hover: null, 34 | button-dark: null, 35 | button-dark-hover: null, 36 | button-primary: null, 37 | button-primary-hover: null, 38 | button-secondary: null, 39 | button-secondary-hover: null, 40 | button-disabled: null 41 | ); 42 | 43 | // Buttons: font size 44 | $button--size: ( 45 | button: 'eta' 46 | ); 47 | 48 | // Buttons: font weight 49 | $button--weight: ( 50 | button: 600 51 | ); 52 | 53 | // More buttons settings 54 | $button--padding-h: 32px; // button, left and right padding 55 | $button-sm--padding-h: 24px; // button (small), left and right padding 56 | $button-w-form--padding-h: 24px; // button, left and right padding in a form group (.form-group) - Overrides button default padding 57 | $button-sm-w-form--padding-h: null; // button (small), left and right padding in a form group (.form-group) - Overrides button default padding 58 | $button--radius: 2px; // button radius (never use null) 59 | $button--transform: null; // button text-transform property (null is allowed) 60 | $button--max-size-mobile: 280px; // button max width on mobile (.button-wide-mobile) 61 | $button-group-padding: 16px; // padding between sibling buttons (nested into .button-group) 62 | $button-loading--thickness: 2px; // button loading spinner, stroke width (.button.is-loading) 63 | 64 | // Forms: color 65 | $form--color: ( 66 | input: get-color(dark, 1), 67 | input-placeholder: get-color(light, 2), 68 | label: get-color(light, 3), 69 | check-radio: get-color(light, 2), 70 | // ↓ Inverted colors 71 | input-inverse: get-color(dark, 3), 72 | input-placeholder-inverse: null, 73 | label-inverse: get-color(dark, 3), 74 | check-radio-inverse: get-color(dark, 3) 75 | ); 76 | 77 | // Forms: background color 78 | $form--bg: ( 79 | input: get-color(light, 1), 80 | input-focus: null, 81 | input-disabled: get-color(dark, 3), 82 | check-radio-checked: get-color(primary, 1), 83 | switch: get-color(dark, 3), 84 | switch-checked: get-color(primary, 1), 85 | range-track: get-color(light, 2), 86 | range-thumb: get-color(primary, 1), 87 | // ↓ Inverted colors 88 | input-inverse: null, 89 | input-focus-inverse: null, 90 | input-disabled-inverse: darken(get-color(light, 1), 4%), 91 | check-radio-checked-inverse: null, 92 | switch-inverse: null, 93 | switch-checked-inverse: null, 94 | range-track-inverse: null, 95 | range-thumb-inverse: null 96 | ); 97 | 98 | // Forms: border color 99 | $form--border: ( 100 | input: get-color(dark, 1), 101 | input-hover: get-color(light, 3), 102 | input-focus: get-color(primary, 1), 103 | input-disabled: get-color(dark, 2), 104 | // ↓ Inverted colors 105 | input-inverse: darken(get-color(light, 1), 4%), 106 | input-hover-inverse: null, 107 | input-focus-inverse: get-color(primary, 1), 108 | input-disabled-inverse: null 109 | ); 110 | 111 | // Forms: background color 112 | $form--icon: ( 113 | select-arrow: get-color(light, 1), 114 | range: get-color(light, 1), 115 | // ↓ Inverted colors 116 | select-arrow-inverse: get-color(dark, 3), 117 | range-inverse: get-color(light, 1) 118 | ); 119 | 120 | // Forms: font size 121 | $form--size: ( 122 | input: 'eta', 123 | label: 'theta', 124 | check-radio: 'eta', 125 | hint: 'theta' 126 | ); 127 | 128 | // Forms: font weight 129 | $form--weight: ( 130 | input: null, 131 | label: 500, 132 | check-radio: null 133 | ); 134 | 135 | // More forms settings 136 | $form--padding-h: 16px; // form, inner left and right padding 137 | $form-sm--padding-h: 12px; // form (small), inner left and right padding 138 | $form--radius: 0; // form radius (never use null) 139 | $form-hint--margin: 8px; // .form-hint top margin 140 | $range-thumb-size: 36px; // .form-slider, thumb size 141 | 142 | // Don't change lines below! 143 | // Push $button--* and $form--* values 144 | $color: map-push($color, $button--color); 145 | $color: map-push($color, $form--color); 146 | $bg--color: map-push($bg--color, $button--bg); 147 | $bg--color: map-push($bg--color, $form--bg); 148 | $border--color: map-push($border--color, $button--border); 149 | $border--color: map-push($border--color, $form--border); 150 | $icon--color: map-push($icon--color, $form--icon); 151 | $font--size: map-push($font--size, $button--size); 152 | $font--size: map-push($font--size, $form--size); 153 | $font--weight: map-push($font--weight, $button--weight); 154 | $font--weight: map-push($font--weight, $form--weight); 155 | -------------------------------------------------------------------------------- /src/assets/scss/settings/elements/_modal.scss: -------------------------------------------------------------------------------- 1 | // Modal (core/elements/_modal.scss) 2 | 3 | // Background color 4 | $modal--bg: ( 5 | modal: get-color(dark, 2), 6 | modal-outer: rgba(get-color(dark, 1), .88) 7 | ); 8 | 9 | // More modal settings 10 | $modal--min-width: null; // modal min-width 11 | $modal--max-width: 520px; // modal max-width 12 | $modal-video--max-width: 1024px; // modal video max-width 13 | $modal--outer-padding-v__mobile: 16px; // modal, outer top and bottom padding (mobile) 14 | $modal--outer-padding-v__desktop: 48px; // modal, outer top and bottom padding (desktop) 15 | $modal--inner-padding-v__mobile: 48px; // modal, inner top and bottom padding (mobile) 16 | $modal--inner-padding-h__mobile: 16px; // modal, inner left and right padding (mobile) 17 | $modal--inner-padding-v__desktop: 64px; // modal, inner top and bottom padding (desktop) 18 | $modal--inner-padding-h__desktop: 32px; // modal, inner left and right padding (desktop) 19 | $modal-close-icon--size: 16px; // modal close icon, width and height 20 | $modal-close-icon--thickness: 2px; // modal close icon, stroke width 21 | $modal-close-icon--radius: null; // modal close icon, lines radius cap 22 | $modal-close-position: 16px; // icon distance from the top right of the modal 23 | 24 | // Don't change line below! 25 | $bg--color: map-push($bg--color, $modal--bg); 26 | -------------------------------------------------------------------------------- /src/assets/scss/settings/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | // Footer (core/layout/_footer.scss) 2 | 3 | // Color 4 | $footer--color: ( 5 | block-title: get-color(light, 1), 6 | block-title-inverse: get-color(dark, 1) 7 | ); 8 | 9 | // Background color 10 | $footer--bg: ( 11 | footer: get-color(dark, 1) 12 | ); 13 | 14 | // Font size 15 | $footer--size: ( 16 | block-title: 'theta' 17 | ); 18 | 19 | // Font weight 20 | $footer--weight: ( 21 | block-title: 700 22 | ); 23 | 24 | // More footer settings 25 | $footer--padding__mobile: 48px; // footer, top and bottom padding (mobile) 26 | $footer--padding__desktop: 64px; // footer, top and bottom padding (desktop) 27 | $footer-inner--padding-v: 24px; // padding between top and bottom footer 28 | $footer-social--outer-padding-h: 8px; // social links, outer padding (useful when icon has a background) 29 | $footer-social--inner-padding: 8px; // social links, inner padding 30 | $footer-nav--padding-h: 12px; // padding between footer nav links 31 | 32 | // Footer blocks 33 | $footer-blocks--padding: 40px; // footer block, bottom padding 34 | $footer-block--padding_v: 24px; // top and bottom padding between footer blocks 35 | $footer-block--padding_h: 48px; // left and right padding between footer blocks 36 | $footer-block--min-width: 160px; // footer block, minimum width 37 | $footer-block-title--transform: uppercase; // footer block title text-transform property (null is allowed) 38 | $footer-block-title-padding: 8px; // footer block title, bottom padding 39 | $footer-block-list-padding: 4px; // spacing beetwen block lists 40 | 41 | // Don't change line below! 42 | $color: map-push($color, $footer--color); 43 | $bg--color: map-push($bg--color, $footer--bg); 44 | $font--size: map-push($font--size, $footer--size); 45 | $font--weight: map-push($font--weight, $footer--weight); 46 | -------------------------------------------------------------------------------- /src/assets/scss/settings/layout/_header.scss: -------------------------------------------------------------------------------- 1 | // Header (core/layout/_header.scss) 2 | 3 | // Background color 4 | $header--bg: ( 5 | header: null, 6 | menu-mobile: darken(get-color(dark, 1), 3%) 7 | ); 8 | 9 | // More header settings 10 | $header-height__mobile: 80px; // header height (mobile) 11 | $header-height__desktop: null; // header height (desktop) 12 | $header-nav--padding-h: 32px; // horizontal padding between header links (desktop) 13 | $header-nav--padding-v__mobile: 24px; // vertical padding between header links (mobile) 14 | $header-hamburger--size: 24px; // hamburger button, width and height 15 | $header-hamburger--thickness: 2px; // hamburger button, stroke width 16 | $header-hamburger--radius: null; // hamburger button, lines radius cap 17 | $header-hamburger--distance: 7px; // hamburger button, top and bottom lines distance from center 18 | 19 | // Don't change line below! 20 | $bg--color: map-push($bg--color, $header--bg); 21 | -------------------------------------------------------------------------------- /src/assets/scss/settings/patterns/_split.scss: -------------------------------------------------------------------------------- 1 | // Split (core/patterns/_split.scss) 2 | $split-item--padding-v__mobile: 48px; // split item, top and bottom padding (mobile) 3 | $split-item--padding-v__desktop: 80px; // split item, top and bottom padding (desktop) 4 | $split-item-content--padding-h: 52px; // padding distanciating content from the middle of container (desktop) 5 | $split-item-image--padding-h: 12px; // padding distanciating image from the middle of container (desktop) 6 | $split-item--inner-padding-h: $split-item-content--padding-h + $split-item-image--padding-h; // horizontal padding sum, i.e. padding between content and image (desktop) 7 | $split-item--inner-padding-v_mobile: 32px; // vertical padding, i.e. padding between content and image (mobile) 8 | -------------------------------------------------------------------------------- /src/assets/scss/settings/patterns/_tiles.scss: -------------------------------------------------------------------------------- 1 | // Tiles (core/patterns/_tiles.scss) 2 | $tiles-items--padding__mobile: 24px; // padding between tiles (mobile) 3 | $tiles-items--padding__desktop: null; // padding between tiles (desktop) 4 | $tiles-item--width: 330px; // tile item, width 5 | $tiles-item--inner-padding-v: 32px; // tile item, inner top and bottom padding 6 | $tiles-item--inner-padding-h: 24px; // tile item, inner left and right padding 7 | -------------------------------------------------------------------------------- /src/assets/scss/settings/sections/_cta.scss: -------------------------------------------------------------------------------- 1 | // Call to action (core/sections/_cta.scss) 2 | $cta--padding-t__mobile: 48px; // cta, top padding (mobile) 3 | $cta--padding-b__mobile: 48px; // cta, bottom padding (mobile) 4 | $cta--padding-t__desktop: 64px; // cta, top padding (desktop) 5 | $cta--padding-b__desktop: 64px; // cta, bottom padding (desktop) 6 | $cta-slogan--padding-v__mobile: 40px; // cta slogan, margin bottom (mobile) 7 | $cta-slogan--padding-v__desktop: null; // cta slogan, margin bottom (desktop) 8 | $cta-slogan--padding-h__desktop: 48px; // cta slogan, minimum distance between slogan and actions (only .cta-split desktop) 9 | -------------------------------------------------------------------------------- /src/assets/scss/settings/sections/_features-split.scss: -------------------------------------------------------------------------------- 1 | // Features split (core/sections/_features-split.scss) --------- 2 | $features-split--padding-t__mobile: null; // features split, top padding (mobile) 3 | $features-split--padding-b__mobile: null; // features split, bottom padding (mobile) 4 | $features-split--padding-t__desktop: null; // features split, top padding (desktop) 5 | $features-split--padding-b__desktop: null; // features split, bottom padding (desktop) 6 | $features-split-header--padding__mobile: null; // features split header, bottom padding (mobile) 7 | $features-split-header--padding__desktop: 92px; // features split header, bottom padding (desktop) 8 | -------------------------------------------------------------------------------- /src/assets/scss/settings/sections/_features-tiles.scss: -------------------------------------------------------------------------------- 1 | // Features tiles (core/sections/_features-tiles.scss) --------- 2 | $features-tiles--padding-t__mobile: null; // features tiles, top padding (mobile) 3 | $features-tiles--padding-b__mobile: null; // features tiles, bottom padding (mobile) 4 | $features-tiles--padding-t__desktop: null; // features tiles, top padding (desktop) 5 | $features-tiles--padding-b__desktop: null; // features tiles, bottom padding (desktop) 6 | $features-tiles-header--padding__mobile: null; // features tiles header, bottom padding (mobile) 7 | $features-tiles-header--padding__desktop: null; // features tiles header, bottom padding (desktop) 8 | $features-tiles-items--padding__mobile: 32px; // padding between features tiles (mobile) 9 | $features-tiles-items--padding__desktop: 64px; // padding between features tiles (desktop) 10 | $features-tiles-item--width: 317px; // features tiles item, width 11 | $features-tiles-item--inner-padding-v: 0; // features tiles item, inner top and bottom padding (it inherits $tiles-item--inner-padding-v unless you replace null with a new value) 12 | $features-tiles-item--inner-padding-h: 0; // features tiles item, inner left and right padding (it inherits $tiles-item--inner-padding-h unless you replace null with a new value) 13 | -------------------------------------------------------------------------------- /src/assets/scss/settings/sections/_hero.scss: -------------------------------------------------------------------------------- 1 | // Hero (core/sections/_hero.scss) ----------------------------- 2 | $hero--padding-t__mobile: null; // hero, top padding (mobile) 3 | $hero--padding-b__mobile: null; // hero, bottom padding (mobile) 4 | $hero--padding-t__desktop: null; // hero, top padding (desktop) 5 | $hero--padding-b__desktop: null; // hero, bottom padding (desktop) 6 | $hero--inner-padding-v_mobile: 48px; // vertical padding, i.e. padding between content and image (mobile, both hero split and hero full) 7 | $hero--inner-padding-v_desktop: 64px; // vertical padding, i.e. padding between content and image (desktop, only hero full) 8 | -------------------------------------------------------------------------------- /src/assets/scss/settings/sections/_testimonial.scss: -------------------------------------------------------------------------------- 1 | // Testimonial (core/sections/_testimonial.scss) --------------- 2 | $testimonial--padding-t__mobile: null; // testimonial, top padding (mobile) 3 | $testimonial--padding-b__mobile: null; // testimonial, bottom padding (mobile) 4 | $testimonial--padding-t__desktop: null; // testimonial, top padding (desktop) 5 | $testimonial--padding-b__desktop: null; // testimonial, bottom padding (desktop) 6 | $testimonial-header--padding__mobile: null; // testimonial header, bottom padding (mobile) 7 | $testimonial-header--padding__desktop: null; // testimonial header, bottom padding (desktop) 8 | $testimonial-items--padding__mobile: null; // padding between testimonial items (mobile) 9 | $testimonial-items--padding__desktop: null; // padding between testimonial items (desktop) 10 | $testimonial-item--width: 344px; // testimonial item, width 11 | $testimonial-item--inner-padding-v: 24px; // testimonial item, inner top and bottom padding (it inherits $tiles-item--inner-padding-v unless you replace null with a new value) 12 | $testimonial-item--inner-padding-h: 32px; // testimonial item, inner left and right padding (it inherits $tiles-item--inner-padding-h unless you replace null with a new value) 13 | -------------------------------------------------------------------------------- /src/assets/scss/style.scss: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------- 2 | # Based on Cruip framework - v1.0.0 3 | --------------------------------------------------------------*/ 4 | 5 | /*-------------------------------------------------------------- 6 | # Variables, functions and mixins 7 | --------------------------------------------------------------*/ 8 | @import "core/abstracts/functions", 9 | "settings/settings", 10 | "core/abstracts/mixins", 11 | 'core/abstracts/include-media'; 12 | 13 | /*-------------------------------------------------------------- 14 | # Normalize 15 | * normalize.css v7.0.0 | MIT License 16 | * github.com/necolas/normalize.css 17 | --------------------------------------------------------------*/ 18 | @import "core/normalize"; 19 | 20 | /*-------------------------------------------------------------- 21 | # Fonts 22 | --------------------------------------------------------------*/ 23 | @import "core/base/fonts"; 24 | 25 | /*-------------------------------------------------------------- 26 | # Scroll reveal 27 | --------------------------------------------------------------*/ 28 | @import "core/base/scroll-reveal"; 29 | 30 | /*-------------------------------------------------------------- 31 | # Base 32 | --------------------------------------------------------------*/ 33 | @import "core/base/base"; 34 | 35 | /*-------------------------------------------------------------- 36 | # Typography 37 | --------------------------------------------------------------*/ 38 | @import "core/base/typography"; 39 | 40 | /*-------------------------------------------------------------- 41 | # Containers 42 | --------------------------------------------------------------*/ 43 | @import "core/elements/containers"; 44 | 45 | /*-------------------------------------------------------------- 46 | # Buttons 47 | --------------------------------------------------------------*/ 48 | @import "core/elements/buttons"; 49 | 50 | /*-------------------------------------------------------------- 51 | # Forms 52 | --------------------------------------------------------------*/ 53 | @import "core/elements/forms"; 54 | 55 | /*-------------------------------------------------------------- 56 | # Hamburger 57 | --------------------------------------------------------------*/ 58 | @import "core/elements/hamburger"; 59 | 60 | /*-------------------------------------------------------------- 61 | # Modal 62 | --------------------------------------------------------------*/ 63 | @import "core/elements/modal"; 64 | 65 | /*-------------------------------------------------------------- 66 | # Split pattern 67 | --------------------------------------------------------------*/ 68 | @import "core/patterns/split"; 69 | 70 | /*-------------------------------------------------------------- 71 | # Tiles pattern 72 | --------------------------------------------------------------*/ 73 | @import "core/patterns/tiles"; 74 | 75 | /*-------------------------------------------------------------- 76 | # Header 77 | --------------------------------------------------------------*/ 78 | @import "core/layout/header"; 79 | 80 | /*-------------------------------------------------------------- 81 | # Site content 82 | --------------------------------------------------------------*/ 83 | @import "core/layout/main"; 84 | 85 | /*-------------------------------------------------------------- 86 | # Footer 87 | --------------------------------------------------------------*/ 88 | @import "core/layout/footer"; 89 | 90 | /*-------------------------------------------------------------- 91 | # Section 92 | --------------------------------------------------------------*/ 93 | @import "core/sections/section"; 94 | 95 | /*-------------------------------------------------------------- 96 | # Hero 97 | --------------------------------------------------------------*/ 98 | @import "core/sections/hero"; 99 | 100 | /*-------------------------------------------------------------- 101 | # Features split 102 | --------------------------------------------------------------*/ 103 | @import "core/sections/features-split"; 104 | 105 | /*-------------------------------------------------------------- 106 | # Features tiles 107 | --------------------------------------------------------------*/ 108 | @import "core/sections/features-tiles"; 109 | 110 | /*-------------------------------------------------------------- 111 | # Testimonial 112 | --------------------------------------------------------------*/ 113 | @import "core/sections/testimonial"; 114 | 115 | /*-------------------------------------------------------------- 116 | # Call to action 117 | --------------------------------------------------------------*/ 118 | @import "core/sections/cta"; 119 | 120 | /*-------------------------------------------------------------- 121 | # Theme 122 | --------------------------------------------------------------*/ 123 | @import "theme/theme"; 124 | 125 | /*-------------------------------------------------------------- 126 | # Helpers 127 | --------------------------------------------------------------*/ 128 | @import "core/base/helpers"; 129 | -------------------------------------------------------------------------------- /src/assets/scss/theme/_theme.scss: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------- 2 | # Illustrations 3 | --------------------------------------------------------------*/ 4 | @import "illustrations/illustrations"; 5 | 6 | /*-------------------------------------------------------------- 7 | # Fonts 8 | --------------------------------------------------------------*/ 9 | @import "base/fonts"; 10 | 11 | /*-------------------------------------------------------------- 12 | # Scroll reveal 13 | --------------------------------------------------------------*/ 14 | @import "base/scroll-reveal"; 15 | 16 | /*-------------------------------------------------------------- 17 | # Base 18 | --------------------------------------------------------------*/ 19 | @import "base/base"; 20 | 21 | /*-------------------------------------------------------------- 22 | # Typography 23 | --------------------------------------------------------------*/ 24 | @import "base/typography"; 25 | 26 | /*-------------------------------------------------------------- 27 | # Containers 28 | --------------------------------------------------------------*/ 29 | @import "elements/containers"; 30 | 31 | /*-------------------------------------------------------------- 32 | # Buttons 33 | --------------------------------------------------------------*/ 34 | @import "elements/buttons"; 35 | 36 | /*-------------------------------------------------------------- 37 | # Forms 38 | --------------------------------------------------------------*/ 39 | @import "elements/forms"; 40 | 41 | /*-------------------------------------------------------------- 42 | # Hamburger 43 | --------------------------------------------------------------*/ 44 | @import "elements/hamburger"; 45 | 46 | /*-------------------------------------------------------------- 47 | # Modal 48 | --------------------------------------------------------------*/ 49 | @import "elements/modal"; 50 | 51 | /*-------------------------------------------------------------- 52 | # Split pattern 53 | --------------------------------------------------------------*/ 54 | @import "patterns/split"; 55 | 56 | /*-------------------------------------------------------------- 57 | # Tiles pattern 58 | --------------------------------------------------------------*/ 59 | @import "patterns/tiles"; 60 | 61 | /*-------------------------------------------------------------- 62 | # Header 63 | --------------------------------------------------------------*/ 64 | @import "layout/header"; 65 | 66 | /*-------------------------------------------------------------- 67 | # Site content 68 | --------------------------------------------------------------*/ 69 | @import "layout/main"; 70 | 71 | /*-------------------------------------------------------------- 72 | # Footer 73 | --------------------------------------------------------------*/ 74 | @import "layout/footer"; 75 | 76 | /*-------------------------------------------------------------- 77 | # Section 78 | --------------------------------------------------------------*/ 79 | @import "sections/section"; 80 | 81 | /*-------------------------------------------------------------- 82 | # Hero 83 | --------------------------------------------------------------*/ 84 | @import "sections/hero"; 85 | 86 | /*-------------------------------------------------------------- 87 | # Features split 88 | --------------------------------------------------------------*/ 89 | @import "sections/features-split"; 90 | 91 | /*-------------------------------------------------------------- 92 | # Features tiles 93 | --------------------------------------------------------------*/ 94 | @import "sections/features-tiles"; 95 | 96 | /*-------------------------------------------------------------- 97 | # Testimonial 98 | --------------------------------------------------------------*/ 99 | @import "sections/testimonial"; 100 | 101 | /*-------------------------------------------------------------- 102 | # Call to action 103 | --------------------------------------------------------------*/ 104 | @import "sections/cta"; 105 | -------------------------------------------------------------------------------- /src/assets/scss/theme/base/_base.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/base/_base.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/base/_fonts.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/base/_fonts.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/base/_scroll-reveal.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/base/_scroll-reveal.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/base/_typography.scss: -------------------------------------------------------------------------------- 1 | h3, h4, h5, h6, 2 | .h3, .h4, .h5, .h6 { 3 | font-weight: 700; 4 | } -------------------------------------------------------------------------------- /src/assets/scss/theme/elements/_buttons.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/elements/_buttons.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/elements/_containers.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/elements/_containers.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/elements/_forms.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/elements/_forms.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/elements/_hamburger.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/elements/_hamburger.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/elements/_modal.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/elements/_modal.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/illustrations/_illustrations.scss: -------------------------------------------------------------------------------- 1 | [class*=illustration-] { 2 | position: relative; 3 | 4 | &::after { 5 | pointer-events: none; 6 | } 7 | } 8 | 9 | [class*=illustration-element-]::after { 10 | z-index: -1; 11 | } 12 | 13 | [class*=illustration-section-]::after { 14 | z-index: -2; 15 | } 16 | 17 | // Hero illustration 18 | .illustration-section-01::after { 19 | @include illustration('illustration-section-01.svg', 100%, 286px, top); 20 | } 21 | 22 | // Features illustration 02 23 | .illustration-section-02::after { 24 | @include illustration('illustration-section-02.svg', 100%, 253px, null, null, 30px); 25 | } -------------------------------------------------------------------------------- /src/assets/scss/theme/layout/_footer.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/layout/_footer.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/layout/_header.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/layout/_header.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/layout/_main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/layout/_main.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/patterns/_split.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/patterns/_split.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/patterns/_tiles.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/patterns/_tiles.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_cta.scss: -------------------------------------------------------------------------------- 1 | .cta { 2 | 3 | .form-input { 4 | border-color: transparent; 5 | border-radius: 2px; 6 | } 7 | } 8 | 9 | .cta-inner { 10 | padding-left: 16px; 11 | padding-right: 16px; 12 | background-color: get-color(primary, 3); 13 | background-image: url(../../../images/cta-illustration.svg); 14 | background-repeat: no-repeat; 15 | background-size: cover; 16 | background-position: right bottom; 17 | } 18 | 19 | @include media( '>medium' ) { 20 | 21 | .cta { 22 | 23 | .form-input { 24 | min-width: 280px; 25 | } 26 | } 27 | 28 | .cta-inner { 29 | padding-left: 48px; 30 | padding-right: 48px; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_features-split.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/sections/_features-split.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_features-tiles.scss: -------------------------------------------------------------------------------- 1 | .features-tiles-item-image { 2 | display: inline-flex; 3 | border-radius: 50%; 4 | background-color: get-color(primary, 3); 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_hero.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/sections/_hero.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_section.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/srsedev/open-react-template/e56e2c86e4accfb2c3702bfa0f5f010c144a2f8c/src/assets/scss/theme/sections/_section.scss -------------------------------------------------------------------------------- /src/assets/scss/theme/sections/_testimonial.scss: -------------------------------------------------------------------------------- 1 | .testimonial { 2 | 3 | .tiles-item-inner { 4 | background: get-color(dark, 2); 5 | } 6 | } 7 | 8 | .testimonial-item-content { 9 | position: relative; 10 | 11 | &::before { 12 | content: ''; 13 | display: block; 14 | width: 24px; 15 | height: 18px; 16 | margin-top: 12px; 17 | margin-bottom: 16px; 18 | background-image: inline-svg(''); 19 | background-repeat: no-repeat; 20 | } 21 | } 22 | 23 | .testimonial-item-footer { 24 | font-weight: 600; 25 | padding-top: 20px; 26 | 27 | &.has-top-divider { 28 | 29 | &::before { 30 | background: get-color(dark, 3); 31 | } 32 | } 33 | } 34 | 35 | .testimonial-item-link { 36 | color: get-color(secondary, 3); 37 | 38 | a { 39 | color: get-color(secondary, 3); 40 | text-decoration: none; 41 | 42 | &:hover { 43 | color: get-color(secondary, 2); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/components/elements/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | tag: PropTypes.elementType, 7 | color: PropTypes.string, 8 | size: PropTypes.string, 9 | loading: PropTypes.bool, 10 | wide: PropTypes.bool, 11 | wideMobile: PropTypes.bool, 12 | disabled: PropTypes.bool 13 | } 14 | 15 | const defaultProps = { 16 | tag: 'button', 17 | color: '', 18 | size: '', 19 | loading: false, 20 | wide: false, 21 | wideMobile: false, 22 | disabled: false 23 | } 24 | 25 | const Button = ({ 26 | className, 27 | tag, 28 | color, 29 | size, 30 | loading, 31 | wide, 32 | wideMobile, 33 | disabled, 34 | ...props 35 | }) => { 36 | 37 | const classes = classNames( 38 | 'button', 39 | color && `button-${color}`, 40 | size && `button-${size}`, 41 | loading && 'is-loading', 42 | wide && 'button-block', 43 | wideMobile && 'button-wide-mobile', 44 | className 45 | ); 46 | 47 | const Component = tag; 48 | return ( 49 | 54 | ); 55 | } 56 | 57 | Button.propTypes = propTypes; 58 | Button.defaultProps = defaultProps; 59 | 60 | export default Button; -------------------------------------------------------------------------------- /src/components/elements/ButtonGroup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | const ButtonGroup = ({ 5 | className, 6 | ...props 7 | }) => { 8 | 9 | const classes = classNames( 10 | 'button-group', 11 | className 12 | ); 13 | 14 | return ( 15 |
19 | ); 20 | } 21 | 22 | export default ButtonGroup; -------------------------------------------------------------------------------- /src/components/elements/Checkbox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | name: PropTypes.string, 8 | value: PropTypes.string, 9 | disabled: PropTypes.bool, 10 | checked: PropTypes.bool 11 | } 12 | 13 | const defaultProps = { 14 | children: null, 15 | name: undefined, 16 | value: undefined, 17 | disabled: false, 18 | checked: undefined 19 | } 20 | 21 | const Checkbox = ({ 22 | className, 23 | children, 24 | name, 25 | value, 26 | disabled, 27 | checked, 28 | ...props 29 | }) => { 30 | 31 | const classes = classNames( 32 | 'form-checkbox', 33 | className 34 | ); 35 | 36 | return ( 37 | 48 | ); 49 | } 50 | 51 | Checkbox.propTypes = propTypes; 52 | Checkbox.defaultProps = defaultProps; 53 | 54 | export default Checkbox; -------------------------------------------------------------------------------- /src/components/elements/FormHint.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | status: PropTypes.string 8 | } 9 | 10 | const defaultProps = { 11 | children: null, 12 | status: false 13 | } 14 | 15 | const FormHint = ({ 16 | children, 17 | className, 18 | status, 19 | ...props 20 | }) => { 21 | 22 | const classes = classNames( 23 | 'form-hint', 24 | status && `text-color-${status}`, 25 | className 26 | ); 27 | 28 | return ( 29 |
33 | {children} 34 |
35 | ); 36 | } 37 | 38 | FormHint.propTypes = propTypes; 39 | FormHint.defaultProps = defaultProps; 40 | 41 | export default FormHint; -------------------------------------------------------------------------------- /src/components/elements/FormLabel.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | labelHidden: PropTypes.bool, 8 | id: PropTypes.string 9 | } 10 | 11 | const defaultProps = { 12 | children: null, 13 | labelHidden: false, 14 | id: null 15 | } 16 | 17 | const FormLabel = ({ 18 | className, 19 | children, 20 | labelHidden, 21 | id, 22 | ...props 23 | }) => { 24 | 25 | const classes = classNames( 26 | 'form-label', 27 | labelHidden && 'screen-reader', 28 | className 29 | ); 30 | 31 | return ( 32 | 39 | ); 40 | } 41 | 42 | FormLabel.propTypes = propTypes; 43 | FormLabel.defaultProps = defaultProps; 44 | 45 | export default FormLabel; -------------------------------------------------------------------------------- /src/components/elements/Image.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const propTypes = { 5 | src: PropTypes.oneOfType([ 6 | PropTypes.object, 7 | PropTypes.string 8 | ]).isRequired, 9 | width: PropTypes.number, 10 | height: PropTypes.number, 11 | alt: PropTypes.string 12 | } 13 | 14 | const defaultProps = { 15 | src: undefined, 16 | width: undefined, 17 | height: undefined, 18 | alt: undefined 19 | } 20 | 21 | const Image = ({ 22 | className, 23 | src, 24 | width, 25 | height, 26 | alt, 27 | ...props 28 | }) => { 29 | 30 | const [loaded, setLoaded] = useState(false); 31 | 32 | const image = useRef(null); 33 | 34 | useEffect(() => { 35 | handlePlaceholder(image.current); 36 | // eslint-disable-next-line react-hooks/exhaustive-deps 37 | }, []); 38 | 39 | const placeholderSrc = (w, h) => { 40 | return `data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${w} ${h}"%3E%3C/svg%3E`; 41 | } 42 | 43 | const handlePlaceholder = (img) => { 44 | const placeholder = document.createElement('img'); 45 | if (!loaded) { 46 | img.style.display = 'none'; 47 | img.before(placeholder); 48 | placeholder.src = placeholderSrc( 49 | img.getAttribute('width') || 0, 50 | img.getAttribute('height') || 0 51 | ); 52 | placeholder.width = img.getAttribute('width'); 53 | placeholder.height = img.getAttribute('height'); 54 | placeholder.style.opacity = '0'; 55 | img.className && placeholder.classList.add(img.className); 56 | placeholder.remove(); 57 | img.style.display = ''; 58 | } 59 | } 60 | 61 | function onLoad() { 62 | setLoaded(true); 63 | } 64 | 65 | return ( 66 | {alt} 75 | ); 76 | } 77 | 78 | Image.propTypes = propTypes; 79 | Image.defaultProps = defaultProps; 80 | 81 | export default Image; -------------------------------------------------------------------------------- /src/components/elements/Input.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import FormLabel from './FormLabel'; 5 | import FormHint from './FormHint'; 6 | 7 | const propTypes = { 8 | children: PropTypes.node, 9 | label: PropTypes.string, 10 | labelHidden: PropTypes.bool, 11 | type: PropTypes.oneOf(['textarea', 'text', 'email', 'tel', 'password', 'number', 'search', 'color', 'date', 'time', 'datetime-local']), 12 | name: PropTypes.string, 13 | status: PropTypes.string, 14 | disabled: PropTypes.bool, 15 | value: PropTypes.string, 16 | formGroup: PropTypes.string, 17 | hasIcon: PropTypes.string, 18 | size: PropTypes.string, 19 | placeholder: PropTypes.string, 20 | rows: PropTypes.number, 21 | hint: PropTypes.string 22 | } 23 | 24 | const defaultProps = { 25 | children: null, 26 | label: '', 27 | labelHidden: false, 28 | type: 'text', 29 | name: undefined, 30 | status: '', 31 | disabled: false, 32 | value: undefined, 33 | formGroup: null, 34 | hasIcon: null, 35 | size: '', 36 | placeholder: '', 37 | rows: 3, 38 | hint: null 39 | } 40 | 41 | const Input = ({ 42 | className, 43 | children, 44 | label, 45 | labelHidden, 46 | type, 47 | name, 48 | status, 49 | disabled, 50 | value, 51 | formGroup, 52 | hasIcon, 53 | size, 54 | placeholder, 55 | rows, 56 | hint, 57 | ...props 58 | }) => { 59 | 60 | const wrapperClasses = classNames( 61 | (formGroup && formGroup !== '') && (formGroup === 'desktop' ? 'form-group-desktop' : 'form-group'), 62 | (hasIcon && hasIcon !== '') && 'has-icon-' + hasIcon 63 | ); 64 | 65 | const classes = classNames( 66 | 'form-input', 67 | size && `form-input-${size}`, 68 | status && `form-${status}`, 69 | className 70 | ); 71 | 72 | const Component = type === 'textarea' ? 'textarea' : 'input'; 73 | return ( 74 | <> 75 | {label && {label}} 76 |
79 | 89 | {children} 90 |
91 | {hint && {hint}} 92 | 93 | ); 94 | } 95 | 96 | Input.propTypes = propTypes; 97 | Input.defaultProps = defaultProps; 98 | 99 | export default Input; 100 | -------------------------------------------------------------------------------- /src/components/elements/Modal.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | handleClose: PropTypes.func.isRequired, 8 | show: PropTypes.bool.isRequired, 9 | closeHidden: PropTypes.bool, 10 | video: PropTypes.string, 11 | videoTag: PropTypes.oneOf(['iframe', 'video']) 12 | } 13 | 14 | const defaultProps = { 15 | children: null, 16 | show: false, 17 | closeHidden: false, 18 | video: '', 19 | videoTag: 'iframe' 20 | } 21 | 22 | const Modal = ({ 23 | className, 24 | children, 25 | handleClose, 26 | show, 27 | closeHidden, 28 | video, 29 | videoTag, 30 | ...props 31 | }) => { 32 | 33 | useEffect(() => { 34 | document.addEventListener('keydown', keyPress); 35 | document.addEventListener('click', stopProgagation); 36 | return () => { 37 | document.removeEventListener('keydown', keyPress); 38 | document.removeEventListener('click', stopProgagation); 39 | }; 40 | }); 41 | 42 | useEffect(() => { 43 | handleBodyClass(); 44 | }, [props.show]); 45 | 46 | const handleBodyClass = () => { 47 | if (document.querySelectorAll('.modal.is-active').length) { 48 | document.body.classList.add('modal-is-active'); 49 | } else { 50 | document.body.classList.remove('modal-is-active'); 51 | } 52 | } 53 | 54 | const keyPress = (e) => { 55 | e.keyCode === 27 && handleClose(e); 56 | } 57 | 58 | const stopProgagation = (e) => { 59 | e.stopPropagation(); 60 | } 61 | 62 | const classes = classNames( 63 | 'modal', 64 | show && 'is-active', 65 | video && 'modal-video', 66 | className 67 | ); 68 | 69 | return ( 70 | <> 71 | {show && 72 |
77 |
78 | {video ? 79 |
80 | {videoTag === 'iframe' ? 81 | : 87 | 92 | } 93 |
: 94 | <> 95 | {!closeHidden && 96 | 101 | } 102 |
103 | {children} 104 |
105 | 106 | } 107 |
108 |
109 | } 110 | 111 | ) 112 | } 113 | 114 | Modal.propTypes = propTypes; 115 | Modal.defaultProps = defaultProps; 116 | 117 | export default Modal; -------------------------------------------------------------------------------- /src/components/elements/Radio.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | name: PropTypes.string.isRequired, 8 | value: PropTypes.string, 9 | disabled: PropTypes.bool, 10 | checked: PropTypes.bool 11 | } 12 | 13 | const defaultProps = { 14 | children: null, 15 | name: undefined, 16 | value: '', 17 | disabled: false, 18 | checked: false 19 | } 20 | 21 | const Radio = ({ 22 | className, 23 | children, 24 | name, 25 | value, 26 | disabled, 27 | checked, 28 | ...props 29 | }) => { 30 | 31 | const classes = classNames( 32 | 'form-radio', 33 | className 34 | ); 35 | 36 | return ( 37 | 48 | ); 49 | } 50 | 51 | Radio.propTypes = propTypes; 52 | Radio.defaultProps = defaultProps; 53 | 54 | export default Radio; 55 | -------------------------------------------------------------------------------- /src/components/elements/Select.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import FormLabel from './FormLabel'; 5 | import FormHint from './FormHint'; 6 | 7 | const propTypes = { 8 | children: PropTypes.node, 9 | label: PropTypes.string, 10 | labelHidden: PropTypes.bool, 11 | name: PropTypes.string, 12 | status: PropTypes.string, 13 | disabled: PropTypes.bool, 14 | value: PropTypes.oneOfType([ 15 | PropTypes.string, 16 | PropTypes.number, 17 | ]), 18 | size: PropTypes.string, 19 | placeholder: PropTypes.string, 20 | hint: PropTypes.string 21 | } 22 | 23 | const defaultProps = { 24 | children: null, 25 | label: '', 26 | labelHidden: false, 27 | name: undefined, 28 | status: '', 29 | disabled: false, 30 | value: undefined, 31 | size: '', 32 | placeholder: null, 33 | hint: null 34 | } 35 | 36 | const Select = ({ 37 | className, 38 | children, 39 | label, 40 | labelHidden, 41 | name, 42 | status, 43 | disabled, 44 | value, 45 | size, 46 | placeholder, 47 | hint, 48 | ...props 49 | }) => { 50 | 51 | const classes = classNames( 52 | 'form-select', 53 | size && `form-select-${size}`, 54 | status && `form-${status}`, 55 | className 56 | ); 57 | 58 | return ( 59 | <> 60 | {label && {label}} 61 | 71 | {hint && {hint}} 72 | 73 | ); 74 | } 75 | 76 | Select.propTypes = propTypes; 77 | Select.defaultProps = defaultProps; 78 | 79 | export default Select; 80 | -------------------------------------------------------------------------------- /src/components/elements/SmoothScroll.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | to: PropTypes.string.isRequired, 8 | duration: PropTypes.number, 9 | onLinkClick: PropTypes.func 10 | } 11 | 12 | const SmoothScroll = ({ 13 | className, 14 | children, 15 | to, 16 | duration, 17 | onLinkClick, 18 | ...props 19 | }) => { 20 | 21 | const easeInOutQuad = (t) => { 22 | return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t 23 | }; 24 | 25 | const scrollToEl = (startTime, currentTime, duration, scrollEndElemTop, startScrollOffset) => { 26 | const runtime = currentTime - startTime; 27 | let progress = runtime / duration; 28 | 29 | progress = Math.min(progress, 1); 30 | 31 | const ease = easeInOutQuad(progress); 32 | 33 | window.scroll(0, startScrollOffset + (scrollEndElemTop * ease)); 34 | if (runtime < duration) { 35 | window.requestAnimationFrame((timestamp) => { 36 | const currentTime = timestamp || new Date().getTime(); 37 | scrollToEl(startTime, currentTime, duration, scrollEndElemTop, startScrollOffset); 38 | }); 39 | } 40 | }; 41 | 42 | const smoothScroll = (e) => { 43 | e.preventDefault(); 44 | 45 | const targetId = to; 46 | const target = document.getElementById(targetId); 47 | const timing = duration || 1000; 48 | 49 | if (!target) return; 50 | 51 | onLinkClick && onLinkClick(); 52 | 53 | window.requestAnimationFrame((timestamp) => { 54 | const stamp = timestamp || new Date().getTime(); 55 | const start = stamp; 56 | 57 | const startScrollOffset = window.pageYOffset; 58 | const scrollEndElemTop = target.getBoundingClientRect().top; 59 | 60 | scrollToEl(start, stamp, timing, scrollEndElemTop, startScrollOffset); 61 | }) 62 | }; 63 | 64 | const classes = classNames( 65 | className 66 | ); 67 | 68 | return ( 69 | 74 | {children} 75 | 76 | ) 77 | } 78 | 79 | SmoothScroll.propTypes = propTypes; 80 | 81 | export default SmoothScroll; -------------------------------------------------------------------------------- /src/components/elements/Switch.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | children: PropTypes.node, 7 | name: PropTypes.string, 8 | value: PropTypes.string, 9 | rightLabel: PropTypes.string, 10 | disabled: PropTypes.bool, 11 | checked: PropTypes.bool 12 | } 13 | 14 | const defaultProps = { 15 | children: null, 16 | name: undefined, 17 | value: undefined, 18 | rightLabel: undefined, 19 | disabled: false, 20 | checked: undefined 21 | } 22 | 23 | const Switch = ({ 24 | className, 25 | children, 26 | name, 27 | value, 28 | rightLabel, 29 | disabled, 30 | checked, 31 | ...props 32 | }) => { 33 | 34 | const classes = classNames( 35 | 'form-switch', 36 | className 37 | ); 38 | 39 | return ( 40 | 59 | ); 60 | } 61 | 62 | Switch.propTypes = propTypes; 63 | Switch.defaultProps = defaultProps; 64 | 65 | export default Switch; -------------------------------------------------------------------------------- /src/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import Logo from './partials/Logo'; 5 | import FooterNav from './partials/FooterNav'; 6 | import FooterSocial from './partials/FooterSocial'; 7 | 8 | const propTypes = { 9 | topOuterDivider: PropTypes.bool, 10 | topDivider: PropTypes.bool 11 | } 12 | 13 | const defaultProps = { 14 | topOuterDivider: false, 15 | topDivider: false 16 | } 17 | 18 | const Footer = ({ 19 | className, 20 | topOuterDivider, 21 | topDivider, 22 | ...props 23 | }) => { 24 | 25 | const classes = classNames( 26 | 'site-footer center-content-mobile', 27 | topOuterDivider && 'has-top-divider', 28 | className 29 | ); 30 | 31 | return ( 32 |
36 |
37 |
42 |
43 | 44 | 45 |
46 |
47 | 48 |
Made by Cruip. All right reserved
49 |
50 |
51 |
52 |
53 | ); 54 | } 55 | 56 | Footer.propTypes = propTypes; 57 | Footer.defaultProps = defaultProps; 58 | 59 | export default Footer; -------------------------------------------------------------------------------- /src/components/layout/Header.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useRef, useEffect } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import { Link } from 'react-router-dom'; 5 | import Logo from './partials/Logo'; 6 | 7 | const propTypes = { 8 | navPosition: PropTypes.string, 9 | hideNav: PropTypes.bool, 10 | hideSignin: PropTypes.bool, 11 | bottomOuterDivider: PropTypes.bool, 12 | bottomDivider: PropTypes.bool 13 | } 14 | 15 | const defaultProps = { 16 | navPosition: '', 17 | hideNav: false, 18 | hideSignin: false, 19 | bottomOuterDivider: false, 20 | bottomDivider: false 21 | } 22 | 23 | const Header = ({ 24 | className, 25 | navPosition, 26 | hideNav, 27 | hideSignin, 28 | bottomOuterDivider, 29 | bottomDivider, 30 | ...props 31 | }) => { 32 | 33 | const [isActive, setIsactive] = useState(false); 34 | 35 | const nav = useRef(null); 36 | const hamburger = useRef(null); 37 | 38 | useEffect(() => { 39 | isActive && openMenu(); 40 | document.addEventListener('keydown', keyPress); 41 | document.addEventListener('click', clickOutside); 42 | return () => { 43 | document.removeEventListener('keydown', keyPress); 44 | document.addEventListener('click', clickOutside); 45 | closeMenu(); 46 | }; 47 | }); 48 | 49 | const openMenu = () => { 50 | document.body.classList.add('off-nav-is-active'); 51 | nav.current.style.maxHeight = nav.current.scrollHeight + 'px'; 52 | setIsactive(true); 53 | } 54 | 55 | const closeMenu = () => { 56 | document.body.classList.remove('off-nav-is-active'); 57 | nav.current && (nav.current.style.maxHeight = null); 58 | setIsactive(false); 59 | } 60 | 61 | const keyPress = (e) => { 62 | isActive && e.keyCode === 27 && closeMenu(); 63 | } 64 | 65 | const clickOutside = (e) => { 66 | if (!nav.current) return 67 | if (!isActive || nav.current.contains(e.target) || e.target === hamburger.current) return; 68 | closeMenu(); 69 | } 70 | 71 | const classes = classNames( 72 | 'site-header', 73 | bottomOuterDivider && 'has-bottom-divider', 74 | className 75 | ); 76 | 77 | return ( 78 |
82 |
83 |
88 | 89 | {!hideNav && 90 | <> 91 | 101 | 128 | } 129 |
130 |
131 |
132 | ); 133 | } 134 | 135 | Header.propTypes = propTypes; 136 | Header.defaultProps = defaultProps; 137 | 138 | export default Header; -------------------------------------------------------------------------------- /src/components/layout/partials/FooterNav.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | const FooterNav = ({ 6 | className, 7 | ...props 8 | }) => { 9 | 10 | const classes = classNames( 11 | 'footer-nav', 12 | className 13 | ); 14 | 15 | return ( 16 | 35 | ); 36 | } 37 | 38 | export default FooterNav; -------------------------------------------------------------------------------- /src/components/layout/partials/FooterSocial.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | 4 | const FooterSocial = ({ 5 | className, 6 | ...props 7 | }) => { 8 | 9 | const classes = classNames( 10 | 'footer-social', 11 | className 12 | ); 13 | 14 | return ( 15 |
19 | 65 |
66 | ); 67 | } 68 | 69 | export default FooterSocial; -------------------------------------------------------------------------------- /src/components/layout/partials/Logo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { Link } from 'react-router-dom'; 4 | import Image from '../../elements/Image'; 5 | 6 | const Logo = ({ 7 | className, 8 | ...props 9 | }) => { 10 | 11 | const classes = classNames( 12 | 'brand', 13 | className 14 | ); 15 | 16 | return ( 17 |
21 |

22 | 23 | Open 28 | 29 |

30 |
31 | ); 32 | } 33 | 34 | export default Logo; -------------------------------------------------------------------------------- /src/components/sections/Cta.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import { SectionProps } from '../../utils/SectionProps'; 5 | import Input from '../elements/Input'; 6 | 7 | const propTypes = { 8 | ...SectionProps.types, 9 | split: PropTypes.bool 10 | } 11 | 12 | const defaultProps = { 13 | ...SectionProps.defaults, 14 | split: false 15 | } 16 | 17 | const Cta = ({ 18 | className, 19 | topOuterDivider, 20 | bottomOuterDivider, 21 | topDivider, 22 | bottomDivider, 23 | hasBgColor, 24 | invertColor, 25 | split, 26 | ...props 27 | }) => { 28 | 29 | const outerClasses = classNames( 30 | 'cta section center-content-mobile reveal-from-bottom', 31 | topOuterDivider && 'has-top-divider', 32 | bottomOuterDivider && 'has-bottom-divider', 33 | hasBgColor && 'has-bg-color', 34 | invertColor && 'invert-color', 35 | className 36 | ); 37 | 38 | const innerClasses = classNames( 39 | 'cta-inner section-inner', 40 | topDivider && 'has-top-divider', 41 | bottomDivider && 'has-bottom-divider', 42 | split && 'cta-split' 43 | ); 44 | 45 | return ( 46 |
50 |
51 |
54 |
55 |

56 | For previewing layouts and visual? 57 |

58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 |
66 |
67 |
68 |
69 | ); 70 | } 71 | 72 | Cta.propTypes = propTypes; 73 | Cta.defaultProps = defaultProps; 74 | 75 | export default Cta; -------------------------------------------------------------------------------- /src/components/sections/FeaturesSplit.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { SectionSplitProps } from '../../utils/SectionProps'; 4 | import SectionHeader from './partials/SectionHeader'; 5 | import Image from '../elements/Image'; 6 | 7 | const propTypes = { 8 | ...SectionSplitProps.types 9 | } 10 | 11 | const defaultProps = { 12 | ...SectionSplitProps.defaults 13 | } 14 | 15 | const FeaturesSplit = ({ 16 | className, 17 | topOuterDivider, 18 | bottomOuterDivider, 19 | topDivider, 20 | bottomDivider, 21 | hasBgColor, 22 | invertColor, 23 | invertMobile, 24 | invertDesktop, 25 | alignTop, 26 | imageFill, 27 | ...props 28 | }) => { 29 | 30 | const outerClasses = classNames( 31 | 'features-split section', 32 | topOuterDivider && 'has-top-divider', 33 | bottomOuterDivider && 'has-bottom-divider', 34 | hasBgColor && 'has-bg-color', 35 | invertColor && 'invert-color', 36 | className 37 | ); 38 | 39 | const innerClasses = classNames( 40 | 'features-split-inner section-inner', 41 | topDivider && 'has-top-divider', 42 | bottomDivider && 'has-bottom-divider' 43 | ); 44 | 45 | const splitClasses = classNames( 46 | 'split-wrap', 47 | invertMobile && 'invert-mobile', 48 | invertDesktop && 'invert-desktop', 49 | alignTop && 'align-top' 50 | ); 51 | 52 | const sectionHeader = { 53 | title: 'Workflow that just works', 54 | paragraph: 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum — semper quis lectus nulla at volutpat diam ut venenatis.' 55 | }; 56 | 57 | return ( 58 |
62 |
63 |
64 | 65 |
66 | 67 |
68 |
69 |
70 | Lightning fast workflow 71 |
72 |

73 | Data-driven insights 74 |

75 |

76 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua — Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 77 |

78 |
79 |
85 | Features split 01 90 |
91 |
92 | 93 |
94 |
95 |
96 | Lightning fast workflow 97 |
98 |

99 | Data-driven insights 100 |

101 |

102 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua — Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 103 |

104 |
105 |
111 | Features split 02 116 |
117 |
118 | 119 |
120 |
121 |
122 | Lightning fast workflow 123 |
124 |

125 | Data-driven insights 126 |

127 |

128 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua — Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 129 |

130 |
131 |
137 | Features split 03 142 |
143 |
144 | 145 |
146 |
147 |
148 |
149 | ); 150 | } 151 | 152 | FeaturesSplit.propTypes = propTypes; 153 | FeaturesSplit.defaultProps = defaultProps; 154 | 155 | export default FeaturesSplit; -------------------------------------------------------------------------------- /src/components/sections/FeaturesTiles.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { SectionTilesProps } from '../../utils/SectionProps'; 4 | import SectionHeader from './partials/SectionHeader'; 5 | import Image from '../elements/Image'; 6 | 7 | const propTypes = { 8 | ...SectionTilesProps.types 9 | } 10 | 11 | const defaultProps = { 12 | ...SectionTilesProps.defaults 13 | } 14 | const FeaturesTiles = ({ 15 | className, 16 | topOuterDivider, 17 | bottomOuterDivider, 18 | topDivider, 19 | bottomDivider, 20 | hasBgColor, 21 | invertColor, 22 | pushLeft, 23 | ...props 24 | }) => { 25 | 26 | const outerClasses = classNames( 27 | 'features-tiles section', 28 | topOuterDivider && 'has-top-divider', 29 | bottomOuterDivider && 'has-bottom-divider', 30 | hasBgColor && 'has-bg-color', 31 | invertColor && 'invert-color', 32 | className 33 | ); 34 | 35 | const innerClasses = classNames( 36 | 'features-tiles-inner section-inner pt-0', 37 | topDivider && 'has-top-divider', 38 | bottomDivider && 'has-bottom-divider' 39 | ); 40 | 41 | const tilesClasses = classNames( 42 | 'tiles-wrap center-content', 43 | pushLeft && 'push-left' 44 | ); 45 | 46 | const sectionHeader = { 47 | title: 'Build up the whole picture', 48 | paragraph: 'Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum — semper quis lectus nulla at volutpat diam ut venenatis.' 49 | }; 50 | 51 | return ( 52 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 |
65 | Features tile icon 01 70 |
71 |
72 |
73 |

74 | Robust Workflow 75 |

76 |

77 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 78 |

79 |
80 |
81 |
82 | 83 |
84 |
85 |
86 |
87 | Features tile icon 02 92 |
93 |
94 |
95 |

96 | Robust Workflow 97 |

98 |

99 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 100 |

101 |
102 |
103 |
104 | 105 |
106 |
107 |
108 |
109 | Features tile icon 03 114 |
115 |
116 |
117 |

118 | Robust Workflow 119 |

120 |

121 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 122 |

123 |
124 |
125 |
126 | 127 |
128 |
129 |
130 |
131 | Features tile icon 04 136 |
137 |
138 |
139 |

140 | Robust Workflow 141 |

142 |

143 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 144 |

145 |
146 |
147 |
148 | 149 |
150 |
151 |
152 |
153 | Features tile icon 05 158 |
159 |
160 |
161 |

162 | Robust Workflow 163 |

164 |

165 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 166 |

167 |
168 |
169 |
170 | 171 |
172 |
173 |
174 |
175 | Features tile icon 06 180 |
181 |
182 |
183 |

184 | Robust Workflow 185 |

186 |

187 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat. 188 |

189 |
190 |
191 |
192 | 193 |
194 |
195 |
196 |
197 | ); 198 | } 199 | 200 | FeaturesTiles.propTypes = propTypes; 201 | FeaturesTiles.defaultProps = defaultProps; 202 | 203 | export default FeaturesTiles; -------------------------------------------------------------------------------- /src/components/sections/GenericSection.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | import { SectionProps } from '../../utils/SectionProps'; 5 | 6 | const propTypes = { 7 | children: PropTypes.node, 8 | ...SectionProps.types 9 | } 10 | 11 | const defaultProps = { 12 | children: null, 13 | ...SectionProps.defaults 14 | } 15 | 16 | const GenericSection = ({ 17 | className, 18 | children, 19 | topOuterDivider, 20 | bottomOuterDivider, 21 | topDivider, 22 | bottomDivider, 23 | hasBgColor, 24 | invertColor, 25 | ...props 26 | }) => { 27 | 28 | const outerClasses = classNames( 29 | 'section', 30 | topOuterDivider && 'has-top-divider', 31 | bottomOuterDivider && 'has-bottom-divider', 32 | hasBgColor && 'has-bg-color', 33 | invertColor && 'invert-color', 34 | className 35 | ); 36 | 37 | const innerClasses = classNames( 38 | 'section-inner', 39 | topDivider && 'has-top-divider', 40 | bottomDivider && 'has-bottom-divider' 41 | ); 42 | 43 | return ( 44 |
48 |
49 |
50 | {children} 51 |
52 |
53 |
54 | ); 55 | } 56 | 57 | GenericSection.propTypes = propTypes; 58 | GenericSection.defaultProps = defaultProps; 59 | 60 | export default GenericSection; -------------------------------------------------------------------------------- /src/components/sections/Hero.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import classNames from 'classnames'; 3 | import { SectionProps } from '../../utils/SectionProps'; 4 | import ButtonGroup from '../elements/ButtonGroup'; 5 | import Button from '../elements/Button'; 6 | import Image from '../elements/Image'; 7 | import Modal from '../elements/Modal'; 8 | 9 | const propTypes = { 10 | ...SectionProps.types 11 | } 12 | 13 | const defaultProps = { 14 | ...SectionProps.defaults 15 | } 16 | 17 | const Hero = ({ 18 | className, 19 | topOuterDivider, 20 | bottomOuterDivider, 21 | topDivider, 22 | bottomDivider, 23 | hasBgColor, 24 | invertColor, 25 | ...props 26 | }) => { 27 | 28 | const [videoModalActive, setVideomodalactive] = useState(false); 29 | 30 | const openModal = (e) => { 31 | e.preventDefault(); 32 | setVideomodalactive(true); 33 | } 34 | 35 | const closeModal = (e) => { 36 | e.preventDefault(); 37 | setVideomodalactive(false); 38 | } 39 | 40 | const outerClasses = classNames( 41 | 'hero section center-content', 42 | topOuterDivider && 'has-top-divider', 43 | bottomOuterDivider && 'has-bottom-divider', 44 | hasBgColor && 'has-bg-color', 45 | invertColor && 'invert-color', 46 | className 47 | ); 48 | 49 | const innerClasses = classNames( 50 | 'hero-inner section-inner', 51 | topDivider && 'has-top-divider', 52 | bottomDivider && 'has-bottom-divider' 53 | ); 54 | 55 | return ( 56 |
60 |
61 |
62 |
63 |

64 | Landing template for startups 65 |

66 |
67 |

68 | Our landing page template works on all devices, so you only have to set it up once, and get beautiful results forever. 69 |

70 |
71 | 72 | 75 | 78 | 79 |
80 |
81 |
82 |
83 | 89 | Hero 95 | 96 |
97 | 103 |
104 |
105 |
106 | ); 107 | } 108 | 109 | Hero.propTypes = propTypes; 110 | Hero.defaultProps = defaultProps; 111 | 112 | export default Hero; -------------------------------------------------------------------------------- /src/components/sections/Testimonial.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import classNames from 'classnames'; 3 | import { SectionTilesProps } from '../../utils/SectionProps'; 4 | import SectionHeader from './partials/SectionHeader'; 5 | 6 | const propTypes = { 7 | ...SectionTilesProps.types 8 | } 9 | 10 | const defaultProps = { 11 | ...SectionTilesProps.defaults 12 | } 13 | 14 | const Testimonial = ({ 15 | className, 16 | topOuterDivider, 17 | bottomOuterDivider, 18 | topDivider, 19 | bottomDivider, 20 | hasBgColor, 21 | invertColor, 22 | pushLeft, 23 | ...props 24 | }) => { 25 | 26 | const outerClasses = classNames( 27 | 'testimonial section', 28 | topOuterDivider && 'has-top-divider', 29 | bottomOuterDivider && 'has-bottom-divider', 30 | hasBgColor && 'has-bg-color', 31 | invertColor && 'invert-color', 32 | className 33 | ); 34 | 35 | const innerClasses = classNames( 36 | 'testimonial-inner section-inner', 37 | topDivider && 'has-top-divider', 38 | bottomDivider && 'has-bottom-divider' 39 | ); 40 | 41 | const tilesClasses = classNames( 42 | 'tiles-wrap', 43 | pushLeft && 'push-left' 44 | ); 45 | 46 | const sectionHeader = { 47 | title: 'Customer testimonials', 48 | paragraph: 'Vitae aliquet nec ullamcorper sit amet risus nullam eget felis semper quis lectus nulla at volutpat diam ut venenatis tellus—in ornare.' 49 | }; 50 | 51 | return ( 52 |
56 |
57 |
58 | 59 |
60 | 61 |
62 |
63 |
64 |

65 | — Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum cillum dolore eu fugiat. 66 |

67 |
68 |
69 | Roman Level 70 | / 71 | 72 | AppName 73 | 74 |
75 |
76 |
77 | 78 |
79 |
80 |
81 |

82 | — Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum cillum dolore eu fugiat. 83 |

84 |
85 |
86 | Diana Rynzhuk 87 | / 88 | 89 | AppName 90 | 91 |
92 |
93 |
94 | 95 |
96 |
97 |
98 |

99 | — Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum cillum dolore eu fugiat. 100 |

101 |
102 |
103 | Ben Stafford 104 | / 105 | 106 | AppName 107 | 108 |
109 |
110 |
111 | 112 |
113 |
114 |
115 |
116 | ); 117 | } 118 | 119 | Testimonial.propTypes = propTypes; 120 | Testimonial.defaultProps = defaultProps; 121 | 122 | export default Testimonial; -------------------------------------------------------------------------------- /src/components/sections/partials/SectionHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import classNames from 'classnames'; 4 | 5 | const propTypes = { 6 | data: PropTypes.shape({ 7 | title: PropTypes.string, 8 | paragraph: PropTypes.string 9 | }).isRequired, 10 | children: PropTypes.node, 11 | tag: PropTypes.oneOf(['h1', 'h2', 'h3']) 12 | } 13 | 14 | const defaultProps = { 15 | children: null, 16 | tag: 'h2' 17 | } 18 | 19 | const SectionHeader = ({ 20 | className, 21 | data, 22 | children, 23 | tag, 24 | ...props 25 | }) => { 26 | 27 | const classes = classNames( 28 | 'section-header', 29 | className 30 | ); 31 | 32 | const Component = tag; 33 | 34 | return ( 35 | <> 36 | {(data.title || data.paragraph) && 37 |
41 |
42 | {children} 43 | {data.title && 44 | {data.title} 49 | } 50 | {data.paragraph && 51 |

{data.paragraph}

52 | } 53 |
54 |
55 | } 56 | 57 | ); 58 | } 59 | 60 | SectionHeader.propTypes = propTypes; 61 | SectionHeader.defaultProps = defaultProps; 62 | 63 | export default SectionHeader; -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Router } from "react-router-dom"; 4 | import { createBrowserHistory } from "history"; 5 | 6 | import App from './App'; 7 | import * as serviceWorker from './serviceWorker'; 8 | 9 | //import './App.css'; 10 | import './assets/scss/style.scss'; 11 | 12 | const history = createBrowserHistory(); 13 | 14 | ReactDOM.render( 15 | 16 | 17 | , 18 | document.getElementById('root') 19 | ); 20 | 21 | // If you want your app to work offline and load faster, you can change 22 | // unregister() to register() below. Note this comes with some pitfalls. 23 | // Learn more about service workers: https://bit.ly/CRA-PWA 24 | serviceWorker.unregister(); 25 | -------------------------------------------------------------------------------- /src/layouts/LayoutDefault.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Header from '../components/layout/Header'; 3 | import Footer from '../components/layout/Footer'; 4 | 5 | const LayoutDefault = ({ children }) => ( 6 | <> 7 |
8 |
9 | {children} 10 |
11 |