├── .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 | 
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 | You need to enable JavaScript to run this app.
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 |
38 |
46 | {children}
47 |
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 |
37 | {children}
38 |
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 |
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 |
38 |
46 | {children}
47 |
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 |
68 | {placeholder && {placeholder} }
69 | {children}
70 |
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 |
41 |
49 |
50 |
51 | {children}
52 |
53 | {rightLabel &&
54 |
55 | {rightLabel}
56 |
57 | }
58 |
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 |
96 | Menu
97 |
98 |
99 |
100 |
101 |
108 |
109 |
114 |
115 | Documentation
116 |
117 |
118 | {!hideSignin &&
119 |
122 |
123 | Sign up
124 |
125 | }
126 |
127 |
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 |
20 |
21 |
22 | Contact
23 |
24 |
25 | About us
26 |
27 |
28 | FAQ's
29 |
30 |
31 | Support
32 |
33 |
34 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
73 | Get started
74 |
75 |
76 | View on Github
77 |
78 |
79 |
80 |
81 |
82 |
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 |
12 | >
13 | );
14 |
15 | export default LayoutDefault;
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/utils/AppRoute.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route } from 'react-router-dom';
3 |
4 | const AppRoute = ({
5 | component: Component,
6 | layout: Layout,
7 | ...rest
8 | }) => {
9 |
10 | Layout = (Layout === undefined) ? props => (<>{props.children}>) : Layout;
11 |
12 | return (
13 | (
16 |
17 |
18 |
19 | )} />
20 | );
21 | }
22 |
23 | export default AppRoute;
--------------------------------------------------------------------------------
/src/utils/ScrollReveal.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useImperativeHandle } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { throttle } from 'lodash';
4 |
5 | const ScrollReveal = React.forwardRef((props, ref) => {
6 |
7 | const [viewportHeight, setViewportheight] = useState(window.innerHeight);
8 | const [revealEl, setRevealel] = useState([]);
9 |
10 | const checkComplete = () => {
11 | return revealEl.length <= document.querySelectorAll('[class*=reveal-].is-revealed').length;
12 | };
13 |
14 | const elementIsVisible = (el, offset) => {
15 | return (el.getBoundingClientRect().top <= viewportHeight - offset);
16 | };
17 |
18 | const revealElements = () => {
19 | if (checkComplete()) return;
20 | for (let i = 0; i < revealEl.length; i++) {
21 | let el = revealEl[i];
22 | let revealDelay = el.getAttribute('data-reveal-delay');
23 | let revealOffset = (el.getAttribute('data-reveal-offset') ? el.getAttribute('data-reveal-offset') : '200');
24 | let listenedEl = (el.getAttribute('data-reveal-container') ? el.closest(el.getAttribute('data-reveal-container')) : el);
25 | if (elementIsVisible(listenedEl, revealOffset) && !el.classList.contains('is-revealed')) {
26 | if (revealDelay && revealDelay !== 0) {
27 | setTimeout(function () {
28 | el.classList.add('is-revealed');
29 | }, revealDelay);
30 | } else {
31 | el.classList.add('is-revealed');
32 | }
33 | }
34 | }
35 | };
36 |
37 | useImperativeHandle(ref, () => ({
38 | init() {
39 | setRevealel(document.querySelectorAll('[class*=reveal-]'));
40 | }
41 | }));
42 |
43 | useEffect(() => {
44 | if (typeof revealEl !== 'undefined' && revealEl.length > 0) {
45 | if (!checkComplete()) {
46 | window.addEventListener('scroll', handleScroll);
47 | window.addEventListener('resize', handleResize);
48 | }
49 | revealElements();
50 | }
51 | // eslint-disable-next-line react-hooks/exhaustive-deps
52 | }, [revealEl]);
53 |
54 | const handleListeners = () => {
55 | if (!checkComplete()) return;
56 | window.removeEventListener('scroll', handleScroll);
57 | window.removeEventListener('resize', handleResize);
58 | };
59 |
60 | const handleScroll = throttle(() => {
61 | handleListeners();
62 | revealElements();
63 | }, 30);
64 |
65 | const handleResize = throttle(() => {
66 | setViewportheight(window.innerHeight);
67 | }, 30);
68 |
69 | useEffect(() => {
70 | handleListeners();
71 | revealElements();
72 | // eslint-disable-next-line react-hooks/exhaustive-deps
73 | }, [viewportHeight]);
74 |
75 | return (
76 | <>
77 | {props.children()}
78 | >
79 | );
80 | });
81 |
82 | ScrollReveal.propTypes = {
83 | children: PropTypes.func.isRequired
84 | };
85 |
86 | export default ScrollReveal;
--------------------------------------------------------------------------------
/src/utils/SectionProps.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | // Props shared by all sections
4 | const SectionShared = {
5 | types: {
6 | topOuterDivider: PropTypes.bool,
7 | bottomOuterDivider: PropTypes.bool,
8 | topDivider: PropTypes.bool,
9 | bottomDivider: PropTypes.bool,
10 | hasBgColor: PropTypes.bool,
11 | invertColor: PropTypes.bool
12 | },
13 | defaults: {
14 | topOuterDivider: false,
15 | bottomOuterDivider: false,
16 | topDivider: false,
17 | bottomDivider: false,
18 | hasBgColor: false,
19 | invertColor: false
20 | }
21 | }
22 |
23 | // Default section props
24 | export const SectionProps = {
25 | types: {
26 | ...SectionShared.types
27 | },
28 | defaults: {
29 | ...SectionShared.defaults
30 | }
31 | }
32 |
33 | // Section split props
34 | export const SectionSplitProps = {
35 | types: {
36 | ...SectionShared.types,
37 | invertMobile: PropTypes.bool,
38 | invertDesktop: PropTypes.bool,
39 | alignTop: PropTypes.bool,
40 | imageFill: PropTypes.bool
41 | },
42 | defaults: {
43 | ...SectionShared.defaults,
44 | invertMobile: false,
45 | invertDesktop: false,
46 | alignTop: false,
47 | imageFill: false
48 | }
49 | }
50 |
51 | // Section tiles props
52 | export const SectionTilesProps = {
53 | types: {
54 | ...SectionShared.types,
55 | pushLeft: PropTypes.bool
56 | },
57 | defaults: {
58 | ...SectionShared.defaults,
59 | pushLeft: false
60 | }
61 | }
--------------------------------------------------------------------------------
/src/views/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // import sections
3 | import Hero from '../components/sections/Hero';
4 | import FeaturesTiles from '../components/sections/FeaturesTiles';
5 | import FeaturesSplit from '../components/sections/FeaturesSplit';
6 | import Testimonial from '../components/sections/Testimonial';
7 | import Cta from '../components/sections/Cta';
8 |
9 | const Home = () => {
10 |
11 | return (
12 | <>
13 |
14 |
15 |
16 |
17 |
18 | >
19 | );
20 | }
21 |
22 | export default Home;
--------------------------------------------------------------------------------