├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .huskyrc ├── .lintstagedrc ├── LICENSE ├── README.md ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── assets │ └── css │ │ ├── base.css │ │ └── normalize.css ├── components │ ├── App.js │ ├── atoms │ │ ├── Box │ │ │ ├── Box.js │ │ │ └── index.js │ │ ├── Button │ │ │ ├── Button.js │ │ │ └── index.js │ │ ├── Col │ │ │ ├── Col.js │ │ │ └── index.js │ │ ├── ColBox │ │ │ ├── ColBox.js │ │ │ └── index.js │ │ ├── Container │ │ │ ├── Container.js │ │ │ └── index.js │ │ ├── Divider │ │ │ ├── Divider.js │ │ │ └── index.js │ │ ├── Flex │ │ │ ├── Flex.js │ │ │ └── index.js │ │ ├── InputField │ │ │ ├── InputField.js │ │ │ └── index.js │ │ ├── Link │ │ │ ├── Link.js │ │ │ └── index.js │ │ ├── Row │ │ │ ├── Row.js │ │ │ └── index.js │ │ ├── Text │ │ │ ├── Text.js │ │ │ └── index.js │ │ ├── Textarea │ │ │ ├── Textarea.js │ │ │ └── index.js │ │ └── Title │ │ │ ├── Title.js │ │ │ └── index.js │ ├── index.js │ ├── molecules │ │ └── Card │ │ │ ├── Card.js │ │ │ └── index.js │ ├── organisms │ │ └── Header │ │ │ ├── Header.js │ │ │ └── index.js │ ├── pages │ │ └── HomePage │ │ │ ├── HomePage.js │ │ │ └── index.js │ └── templates │ │ └── BaseTemplate │ │ ├── BaseTemplate.js │ │ └── index.js ├── index.js └── theme.js ├── styleguide ├── App.js ├── index.js ├── pages │ ├── components │ │ ├── box.js │ │ ├── button.js │ │ ├── card.js │ │ ├── divider.js │ │ ├── flex.js │ │ ├── index.js │ │ ├── inputField.js │ │ ├── link.js │ │ ├── text.js │ │ ├── textarea.js │ │ └── title.js │ ├── core-values.js │ ├── index.js │ ├── introduction.mdx │ ├── principles.js │ └── style │ │ ├── color.js │ │ ├── index.js │ │ ├── theme.js │ │ └── typography.js ├── public │ ├── favicon.ico │ └── index.html ├── routes.js ├── src │ ├── assets │ │ ├── css │ │ │ └── highlight.css │ │ └── img │ │ │ ├── footer_illustration.svg │ │ │ ├── icons │ │ │ ├── components.svg │ │ │ ├── core-values.svg │ │ │ ├── principles.svg │ │ │ └── style.svg │ │ │ └── logo.svg │ └── components │ │ ├── atoms │ │ └── LiveEditor │ │ │ ├── LiveEditor.js │ │ │ ├── index.js │ │ │ └── theme.js │ │ ├── molecules │ │ ├── PropsTable │ │ │ ├── PropsTable.js │ │ │ └── index.js │ │ ├── Sidebar │ │ │ ├── Sidebar.js │ │ │ ├── index.js │ │ │ └── styles.js │ │ └── TopNav │ │ │ ├── TopNav.js │ │ │ └── index.js │ │ ├── pages │ │ ├── HomePage │ │ │ ├── HomePage.js │ │ │ └── index.js │ │ ├── InnerPage │ │ │ ├── InnerPage.js │ │ │ └── index.js │ │ └── NotFoundPage │ │ │ ├── NotFoundPage.js │ │ │ └── index.js │ │ └── templates │ │ └── BaseTemplate │ │ ├── BaseTemplate.js │ │ └── index.js └── utils.js ├── tmp └── cover.png ├── webpack ├── webpack.config.babel.js ├── webpack.config.base.js └── webpack.config.guide.babel.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties", "react-docgen"], 4 | "env": { 5 | "development": { 6 | "plugins": ["react-hot-loader/babel", "babel-plugin-styled-components"] 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | end_of_line = lf 12 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "airbnb", 5 | "prettier", 6 | "prettier/react" 7 | ], 8 | "env": { 9 | "browser": true, 10 | "node": true 11 | }, 12 | "plugins": [ 13 | "react", 14 | "prettier" 15 | ], 16 | "settings": { 17 | "import/resolver": { 18 | "node": { 19 | "paths": ["src"] 20 | } 21 | } 22 | }, 23 | "rules": { 24 | "no-unused-expressions": 0, 25 | "react/jsx-filename-extension": [2, { 26 | "extensions": [".js", ".jsx"] 27 | }], 28 | "react/jsx-one-expression-per-line": 0, 29 | "react/require-default-props": 0, 30 | "prettier/prettier": ["error", { 31 | "singleQuote": true, 32 | "trailingComma": "all" 33 | }], 34 | "import/prefer-default-export": "off" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | 4 | /docs 5 | /trash 6 | /dist 7 | /node_modules 8 | 9 | /npm-debug.log* 10 | /yarn-debug.log* 11 | /yarn-error.log* 12 | 13 | *.sh 14 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "yarn staged" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | ".eslintrc": "node_modules/.bin/eslint --fix", 3 | ".babelrc": "node_modules/.bin/eslint --fix", 4 | "src/**/*.{js,jsx}": "node_modules/.bin/eslint --fix", 5 | "styleguide/**/*.{js,jsx}": "node_modules/.bin/eslint --fix", 6 | "webpack/**/*.{js,jsx}": "node_modules/.bin/eslint --fix" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Pulse](https://raw.githubusercontent.com/heartbeatua/Pulse-Boilerplate/master/tmp/cover.png) 2 | 3 | # Pulse Boilerplate 4 | 5 | We've created this React based boilerplate during our research on the Design System approach. 6 | It consists of modern tools and basic [Atomic Design](http://bradfrost.com/blog/post/atomic-web-design/) structure. 7 | 8 | ## Features 9 | 10 | - Up to date tools and practices for Design System creation 11 | - Focused on [Atomic Design](http://bradfrost.com/blog/post/atomic-web-design/) methodology and naming convention 12 | - Clear and understandable structure of folders 13 | - Documentation 14 | - Highly customizable: themes, pages, templates 15 | - Easy to work with styles using [styled system](https://styled-system.com/getting-started/) 16 | 17 | ## What's included 18 | 19 | #### The actual versions of: 20 | 21 | - webpack, babel, react, react-router 22 | - hot-reloading 23 | - eslint ([airbnb config](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb)) — code linter 24 | - [prettier](https://prettier.io/) — code formatter 25 | - [styled-components](https://www.styled-components.com/) — css-in-js 26 | - [styled-system](https://github.com/jxnblk/styled-system) — stylize your components at an advanced level 27 | 28 | ## Setup 29 | 30 | #### Install dependencies 31 | ```sh 32 | npm install 33 | ``` 34 | 35 | #### Run development server 36 | ```sh 37 | npm run dev 38 | ``` 39 | 40 | *Project will be running at [http://localhost:3000/](http://localhost:3000/)* 41 | 42 | #### Generate production build 43 | ```sh 44 | npm run build 45 | ``` 46 | 47 | *Will create the `dist` folder* 48 | 49 | ## Style guide and documentation 50 | 51 | #### Run a development server 52 | ```sh 53 | npm run guide 54 | ``` 55 | 56 | *Style guide will run at [http://localhost:6060/](http://localhost:6060/)* 57 | 58 | ## ESLint 59 | 60 | Run and get code review (you can pass a `--fix` setting that will try to solve a problem automatically) 61 | ```sh 62 | npm run eslint 63 | ``` 64 | 65 | ## Theming 66 | We use [styled components theming](https://www.styled-components.com/docs/advanced#theming). The styled system provides great [theme-based](https://github.com/styled-system/styled-system/blob/master/docs/getting-started.md#theming) [style props](https://github.com/styled-system/styled-system/blob/master/docs/api.md) for building [responsive](https://github.com/jxnblk/styled-system/blob/master/docs/responsive-styles.md) design systems with React. 67 | 68 | ## A few words about Atomic Design 69 | 70 | Atomic design is a methodology composed of five distinct stages working together to create interface design systems in a more deliberate and hierarchical manner. The five stages of atomic design are: __atoms__, __molecules__, __organisms__, __templates__, __pages__. To get more info about methodology, check out [the original article](http://atomicdesign.bradfrost.com/chapter-2/). 71 | 72 | ## TODO 73 | 74 | - [x] styled components 75 | - [x] styled system 76 | - [ ] tests (Jest) 77 | 78 | ## Got questions or suggestions? 79 | Simply reach through [our website](https://heartbeat.ua/lets-talk) 80 | 81 | ## License 82 | 83 | MIT. 84 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pulse-boilerplate", 3 | "version": "1.1.0", 4 | "description": "React based boilerplate for creating scalable and well documented Design Systems.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "dev": "cross-env NODE_ENV=development webpack-dev-server --mode development --inline --hot --progress --config webpack/webpack.config.babel.js", 8 | "guide": "cross-env NODE_ENV=development webpack-dev-server --mode development --inline --hot --progress --config webpack/webpack.config.guide.babel.js", 9 | "build": "cross-env NODE_ENV=production webpack --mode production --progress --config webpack/webpack.config.babel.js", 10 | "guide:build": "cross-env NODE_ENV=production webpack --mode production --progress --config webpack/webpack.config.guide.babel.js", 11 | "eslint": "eslint src styleguide webpack", 12 | "staged": "node_modules/.bin/lint-staged" 13 | }, 14 | "author": "Heartbeat agency", 15 | "license": "MIT", 16 | "devDependencies": { 17 | "@babel/cli": "^7.5.5", 18 | "@babel/core": "^7.5.5", 19 | "@babel/plugin-proposal-class-properties": "^7.5.5", 20 | "@babel/plugin-syntax-dynamic-import": "^7.2.0", 21 | "@babel/preset-env": "^7.5.5", 22 | "@babel/preset-react": "^7.0.0", 23 | "@babel/register": "^7.5.5", 24 | "@hot-loader/react-dom": "^16.8.6", 25 | "babel-eslint": "^10.0.2", 26 | "babel-loader": "^8.0.6", 27 | "babel-plugin-react-docgen": "^3.1.0", 28 | "babel-plugin-styled-components": "^1.10.0", 29 | "clean-webpack-plugin": "^2.0.2", 30 | "copy-webpack-plugin": "^5.0.3", 31 | "cross-env": "^5.2.0", 32 | "css-loader": "^2.1.1", 33 | "eslint": "^5.16.0", 34 | "eslint-config-airbnb": "^17.1.1", 35 | "eslint-config-prettier": "^4.3.0", 36 | "eslint-plugin-import": "^2.18.2", 37 | "eslint-plugin-jsx-a11y": "^6.2.3", 38 | "eslint-plugin-prettier": "^3.1.0", 39 | "eslint-plugin-react": "^7.14.2", 40 | "file-loader": "^3.0.1", 41 | "html-loader": "^0.5.5", 42 | "html-webpack-plugin": "^3.2.0", 43 | "husky": "^2.3.0", 44 | "lint-staged": "^8.1.7", 45 | "mini-css-extract-plugin": "^0.6.0", 46 | "optimize-css-assets-webpack-plugin": "^5.0.3", 47 | "prettier": "^1.18.2", 48 | "style-loader": "^0.23.1", 49 | "terser-webpack-plugin": "^1.3.0", 50 | "url-loader": "^1.1.2", 51 | "webpack": "^4.36.1", 52 | "webpack-cli": "^3.3.6", 53 | "webpack-dev-server": "^3.7.2", 54 | "webpack-merge": "^4.2.1" 55 | }, 56 | "dependencies": { 57 | "@mdx-js/loader": "^1.1.0", 58 | "@mdx-js/react": "^1.0.27", 59 | "clean-tag": "2.0.3", 60 | "lodash": "^4.17.15", 61 | "path-parse": "^1.0.6", 62 | "prop-types": "^15.7.2", 63 | "react": "^16.8.6", 64 | "react-dom": "^16.8.6", 65 | "react-highlight": "^0.12.0", 66 | "react-hot-loader": "^4.12.8", 67 | "react-live": "^2.1.2", 68 | "react-router-dom": "^5.0.1", 69 | "styled-components": "^4.2.0", 70 | "styled-system": "^4.2.2" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heartbeatua/Pulse-Boilerplate/57647172b1a1041cd8731c2802a3989eb1aaab3e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Pulse Boilerplate 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/assets/css/base.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | html { 6 | -webkit-tap-highlight-color: transparent; 7 | } 8 | 9 | body { 10 | -webkit-font-smoothing: antialiased; 11 | -moz-osx-font-smoothing: grayscale; 12 | } 13 | 14 | img { 15 | vertical-align: middle; 16 | } 17 | 18 | button, 19 | textarea, 20 | input { 21 | font: inherit; 22 | color: inherit; 23 | } 24 | -------------------------------------------------------------------------------- /src/assets/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in iOS. 9 | */ 10 | 11 | html { 12 | line-height: 1.15; /* 1 */ 13 | -webkit-text-size-adjust: 100%; /* 2 */ 14 | } 15 | 16 | /* Sections 17 | ========================================================================== */ 18 | 19 | /** 20 | * Remove the margin in all browsers. 21 | */ 22 | 23 | body { 24 | margin: 0; 25 | } 26 | 27 | /** 28 | * Render the `main` element consistently in IE. 29 | */ 30 | 31 | main { 32 | display: block; 33 | } 34 | 35 | /** 36 | * Correct the font size and margin on `h1` elements within `section` and 37 | * `article` contexts in Chrome, Firefox, and Safari. 38 | */ 39 | 40 | h1 { 41 | font-size: 2em; 42 | margin: 0.67em 0; 43 | } 44 | 45 | /* Grouping content 46 | ========================================================================== */ 47 | 48 | /** 49 | * 1. Add the correct box sizing in Firefox. 50 | * 2. Show the overflow in Edge and IE. 51 | */ 52 | 53 | hr { 54 | box-sizing: content-box; /* 1 */ 55 | height: 0; /* 1 */ 56 | overflow: visible; /* 2 */ 57 | } 58 | 59 | /** 60 | * 1. Correct the inheritance and scaling of font size in all browsers. 61 | * 2. Correct the odd `em` font sizing in all browsers. 62 | */ 63 | 64 | pre { 65 | font-family: monospace, monospace; /* 1 */ 66 | font-size: 1em; /* 2 */ 67 | } 68 | 69 | /* Text-level semantics 70 | ========================================================================== */ 71 | 72 | /** 73 | * Remove the gray background on active links in IE 10. 74 | */ 75 | 76 | a { 77 | background-color: transparent; 78 | } 79 | 80 | /** 81 | * 1. Remove the bottom border in Chrome 57- 82 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 83 | */ 84 | 85 | abbr[title] { 86 | border-bottom: none; /* 1 */ 87 | text-decoration: underline; /* 2 */ 88 | text-decoration: underline dotted; /* 2 */ 89 | } 90 | 91 | /** 92 | * Add the correct font weight in Chrome, Edge, and Safari. 93 | */ 94 | 95 | b, 96 | strong { 97 | font-weight: bolder; 98 | } 99 | 100 | /** 101 | * 1. Correct the inheritance and scaling of font size in all browsers. 102 | * 2. Correct the odd `em` font sizing in all browsers. 103 | */ 104 | 105 | code, 106 | kbd, 107 | samp { 108 | font-family: monospace, monospace; /* 1 */ 109 | font-size: 1em; /* 2 */ 110 | } 111 | 112 | /** 113 | * Add the correct font size in all browsers. 114 | */ 115 | 116 | small { 117 | font-size: 80%; 118 | } 119 | 120 | /** 121 | * Prevent `sub` and `sup` elements from affecting the line height in 122 | * all browsers. 123 | */ 124 | 125 | sub, 126 | sup { 127 | font-size: 75%; 128 | line-height: 0; 129 | position: relative; 130 | vertical-align: baseline; 131 | } 132 | 133 | sub { 134 | bottom: -0.25em; 135 | } 136 | 137 | sup { 138 | top: -0.5em; 139 | } 140 | 141 | /* Embedded content 142 | ========================================================================== */ 143 | 144 | /** 145 | * Remove the border on images inside links in IE 10. 146 | */ 147 | 148 | img { 149 | border-style: none; 150 | } 151 | 152 | /* Forms 153 | ========================================================================== */ 154 | 155 | /** 156 | * 1. Change the font styles in all browsers. 157 | * 2. Remove the margin in Firefox and Safari. 158 | */ 159 | 160 | button, 161 | input, 162 | optgroup, 163 | select, 164 | textarea { 165 | font-family: inherit; /* 1 */ 166 | font-size: 100%; /* 1 */ 167 | line-height: 1.15; /* 1 */ 168 | margin: 0; /* 2 */ 169 | } 170 | 171 | /** 172 | * Show the overflow in IE. 173 | * 1. Show the overflow in Edge. 174 | */ 175 | 176 | button, 177 | input { /* 1 */ 178 | overflow: visible; 179 | } 180 | 181 | /** 182 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 183 | * 1. Remove the inheritance of text transform in Firefox. 184 | */ 185 | 186 | button, 187 | select { /* 1 */ 188 | text-transform: none; 189 | } 190 | 191 | /** 192 | * Correct the inability to style clickable types in iOS and Safari. 193 | */ 194 | 195 | button, 196 | [type="button"], 197 | [type="reset"], 198 | [type="submit"] { 199 | -webkit-appearance: button; 200 | } 201 | 202 | /** 203 | * Remove the inner border and padding in Firefox. 204 | */ 205 | 206 | button::-moz-focus-inner, 207 | [type="button"]::-moz-focus-inner, 208 | [type="reset"]::-moz-focus-inner, 209 | [type="submit"]::-moz-focus-inner { 210 | border-style: none; 211 | padding: 0; 212 | } 213 | 214 | /** 215 | * Restore the focus styles unset by the previous rule. 216 | */ 217 | 218 | button:-moz-focusring, 219 | [type="button"]:-moz-focusring, 220 | [type="reset"]:-moz-focusring, 221 | [type="submit"]:-moz-focusring { 222 | outline: 1px dotted ButtonText; 223 | } 224 | 225 | /** 226 | * Correct the padding in Firefox. 227 | */ 228 | 229 | fieldset { 230 | padding: 0.35em 0.75em 0.625em; 231 | } 232 | 233 | /** 234 | * 1. Correct the text wrapping in Edge and IE. 235 | * 2. Correct the color inheritance from `fieldset` elements in IE. 236 | * 3. Remove the padding so developers are not caught out when they zero out 237 | * `fieldset` elements in all browsers. 238 | */ 239 | 240 | legend { 241 | box-sizing: border-box; /* 1 */ 242 | color: inherit; /* 2 */ 243 | display: table; /* 1 */ 244 | max-width: 100%; /* 1 */ 245 | padding: 0; /* 3 */ 246 | white-space: normal; /* 1 */ 247 | } 248 | 249 | /** 250 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 251 | */ 252 | 253 | progress { 254 | vertical-align: baseline; 255 | } 256 | 257 | /** 258 | * Remove the default vertical scrollbar in IE 10+. 259 | */ 260 | 261 | textarea { 262 | overflow: auto; 263 | } 264 | 265 | /** 266 | * 1. Add the correct box sizing in IE 10. 267 | * 2. Remove the padding in IE 10. 268 | */ 269 | 270 | [type="checkbox"], 271 | [type="radio"] { 272 | box-sizing: border-box; /* 1 */ 273 | padding: 0; /* 2 */ 274 | } 275 | 276 | /** 277 | * Correct the cursor style of increment and decrement buttons in Chrome. 278 | */ 279 | 280 | [type="number"]::-webkit-inner-spin-button, 281 | [type="number"]::-webkit-outer-spin-button { 282 | height: auto; 283 | } 284 | 285 | /** 286 | * 1. Correct the odd appearance in Chrome and Safari. 287 | * 2. Correct the outline style in Safari. 288 | */ 289 | 290 | [type="search"] { 291 | -webkit-appearance: textfield; /* 1 */ 292 | outline-offset: -2px; /* 2 */ 293 | } 294 | 295 | /** 296 | * Remove the inner padding in Chrome and Safari on macOS. 297 | */ 298 | 299 | [type="search"]::-webkit-search-decoration { 300 | -webkit-appearance: none; 301 | } 302 | 303 | /** 304 | * 1. Correct the inability to style clickable types in iOS and Safari. 305 | * 2. Change font properties to `inherit` in Safari. 306 | */ 307 | 308 | ::-webkit-file-upload-button { 309 | -webkit-appearance: button; /* 1 */ 310 | font: inherit; /* 2 */ 311 | } 312 | 313 | /* Interactive 314 | ========================================================================== */ 315 | 316 | /* 317 | * Add the correct display in Edge, IE 10+, and Firefox. 318 | */ 319 | 320 | details { 321 | display: block; 322 | } 323 | 324 | /* 325 | * Add the correct display in all browsers. 326 | */ 327 | 328 | summary { 329 | display: list-item; 330 | } 331 | 332 | /* Misc 333 | ========================================================================== */ 334 | 335 | /** 336 | * Add the correct display in IE 10+. 337 | */ 338 | 339 | template { 340 | display: none; 341 | } 342 | 343 | /** 344 | * Add the correct display in IE 10. 345 | */ 346 | 347 | [hidden] { 348 | display: none; 349 | } 350 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { BrowserRouter, Switch, Route } from 'react-router-dom'; 3 | import { hot } from 'react-hot-loader/root'; 4 | import { ThemeProvider } from 'styled-components'; 5 | import theme from '../theme'; 6 | import HomePage from './pages/HomePage'; 7 | import '../assets/css/normalize.css'; 8 | import '../assets/css/base.css'; 9 | 10 | const App = () => ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | 20 | export default hot(App); 21 | -------------------------------------------------------------------------------- /src/components/atoms/Box/Box.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import tag from 'clean-tag'; 4 | import { 5 | space, 6 | width, 7 | fontSize, 8 | color, 9 | fontFamily, 10 | textAlign, 11 | lineHeight, 12 | fontWeight, 13 | fontStyle, 14 | letterSpacing, 15 | display, 16 | maxWidth, 17 | minWidth, 18 | height, 19 | maxHeight, 20 | minHeight, 21 | verticalAlign, 22 | alignItems, 23 | justifyContent, 24 | flexWrap, 25 | flexDirection, 26 | flex, 27 | alignContent, 28 | justifyItems, 29 | justifySelf, 30 | alignSelf, 31 | order, 32 | flexBasis, 33 | gridGap, 34 | gridRowGap, 35 | gridColumnGap, 36 | gridColumn, 37 | gridRow, 38 | gridArea, 39 | gridAutoFlow, 40 | gridAutoRows, 41 | gridAutoColumns, 42 | gridTemplateRows, 43 | gridTemplateColumns, 44 | gridTemplateAreas, 45 | background, 46 | backgroundImage, 47 | backgroundSize, 48 | backgroundPosition, 49 | backgroundRepeat, 50 | borderRadius, 51 | borderColor, 52 | borders, 53 | boxShadow, 54 | opacity, 55 | overflow, 56 | position, 57 | zIndex, 58 | top, 59 | right, 60 | bottom, 61 | left, 62 | textStyle, 63 | colorStyle, 64 | buttonStyle, 65 | } from 'styled-system'; 66 | 67 | const StyledBox = styled(tag)` 68 | ${space}; 69 | ${width}; 70 | ${fontSize}; 71 | ${color}; 72 | ${fontFamily}; 73 | ${textAlign}; 74 | ${lineHeight}; 75 | ${fontWeight}; 76 | ${fontStyle}; 77 | ${letterSpacing}; 78 | ${display}; 79 | ${maxWidth}; 80 | ${minWidth}; 81 | ${height}; 82 | ${maxHeight}; 83 | ${minHeight}; 84 | ${verticalAlign}; 85 | ${alignItems}; 86 | ${justifyContent}; 87 | ${flexWrap}; 88 | ${flexDirection}; 89 | ${flex}; 90 | ${alignContent}; 91 | ${justifyItems}; 92 | ${justifySelf}; 93 | ${alignSelf}; 94 | ${order}; 95 | ${flexBasis}; 96 | ${gridGap}; 97 | ${gridRowGap}; 98 | ${gridColumnGap}; 99 | ${gridColumn}; 100 | ${gridRow}; 101 | ${gridArea}; 102 | ${gridAutoFlow}; 103 | ${gridAutoRows}; 104 | ${gridAutoColumns}; 105 | ${gridTemplateRows}; 106 | ${gridTemplateColumns}; 107 | ${gridTemplateAreas}; 108 | ${background}; 109 | ${backgroundImage}; 110 | ${backgroundSize}; 111 | ${backgroundPosition}; 112 | ${backgroundRepeat}; 113 | ${borderRadius}; 114 | ${borderColor}; 115 | ${borders}; 116 | ${boxShadow}; 117 | ${opacity}; 118 | ${overflow}; 119 | ${position}; 120 | ${zIndex}; 121 | ${top}; 122 | ${right}; 123 | ${bottom}; 124 | ${left}; 125 | ${textStyle}; 126 | ${colorStyle}; 127 | ${buttonStyle}; 128 | `; 129 | 130 | const Box = props => ; 131 | 132 | Box.propTypes = { 133 | ...space.propTypes, 134 | ...width.propTypes, 135 | ...fontSize.propTypes, 136 | ...color.propTypes, 137 | ...fontFamily.propTypes, 138 | ...textAlign.propTypes, 139 | ...lineHeight.propTypes, 140 | ...fontWeight.propTypes, 141 | ...fontStyle.propTypes, 142 | ...letterSpacing.propTypes, 143 | ...display.propTypes, 144 | ...maxWidth.propTypes, 145 | ...minWidth.propTypes, 146 | ...height.propTypes, 147 | ...maxHeight.propTypes, 148 | ...minHeight.propTypes, 149 | ...verticalAlign.propTypes, 150 | ...alignItems.propTypes, 151 | ...justifyContent.propTypes, 152 | ...flexWrap.propTypes, 153 | ...flexDirection.propTypes, 154 | ...flex.propTypes, 155 | ...alignContent.propTypes, 156 | ...justifyItems.propTypes, 157 | ...justifySelf.propTypes, 158 | ...alignSelf.propTypes, 159 | ...order.propTypes, 160 | ...flexBasis.propTypes, 161 | ...gridGap.propTypes, 162 | ...gridRowGap.propTypes, 163 | ...gridColumnGap.propTypes, 164 | ...gridColumn.propTypes, 165 | ...gridRow.propTypes, 166 | ...gridArea.propTypes, 167 | ...gridAutoFlow.propTypes, 168 | ...gridAutoRows.propTypes, 169 | ...gridAutoColumns.propTypes, 170 | ...gridTemplateRows.propTypes, 171 | ...gridTemplateColumns.propTypes, 172 | ...gridTemplateAreas.propTypes, 173 | ...background.propTypes, 174 | ...backgroundImage.propTypes, 175 | ...backgroundSize.propTypes, 176 | ...backgroundPosition.propTypes, 177 | ...backgroundRepeat.propTypes, 178 | ...borderRadius.propTypes, 179 | ...borderColor.propTypes, 180 | ...borders.propTypes, 181 | ...boxShadow.propTypes, 182 | ...opacity.propTypes, 183 | ...overflow.propTypes, 184 | ...position.propTypes, 185 | ...zIndex.propTypes, 186 | ...top.propTypes, 187 | ...right.propTypes, 188 | ...bottom.propTypes, 189 | ...left.propTypes, 190 | ...textStyle.propTypes, 191 | ...colorStyle.propTypes, 192 | ...buttonStyle.propTypes, 193 | }; 194 | 195 | export default Box; 196 | -------------------------------------------------------------------------------- /src/components/atoms/Box/index.js: -------------------------------------------------------------------------------- 1 | import Box from './Box'; 2 | 3 | export default Box; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Button/Button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled, { css } from 'styled-components'; 4 | import { NavLink } from 'react-router-dom'; 5 | import { space, display, maxWidth, fontSize, themeGet } from 'styled-system'; 6 | 7 | const width = ({ wide }) => wide === 'true' && '100%'; 8 | const cursor = ({ disabled }) => (disabled ? 'not-allowed' : 'pointer'); 9 | const opacity = ({ disabled }) => disabled && '0.65'; 10 | const btnBg = ({ color, skin }) => 11 | themeGet(skin === 'outline' ? `colors.white` : `colors.${color}`); 12 | const btnColor = ({ color, skin }) => 13 | themeGet(skin === 'fill' ? `colors.white` : `colors.${color}`); 14 | 15 | const styles = css` 16 | ${display}; 17 | vertical-align: middle; 18 | text-align: center; 19 | text-decoration: none; 20 | touch-action: manipulation; 21 | outline: none; 22 | user-select: none; 23 | transition: 0.1s ease; 24 | border-radius: 0; 25 | text-transform: lowercase; 26 | width: ${width}; 27 | cursor: ${cursor}; 28 | opacity: ${opacity}; 29 | color: ${btnColor}; 30 | background: ${btnBg}; 31 | padding: 10px 23px; 32 | line-height: 1.5; 33 | ${space}; 34 | ${fontSize}; 35 | ${maxWidth}; 36 | border: 1px solid ${({ color }) => themeGet(`colors.${color}`)}; 37 | ${({ disabled }) => 38 | !disabled && 39 | css` 40 | &:hover { 41 | border-color: ${themeGet('colors.black')}; 42 | background: ${({ color, skin }) => 43 | themeGet( 44 | color === 'black' && skin === 'fill' 45 | ? 'colors.white' 46 | : 'colors.black', 47 | )}; 48 | color: ${({ color, skin }) => 49 | themeGet( 50 | color === 'black' && skin === 'fill' 51 | ? 'colors.black' 52 | : 'colors.white', 53 | )}; 54 | } 55 | `}; 56 | `; 57 | 58 | const StyledNavLink = styled(NavLink)` 59 | ${styles}; 60 | `; 61 | const StyledLink = styled.a` 62 | ${styles}; 63 | `; 64 | const StyledButton = styled.button` 65 | ${styles}; 66 | `; 67 | 68 | const Button = ({ to, href, type, wide, disabled, ...rest }) => { 69 | const isWide = wide.toString(); 70 | const DefaultBtn = ( 71 | 72 | ); 73 | if (disabled) { 74 | return DefaultBtn; 75 | } 76 | if (to) { 77 | return ; 78 | } 79 | if (href) { 80 | return ( 81 | 88 | ); 89 | } 90 | return DefaultBtn; 91 | }; 92 | 93 | Button.propTypes = { 94 | color: PropTypes.oneOf(['brand', 'cta', 'black']), 95 | skin: PropTypes.oneOf(['fill', 'outline']), 96 | wide: PropTypes.bool, 97 | disabled: PropTypes.bool, 98 | type: PropTypes.oneOf(['submit', 'button']), 99 | display: PropTypes.string, 100 | fontSize: PropTypes.string, 101 | ...space.propTypes, 102 | ...maxWidth.propTypes, 103 | }; 104 | 105 | Button.defaultProps = { 106 | color: 'black', 107 | skin: 'fill', 108 | type: 'button', 109 | display: 'inline-block', 110 | fontSize: 's', 111 | disabled: false, 112 | wide: false, 113 | }; 114 | 115 | export default Button; 116 | -------------------------------------------------------------------------------- /src/components/atoms/Button/index.js: -------------------------------------------------------------------------------- 1 | import Button from './Button'; 2 | 3 | export default Button; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Col/Col.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import PropTypes from 'prop-types'; 4 | import { style, top } from 'styled-system'; 5 | import ColBox from '../ColBox'; 6 | 7 | const flex = style({ 8 | prop: 'width', 9 | cssProperty: 'flex', 10 | transformValue(n) { 11 | switch (n) { 12 | case 'auto': 13 | return '1 1 0%'; 14 | case 'contains': 15 | return '0 0 auto'; 16 | default: 17 | return `0 0 ${n * 100}%;`; 18 | } 19 | }, 20 | }); 21 | 22 | const StyledCol = styled(ColBox)` 23 | position: relative; 24 | ${flex}; 25 | ${top}; 26 | padding-left: ${({ gap }) => (gap ? `${gap / 2}px` : null)}; 27 | padding-right: ${({ gap }) => (gap ? `${gap / 2}px` : null)}; 28 | `; 29 | 30 | const Col = props => ; 31 | 32 | Col.propTypes = { 33 | width: PropTypes.oneOfType([ 34 | PropTypes.array, 35 | PropTypes.number, 36 | PropTypes.string, 37 | ]), 38 | ...ColBox.propTypes, 39 | }; 40 | 41 | Col.defaultProps = { 42 | width: 'auto', 43 | }; 44 | 45 | export default Col; 46 | -------------------------------------------------------------------------------- /src/components/atoms/Col/index.js: -------------------------------------------------------------------------------- 1 | import Col from './Col'; 2 | 3 | export default Col; 4 | -------------------------------------------------------------------------------- /src/components/atoms/ColBox/ColBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { 4 | space, 5 | fontSize, 6 | color, 7 | fontFamily, 8 | textAlign, 9 | lineHeight, 10 | fontWeight, 11 | fontStyle, 12 | letterSpacing, 13 | display, 14 | maxWidth, 15 | minWidth, 16 | height, 17 | maxHeight, 18 | minHeight, 19 | size, 20 | verticalAlign, 21 | alignItems, 22 | justifyContent, 23 | flexWrap, 24 | flexDirection, 25 | flex, 26 | alignContent, 27 | justifyItems, 28 | justifySelf, 29 | alignSelf, 30 | order, 31 | flexBasis, 32 | gridGap, 33 | gridRowGap, 34 | gridColumnGap, 35 | gridColumn, 36 | gridRow, 37 | gridArea, 38 | gridAutoFlow, 39 | gridAutoRows, 40 | gridAutoColumns, 41 | gridTemplateRows, 42 | gridTemplateColumns, 43 | gridTemplateAreas, 44 | background, 45 | backgroundImage, 46 | backgroundSize, 47 | backgroundPosition, 48 | backgroundRepeat, 49 | borderRadius, 50 | borderColor, 51 | borders, 52 | boxShadow, 53 | opacity, 54 | overflow, 55 | position, 56 | zIndex, 57 | top, 58 | right, 59 | bottom, 60 | left, 61 | textStyle, 62 | colorStyle, 63 | buttonStyle, 64 | } from 'styled-system'; 65 | 66 | const StyledBox = styled.div` 67 | ${space}; 68 | ${fontSize}; 69 | ${color}; 70 | ${fontFamily}; 71 | ${textAlign}; 72 | ${lineHeight}; 73 | ${fontWeight}; 74 | ${fontStyle}; 75 | ${letterSpacing}; 76 | ${display}; 77 | ${maxWidth}; 78 | ${minWidth}; 79 | ${height}; 80 | ${maxHeight}; 81 | ${minHeight}; 82 | ${size}; 83 | ${verticalAlign}; 84 | ${alignItems}; 85 | ${justifyContent}; 86 | ${flexWrap}; 87 | ${flexDirection}; 88 | ${flex}; 89 | ${alignContent}; 90 | ${justifyItems}; 91 | ${justifySelf}; 92 | ${alignSelf}; 93 | ${order}; 94 | ${flexBasis}; 95 | ${gridGap}; 96 | ${gridRowGap}; 97 | ${gridColumnGap}; 98 | ${gridColumn}; 99 | ${gridRow}; 100 | ${gridArea}; 101 | ${gridAutoFlow}; 102 | ${gridAutoRows}; 103 | ${gridAutoColumns}; 104 | ${gridTemplateRows}; 105 | ${gridTemplateColumns}; 106 | ${gridTemplateAreas}; 107 | ${background}; 108 | ${backgroundImage}; 109 | ${backgroundSize}; 110 | ${backgroundPosition}; 111 | ${backgroundRepeat}; 112 | ${borderRadius}; 113 | ${borders}; 114 | ${borderColor}; 115 | ${boxShadow}; 116 | ${opacity}; 117 | ${overflow}; 118 | ${position}; 119 | ${zIndex}; 120 | ${top}; 121 | ${right}; 122 | ${bottom}; 123 | ${left}; 124 | ${textStyle}; 125 | ${colorStyle}; 126 | ${buttonStyle}; 127 | `; 128 | 129 | const ColBox = props => ; 130 | 131 | ColBox.propTypes = { 132 | ...space.propTypes, 133 | ...fontSize.propTypes, 134 | ...color.propTypes, 135 | ...fontFamily.propTypes, 136 | ...textAlign.propTypes, 137 | ...lineHeight.propTypes, 138 | ...fontWeight.propTypes, 139 | ...fontStyle.propTypes, 140 | ...letterSpacing.propTypes, 141 | ...display.propTypes, 142 | ...maxWidth.propTypes, 143 | ...minWidth.propTypes, 144 | ...height.propTypes, 145 | ...maxHeight.propTypes, 146 | ...minHeight.propTypes, 147 | ...size.propTypes, 148 | ...verticalAlign.propTypes, 149 | ...alignItems.propTypes, 150 | ...justifyContent.propTypes, 151 | ...flexWrap.propTypes, 152 | ...flexDirection.propTypes, 153 | ...flex.propTypes, 154 | ...alignContent.propTypes, 155 | ...justifyItems.propTypes, 156 | ...justifySelf.propTypes, 157 | ...alignSelf.propTypes, 158 | ...order.propTypes, 159 | ...flexBasis.propTypes, 160 | ...gridGap.propTypes, 161 | ...gridRowGap.propTypes, 162 | ...gridColumnGap.propTypes, 163 | ...gridColumn.propTypes, 164 | ...gridRow.propTypes, 165 | ...gridArea.propTypes, 166 | ...gridAutoFlow.propTypes, 167 | ...gridAutoRows.propTypes, 168 | ...gridAutoColumns.propTypes, 169 | ...gridTemplateRows.propTypes, 170 | ...gridTemplateColumns.propTypes, 171 | ...gridTemplateAreas.propTypes, 172 | ...background.propTypes, 173 | ...backgroundImage.propTypes, 174 | ...backgroundSize.propTypes, 175 | ...backgroundPosition.propTypes, 176 | ...backgroundRepeat.propTypes, 177 | ...borderRadius.propTypes, 178 | ...borderColor.propTypes, 179 | ...borders.propTypes, 180 | ...boxShadow.propTypes, 181 | ...opacity.propTypes, 182 | ...overflow.propTypes, 183 | ...position.propTypes, 184 | ...zIndex.propTypes, 185 | ...top.propTypes, 186 | ...right.propTypes, 187 | ...bottom.propTypes, 188 | ...left.propTypes, 189 | ...textStyle.propTypes, 190 | ...colorStyle.propTypes, 191 | ...buttonStyle.propTypes, 192 | }; 193 | 194 | export default ColBox; 195 | -------------------------------------------------------------------------------- /src/components/atoms/ColBox/index.js: -------------------------------------------------------------------------------- 1 | import ColBox from './ColBox'; 2 | 3 | export default ColBox; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Container/Container.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import Box from '../Box'; 5 | 6 | const StyledContainer = styled(Box)` 7 | position: relative; 8 | box-sizing: content-box; 9 | `; 10 | 11 | const Container = props => ; 12 | 13 | Container.propTypes = { 14 | pl: PropTypes.oneOfType([ 15 | PropTypes.array, 16 | PropTypes.number, 17 | PropTypes.string, 18 | ]), 19 | pr: PropTypes.oneOfType([ 20 | PropTypes.array, 21 | PropTypes.number, 22 | PropTypes.string, 23 | ]), 24 | mx: PropTypes.oneOfType([ 25 | PropTypes.array, 26 | PropTypes.number, 27 | PropTypes.string, 28 | ]), 29 | maxWidth: PropTypes.oneOfType([ 30 | PropTypes.array, 31 | PropTypes.number, 32 | PropTypes.string, 33 | ]), 34 | ...Box.propTypes, 35 | }; 36 | 37 | Container.defaultProps = { 38 | pl: 's', 39 | pr: 's', 40 | mx: 'auto', 41 | maxWidth: 'l', 42 | }; 43 | 44 | export default Container; 45 | -------------------------------------------------------------------------------- /src/components/atoms/Container/index.js: -------------------------------------------------------------------------------- 1 | import Container from './Container'; 2 | 3 | export default Container; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Divider/Divider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Box from '../Box'; 4 | 5 | const Divider = props => ; 6 | 7 | Divider.propTypes = { 8 | bg: PropTypes.string, 9 | height: PropTypes.oneOfType([ 10 | PropTypes.string, 11 | PropTypes.number, 12 | PropTypes.array, 13 | ]), 14 | width: PropTypes.oneOfType([ 15 | PropTypes.string, 16 | PropTypes.number, 17 | PropTypes.array, 18 | ]), 19 | ...Box.propTypes, 20 | }; 21 | 22 | Divider.defaultProps = { 23 | bg: 'grayscale.400', 24 | width: 'auto', 25 | height: '1px', 26 | }; 27 | 28 | export default Divider; 29 | -------------------------------------------------------------------------------- /src/components/atoms/Divider/index.js: -------------------------------------------------------------------------------- 1 | import Divider from './Divider'; 2 | 3 | export default Divider; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Flex/Flex.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Box from '../Box'; 4 | 5 | const Flex = props => ; 6 | 7 | Flex.propTypes = { 8 | display: PropTypes.string, 9 | ...Box.propTypes, 10 | }; 11 | Flex.defaultProps = { 12 | display: 'flex', 13 | }; 14 | 15 | export default Flex; 16 | -------------------------------------------------------------------------------- /src/components/atoms/Flex/index.js: -------------------------------------------------------------------------------- 1 | import Flex from './Flex'; 2 | 3 | export default Flex; 4 | -------------------------------------------------------------------------------- /src/components/atoms/InputField/InputField.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { width, height, themeGet, space } from 'styled-system'; 5 | import tag from 'clean-tag'; 6 | 7 | const StyledInput = styled(tag.input)` 8 | ${width}; 9 | ${height}; 10 | ${space}; 11 | display: inline-block; 12 | vertical-align: middle; 13 | border: 0; 14 | padding: 0; 15 | border-bottom: 1px solid; 16 | background: ${themeGet('colors.white')}; 17 | outline: 0; 18 | -webkit-appearance: none; 19 | border-radius: 0; 20 | line-height: normal; 21 | font-size: ${themeGet('fontSizes.m')}px; 22 | `; 23 | 24 | const InputField = props => ; 25 | 26 | InputField.propTypes = { 27 | width: PropTypes.oneOfType([ 28 | PropTypes.array, 29 | PropTypes.number, 30 | PropTypes.string, 31 | ]), 32 | height: PropTypes.string, 33 | }; 34 | InputField.defaultProps = { 35 | width: '100%', 36 | height: '42px', 37 | }; 38 | 39 | export default InputField; 40 | -------------------------------------------------------------------------------- /src/components/atoms/InputField/index.js: -------------------------------------------------------------------------------- 1 | import InputField from './InputField'; 2 | 3 | export default InputField; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Link/Link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled, { css } from 'styled-components'; 3 | import PropTypes from 'prop-types'; 4 | import { NavLink } from 'react-router-dom'; 5 | import { color, space, display, width, height, borders } from 'styled-system'; 6 | 7 | const styles = css` 8 | ${({ underline }) => underline && `border-bottom: ${underline}px solid`}; 9 | ${({ underline }) => 10 | underline && 11 | css` 12 | &:hover { 13 | border-bottom-color: transparent; 14 | } 15 | `}; 16 | cursor: pointer; 17 | text-decoration: none; 18 | ${space}; 19 | ${color}; 20 | ${display}; 21 | ${width}; 22 | ${height}; 23 | ${borders}; 24 | `; 25 | 26 | const StyledLink = styled.a` 27 | ${styles}; 28 | `; 29 | const StyledNavLink = styled(NavLink)` 30 | ${styles}; 31 | `; 32 | 33 | const Link = ({ to, href, ...rest }) => { 34 | if (to) { 35 | return ; 36 | } 37 | if (href) { 38 | return ( 39 | 46 | ); 47 | } 48 | return ( 49 | 55 | ); 56 | }; 57 | 58 | Link.propTypes = { 59 | to: PropTypes.string, 60 | href: PropTypes.string, 61 | underline: PropTypes.number, 62 | color: PropTypes.string, 63 | ...space.propTypes, 64 | ...color.propTypes, 65 | ...display.propTypes, 66 | ...width.propTypes, 67 | ...height.propTypes, 68 | ...borders.propTypes, 69 | }; 70 | Link.defaultProps = { 71 | underline: 0, 72 | color: 'inherit', 73 | }; 74 | 75 | export default Link; 76 | -------------------------------------------------------------------------------- /src/components/atoms/Link/index.js: -------------------------------------------------------------------------------- 1 | import Link from './Link'; 2 | 3 | export default Link; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Row/Row.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import Box from '../Box'; 5 | import { space } from '../../../theme'; 6 | 7 | const StyledRow = styled(Box)` 8 | display: flex; 9 | flex-wrap: wrap; 10 | margin-left: ${({ gap }) => (gap ? `-${gap / 2}px` : null)}; 11 | margin-right: ${({ gap }) => (gap ? `-${gap / 2}px` : null)}; 12 | `; 13 | 14 | const Row = ({ children, ...rest }) => { 15 | const { gap } = rest; 16 | return ( 17 | 18 | {React.Children.map(children, child => 19 | React.cloneElement(child, { gap }), 20 | )} 21 | 22 | ); 23 | }; 24 | 25 | Row.propTypes = { 26 | children: PropTypes.node.isRequired, 27 | gap: PropTypes.number, 28 | ...Box.propTypes, 29 | }; 30 | 31 | Row.defaultProps = { 32 | gap: space.l, 33 | }; 34 | 35 | export default Row; 36 | -------------------------------------------------------------------------------- /src/components/atoms/Row/index.js: -------------------------------------------------------------------------------- 1 | import Row from './Row'; 2 | 3 | export default Row; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Text/Text.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Box from '../Box'; 4 | 5 | const Text = props => ; 6 | 7 | Text.propTypes = { 8 | as: PropTypes.string, 9 | fontSize: PropTypes.oneOfType([ 10 | PropTypes.string, 11 | PropTypes.array, 12 | PropTypes.number, 13 | ]), 14 | m: PropTypes.oneOfType([PropTypes.string, PropTypes.array, PropTypes.number]), 15 | ...Box.propTypes, 16 | }; 17 | Text.defaultProps = { 18 | as: 'p', 19 | m: '0 0 1.1em', 20 | }; 21 | 22 | export default Text; 23 | -------------------------------------------------------------------------------- /src/components/atoms/Text/index.js: -------------------------------------------------------------------------------- 1 | import Text from './Text'; 2 | 3 | export default Text; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Textarea/Textarea.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { themeGet, height, space } from 'styled-system'; 5 | import tag from 'clean-tag'; 6 | 7 | const StyledTextarea = styled(tag.textarea)` 8 | vertical-align: top; 9 | width: 100%; 10 | ${height}; 11 | ${space}; 12 | border: 0; 13 | border-bottom: 1px solid; 14 | background: ${themeGet('colors.white')}; 15 | outline: 0; 16 | -webkit-appearance: none; 17 | border-radius: 0; 18 | font-size: ${themeGet('fontSizes.m')}px; 19 | resize: none; 20 | `; 21 | 22 | const Textarea = props => ; 23 | 24 | Textarea.propTypes = { 25 | height: PropTypes.string, 26 | p: PropTypes.string, 27 | }; 28 | Textarea.defaultProps = { 29 | height: '120px', 30 | p: '13px 0', 31 | }; 32 | 33 | export default Textarea; 34 | -------------------------------------------------------------------------------- /src/components/atoms/Textarea/index.js: -------------------------------------------------------------------------------- 1 | import Textarea from './Textarea'; 2 | 3 | export default Textarea; 4 | -------------------------------------------------------------------------------- /src/components/atoms/Title/Title.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { 5 | themeGet, 6 | space, 7 | fontWeight, 8 | display, 9 | fontFamily, 10 | } from 'styled-system'; 11 | import tag from 'clean-tag'; 12 | 13 | const spaceDefault = ({ mb = 'l', mt = 0, m, ...rest }) => 14 | m === undefined ? { mt, mb, ...rest } : { m, ...rest }; 15 | 16 | const StyledTitle = styled(tag)` 17 | line-height: ${({ size }) => themeGet(`lineHeights.heading.${size}`)}; 18 | font-size: ${({ size }) => themeGet(`fontSizes.heading.${size}`)}px; 19 | ${props => space(spaceDefault(props))}; 20 | ${fontWeight}; 21 | ${display}; 22 | ${fontFamily}; 23 | `; 24 | 25 | const Title = props => ; 26 | 27 | Title.propTypes = { 28 | fontWeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), 29 | fontFamily: PropTypes.oneOf(['heading', 'bodyText']), 30 | as: PropTypes.oneOf(['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div']), 31 | size: PropTypes.oneOf(['h1', 'h2', 'h3', 'h4', 'h5']), 32 | ...space.propTypes, 33 | ...display.propTypes, 34 | }; 35 | Title.defaultProps = { 36 | as: 'h2', 37 | size: 'h2', 38 | fontWeight: 'bold', 39 | fontFamily: 'heading', 40 | }; 41 | 42 | export default Title; 43 | -------------------------------------------------------------------------------- /src/components/atoms/Title/index.js: -------------------------------------------------------------------------------- 1 | import Title from './Title'; 2 | 3 | export default Title; 4 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | import Box from './atoms/Box'; 2 | import Flex from './atoms/Flex'; 3 | import Link from './atoms/Link'; 4 | import Button from './atoms/Button'; 5 | import Divider from './atoms/Divider'; 6 | import Text from './atoms/Text'; 7 | import Title from './atoms/Title'; 8 | import Textarea from './atoms/Textarea'; 9 | import InputField from './atoms/InputField'; 10 | import Container from './atoms/Container'; 11 | import Row from './atoms/Row'; 12 | import Col from './atoms/Col'; 13 | import Card from './molecules/Card'; 14 | 15 | export { 16 | Box, 17 | Flex, 18 | Link, 19 | Button, 20 | Divider, 21 | Text, 22 | Title, 23 | Textarea, 24 | InputField, 25 | Container, 26 | Row, 27 | Col, 28 | Card, 29 | }; 30 | -------------------------------------------------------------------------------- /src/components/molecules/Card/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import { space } from 'styled-system'; 5 | import { pick, keys } from 'lodash'; 6 | import Title from '../../atoms/Title'; 7 | import Text from '../../atoms/Text'; 8 | import Box from '../../atoms/Box'; 9 | import Link from '../../atoms/Link'; 10 | 11 | const StyledCard = styled(Link)` 12 | display: block; 13 | height: 100%; 14 | transition: box-shadow 0.1s ease; 15 | &:hover { 16 | box-shadow: 0 0 0 6px; 17 | } 18 | `; 19 | 20 | const Card = ({ to, icon, title, text, name, border, ...rest }) => { 21 | // eslint-disable-next-line 22 | const spaces = pick(rest, keys(space.propTypes)); 23 | return ( 24 | 25 | {icon && ( 26 | 27 |
28 | 29 |
30 |
31 | )} 32 | 33 | {title} 34 | 35 | 42 |
43 | ); 44 | }; 45 | 46 | Card.propTypes = { 47 | border: PropTypes.string, 48 | p: PropTypes.string, 49 | to: PropTypes.string, 50 | icon: PropTypes.node, 51 | title: PropTypes.string, 52 | text: PropTypes.string, 53 | name: PropTypes.string, 54 | ...space.propTypes, 55 | }; 56 | 57 | Card.defaultProps = { 58 | border: '2px solid', 59 | p: '56px', 60 | }; 61 | 62 | export default Card; 63 | -------------------------------------------------------------------------------- /src/components/molecules/Card/index.js: -------------------------------------------------------------------------------- 1 | import Card from './Card'; 2 | 3 | export default Card; 4 | -------------------------------------------------------------------------------- /src/components/organisms/Header/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Header = () =>
Header
; 4 | 5 | export default Header; 6 | -------------------------------------------------------------------------------- /src/components/organisms/Header/index.js: -------------------------------------------------------------------------------- 1 | import Header from './Header'; 2 | 3 | export default Header; 4 | -------------------------------------------------------------------------------- /src/components/pages/HomePage/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import BaseTemplate from '../../templates/BaseTemplate'; 3 | import Header from '../../organisms/Header'; 4 | 5 | export default () => }>Home page; 6 | -------------------------------------------------------------------------------- /src/components/pages/HomePage/index.js: -------------------------------------------------------------------------------- 1 | import HomePage from './HomePage'; 2 | 3 | export default HomePage; 4 | -------------------------------------------------------------------------------- /src/components/templates/BaseTemplate/BaseTemplate.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | 5 | const Wrapper = styled.div``; 6 | 7 | const BaseTemplate = ({ header, children }) => ( 8 | 9 | {header} 10 | {children} 11 | 12 | ); 13 | 14 | BaseTemplate.propTypes = { 15 | header: PropTypes.node, 16 | children: PropTypes.node, 17 | }; 18 | 19 | export default BaseTemplate; 20 | -------------------------------------------------------------------------------- /src/components/templates/BaseTemplate/index.js: -------------------------------------------------------------------------------- 1 | import BaseTemplate from './BaseTemplate'; 2 | 3 | export default BaseTemplate; 4 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import App from './components/App'; 4 | 5 | render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /src/theme.js: -------------------------------------------------------------------------------- 1 | const colors = { 2 | black: '#191919', 3 | white: '#fff', 4 | brand: '#62e6ac', 5 | cta: '#ff8c5f', 6 | link: '#1755b7', 7 | error: '#ff4d4d', 8 | success: '#75de50', 9 | grayscale: { 10 | 300: '#e3e3e3', 11 | 400: '#d2d2d2', 12 | 600: '#a3a3a3', 13 | 800: '#7d7d7d', 14 | }, 15 | }; 16 | 17 | const fonts = { 18 | heading: "'Josefin Sans', sans-serif", 19 | bodyText: "'Open Sans', sans-serif", 20 | }; 21 | 22 | const fontSizes = { 23 | xs: 14, 24 | s: 16, 25 | m: 18, 26 | l: 20, 27 | heading: { 28 | h1: 182, 29 | h2: 101, 30 | h3: 79, 31 | h4: 47, 32 | h5: 29, 33 | }, 34 | }; 35 | 36 | const lineHeights = { 37 | l: 1.5, 38 | heading: { 39 | h1: 0.8, 40 | h2: 1.06, 41 | h3: 1.14, 42 | h4: 1.25, 43 | h5: 1.32, 44 | }, 45 | }; 46 | 47 | const maxWidths = { 48 | s: '768px', 49 | m: '992px', 50 | l: '1226px', 51 | }; 52 | 53 | const breakpoints = Object.values(maxWidths); 54 | 55 | breakpoints.s = maxWidths.s; 56 | breakpoints.m = maxWidths.m; 57 | breakpoints.l = maxWidths.l; 58 | 59 | const space = { 60 | xs: 8, 61 | s: 16, 62 | m: 24, 63 | l: 32, 64 | xl: 40, 65 | xxl: 48, 66 | }; 67 | 68 | module.exports = { 69 | colors, 70 | fonts, 71 | fontSizes, 72 | lineHeights, 73 | breakpoints, 74 | space, 75 | maxWidths, 76 | }; 77 | -------------------------------------------------------------------------------- /styleguide/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { ThemeProvider } from 'styled-components'; 3 | import { BrowserRouter, Switch, Route } from 'react-router-dom'; 4 | import { hot } from 'react-hot-loader/root'; 5 | import { MDXProvider } from '@mdx-js/react'; 6 | import theme from '../src/theme'; 7 | import routes from './routes'; 8 | import BaseTemplate from './src/components/templates/BaseTemplate'; 9 | import NotFoundPage from './src/components/pages/NotFoundPage'; 10 | import Title from '../src/components/atoms/Title'; 11 | import Text from '../src/components/atoms/Text'; 12 | import '../src/assets/css/normalize.css'; 13 | import '../src/assets/css/base.css'; 14 | import './src/assets/css/highlight.css'; 15 | 16 | const markdown = { 17 | h1: props => , 18 | h2: props => <Title size="h3" mt="xl" mb="l" {...props} />, 19 | h3: props => <Title size="h4" as="h3" mt="l" mb="m" {...props} />, 20 | h4: props => <Title size="h5" as="h4" mt="l" mb="m" {...props} />, 21 | p: props => <Text {...props} maxWidth="700px" />, 22 | }; 23 | 24 | const App = () => ( 25 | <ThemeProvider theme={theme}> 26 | <BrowserRouter> 27 | <MDXProvider components={markdown}> 28 | <Switch> 29 | {routes.map(({ key, path, component: Component }) => ( 30 | <Route 31 | exact 32 | key={key} 33 | path={path} 34 | render={props => ( 35 | <BaseTemplate> 36 | <Component {...props} /> 37 | </BaseTemplate> 38 | )} 39 | /> 40 | ))} 41 | <Route component={NotFoundPage} /> 42 | </Switch> 43 | </MDXProvider> 44 | </BrowserRouter> 45 | </ThemeProvider> 46 | ); 47 | 48 | export default hot(App); 49 | -------------------------------------------------------------------------------- /styleguide/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import App from './App'; 4 | 5 | render(<App />, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /styleguide/pages/components/box.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Box from '../../../src/components/atoms/Box'; 4 | import Text from '../../../src/components/atoms/Text'; 5 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 6 | import PropsTable from '../../src/components/molecules/PropsTable'; 7 | 8 | const scope = { Box }; 9 | const code = `<Box bg="black" color="white" maxWidth="50%" p="10px 20px" fontSize="m">I am a box.</Box>`; 10 | 11 | export default () => ( 12 | <> 13 | <Title size="h3">Box 14 | 15 | 16 | The Box is an element, which can be modified by yourself 17 | as you need. It is like a "div" on steroids. 18 | 19 | 20 | 21 | ); 22 | -------------------------------------------------------------------------------- /styleguide/pages/components/button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Button from '../../../src/components/atoms/Button'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Button }; 8 | const code1 = ``; 9 | const code2 = ``; 10 | const code3 = ``; 11 | const code4 = ``; 12 | const code5 = ``; 13 | const code6 = ``; 14 | 15 | export default () => ( 16 | <> 17 | Button 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ); 27 | -------------------------------------------------------------------------------- /styleguide/pages/components/card.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Card from '../../../src/components/molecules/Card'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Card }; 8 | const code = ``; 9 | 10 | export default () => ( 11 | <> 12 | Card 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /styleguide/pages/components/divider.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Divider from '../../../src/components/atoms/Divider'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Divider }; 8 | const code1 = ``; 9 | const code2 = ``; 10 | 11 | export default () => ( 12 | <> 13 | Divider 14 | 15 | 16 | 17 | 18 | ); 19 | -------------------------------------------------------------------------------- /styleguide/pages/components/flex.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Box from '../../../src/components/atoms/Box'; 4 | import Flex from '../../../src/components/atoms/Flex'; 5 | import Text from '../../../src/components/atoms/Text'; 6 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 7 | import PropsTable from '../../src/components/molecules/PropsTable'; 8 | 9 | const scope = { Box, Flex, Text }; 10 | const code = ` 11 | 12 | Box 1 13 | 14 | 15 | Box 2 16 | 17 | 18 | Box 3 19 | 20 | `; 21 | 22 | export default () => ( 23 | <> 24 | Flex 25 | 26 | 27 | The Flex is an element, used as a Box wrapper to combine 28 | them in one single row. 29 | 30 | 31 | 32 | ); 33 | -------------------------------------------------------------------------------- /styleguide/pages/components/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Redirect } from 'react-router-dom'; 3 | 4 | export default () => ; 5 | -------------------------------------------------------------------------------- /styleguide/pages/components/inputField.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import InputField from '../../../src/components/atoms/InputField'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { InputField }; 8 | const code = ``; 9 | 10 | export default () => ( 11 | <> 12 | Input Field 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /styleguide/pages/components/link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Link from '../../../src/components/atoms/Link'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Link }; 8 | const code1 = `Pure`; 9 | const code2 = `Introduction`; 10 | const code3 = `Heartbeat agency`; 11 | 12 | export default () => ( 13 | <> 14 | Link 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /styleguide/pages/components/text.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Text from '../../../src/components/atoms/Text'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Text }; 8 | const code1 = `Bread has long been a foundational part of the human diet, but a revolt against it has been building for years — and seems to be reaching a crescendo.`; 9 | const code2 = `<> 10 | 11 | Bread has long been a foundational part of the human diet, but a revolt against it has been building for years — and seems to be reaching a crescendo. 12 | 13 | 14 | Bread has long been a foundational part of the human diet, but a revolt against it has been building for years — and seems to be reaching a crescendo. 15 | 16 | 17 | Bread has long been a foundational part of the human diet, but a revolt against it has been building for years — and seems to be reaching a crescendo. 18 | 19 | `; 20 | 21 | export default () => ( 22 | <> 23 | Text 24 | 25 | 26 | 27 | 28 | ); 29 | -------------------------------------------------------------------------------- /styleguide/pages/components/textarea.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Title from '../../../src/components/atoms/Title'; 3 | import Textarea from '../../../src/components/atoms/Textarea'; 4 | import LiveEditor from '../../src/components/atoms/LiveEditor'; 5 | import PropsTable from '../../src/components/molecules/PropsTable'; 6 | 7 | const scope = { Textarea }; 8 | const code = `