├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .travis.yml ├── LICENSE ├── Procfile ├── README.md ├── dist ├── index.html ├── main.098aa9ee0d410b880d633a4523eae478.css ├── main.098aa9ee0d410b880d633a4523eae478.css.map ├── main.0ce33a1ad2a5961809c0.js └── main.0ce33a1ad2a5961809c0.js.map ├── dist_server ├── index.html ├── main.098aa9ee0d410b880d633a4523eae478.css ├── main.098aa9ee0d410b880d633a4523eae478.css.map ├── main.0ce33a1ad2a5961809c0.js ├── main.0ce33a1ad2a5961809c0.js.map └── server.js ├── package.json ├── src ├── actions │ ├── ajaxStatusActions.js │ ├── authActions.js │ ├── commentActions.js │ └── notificationActions.js ├── api │ ├── auth.js │ ├── comments.js │ └── index.js ├── components │ ├── App.js │ ├── Auth │ │ ├── LoginForm.js │ │ ├── LoginPage.js │ │ └── style.scss │ ├── Comments │ │ ├── CommentForm.js │ │ ├── CommentList.js │ │ ├── CommentMain.js │ │ ├── CommentPage.js │ │ ├── ManageCommentPage.js │ │ └── style.scss │ ├── Home │ │ ├── HomePage.js │ │ ├── Welcome.js │ │ └── style.scss │ ├── Main.js │ ├── MainContent │ │ ├── index.js │ │ └── style.scss │ ├── Notifications │ │ ├── index.js │ │ └── style.scss │ ├── PageNotFound.js │ ├── SideNavigation │ │ ├── index.js │ │ └── style.scss │ ├── TopAppBar │ │ ├── index.js │ │ └── style.scss │ ├── _globals.scss │ ├── common │ │ ├── Preloader.js │ │ └── style.scss │ ├── style.scss │ └── theme │ │ └── _config.scss ├── constants │ └── actionTypes.js ├── favicon.ico ├── index.ejs ├── index.js ├── models │ ├── Comment.js │ └── User.js ├── reducers │ ├── ajaxStatusReducer.js │ ├── authReducer.js │ ├── commentReducer.js │ ├── index.js │ ├── initialState.js │ └── notificationsReducer.js ├── routes.js ├── store │ ├── configureStore.dev.js │ ├── configureStore.js │ └── configureStore.prod.js ├── style.scss ├── utils │ ├── ajax.js │ ├── dateHelper.js │ └── dateHelper.spec.js └── webpack-public-path.js ├── tools ├── build.js ├── chalkConfig.js ├── distServer.js ├── srcServer.js ├── startMessage.js └── testSetup.js ├── webpack.config.dev.js └── webpack.config.prod.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "latest", 4 | "react", 5 | "stage-1" 6 | ], 7 | "env": { 8 | "development": { 9 | "presets": [ 10 | "react-hmre" 11 | ] 12 | }, 13 | "production": { 14 | "plugins": [ 15 | "transform-react-constant-elements", 16 | "transform-react-remove-prop-types" 17 | ] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/ 2 | **/dist/ -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "eslint:recommended", 4 | "plugin:import/errors", 5 | "plugin:import/warnings" 6 | ], 7 | "plugins": [ 8 | "babel", 9 | "react" 10 | ], 11 | "parserOptions": { 12 | "ecmaVersion": 6, 13 | "sourceType": "module", 14 | "ecmaFeatures": { 15 | "jsx": true, 16 | "experimentalObjectRestSpread": true 17 | } 18 | }, 19 | "env": { 20 | "es6": true, 21 | "browser": true, 22 | "node": true, 23 | "jquery": true, 24 | "mocha": true 25 | }, 26 | "rules": { 27 | "quotes": 0, 28 | "indent": ["warn", 2, {"SwitchCase": 1}], 29 | "no-console": 1, 30 | "no-debugger": 1, 31 | "no-var": 1, 32 | "semi": [1, "always"], 33 | "no-trailing-spaces": 0, 34 | "eol-last": 0, 35 | "no-underscore-dangle": 0, 36 | "no-alert": 0, 37 | "no-lone-blocks": 0, 38 | "no-unused-vars": [1, { 39 | "vars": "all", 40 | "args": "after-used" 41 | }], 42 | "jsx-quotes": 1, 43 | "react/display-name": [ 1, {"ignoreTranspilerName": false }], 44 | "react/forbid-prop-types": [1, {"forbid": ["any"]}], 45 | "react/jsx-boolean-value": 0, 46 | "react/jsx-closing-bracket-location": 0, 47 | "react/jsx-curly-spacing": 1, 48 | "react/jsx-indent-props": 0, 49 | "react/jsx-key": 1, 50 | "react/jsx-max-props-per-line": 0, 51 | "react/jsx-no-bind": 0, 52 | "react/jsx-no-duplicate-props": 1, 53 | "react/jsx-no-literals": 0, 54 | "react/jsx-no-undef": 1, 55 | "react/jsx-pascal-case": 1, 56 | "react/jsx-sort-prop-types": 0, 57 | "react/jsx-sort-props": 0, 58 | "react/jsx-uses-react": 1, 59 | "react/jsx-uses-vars": 1, 60 | "react/no-danger": 1, 61 | "react/no-did-mount-set-state": 1, 62 | "react/no-did-update-set-state": 1, 63 | "react/no-direct-mutation-state": 1, 64 | "react/no-multi-comp": 1, 65 | "react/no-set-state": 0, 66 | "react/no-unknown-property": 1, 67 | "react/prefer-es6-class": 1, 68 | "react/prop-types": 1, 69 | "react/react-in-jsx-scope": 1, 70 | "react/require-extension": 1, 71 | "react/self-closing-comp": 1, 72 | "react/sort-comp": 1, 73 | "react/wrap-multilines": 1 74 | }, 75 | "globals": { 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Coverage directory used by tools like istanbul 12 | coverage 13 | 14 | # Dependency directories 15 | node_modules 16 | jspm_packages 17 | 18 | # Editor files 19 | .vscode 20 | .idea 21 | *.iml 22 | 23 | # Mac files 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Ricardo Reis 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 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm run dist-server -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://secure.travis-ci.org/rjmreis/react-redux-starter.svg)](http://travis-ci.org/rjmreis/react-redux-starter) 2 | 3 | # react-redux-starter 4 | A React/Redux starter project with login and basic CRUD functionality in a Material flavor 5 | 6 | ## The Goal 7 | The goal of this repo is to provide a general guidance in setting up a react/redux project with tools such as webpack, babel, eslint, trying as much as possible to follow best practises. 8 | 9 | ## Demo 10 | 11 | [reactredux-starter.herokuapp.com](https://reactredux-starter.herokuapp.com/) 12 | 13 | ``` 14 | Login details 15 | 16 | user: admin 17 | password: password 18 | ``` 19 | 20 | ## Quick Start 21 | 22 | Clone project and install dependencies: 23 | ```bash 24 | $ git clone https://github.com/rjmreis/react-redux-starter.git 25 | $ cd react-redux-starter 26 | $ npm install 27 | ``` 28 | 29 | Start the app: 30 | ```bash 31 | $ npm start -s 32 | ``` 33 | 34 | Build the app: 35 | ```bash 36 | $ npm run build 37 | ``` 38 | 39 | ## NOTE 40 | This is a work in progress repo, tests are still missing... 41 | 42 | ## Credits 43 | The foundation of this project is highly based on the amazing **react-slingshot** repo by Cory House. 44 | 45 | [react-slingshot](https://github.com/coryhouse/react-slingshot) 46 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | react-redux-starter
-------------------------------------------------------------------------------- /dist/main.098aa9ee0d410b880d633a4523eae478.css: -------------------------------------------------------------------------------- 1 | .theme__ripple___3cRG3{position:absolute;top:50%;left:50%;z-index:100;pointer-events:none;background-color:currentColor;border-radius:50%;-webkit-transform-origin:50% 50%;transform-origin:50% 50%}.theme__rippleWrapper___2AWhQ{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:none}.theme__ripple___3cRG3{-webkit-transition-duration:.8s;transition-duration:.8s}.theme__ripple___3cRG3.theme__rippleRestarting___y45XA{opacity:.3;-webkit-transition-property:none;transition-property:none}.theme__ripple___3cRG3.theme__rippleActive___1QiQf{opacity:.3;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform}.theme__ripple___3cRG3:not(.theme__rippleActive___1QiQf):not(.theme__rippleRestarting___y45XA){opacity:0;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform}.theme__button___1iKuo{position:relative}.theme__button___1iKuo>input{position:absolute;top:0;left:0;z-index:0;width:.1px;height:.1px;padding:0;margin:0;overflow:hidden;opacity:0}.theme__flat___2ui7t,.theme__floating___1mZ5E,.theme__raised___ONZv6,.theme__toggle___1Zy-o{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:1.4rem;font-weight:500;line-height:1;text-transform:uppercase;letter-spacing:0;position:relative;display:inline-block;height:3.6rem;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;line-height:3.6rem;text-align:center;text-decoration:none;white-space:nowrap;cursor:pointer;border:0;outline:none;-webkit-transition:box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1);transition:box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1)}.theme__flat___2ui7t::-moz-focus-inner,.theme__floating___1mZ5E::-moz-focus-inner,.theme__raised___ONZv6::-moz-focus-inner,.theme__toggle___1Zy-o::-moz-focus-inner{border:0}.theme__flat___2ui7t>span:not([data-react-toolbox=tooltip]),.theme__floating___1mZ5E>span:not([data-react-toolbox=tooltip]),.theme__raised___ONZv6>span:not([data-react-toolbox=tooltip]),.theme__toggle___1Zy-o>span:not([data-react-toolbox=tooltip]){display:inline-block;line-height:3.6rem;vertical-align:top}.theme__flat___2ui7t>svg,.theme__floating___1mZ5E>svg,.theme__raised___ONZv6>svg,.theme__toggle___1Zy-o>svg{display:inline-block;width:1em;height:3.6rem;font-size:120%;vertical-align:top;fill:currentColor}.theme__flat___2ui7t>*,.theme__floating___1mZ5E>*,.theme__raised___ONZv6>*,.theme__toggle___1Zy-o>*{pointer-events:none}.theme__flat___2ui7t>.theme__rippleWrapper___2zthi,.theme__floating___1mZ5E>.theme__rippleWrapper___2zthi,.theme__raised___ONZv6>.theme__rippleWrapper___2zthi,.theme__toggle___1Zy-o>.theme__rippleWrapper___2zthi{overflow:hidden}[disabled].theme__flat___2ui7t,[disabled].theme__floating___1mZ5E,[disabled].theme__raised___ONZv6,[disabled].theme__toggle___1Zy-o{color:rgba(0,0,0,.26);pointer-events:none;cursor:auto}.theme__flat___2ui7t,.theme__raised___ONZv6{min-width:9rem;padding:0 1.2rem;border-radius:.2rem}.theme__flat___2ui7t .theme__icon___1BTd6,.theme__raised___ONZv6 .theme__icon___1BTd6{margin-right:.6rem;font-size:120%;vertical-align:middle}.theme__flat___2ui7t>svg,.theme__raised___ONZv6>svg{margin-right:.5rem}[disabled].theme__floating___1mZ5E,[disabled].theme__raised___ONZv6{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);background-color:rgba(0,0,0,.12)}.theme__floating___1mZ5E:active,.theme__raised___ONZv6:active{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2)}.theme__floating___1mZ5E:focus:not(:active),.theme__raised___ONZv6:focus:not(:active){box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36)}.theme__raised___ONZv6{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.theme__flat___2ui7t{background:transparent}.theme__floating___1mZ5E{width:5.6rem;height:5.6rem;font-size:2.4rem;border-radius:50%;box-shadow:0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24)}.theme__floating___1mZ5E .theme__icon___1BTd6{line-height:5.6rem}.theme__floating___1mZ5E>.theme__rippleWrapper___2zthi{border-radius:50%}.theme__floating___1mZ5E.theme__mini___2oXdC{width:4rem;height:4rem;font-size:1.77778rem}.theme__floating___1mZ5E.theme__mini___2oXdC .theme__icon___1BTd6{line-height:4rem}.theme__toggle___1Zy-o{width:3.6rem;background:transparent;border-radius:50%}.theme__toggle___1Zy-o>.theme__icon___1BTd6,.theme__toggle___1Zy-o svg{font-size:2rem;line-height:3.6rem;vertical-align:top}.theme__toggle___1Zy-o>.theme__rippleWrapper___2zthi{border-radius:50%}.theme__neutral___uDC3j:not([disabled]).theme__floating___1mZ5E,.theme__neutral___uDC3j:not([disabled]).theme__raised___ONZv6{color:#212121;background-color:#fff}.theme__neutral___uDC3j:not([disabled]).theme__flat___2ui7t,.theme__neutral___uDC3j:not([disabled]).theme__toggle___1Zy-o{color:#212121}.theme__neutral___uDC3j:not([disabled]).theme__flat___2ui7t:focus:not(:active),.theme__neutral___uDC3j:not([disabled]).theme__flat___2ui7t:hover,.theme__neutral___uDC3j:not([disabled]).theme__toggle___1Zy-o:focus:not(:active){background:rgba(33,33,33,.2)}.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__floating___1mZ5E,.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__raised___ONZv6{color:#fff;background-color:#212121}.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__flat___2ui7t,.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__toggle___1Zy-o{color:#fff}.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__flat___2ui7t:focus:not(:active),.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__flat___2ui7t:hover,.theme__neutral___uDC3j:not([disabled]).theme__inverse___2Z8iZ.theme__toggle___1Zy-o:focus:not(:active){background:rgba(33,33,33,.2)}.theme__neutral___uDC3j.theme__inverse___2Z8iZ[disabled]{color:hsla(0,0%,100%,.54);background-color:hsla(0,0%,100%,.08)}.theme__primary___2NhN1:not([disabled]).theme__floating___1mZ5E,.theme__primary___2NhN1:not([disabled]).theme__raised___ONZv6{color:#fff;background:#ff5722}.theme__primary___2NhN1:not([disabled]).theme__flat___2ui7t,.theme__primary___2NhN1:not([disabled]).theme__toggle___1Zy-o{color:#ff5722}.theme__primary___2NhN1:not([disabled]).theme__flat___2ui7t:focus:not(:active),.theme__primary___2NhN1:not([disabled]).theme__flat___2ui7t:hover,.theme__primary___2NhN1:not([disabled]).theme__toggle___1Zy-o:focus:not(:active){background:rgba(255,87,34,.2)}.theme__accent___3MS_k:not([disabled]).theme__floating___1mZ5E,.theme__accent___3MS_k:not([disabled]).theme__raised___ONZv6{color:#fff;background:#546e7a}.theme__accent___3MS_k:not([disabled]).theme__flat___2ui7t,.theme__accent___3MS_k:not([disabled]).theme__toggle___1Zy-o{color:#546e7a}.theme__accent___3MS_k:not([disabled]).theme__flat___2ui7t:focus:not(:active),.theme__accent___3MS_k:not([disabled]).theme__flat___2ui7t:hover,.theme__accent___3MS_k:not([disabled]).theme__toggle___1Zy-o:focus:not(:active){background:rgba(84,110,122,.2)}.theme__avatar___3GCeP{position:relative;display:inline-block;width:4rem;height:4rem;overflow:hidden;font-size:2.4rem;color:#fff;text-align:center;vertical-align:middle;background-color:#9e9e9e;border-radius:50%}.theme__avatar___3GCeP>svg{width:1em;height:4rem;fill:currentColor}.theme__avatar___3GCeP>img{max-width:100%;height:auto}.theme__image___1H3TP{position:absolute;display:block;width:100%;height:100%;background-color:transparent;background-position:50%;background-size:cover;border-radius:50%}.theme__letter___34Q66{display:block;width:100%;line-height:4rem}.theme__card___2nWQb{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;overflow:hidden;font-size:1.4rem;background:#fff;border-radius:.2rem}.theme__card___2nWQb.theme__raised___2PPOH{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.2)}.theme__card___2nWQb [data-react-toolbox=avatar]{display:block}.theme__cardMedia___3WTvG{position:relative;background-repeat:no-repeat;background-position:50%;background-size:cover}.theme__cardMedia___3WTvG.theme__square___1a9i8,.theme__cardMedia___3WTvG.theme__wide___3c58S{width:100%}.theme__cardMedia___3WTvG.theme__square___1a9i8 .theme__content___Fopuf,.theme__cardMedia___3WTvG.theme__wide___3c58S .theme__content___Fopuf{position:absolute;height:100%}.theme__cardMedia___3WTvG.theme__square___1a9i8 .theme__content___Fopuf>iframe,.theme__cardMedia___3WTvG.theme__square___1a9i8 .theme__content___Fopuf>img,.theme__cardMedia___3WTvG.theme__square___1a9i8 .theme__content___Fopuf>video,.theme__cardMedia___3WTvG.theme__wide___3c58S .theme__content___Fopuf>iframe,.theme__cardMedia___3WTvG.theme__wide___3c58S .theme__content___Fopuf>img,.theme__cardMedia___3WTvG.theme__wide___3c58S .theme__content___Fopuf>video{max-width:100%}.theme__cardMedia___3WTvG:after{display:block;height:0;content:""}.theme__cardMedia___3WTvG.theme__wide___3c58S:after{padding-top:56.25%}.theme__cardMedia___3WTvG.theme__square___1a9i8:after{padding-top:100%}.theme__cardMedia___3WTvG .theme__content___Fopuf{position:relative;top:0;left:0;display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;overflow:hidden}.theme__cardMedia___3WTvG .theme__contentOverlay___1KYpi .theme__cardActions___1aHjq,.theme__cardMedia___3WTvG .theme__contentOverlay___1KYpi .theme__cardText___3ElKZ,.theme__cardMedia___3WTvG .theme__contentOverlay___1KYpi .theme__cardTitle___3Tyrr{background-color:rgba(0,0,0,.35)}.theme__cardTitle___3Tyrr{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.theme__cardTitle___3Tyrr [data-react-toolbox=avatar]{margin-right:1.3rem}.theme__cardTitle___3Tyrr .theme__subtitle___grD6g{color:#757575}.theme__cardTitle___3Tyrr.theme__large___3eNqf{padding:2rem 1.6rem 1.4rem}.theme__cardTitle___3Tyrr.theme__large___3eNqf .theme__title___35Wsy{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:2.4rem;font-weight:400;line-height:3.2rem;-moz-osx-font-smoothing:grayscale;line-height:1.25}.theme__cardTitle___3Tyrr.theme__small___3Q56x{padding:1.6rem}.theme__cardTitle___3Tyrr.theme__small___3Q56x .theme__title___35Wsy{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:1.4rem;line-height:2.4rem;letter-spacing:0;font-weight:500;line-height:1.4}.theme__cardTitle___3Tyrr.theme__small___3Q56x .theme__subtitle___grD6g{font-weight:500;line-height:1.4}.theme__cardMedia___3WTvG .theme__cardTitle___3Tyrr .theme__subtitle___grD6g,.theme__cardMedia___3WTvG .theme__cardTitle___3Tyrr .theme__title___35Wsy{color:#fff}.theme__cardText___3ElKZ,.theme__cardTitle___3Tyrr{padding:1.4rem 1.6rem}.theme__cardText___3ElKZ:last-child,.theme__cardTitle___3Tyrr:last-child{padding-bottom:2rem}.theme__cardText___3ElKZ+.theme__cardText___3ElKZ,.theme__cardTitle___3Tyrr+.theme__cardText___3ElKZ{padding-top:0}.theme__cardActions___1aHjq{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;padding:.8rem}.theme__cardActions___1aHjq [data-react-toolbox=button]{min-width:0;padding:0 .8rem;margin:0 .4rem}.theme__cardActions___1aHjq [data-react-toolbox=button]:first-child{margin-left:0}.theme__cardActions___1aHjq [data-react-toolbox=button]:last-child{margin-right:0}.theme__layout___2DIC_{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;height:100%;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;overflow-y:hidden}.theme__layout___2DIC_ .theme__navDrawer___1rdra{width:0;min-width:0;height:100%;overflow-x:hidden;overflow-y:hidden;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:width,min-width;transition-property:width,min-width}.theme__layout___2DIC_ .theme__navDrawer___1rdra .theme__scrim___2QDhH{position:absolute;top:0;bottom:0;left:0;z-index:200;width:0;height:100%;background-color:transparent;-webkit-transition:background-color .35s cubic-bezier(.4,0,.2,1),width 10ms linear .35s;transition:background-color .35s cubic-bezier(.4,0,.2,1),width 10ms linear .35s}.theme__layout___2DIC_ .theme__navDrawer___1rdra .theme__drawerContent___unz6w{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);position:absolute;z-index:300;display:-webkit-box;display:-ms-flexbox;display:flex;width:28rem;max-width:calc(100% - 5.6rem);height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;overflow-x:hidden;overflow-y:hidden;color:#424242;pointer-events:none;background-color:#fafafa;border-right:1px solid #e0e0e0;-webkit-transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1),-webkit-transform .35s cubic-bezier(.4,0,.2,1);-webkit-transform:translateX(-100%);transform:translateX(-100%)}.theme__layout___2DIC_ .theme__navDrawer___1rdra .theme__drawerContent___unz6w.theme__scrollY___1AG90{overflow-y:auto}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__pinned___oVgJU{-webkit-transition-delay:.07s;transition-delay:.07s;width:28rem;max-width:calc(100% - 5.6rem)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__pinned___oVgJU .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__active___1P57z:not(.theme__pinned___oVgJU){-webkit-transition-delay:.07s;transition-delay:.07s}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__active___1P57z:not(.theme__pinned___oVgJU) .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__active___1P57z:not(.theme__pinned___oVgJU) .theme__scrim___2QDhH{width:100%;background-color:rgba(0,0,0,.6);-webkit-transition:background-color .35s cubic-bezier(.4,0,.2,1);transition:background-color .35s cubic-bezier(.4,0,.2,1)}@media screen and (min-width:600px){.theme__layout___2DIC_ .theme__navDrawer___1rdra .theme__drawerContent___unz6w,.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__pinned___oVgJU{width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__wide___3X5rC .theme__drawerContent___unz6w,.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__wide___3X5rC.theme__pinned___oVgJU{width:40rem;max-width:40rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smPermanent___1QkG3{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smPermanent___1QkG3 .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smPermanent___1QkG3.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smPermanent___1QkG3.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smTabletPermanent___1Ntvp{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smTabletPermanent___1Ntvp .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smTabletPermanent___1Ntvp.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__smTabletPermanent___1Ntvp.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:960px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__mdPermanent___3v_k7{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__mdPermanent___3v_k7 .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__mdPermanent___3v_k7.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__mdPermanent___3v_k7.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:1280px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgPermanent___3rQEf{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgPermanent___3rQEf .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgPermanent___3rQEf.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgPermanent___3rQEf.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:1024px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgTabletPermanent___NlW9h{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgTabletPermanent___NlW9h .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgTabletPermanent___NlW9h.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__lgTabletPermanent___NlW9h.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:1440px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xlPermanent___3O4lD{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xlPermanent___3O4lD .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xlPermanent___3O4lD.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xlPermanent___3O4lD.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:1600px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxlPermanent___yB-xN{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxlPermanent___yB-xN .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxlPermanent___yB-xN.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxlPermanent___yB-xN.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}@media screen and (min-width:1920px){.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxxlPermanent___2PMir{-webkit-transition-delay:.07s;transition-delay:.07s;width:32rem;max-width:32rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxxlPermanent___2PMir .theme__drawerContent___unz6w{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxxlPermanent___2PMir.theme__wide___3X5rC{width:40rem;max-width:40rem}.theme__layout___2DIC_ .theme__navDrawer___1rdra.theme__xxxlPermanent___2PMir.theme__active___1P57z>.theme__scrim___2QDhH{width:0;background-color:transparent}}.theme__layout___2DIC_ .theme__layout___2DIC_ .theme__scrim___2QDhH{z-index:299}.theme__layout___2DIC_ .theme__layout___2DIC_ .theme__layout___2DIC_ .theme__scrim___2QDhH{z-index:298}.theme__layout___2DIC_ .theme__panel___o2a2H{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;overflow-y:hidden}.theme__layout___2DIC_ .theme__panel___o2a2H.theme__scrollY___1AG90{overflow-y:auto}.theme__layout___2DIC_ .theme__sidebar___t1TKH{position:absolute;top:0;right:0;bottom:0;z-index:299;width:0;height:100%;overflow-x:hidden;overflow-y:hidden;color:#424242;background-color:#fafafa;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:width;transition-property:width}.theme__layout___2DIC_ .theme__sidebar___t1TKH .theme__sidebarContent___1MT-m{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;overflow-y:hidden}.theme__layout___2DIC_ .theme__sidebar___t1TKH .theme__sidebarContent___1MT-m.theme__scrollY___1AG90{overflow-y:auto}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA .theme__sidebarContent___1MT-m{min-width:5.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA.theme__pinned___oVgJU{width:5.6rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA .theme__sidebarContent___1MT-m{min-width:6.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA.theme__pinned___oVgJU{width:6.4rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA .theme__sidebarContent___1MT-m{min-width:6.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA.theme__pinned___oVgJU{width:6.4rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA .theme__sidebarContent___1MT-m{min-width:6.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-1___3dCDA.theme__pinned___oVgJU{width:6.4rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL .theme__sidebarContent___1MT-m{min-width:11.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL.theme__pinned___oVgJU{width:11.2rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL .theme__sidebarContent___1MT-m{min-width:12.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL.theme__pinned___oVgJU{width:12.8rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL .theme__sidebarContent___1MT-m{min-width:12.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL.theme__pinned___oVgJU{width:12.8rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL .theme__sidebarContent___1MT-m{min-width:12.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-2___2OjoL.theme__pinned___oVgJU{width:12.8rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL .theme__sidebarContent___1MT-m{min-width:16.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL.theme__pinned___oVgJU{width:16.8rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL .theme__sidebarContent___1MT-m{min-width:19.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL.theme__pinned___oVgJU{width:19.2rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL .theme__sidebarContent___1MT-m{min-width:19.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL.theme__pinned___oVgJU{width:19.2rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL .theme__sidebarContent___1MT-m{min-width:19.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-3___26_RL.theme__pinned___oVgJU{width:19.2rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf .theme__sidebarContent___1MT-m{min-width:22.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf.theme__pinned___oVgJU{width:22.4rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf .theme__sidebarContent___1MT-m{min-width:25.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf.theme__pinned___oVgJU{width:25.6rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf .theme__sidebarContent___1MT-m{min-width:25.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf.theme__pinned___oVgJU{width:25.6rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf .theme__sidebarContent___1MT-m{min-width:25.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-4___kGxrf.theme__pinned___oVgJU{width:25.6rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ .theme__sidebarContent___1MT-m{min-width:28rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ.theme__pinned___oVgJU{width:28rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ .theme__sidebarContent___1MT-m{min-width:32rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ.theme__pinned___oVgJU{width:32rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ .theme__sidebarContent___1MT-m{min-width:32rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ.theme__pinned___oVgJU{width:32rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ .theme__sidebarContent___1MT-m{min-width:32rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-5___3HyHQ.theme__pinned___oVgJU{width:32rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh .theme__sidebarContent___1MT-m{min-width:33.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh.theme__pinned___oVgJU{width:33.6rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh .theme__sidebarContent___1MT-m{min-width:38.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh.theme__pinned___oVgJU{width:38.4rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh .theme__sidebarContent___1MT-m{min-width:38.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh.theme__pinned___oVgJU{width:38.4rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh .theme__sidebarContent___1MT-m{min-width:38.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-6___VWIJh.theme__pinned___oVgJU{width:38.4rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM .theme__sidebarContent___1MT-m{min-width:39.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM.theme__pinned___oVgJU{width:39.2rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM .theme__sidebarContent___1MT-m{min-width:44.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM.theme__pinned___oVgJU{width:44.8rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM .theme__sidebarContent___1MT-m{min-width:44.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM.theme__pinned___oVgJU{width:44.8rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM .theme__sidebarContent___1MT-m{min-width:44.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-7___RMBsM.theme__pinned___oVgJU{width:44.8rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4 .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4 .theme__sidebarContent___1MT-m{min-width:44.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4.theme__pinned___oVgJU{width:44.8rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4 .theme__sidebarContent___1MT-m{min-width:51.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4.theme__pinned___oVgJU{width:51.2rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4 .theme__sidebarContent___1MT-m{min-width:51.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4.theme__pinned___oVgJU{width:51.2rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4 .theme__sidebarContent___1MT-m{min-width:51.2rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-8___2p9V4.theme__pinned___oVgJU{width:51.2rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V.theme__pinned___oVgJU{width:100%}@media screen and (min-width:600px) and (orientation:landscape){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V .theme__sidebarContent___1MT-m{min-width:50.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V.theme__pinned___oVgJU{width:50.4rem}}@media screen and (min-width:600px) and (orientation:portrait){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V .theme__sidebarContent___1MT-m{min-width:57.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V.theme__pinned___oVgJU{width:57.6rem}}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V .theme__sidebarContent___1MT-m{min-width:57.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V.theme__pinned___oVgJU{width:57.6rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V .theme__sidebarContent___1MT-m{min-width:57.6rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-9___3JV_V.theme__pinned___oVgJU{width:57.6rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC.theme__pinned___oVgJU{width:100%}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC .theme__sidebarContent___1MT-m{min-width:64rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC.theme__pinned___oVgJU{width:64rem}}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC .theme__sidebarContent___1MT-m{min-width:64rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-10___IFhjC.theme__pinned___oVgJU{width:64rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-11___2gqr4 .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-11___2gqr4.theme__pinned___oVgJU{width:100%}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-11___2gqr4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-11___2gqr4 .theme__sidebarContent___1MT-m{min-width:70.4rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-11___2gqr4.theme__pinned___oVgJU{width:70.4rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-12___3Fqrn .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-12___3Fqrn.theme__pinned___oVgJU{width:100%}@media screen and (min-width:840px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-12___3Fqrn{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-12___3Fqrn .theme__sidebarContent___1MT-m{min-width:76.8rem}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-12___3Fqrn.theme__pinned___oVgJU{width:76.8rem}}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-100___cH-H3{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-100___cH-H3 .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-100___cH-H3.theme__pinned___oVgJU{width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw.theme__pinned___oVgJU{width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi.theme__pinned___oVgJU{width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4 .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4.theme__pinned___oVgJU{width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX.theme__pinned___oVgJU{width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb{position:absolute}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb .theme__sidebarContent___1MT-m{min-width:100%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb.theme__pinned___oVgJU{width:100%}@media screen and (min-width:720px){.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw .theme__sidebarContent___1MT-m{min-width:25%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-25___2wWPw.theme__pinned___oVgJU{width:25%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi .theme__sidebarContent___1MT-m{min-width:33%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-33___1MMwi.theme__pinned___oVgJU{width:33%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4 .theme__sidebarContent___1MT-m{min-width:50%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-50___gURY4.theme__pinned___oVgJU{width:50%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX .theme__sidebarContent___1MT-m{min-width:66%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-66___1TeEX.theme__pinned___oVgJU{width:66%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb{position:relative}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb .theme__sidebarContent___1MT-m{min-width:75%}.theme__layout___2DIC_ .theme__sidebar___t1TKH.theme__width-75___1smcb.theme__pinned___oVgJU{width:75%}}.theme__field___14tiU{position:relative;display:block;height:1.8rem;margin-bottom:1.5rem;white-space:nowrap;vertical-align:middle}.theme__field___14tiU .theme__ripple___1-Txn{background-color:#ff5722;opacity:.3;-webkit-transition-duration:.65s;transition-duration:.65s}.theme__text___1nV6f{display:inline-block;padding-left:1rem;font-size:1.4rem;line-height:1.8rem;color:#000;white-space:nowrap;vertical-align:top}.theme__input___3zqc3{position:absolute;width:0;height:0;overflow:hidden;opacity:0}.theme__input___3zqc3:focus~.theme__check___2B20W:before{position:absolute;top:50%;left:50%;width:4.14rem;height:4.14rem;margin-top:-2.07rem;margin-left:-2.07rem;pointer-events:none;content:"";background-color:rgba(0,0,0,.1);border-radius:50%}.theme__input___3zqc3:focus~.theme__check___2B20W.theme__checked___2NQ9n:before{background-color:rgba(255,87,34,.26)}.theme__check___2B20W{position:relative;display:inline-block;width:1.8rem;height:1.8rem;vertical-align:top;cursor:pointer;border:2px solid #000;border-radius:2px;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.2s;transition-duration:.2s;-webkit-transition-property:background-color;transition-property:background-color}.theme__check___2B20W.theme__checked___2NQ9n{background-color:#ff5722;border-color:#ff5722}.theme__check___2B20W.theme__checked___2NQ9n:after{position:absolute;top:-.1rem;left:.4rem;width:.7rem;height:1.2rem;content:"";border-color:#fff;border-style:solid;border-top:0;border-right-width:2px;border-bottom-width:2px;border-left:0;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-animation:theme__checkmark-expand___1k7UD .14s ease-out forwards;animation:theme__checkmark-expand___1k7UD .14s ease-out forwards}.theme__disabled___3tar9>.theme__text___1nV6f{color:rgba(0,0,0,.26)}.theme__disabled___3tar9>.theme__check___2B20W{cursor:auto;border-color:rgba(0,0,0,.26)}.theme__disabled___3tar9>.theme__check___2B20W.theme__checked___2NQ9n{cursor:auto;background-color:rgba(0,0,0,.26);border-color:transparent}@-webkit-keyframes theme__checkmark-expand___1k7UD{0%{top:.9rem;left:.6rem;width:0;height:0}to{top:-.1rem;left:.4rem;width:.7rem;height:1.2rem}}@keyframes theme__checkmark-expand___1k7UD{0%{top:.9rem;left:.6rem;width:0;height:0}to{top:-.1rem;left:.4rem;width:.7rem;height:1.2rem}}.theme__list___3Ahlg{position:relative;display:inline-block;width:100%;padding:.8rem 0;text-align:left;white-space:nowrap;list-style:none}.theme__subheader___2hnyo{padding-left:1.6rem;margin:-.8rem 0 0;font-size:1.4rem;font-weight:500;line-height:4.8rem;color:#757575}.theme__divider___1WuUG{height:.1rem;margin:-.1rem 0 0;background-color:#eee;border:0}.theme__divider___1WuUG.theme__inset___2XT51{margin-right:1.6rem;margin-left:7.2rem}.theme__list___3Ahlg+.theme__divider___1WuUG{margin-top:-.8rem}.theme__listItem___25deI~.theme__divider___1WuUG{margin-top:.8rem;margin-bottom:.8rem}.theme__listItem___25deI{position:relative}.theme__listItem___25deI>[data-react-toolbox=ripple]{overflow:hidden}.theme__listItem___25deI .theme__ripple___3BKMI{color:#757575}.theme__item___QgVrb{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;min-height:4.8rem;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 1.6rem;color:#212121}.theme__item___QgVrb.theme__selectable___pSlvM:not(.theme__disabled___281Pb):hover{cursor:pointer;background-color:#eee}.theme__item___QgVrb.theme__disabled___281Pb{pointer-events:none}.theme__item___QgVrb.theme__disabled___281Pb:not(.theme__checkboxItem___3FtoG),.theme__item___QgVrb.theme__disabled___281Pb>.theme__checkbox___2pdgS>[data-react-toolbox=label]{opacity:.5}.theme__left___1KL1E [data-react-toolbox=font-icon]{width:1.8rem}.theme__left___1KL1E :last-child>[data-react-toolbox=font-icon]{margin-right:2.2rem}.theme__right___3itF1>:last-child{margin-right:0}.theme__right___3itF1>:first-child{margin-left:1.6rem}.theme__left___1KL1E,.theme__right___3itF1{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:0;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-box-align:center;-ms-flex-align:center;align-items:center;vertical-align:middle}.theme__itemAction___1SOd4{display:-webkit-box;display:-ms-flexbox;display:flex;margin:.8rem 1.6rem .8rem 0}.theme__itemAction___1SOd4>*{padding:0}.theme__itemAction___1SOd4>[data-react-toolbox=font-icon]{font-size:2.4rem;color:#757575}.theme__itemContentRoot___3ofPf{display:block;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.theme__itemContentRoot___3ofPf.theme__large___2vIAA{display:-webkit-box;display:-ms-flexbox;display:flex;height:7.2rem;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.theme__checkbox___2pdgS{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;height:100%;min-height:4.8rem;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0;cursor:pointer}.theme__checkbox___2pdgS>[data-react-toolbox=check]{margin-right:3.8rem}.theme__checkbox___2pdgS>[data-react-toolbox=label]{padding-left:0}.theme__itemText___D709k{display:block}.theme__itemText___D709k:not(.theme__primary___22ZvQ){padding-top:.3rem;font-size:1.4rem;color:#757575;white-space:normal}.theme__itemText___D709k.theme__primary___22ZvQ{font-size:1.6rem;color:#212121}.theme__iconMenu___1K6XK{position:relative;display:inline-block;text-align:center}.theme__iconMenu___1K6XK .theme__icon___Q98zC{cursor:pointer}.theme__menu___2bOZL{position:relative;display:inline-block}.theme__menu___2bOZL.theme__topLeft___49yru{position:absolute;top:0;left:0}.theme__menu___2bOZL.theme__topLeft___49yru>.theme__outline___3LItQ{-webkit-transform-origin:0 0;transform-origin:0 0}.theme__menu___2bOZL.theme__topRight___tGYgQ{position:absolute;top:0;right:0}.theme__menu___2bOZL.theme__topRight___tGYgQ>.theme__outline___3LItQ{-webkit-transform-origin:100% 0;transform-origin:100% 0}.theme__menu___2bOZL.theme__bottomLeft___1TaYY{position:absolute;bottom:0;left:0}.theme__menu___2bOZL.theme__bottomLeft___1TaYY>.theme__outline___3LItQ{-webkit-transform-origin:0 100%;transform-origin:0 100%}.theme__menu___2bOZL.theme__bottomRight___1_dUK{position:absolute;right:0;bottom:0}.theme__menu___2bOZL.theme__bottomRight___1_dUK>.theme__outline___3LItQ{-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.theme__menu___2bOZL:not(.theme__static___25uHO){z-index:200;pointer-events:none}.theme__menu___2bOZL:not(.theme__static___25uHO)>.theme__outline___3LItQ{opacity:0;-webkit-transition:opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1);transition:opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1);transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1);transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1);-webkit-transform:scale(0);transform:scale(0);will-change:transform}.theme__menu___2bOZL:not(.theme__static___25uHO)>.theme__menuInner___1k3_X{position:absolute;top:0;left:0;opacity:0}.theme__menu___2bOZL:not(.theme__static___25uHO).theme__rippled___2pZcI:not(.theme__active___3owm6)>.theme__menuInner___1k3_X,.theme__menu___2bOZL:not(.theme__static___25uHO).theme__rippled___2pZcI:not(.theme__active___3owm6)>.theme__outline___3LItQ{-webkit-transition-delay:.3s;transition-delay:.3s}.theme__menu___2bOZL:not(.theme__static___25uHO).theme__active___3owm6{pointer-events:all}.theme__menu___2bOZL:not(.theme__static___25uHO).theme__active___3owm6>.theme__outline___3LItQ{opacity:1;-webkit-transform:scale(1);transform:scale(1)}.theme__menu___2bOZL:not(.theme__static___25uHO).theme__active___3owm6>.theme__menuInner___1k3_X{opacity:1;-webkit-transition:opacity .2s cubic-bezier(.4,0,.2,1),clip .3s cubic-bezier(.4,0,.2,1);transition:opacity .2s cubic-bezier(.4,0,.2,1),clip .3s cubic-bezier(.4,0,.2,1)}.theme__outline___3LItQ{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);position:absolute;top:0;left:0;display:block;background-color:#fff;border-radius:.2rem}.theme__menuInner___1k3_X{position:relative;display:block;padding:.8rem 0;text-align:left;white-space:nowrap;list-style:none}.theme__menuItem___3SQPN{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;height:4.8rem;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 1.6rem;overflow:hidden;font-size:1.6rem;color:#212121}.theme__menuItem___3SQPN:not(.theme__disabled___tYdgT):hover{cursor:pointer;background-color:#eee}.theme__menuItem___3SQPN.theme__disabled___tYdgT{pointer-events:none;opacity:.5}.theme__menuItem___3SQPN.theme__selected___3zlED{font-weight:500;background-color:transparent}.theme__menuItem___3SQPN .theme__ripple___2PP2K{color:#757575}.theme__menuItem___3SQPN .theme__icon___Q98zC{width:3.84rem;font-size:2.4rem!important}.theme__caption___1TBtj{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;font-size:1.6rem}.theme__shortcut___1VR3f{margin-left:1.6rem}.theme__menuDivider___2aLZ3{display:block;width:100%;height:1px;margin:1.2rem 0;background-color:#eee}.theme__radio___-qz0o,.theme__radioChecked___37vlk{position:relative;display:inline-block;width:2rem;height:2rem;vertical-align:top;cursor:pointer;border:.2rem solid #000;border-radius:50%}.theme__radio___-qz0o:before,.theme__radioChecked___37vlk:before{position:absolute;top:0;left:0;width:100%;height:100%;content:"";background-color:#ff5722;border-radius:50%;-webkit-transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1),-webkit-transform .35s cubic-bezier(.4,0,.2,1);-webkit-transform:scale(0);transform:scale(0)}.theme__radio___-qz0o .theme__ripple___3p5ha,.theme__radioChecked___37vlk .theme__ripple___3p5ha{background-color:#ff5722;opacity:.3;-webkit-transition-duration:.65s;transition-duration:.65s}.theme__radioChecked___37vlk{border:.2rem solid #ff5722}.theme__radioChecked___37vlk:before{-webkit-transform:scale(.65);transform:scale(.65)}.theme__disabled___15z04,.theme__field___30YjY{position:relative;display:block;height:2rem;margin-bottom:1.5rem;white-space:nowrap;vertical-align:middle}.theme__text___1gqkQ{display:inline-block;padding-left:1rem;font-size:1.4rem;line-height:2rem;color:#000;white-space:nowrap;vertical-align:top}.theme__input___Z_QPq{position:absolute;width:0;height:0;padding:0;margin:0;border:0;opacity:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.theme__input___Z_QPq:focus~.theme__radio___-qz0o,.theme__input___Z_QPq:focus~.theme__radioChecked___37vlk{box-shadow:0 0 0 1rem rgba(0,0,0,.1)}.theme__input___Z_QPq:focus~.theme__radioChecked___37vlk{box-shadow:0 0 0 1rem rgba(255,87,34,.26)}.theme__disabled___15z04 .theme__text___1gqkQ{color:rgba(0,0,0,.26)}.theme__disabled___15z04 .theme__radio___-qz0o,.theme__disabled___15z04 .theme__radioChecked___37vlk{cursor:auto;border-color:rgba(0,0,0,.26)}.theme__disabled___15z04 .theme__radioChecked___37vlk:before{background-color:rgba(0,0,0,.26)}.theme__tabs___2lGJI{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.theme__navigation___2N9WO,.theme__tabs___2lGJI{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-direction:normal}.theme__navigation___2N9WO{position:relative;-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row;overflow-x:hidden;box-shadow:inset 0 -1px #eee}.theme__navigationContainer___rLpe4{display:-webkit-box;display:-ms-flexbox;display:flex}.theme__navigationContainer___rLpe4 .theme__navigation___2N9WO{-webkit-box-flex:1;-ms-flex:1;flex:1}.theme__arrow___1Bm49{padding:0 1.2rem;color:#000}.theme__arrowContainer___1HYX7{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;cursor:pointer;box-shadow:inset 0 -1px #eee}.theme__label___3A-Tl{padding:1.7rem 1.2rem;font-size:1.4rem;font-weight:500;line-height:1;color:rgba(0,0,0,.7);text-align:center;text-transform:uppercase;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:box-shadow,color;transition-property:box-shadow,color}.theme__label___3A-Tl.theme__active___2SLiK{color:#000}.theme__label___3A-Tl.theme__disabled___1mq-I{opacity:.2}.theme__label___3A-Tl:not(.theme__disabled___1mq-I){cursor:pointer}.theme__label___3A-Tl.theme__hidden___1XZZy{display:none}.theme__label___3A-Tl.theme__withIcon___pi4k-{padding-top:1.3rem;padding-bottom:1.3rem}.theme__label___3A-Tl.theme__withText___2-Su2 .theme__icon___wI5gE{margin-bottom:.8rem}.theme__icon___wI5gE{display:block;height:2.4rem;margin:0 auto;line-height:2.4rem}.theme__pointer___pWCM7{position:absolute;width:0;height:.2rem;margin-top:-.2rem;background-color:#ff5722;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:left,width;transition-property:left,width}.theme__pointer___pWCM7.theme__disableAnimation___mBuDO{-webkit-transition:none;transition:none}.theme__tab___2YMGw{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding:1.7rem 1.2rem}.theme__tab___2YMGw:not(.theme__active___2SLiK){display:none}.theme__tab___2YMGw.theme__active___2SLiK{display:-webkit-box;display:-ms-flexbox;display:flex}.theme__fixed___3dgXb .theme__label___3A-Tl{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.theme__inverse___x1bCH .theme__arrowContainer___1HYX7,.theme__inverse___x1bCH .theme__navigation___2N9WO{background-color:#ff5722}.theme__inverse___x1bCH .theme__label___3A-Tl{color:hsla(0,0%,100%,.7)}.theme__inverse___x1bCH .theme__arrow___1Bm49,.theme__inverse___x1bCH .theme__label___3A-Tl.theme__active___2SLiK{color:#fff}.theme__inverse___x1bCH .theme__pointer___pWCM7{background-color:#546e7a}.theme__appBar___wbg0y{display:-webkit-box;display:-ms-flexbox;display:flex;height:6.4rem;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 2.4rem;color:#fff;background:#f4511e;-webkit-transition-timing-function:cubic-bezier(.215,.61,.355,1);transition-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transition-duration:.5s;transition-duration:.5s;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform}@media screen and (max-width:480px) and (orientation:portrait){.theme__appBar___wbg0y{height:5.6rem}}@media screen and (max-width:600px) and (orientation:landscape){.theme__appBar___wbg0y{height:4.8rem}}.theme__appBar___wbg0y:not(.theme__flat___1lt-1){z-index:100;box-shadow:0 2px 5px rgba(0,0,0,.26)}.theme__appBar___wbg0y.theme__fixed___3rLFE{position:fixed;top:0;right:0;left:0;z-index:300}.theme__appBar___wbg0y a{color:#fff}.theme__appBar___wbg0y .theme__title___mFCzt{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;font-size:1.8rem;font-weight:700}.theme__appBar___wbg0y .theme__title___mFCzt>small{font-size:1.8rem;font-weight:400}.theme__appBar___wbg0y .theme__leftIcon___3lBT0{margin-left:-1.2rem}.theme__appBar___wbg0y .theme__rightIcon___3I1u6{margin-right:-1.2rem;margin-left:auto}.theme__appBar___wbg0y.theme__scrollHide___375zR{-webkit-transform:translateY(-100%);transform:translateY(-100%)}.theme__chip___3Gjj_{position:relative;display:inline-block;max-width:100%;padding:0 1.2rem;margin-right:.25rem;overflow:hidden;font-size:1.4rem;line-height:3.2rem;color:#757575;text-overflow:ellipsis;white-space:nowrap;background-color:#eee;border-radius:3.2rem}.theme__avatar___1IEZZ{padding-left:0}.theme__avatar___1IEZZ>[data-react-toolbox=avatar]{width:3.2rem;height:3.2rem;margin-right:.8rem;vertical-align:middle}.theme__avatar___1IEZZ>[data-react-toolbox=avatar]>span{font-size:2rem;line-height:3.2rem}.theme__deletable___3k2SH{padding-right:3.2rem}.theme__delete___2LAZw{position:absolute;right:0;display:inline-block;width:2.4rem;height:2.4rem;padding:.4rem;margin:.4rem;vertical-align:middle;cursor:pointer}.theme__delete___2LAZw:hover .theme__deleteIcon___3XWBI{background:#9e9e9e}.theme__deleteIcon___3XWBI{vertical-align:top;background:#bdbdbd;border-radius:2.4rem}.theme__deleteIcon___3XWBI .theme__deleteX___2hNz-{fill:transparent;stroke-width:.4rem;stroke:#fff}.theme__input___qUQeP{position:relative;padding:2rem 0}.theme__input___qUQeP.theme__withIcon___f6YT1{margin-left:4.8rem}.theme__icon___1_C6Z{position:absolute;top:1.6rem;left:-4.8rem;display:block;width:4.8rem;height:4.8rem;font-size:2.4rem!important;line-height:4.8rem!important;color:rgba(0,0,0,.26);text-align:center;-webkit-transition:color .35s cubic-bezier(.4,0,.2,1);transition:color .35s cubic-bezier(.4,0,.2,1)}.theme__inputElement___27dyY{display:block;width:100%;padding:.8rem 0;font-size:1.6rem;color:#212121;background-color:transparent;border:0;border-bottom:1px solid rgba(0,0,0,.12);outline:none}.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__bar___2GHeb:after,.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__bar___2GHeb:before{width:50%}.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__label___tqKDt:not(.theme__fixed___2pXa4){color:#ff5722}.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__label___tqKDt>.theme__required___2OgFq{color:#de3226}.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__hint___2D9g-{display:block;opacity:1}.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__icon___1_C6Z{color:#ff5722}.theme__inputElement___27dyY.theme__filled___1UI7Z~.theme__label___tqKDt:not(.theme__fixed___2pXa4),.theme__inputElement___27dyY:focus:not([disabled]):not([readonly])~.theme__label___tqKDt:not(.theme__fixed___2pXa4),.theme__inputElement___27dyY[type=date]~.theme__label___tqKDt:not(.theme__fixed___2pXa4),.theme__inputElement___27dyY[type=time]~.theme__label___tqKDt:not(.theme__fixed___2pXa4){top:.6rem;font-size:1.2rem}.theme__inputElement___27dyY.theme__filled___1UI7Z.theme__filled___1UI7Z~.theme__hint___2D9g-,.theme__inputElement___27dyY:focus:not([disabled]):not([readonly]).theme__filled___1UI7Z~.theme__hint___2D9g-,.theme__inputElement___27dyY[type=date].theme__filled___1UI7Z~.theme__hint___2D9g-,.theme__inputElement___27dyY[type=time].theme__filled___1UI7Z~.theme__hint___2D9g-{opacity:0}.theme__inputElement___27dyY.theme__filled___1UI7Z~.theme__hint___2D9g-,.theme__inputElement___27dyY.theme__filled___1UI7Z~.theme__label___tqKDt.theme__fixed___2pXa4{display:none}.theme__label___tqKDt{position:absolute;top:3.2rem;left:0;font-size:1.6rem;line-height:1.6rem;color:rgba(0,0,0,.26);pointer-events:none;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:top,font-size,color;transition-property:top,font-size,color}.theme__label___tqKDt.theme__fixed___2pXa4~.theme__hint___2D9g-{display:none}.theme__hint___2D9g-{position:absolute;top:3.2rem;left:0;font-size:1.6rem;line-height:1.6rem;color:rgba(0,0,0,.26);pointer-events:none;opacity:1;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:opacity;transition-property:opacity}.theme__bar___2GHeb{position:relative;display:block;width:100%}.theme__bar___2GHeb:after,.theme__bar___2GHeb:before{-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.2s;transition-duration:.2s;position:absolute;bottom:0;width:0;height:2px;content:"";background-color:#ff5722;-webkit-transition-property:width,background-color;transition-property:width,background-color}.theme__bar___2GHeb:before{left:50%}.theme__bar___2GHeb:after{right:50%}.theme__counter___398RE,.theme__error___3ilni{margin-bottom:-2rem;font-size:1.2rem;line-height:2rem;color:#de3226}.theme__counter___398RE{position:absolute;right:0;color:rgba(0,0,0,.26)}.theme__disabled___6VTPW>.theme__inputElement___27dyY{color:rgba(0,0,0,.26);border-bottom-style:dotted}.theme__errored___3peD4{padding-bottom:0}.theme__errored___3peD4>.theme__inputElement___27dyY{margin-top:1px;border-bottom-color:#de3226}.theme__errored___3peD4>.theme__counter___398RE,.theme__errored___3peD4>.theme__label___tqKDt,.theme__errored___3peD4>.theme__label___tqKDt>.theme__required___2OgFq{color:#de3226}.theme__hidden___3lRxh{display:none}.theme__autocomplete___13r65{position:relative;padding:1rem 0}.theme__autocomplete___13r65.theme__focus___35ZTa .theme__suggestions___3bxnc{max-height:45vh;visibility:visible;box-shadow:0 1px 6px rgba(0,0,0,.12),0 1px 4px rgba(0,0,0,.24)}.theme__values___ky6NA{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-bottom:.5rem}.theme__value___26Cd8{margin:.25rem .5rem .25rem 0}.theme__suggestions___3bxnc{position:absolute;z-index:100;width:100%;max-height:0;overflow-x:hidden;overflow-y:auto;visibility:hidden;background-color:#fff;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:max-height,box-shadow;transition-property:max-height,box-shadow}.theme__suggestions___3bxnc::-webkit-scrollbar{width:0;height:0}.theme__suggestions___3bxnc:not(.theme__up___FUauw){margin-top:-2rem}.theme__suggestions___3bxnc.theme__up___FUauw{bottom:0}.theme__suggestion___shQpe{padding:1rem;font-size:1.6rem;cursor:pointer}.theme__suggestion___shQpe.theme__active___nQ-Lu{background-color:#eee}.theme__input___77Yss{position:relative}.theme__input___77Yss:after{position:absolute;top:50%;right:.8rem;width:0;height:0;pointer-events:none;content:"";border-top:.54857rem solid rgba(0,0,0,.12);border-right:.54857rem solid transparent;border-left:.54857rem solid transparent;-webkit-transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1),-webkit-transform .35s cubic-bezier(.4,0,.2,1)}.slide-left__enter___UDCzm,.slide-left__leave___1yls4{position:absolute;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform}.slide-left__enter___UDCzm{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.slide-left__enter___UDCzm.slide-left__enterActive___2llDv,.slide-left__leave___1yls4{opacity:1;-webkit-transform:translateZ(0);transform:translateZ(0)}.slide-left__leave___1yls4.slide-left__leaveActive___1ImVa{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.slide-right__enter___8bk-m,.slide-right__leave___3NliL{position:absolute}.slide-right__enterActive___3pxpZ,.slide-right__leaveActive___3spKq{-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:transform,opacity;transition-property:transform,opacity,-webkit-transform}.slide-right__enter___8bk-m{opacity:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.slide-right__enter___8bk-m.slide-right__enterActive___3pxpZ,.slide-right__leave___3NliL{opacity:1;-webkit-transform:translateX(0);transform:translateX(0)}.slide-right__leave___3NliL.slide-right__leaveActive___3spKq{opacity:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.zoom-in__enter___3Ti1d,.zoom-in__leave___3EnQZ{position:absolute}.zoom-in__enterActive___1eFhL,.zoom-in__leaveActive___3dBpi{-webkit-transition:opacity,-webkit-transform;transition:opacity,-webkit-transform;transition:transform,opacity;transition:transform,opacity,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.5s;transition-duration:.5s}.zoom-in__enter___3Ti1d{opacity:0;-webkit-transform:scale(.85);transform:scale(.85)}.zoom-in__enter___3Ti1d.zoom-in__enterActive___1eFhL,.zoom-in__leave___3EnQZ{opacity:1;-webkit-transform:scale(1);transform:scale(1)}.zoom-in__leave___3EnQZ.zoom-in__leaveActive___3dBpi{opacity:0;-webkit-transform:scale(1.25);transform:scale(1.25)}.zoom-out__enter___xiACW,.zoom-out__leave___3wDWL{position:absolute}.zoom-out__enterActive___3QrhD,.zoom-out__leaveActive___3C11f{-webkit-transition:opacity,-webkit-transform;transition:opacity,-webkit-transform;transition:transform,opacity;transition:transform,opacity,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.5s;transition-duration:.5s}.zoom-out__enter___xiACW{opacity:0;-webkit-transform:scale(1.25);transform:scale(1.25)}.zoom-out__enter___xiACW.zoom-out__enterActive___3QrhD,.zoom-out__leave___3wDWL{opacity:1;-webkit-transform:scale(1);transform:scale(1)}.zoom-out__leave___3wDWL.zoom-out__leaveActive___3C11f{opacity:0;-webkit-transform:scale(.85);transform:scale(.85)}.theme__overlay___PiEHX{position:fixed;top:0;left:0;z-index:300;display:-webkit-box;display:-ms-flexbox;display:flex;width:100vw;height:100vh;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;pointer-events:none}.theme__overlay___PiEHX.theme__invisible___3SslD>:not(.theme__backdrop___WbaQn){pointer-events:all}.theme__backdrop___WbaQn{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:0;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:opacity;transition-property:opacity}.theme__active___2oZU5{pointer-events:all}.theme__active___2oZU5>.theme__backdrop___WbaQn{opacity:.6}.theme__dialog___1f3Zg{display:-webkit-box;display:-ms-flexbox;display:flex;max-width:96vw;max-height:96vh;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;background-color:#fff;border-radius:.2rem;box-shadow:0 19px 60px rgba(0,0,0,.3),0 15px 20px rgba(0,0,0,.22);opacity:0;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:opacity,-webkit-transform;transition-property:opacity,-webkit-transform;transition-property:opacity,transform;transition-property:opacity,transform,-webkit-transform;-webkit-transform:translateY(-4rem);transform:translateY(-4rem)}.theme__dialog___1f3Zg.theme__active___3rz6t{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}.theme__small___WKoav{width:30vw}@media screen and (max-width:720px){.theme__small___WKoav{width:50vw}}@media screen and (max-width:600px){.theme__small___WKoav{width:75vw}}.theme__normal___1WehK{width:50vw}@media screen and (max-width:600px){.theme__normal___1WehK{width:96vw}}.theme__fullscreen___2Akul,.theme__large___10bxm{width:96vw}@media screen and (max-width:600px){.theme__fullscreen___2Akul{width:100vw;max-width:100vw;min-height:100vh;max-height:100vh;border-radius:0}}.theme__title____sEzV{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:2rem;font-weight:500;line-height:1;letter-spacing:.02em;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;margin-bottom:1.6rem;color:#000}.theme__body___1_nNM{-webkit-box-flex:2;-ms-flex-positive:2;flex-grow:2;padding:2.4rem;color:#757575}.theme__navigation___3eiS-{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;padding:.8rem;text-align:right}.theme__button___3HGWm{min-width:0;padding-right:.8rem;padding-left:.8rem;margin-left:.8rem}.theme__input___1TiDt:not(.theme__disabled___2N4Gy)>.theme__inputElement___1oBGc{cursor:pointer}.theme__header___1DCA-{padding:1.6rem 2rem;color:#fff;cursor:pointer;background-color:#ff5722}.theme__year___38-P5{display:inline-block;font-size:1.4rem;-webkit-transition:opacity,font-size .35s cubic-bezier(.4,0,.2,1);transition:opacity,font-size .35s cubic-bezier(.4,0,.2,1)}.theme__date___2R1Ad{display:block;font-weight:500;text-transform:capitalize;-webkit-transition:opacity .35s cubic-bezier(.4,0,.2,1);transition:opacity .35s cubic-bezier(.4,0,.2,1)}.theme__calendarWrapper___15gNf{padding:1rem .5rem 0}.theme__yearsDisplay___24Iwn .theme__date___2R1Ad{opacity:.6}.theme__yearsDisplay___24Iwn .theme__year___38-P5{font-size:1.6rem}.theme__monthsDisplay___5fYTt .theme__year___38-P5{opacity:.6}.theme__dialog___1RQhu{width:33rem}.theme__dialog___1RQhu>[role=body]{padding:0}.theme__dialog___1RQhu>[role=navigation]>.theme__button___14VKJ{color:#ff5722}.theme__dialog___1RQhu>[role=navigation]>.theme__button___14VKJ:focus:not(:active),.theme__dialog___1RQhu>[role=navigation]>.theme__button___14VKJ:hover{background:rgba(255,87,34,.2)}.theme__calendar___1I5OE{position:relative;height:27rem;overflow:hidden;font-size:1.4rem;line-height:3rem;text-align:center;background:#fff}.theme__calendar___1I5OE .theme__next___11dJn,.theme__calendar___1I5OE .theme__prev___xfk7M{position:absolute;top:0;z-index:100;height:3.6rem;cursor:pointer;opacity:.7}.theme__calendar___1I5OE .theme__prev___xfk7M{left:0}.theme__calendar___1I5OE .theme__next___11dJn{right:0}.theme__title___2Ue3-{display:inline-block;font-weight:500;line-height:3rem}.theme__years___3xKtS{height:100%;overflow-y:auto;font-size:1.8rem}.theme__years___3xKtS>li{line-height:2.4;cursor:pointer}.theme__years___3xKtS>li.theme__active___2k63V{font-size:2.4rem;font-weight:500;color:#ff5722}.theme__week___17JkF{display:-webkit-box;display:-ms-flexbox;display:flex;height:3rem;-ms-flex-wrap:wrap;flex-wrap:wrap;font-size:1.3rem;line-height:3rem;opacity:.5}.theme__week___17JkF>span{-webkit-box-flex:0;-ms-flex:0 0 14.28571%;flex:0 0 14.28571%}.theme__days___3kAIy{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;font-size:1.3rem}.theme__day___3cb3g{-webkit-box-flex:0;-ms-flex:0 0 14.28571%;flex:0 0 14.28571%;padding:.2rem 0}.theme__day___3cb3g>span{display:inline-block;width:3rem;height:3rem;line-height:3rem;border-radius:50%}.theme__day___3cb3g:hover:not(.theme__active___2k63V):not(.theme__disabled___2N4Gy)>span{color:#fff;background:rgba(255,87,34,.21)}.theme__day___3cb3g.theme__active___2k63V>span{color:#fff;background:#ff5722}.theme__day___3cb3g:hover:not(.theme__disabled___2N4Gy)>span{cursor:pointer}.theme__day___3cb3g.theme__disabled___2N4Gy{opacity:.25}.theme__month___27O28{background-color:#fff}.theme__drawer___3cqqC{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);position:absolute;top:0;display:block;width:24rem;height:100%;overflow-x:hidden;overflow-y:auto;color:#424242;pointer-events:none;background-color:#fafafa;-webkit-transition-delay:0s;transition-delay:0s;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;will-change:transform}.theme__drawer___3cqqC.theme__active___2tbs1{pointer-events:all;-webkit-transition-delay:.07s;transition-delay:.07s;-webkit-transform:translateX(0);transform:translateX(0)}.theme__drawer___3cqqC.theme__right___ZJiGp{right:0;border-left:1px solid #e0e0e0}.theme__drawer___3cqqC.theme__right___ZJiGp:not(.theme__active___2tbs1){-webkit-transform:translateX(100%);transform:translateX(100%)}.theme__drawer___3cqqC.theme__left___wQVqA{left:0;border-right:1px solid #e0e0e0}.theme__drawer___3cqqC.theme__left___wQVqA:not(.theme__active___2tbs1){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.theme__dropdown___co-4M{position:relative}.theme__dropdown___co-4M:not(.theme__active___31xyK)>.theme__values___1jS4g{max-height:0;visibility:hidden}.theme__dropdown___co-4M.theme__active___31xyK>.theme__label___1lqXI,.theme__dropdown___co-4M.theme__active___31xyK>.theme__value___mflIw{opacity:.5}.theme__dropdown___co-4M.theme__active___31xyK>.theme__values___1jS4g{max-height:45vh;visibility:visible;box-shadow:0 1px 6px rgba(0,0,0,.12),0 1px 4px rgba(0,0,0,.24)}.theme__dropdown___co-4M:not(.theme__up___3kWOP)>.theme__values___1jS4g{top:0;bottom:auto}.theme__dropdown___co-4M.theme__up___3kWOP>.theme__values___1jS4g{top:auto;bottom:0}.theme__dropdown___co-4M.theme__disabled___3yAxB{pointer-events:none;cursor:normal}.theme__value___mflIw>input{cursor:pointer}.theme__value___mflIw:after{position:absolute;top:50%;right:.8rem;width:0;height:0;pointer-events:none;content:"";border-top:.54857rem solid rgba(0,0,0,.12);border-right:.54857rem solid transparent;border-left:.54857rem solid transparent;-webkit-transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1),-webkit-transform .35s cubic-bezier(.4,0,.2,1)}.theme__field___1elDx{position:relative;padding:2rem 0;cursor:pointer}.theme__field___1elDx.theme__errored___w5ZKs{padding-bottom:0}.theme__field___1elDx.theme__errored___w5ZKs>.theme__label___1lqXI{color:#de3226}.theme__field___1elDx.theme__errored___w5ZKs>.theme__templateValue___3if5o{border-bottom:1px solid #de3226}.theme__field___1elDx.theme__errored___w5ZKs>.theme__label___1lqXI>.theme__required___28L-E{color:#de3226}.theme__field___1elDx.theme__disabled___3yAxB{pointer-events:none;cursor:normal}.theme__field___1elDx.theme__disabled___3yAxB>.theme__templateValue___3if5o{border-bottom-style:dotted;opacity:.7}.theme__templateValue___3if5o{position:relative;min-height:3.84rem;padding:.8rem 0;color:#212121;background-color:transparent;border-bottom:1px solid rgba(0,0,0,.12)}.theme__label___1lqXI{position:absolute;top:.6rem;left:0;font-size:1.2rem;line-height:1.6rem;color:rgba(0,0,0,.26)}.theme__label___1lqXI .theme__required___28L-E{color:#de3226}.theme__error___2QR6b{margin-bottom:-2rem;font-size:1.2rem;line-height:2rem;color:#de3226}.theme__values___1jS4g{position:absolute;z-index:100;width:100%;overflow-y:auto;list-style:none;background-color:#fff;border-radius:.2rem;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:max-height,box-shadow;transition-property:max-height,box-shadow}.theme__values___1jS4g::-webkit-scrollbar{width:0;height:0}.theme__values___1jS4g>*{position:relative;padding:1rem;overflow:hidden;cursor:pointer}.theme__values___1jS4g>:hover{background-color:#eee}.theme__values___1jS4g>.theme__selected___2Uc3r{color:#ff5722}.theme__linear___Ljn5d{position:relative;display:inline-block;width:100%;height:.4rem;overflow:hidden;background:#eee}.theme__linear___Ljn5d.theme__indeterminate___3-YPh .theme__value___xShnS{-webkit-transform-origin:center center;transform-origin:center center;-webkit-animation:theme__linear-indeterminate-bar___rBsh8 1s linear infinite;animation:theme__linear-indeterminate-bar___rBsh8 1s linear infinite}.theme__buffer___2D7u0,.theme__value___xShnS{position:absolute;top:0;right:0;bottom:0;left:0;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transform:scaleX(0);transform:scaleX(0);-webkit-transform-origin:left center;transform-origin:left center}.theme__value___xShnS{background-color:#ff5722}[disabled] .theme__value___xShnS{background-color:rgba(0,0,0,.26)}.theme__buffer___2D7u0{background-image:-webkit-linear-gradient(left,hsla(0,0%,100%,.7),hsla(0,0%,100%,.7)),-webkit-linear-gradient(left,#ff5722,#ff5722);background-image:linear-gradient(90deg,hsla(0,0%,100%,.7),hsla(0,0%,100%,.7)),linear-gradient(90deg,#ff5722,#ff5722)}[disabled] .theme__buffer___2D7u0{background-image:-webkit-linear-gradient(left,hsla(0,0%,100%,.7),hsla(0,0%,100%,.7)),-webkit-linear-gradient(left,rgba(0,0,0,.26),rgba(0,0,0,.26));background-image:linear-gradient(90deg,hsla(0,0%,100%,.7),hsla(0,0%,100%,.7)),linear-gradient(90deg,rgba(0,0,0,.26),rgba(0,0,0,.26))}.theme__circular___1e2Sg{position:relative;display:inline-block;width:60px;height:60px;-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.theme__circular___1e2Sg.theme__indeterminate___3-YPh .theme__circle___3GNXM{-webkit-animation:theme__circular-indeterminate-bar-rotate___3OG7F 2s linear infinite;animation:theme__circular-indeterminate-bar-rotate___3OG7F 2s linear infinite}.theme__circular___1e2Sg.theme__indeterminate___3-YPh .theme__path___15ZCl{-webkit-animation:theme__circular-indeterminate-bar-dash___3AlSL 1.5s ease-in-out infinite;animation:theme__circular-indeterminate-bar-dash___3AlSL 1.5s ease-in-out infinite;stroke-dasharray:1.25,250;stroke-dashoffset:0}.theme__circular___1e2Sg.theme__indeterminate___3-YPh.theme__multicolor___1RiLp .theme__path___15ZCl{-webkit-animation:theme__circular-indeterminate-bar-dash___3AlSL 1.5s ease-in-out infinite,theme__colors___2VEin 6s ease-in-out infinite;animation:theme__circular-indeterminate-bar-dash___3AlSL 1.5s ease-in-out infinite,theme__colors___2VEin 6s ease-in-out infinite}.theme__circle___3GNXM{width:100%;height:100%}.theme__path___15ZCl{-webkit-transition:stroke-dasharray .35s cubic-bezier(.4,0,.2,1);transition:stroke-dasharray .35s cubic-bezier(.4,0,.2,1);fill:none;stroke-dasharray:0,250;stroke-dashoffset:0;stroke-linecap:round;stroke-miterlimit:20;stroke-width:4;stroke:#ff5722}@-webkit-keyframes theme__linear-indeterminate-bar___rBsh8{0%{-webkit-transform:translate(-50%) scaleX(0);transform:translate(-50%) scaleX(0)}50%{-webkit-transform:translate(0) scaleX(.3);transform:translate(0) scaleX(.3)}to{-webkit-transform:translate(50%) scaleX(0);transform:translate(50%) scaleX(0)}}@keyframes theme__linear-indeterminate-bar___rBsh8{0%{-webkit-transform:translate(-50%) scaleX(0);transform:translate(-50%) scaleX(0)}50%{-webkit-transform:translate(0) scaleX(.3);transform:translate(0) scaleX(.3)}to{-webkit-transform:translate(50%) scaleX(0);transform:translate(50%) scaleX(0)}}@-webkit-keyframes theme__circular-indeterminate-bar-rotate___3OG7F{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes theme__circular-indeterminate-bar-rotate___3OG7F{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes theme__circular-indeterminate-bar-dash___3AlSL{0%{stroke-dasharray:1.25,250;stroke-dashoffset:0}50%{stroke-dasharray:111.25,250;stroke-dashoffset:-43.75}to{stroke-dasharray:111.25,250;stroke-dashoffset:-155}}@keyframes theme__circular-indeterminate-bar-dash___3AlSL{0%{stroke-dasharray:1.25,250;stroke-dashoffset:0}50%{stroke-dasharray:111.25,250;stroke-dashoffset:-43.75}to{stroke-dasharray:111.25,250;stroke-dashoffset:-155}}@-webkit-keyframes theme__colors___2VEin{0%{stroke:#4285f4}25%{stroke:#de3e35}50%{stroke:#f7c223}75%{stroke:#1b9a59}to{stroke:#4285f4}}@keyframes theme__colors___2VEin{0%{stroke:#4285f4}25%{stroke:#de3e35}50%{stroke:#f7c223}75%{stroke:#1b9a59}to{stroke:#4285f4}}.theme__container___3AsSH{position:relative;width:calc(100% - 3.2rem);height:3.2rem;margin-right:3.2rem;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.theme__container___3AsSH:not(:last-child){margin-right:4.2rem}.theme__container___3AsSH:not(:first-child){margin-left:1rem}.theme__knob____QAHG{position:relative;top:0;left:0;z-index:200;display:-webkit-box;display:-ms-flexbox;display:flex;width:3.2rem;height:3.2rem;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;background-color:transparent}.theme__innerknob___20XNj{z-index:100;width:1.2rem;height:1.2rem;background-color:#ff5722;border-radius:50%;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.1s;transition-duration:.1s;-webkit-transition-property:height,width,background-color,border;transition-property:height,width,background-color,border}.theme__snaps___3KjIu{position:absolute;top:1.5rem;left:0;display:-webkit-box;display:-ms-flexbox;display:flex;width:calc(100% + .2rem);height:.2rem;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;pointer-events:none}.theme__snaps___3KjIu:after{display:block;width:.2rem;height:.2rem;content:"";background-color:#000;border-radius:50%}.theme__snap___3PGtj{-webkit-box-flex:1;-ms-flex:1;flex:1}.theme__snap___3PGtj:after{display:block;width:.2rem;height:.2rem;content:"";background-color:#000;border-radius:50%}.theme__input___3BSW2{width:5rem;padding:0;margin-bottom:0}.theme__input___3BSW2>input{text-align:center}.theme__progress___xkm0P{position:absolute;top:0;left:1.6rem;width:100%;height:100%}.theme__progress___xkm0P .theme__innerprogress____LUK-{position:absolute;top:1.5rem;height:.2rem}.theme__progress___xkm0P .theme__innerprogress____LUK- [data-ref=value]{-webkit-transition-duration:0s;transition-duration:0s}.theme__slider___2H6aE:focus .theme__knob____QAHG:before{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:"";background-color:#ff5722;border-radius:50%;opacity:.26}.theme__slider___2H6aE[disabled]{pointer-events:none;cursor:auto}.theme__slider___2H6aE[disabled] .theme__innerknob___20XNj{background-color:#b1b1b1}.theme__slider___2H6aE.theme__editable___3fZo3{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.theme__slider___2H6aE.theme__pinned___3tZ7h .theme__innerknob___20XNj:before{width:2.6rem;margin-left:.3rem;content:"";background-color:#ff5722;border-radius:50% 50% 50% 0;-webkit-transform:rotate(-45deg) scale(0) translate(0);transform:rotate(-45deg) scale(0) translate(0)}.theme__slider___2H6aE.theme__pinned___3tZ7h .theme__innerknob___20XNj:after,.theme__slider___2H6aE.theme__pinned___3tZ7h .theme__innerknob___20XNj:before{position:absolute;top:0;left:0;height:2.6rem;-webkit-transition:background-color .18s ease,-webkit-transform .2s ease;transition:background-color .18s ease,-webkit-transform .2s ease;transition:transform .2s ease,background-color .18s ease;transition:transform .2s ease,background-color .18s ease,-webkit-transform .2s ease}.theme__slider___2H6aE.theme__pinned___3tZ7h .theme__innerknob___20XNj:after{width:3.2rem;font-size:10px;color:#fff;text-align:center;content:attr(data-value);-webkit-transform:scale(0) translate(0);transform:scale(0) translate(0)}.theme__slider___2H6aE.theme__pressed___1GzJj.theme__pinned___3tZ7h .theme__innerknob___20XNj:before{-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transform:rotate(-45deg) scale(1) translate(1.7rem,-1.7rem);transform:rotate(-45deg) scale(1) translate(1.7rem,-1.7rem)}.theme__slider___2H6aE.theme__pressed___1GzJj.theme__pinned___3tZ7h .theme__innerknob___20XNj:after{-webkit-transition-delay:.1s;transition-delay:.1s;-webkit-transform:scale(1) translateY(-1.7rem);transform:scale(1) translateY(-1.7rem)}.theme__slider___2H6aE.theme__pressed___1GzJj:not(.theme__pinned___3tZ7h).theme__ring___N87_t .theme__progress___xkm0P{left:3rem;width:calc(100% - 1.4rem)}.theme__slider___2H6aE.theme__pressed___1GzJj:not(.theme__pinned___3tZ7h) .theme__innerknob___20XNj{width:100%;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0)}.theme__slider___2H6aE.theme__ring___N87_t .theme__innerknob___20XNj{background-color:transparent;border:.2rem solid #eee}.theme__slider___2H6aE.theme__ring___N87_t .theme__innerknob___20XNj:before{background-color:#ff5722}.theme__slider___2H6aE.theme__ring___N87_t .theme__progress___xkm0P{left:2rem;width:calc(100% - .4rem);-webkit-transition:left .18s ease,width .18s ease;transition:left .18s ease,width .18s ease}.theme__slider___2H6aE.theme__ring___N87_t.theme__pinned___3tZ7h .theme__innerknob___20XNj{background-color:#fff}.theme__slider___2H6aE.theme__ring___N87_t.theme__pinned___3tZ7h .theme__progress___xkm0P{left:1.6rem;width:100%}.theme__disabled___3HqAo,.theme__field___2rog8{position:relative;display:block;height:auto;margin-bottom:1.5rem;white-space:nowrap;vertical-align:middle}.theme__text___3b1B6{display:inline-block;padding-left:1rem;font-size:1.4rem;line-height:2.4rem;color:#000;white-space:normal;vertical-align:top}.theme__off___Ih3qa,.theme__on___3ocqI{position:relative;display:inline-block;width:3.6rem;height:1.4rem;margin-top:.5rem;vertical-align:top;cursor:pointer;border-radius:1.4rem}.theme__thumb___3ryrT{-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1);-webkit-transition-duration:.28s;transition-duration:.28s;position:absolute;top:-.3rem;width:2rem;height:2rem;cursor:pointer;border-radius:50%;-webkit-transition-property:left;transition-property:left}.theme__thumb___3ryrT .theme__ripple___1A_Pi{background-color:#ff5722;opacity:.3;-webkit-transition-duration:.65s;transition-duration:.65s}.theme__on___3ocqI{background:rgba(255,87,34,.5)}.theme__on___3ocqI .theme__thumb___3ryrT{box-shadow:0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.2),0 1px 8px 0 rgba(0,0,0,.12);left:1.6rem;background:#ff5722}.theme__off___Ih3qa{background:rgba(0,0,0,.26)}.theme__off___Ih3qa .theme__thumb___3ryrT{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);left:0;background:#fafafa}.theme__off___Ih3qa .theme__ripple___1A_Pi{background:rgba(0,0,0,.4)}.theme__input___10E4S:focus:not(:active)+.theme__switch-off___105FO>.theme__thumb___3ryrT:before,.theme__input___10E4S:focus:not(:active)+.theme__switch-on___2n4g1>.theme__thumb___3ryrT:before{position:absolute;top:50%;left:50%;box-sizing:border-box;display:inline-block;width:.8rem;height:.8rem;content:"";background-color:transparent;border-radius:50%;-webkit-transform:translate(-.4rem,-.4rem);transform:translate(-.4rem,-.4rem)}.theme__input___10E4S{width:0;height:0;overflow:hidden;opacity:0}.theme__input___10E4S:focus:not(:active)+.theme__switch-on___2n4g1>.theme__thumb___3ryrT:before{background-color:rgba(255,87,34,.26);box-shadow:0 0 0 2rem rgba(255,87,34,.26)}.theme__input___10E4S:focus:not(:active)+.theme__switch-off___105FO>.theme__thumb___3ryrT:before{background-color:rgba(0,0,0,.1);box-shadow:0 0 0 2rem rgba(0,0,0,.1)}.theme__disabled___3HqAo .theme__text___3b1B6{color:rgba(0,0,0,.26)}.theme__disabled___3HqAo .theme__off___Ih3qa,.theme__disabled___3HqAo .theme__on___3ocqI{cursor:auto;background:rgba(0,0,0,.12)}.theme__disabled___3HqAo .theme__thumb___3ryrT{cursor:auto;background-color:#bdbdbd;border-color:transparent}.theme__input___33OFH:not(.theme__disabled___3zAd9)>.theme__inputElement___3V_R1{cursor:pointer}.theme__header___B8avX{position:relative;width:100%;padding:1rem;font-size:5.2rem;color:#fff;text-align:center;background:#ff5722}.theme__hours___2bCtV,.theme__minutes___fKY3r{display:inline-block;cursor:pointer;opacity:.6}.theme__separator___1wf1f{margin:0 .5rem;opacity:.6}.theme__ampm___2zwK2{position:absolute;top:50%;right:2rem;width:4rem;height:4.4rem;margin-top:-2.2rem;font-size:1.6rem;line-height:2.2rem;text-align:center}.theme__am___ZDt_I,.theme__pm___15BOL{display:block;cursor:pointer;opacity:.6}.theme__dialog___2xstp{width:30rem}.theme__dialog___2xstp>[role=body]{padding:0;overflow-y:visible}.theme__dialog___2xstp>[role=navigation]>.theme__button___2Naxh{color:#ff5722}.theme__dialog___2xstp>[role=navigation]>.theme__button___2Naxh:focus:not(:active),.theme__dialog___2xstp>[role=navigation]>.theme__button___2Naxh:hover{background:rgba(255,87,34,.2)}.theme__dialog___2xstp.theme__amFormat___3V_aj .theme__am___ZDt_I,.theme__dialog___2xstp.theme__hoursDisplay___2XYVr .theme__hours___2bCtV,.theme__dialog___2xstp.theme__minutesDisplay___2lM_9 .theme__minutes___fKY3r,.theme__dialog___2xstp.theme__pmFormat___EeG6D .theme__pm___15BOL{opacity:1}.theme__clock___2Wdtj{padding:1.5rem 2rem}.theme__placeholder___49iU5{position:relative;z-index:100}.theme__clockWrapper___nVLna{position:absolute;width:100%;background-color:#eee;border-radius:50%}.theme__face___3ZQPp{position:absolute;top:50%;left:50%;z-index:100;cursor:pointer;border-radius:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.theme__number___19LR-{position:relative;width:2rem;height:2rem;margin-top:-1rem;margin-left:-1rem;text-align:center;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.theme__number___19LR-.theme__active___2hiVT{color:#fff}.theme__hand___Ff-XL{bottom:50%;display:block;width:.4rem;margin-left:-.2rem;-webkit-transform-origin:50% 100%;transform-origin:50% 100%}.theme__hand___Ff-XL,.theme__hand___Ff-XL:before{position:absolute;left:50%;background-color:#ff5722}.theme__hand___Ff-XL:before{bottom:0;width:1rem;height:1rem;margin-bottom:-.5rem;margin-left:-.5rem;content:"";border-radius:50%}.theme__hand___Ff-XL.theme__small___Cthf4>.theme__knob___3yr7J{background-color:rgba(255,87,34,.2)}.theme__hand___Ff-XL.theme__small___Cthf4>.theme__knob___3yr7J:after{position:absolute;top:50%;left:50%;width:1.2rem;height:1.2rem;margin-top:-.6rem;margin-left:-.6rem;content:"";background:#ff5722;border-radius:50%}.theme__hand___Ff-XL.theme__small___Cthf4>.theme__knob___3yr7J:before{position:absolute;bottom:0;left:50%;width:.4rem;height:2.2rem;margin-left:-.2rem;content:"";background:#ff5722}.theme__knob___3yr7J{position:absolute;top:-3.4rem;left:50%;width:3.4rem;height:3.4rem;margin-left:-1.7rem;cursor:pointer;background-color:#ff5722;border-radius:50%}.theme__icon___oJcgi{margin-right:1rem;font-size:1.8rem}.theme__link___AKdRk{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-line-pack:center;align-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;line-height:1.5;cursor:pointer;-webkit-transition:opacity .35s cubic-bezier(.4,0,.2,1);transition:opacity .35s cubic-bezier(.4,0,.2,1)}.theme__link___AKdRk:not(.theme__active___1r_T0){opacity:.5}.theme__link___AKdRk:active,.theme__link___AKdRk:hover{opacity:1}.theme__link___AKdRk>*{vertical-align:middle}.theme__link___AKdRk>abbr{text-transform:capitalize}.theme__link___AKdRk>small{margin-left:.8rem;font-size:1.2rem;text-align:center}.theme__horizontal___1Gx6_>[data-react-toolbox=button],.theme__horizontal___1Gx6_>[data-react-toolbox=link]{display:inline-block;margin:0 .5rem}.theme__vertical___29Teo>[data-react-toolbox=button],.theme__vertical___29Teo>[data-react-toolbox=link]{display:block;margin:.5rem}.theme__horizontal___1Gx6_,.theme__vertical___29Teo{padding:.5rem}.theme__horizontal___1Gx6_>[data-react-toolbox=link],.theme__vertical___29Teo>[data-react-toolbox=link]{color:#000}.theme__snackbar___33MRN{position:fixed;right:2.4rem;bottom:0;left:2.4rem;z-index:200;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:1.4rem 2.4rem;margin:0 auto;margin-top:1.4rem;color:#fff;background-color:#212121;border-radius:.2rem;-webkit-transition:all .35s cubic-bezier(.4,0,.2,1) .35s;transition:all .35s cubic-bezier(.4,0,.2,1) .35s}.theme__snackbar___33MRN.theme__accept___I_Pq1 .theme__button___psiy3{color:#4caf50}.theme__snackbar___33MRN.theme__warning___29XlW .theme__button___psiy3{color:#eeff41}.theme__snackbar___33MRN.theme__cancel___1C-_T .theme__button___psiy3{color:#f44336}.theme__snackbar___33MRN:not(.theme__active___1U6m8){-webkit-transform:translateY(100%);transform:translateY(100%)}.theme__snackbar___33MRN.theme__active___1U6m8{-webkit-transform:translateY(0);transform:translateY(0)}.theme__label___2EWLb{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;font-size:1.4rem}.theme__button___psiy3{min-width:inherit;margin:-.7rem -1.2rem -.7rem 4.8rem}.theme__table___3Gpgy{width:100%;font-size:1.2rem;color:#757575;text-align:left;border-spacing:0}.theme__table___3Gpgy tr{height:48px;line-height:48px}.theme__table___3Gpgy th{font-weight:700}.theme__table___3Gpgy th:first-letter{text-transform:capitalize}.theme__table___3Gpgy td,.theme__table___3Gpgy th{position:relative;padding:0 1.8rem;border-bottom:1px solid rgba(0,0,0,.12)}.theme__table___3Gpgy td.theme__selectable___3T6wF,.theme__table___3Gpgy th.theme__selectable___3T6wF{width:1.8rem;padding-right:0}.theme__table___3Gpgy td.theme__selectable___3T6wF>*,.theme__table___3Gpgy th.theme__selectable___3T6wF>*{margin:0}.theme__row___2iik7{-webkit-transition:background-color .35s cubic-bezier(.4,0,.2,1);transition:background-color .35s cubic-bezier(.4,0,.2,1)}.theme__row___2iik7:last-child td{border-color:transparent}.theme__row___2iik7>td>input{display:block;width:100%;background-color:transparent;border:0}.theme__row___2iik7:hover,.theme__selected___3xb9B{background-color:#eee}.theme__editable___1aYHG>*{cursor:pointer}.theme__tooltip___3uHDc{position:absolute;z-index:200;display:block;max-width:17rem;padding:.5rem;font-family:Roboto,sans-serif;font-size:1rem;font-weight:700;line-height:1.4rem;text-align:center;text-transform:none;pointer-events:none;-webkit-transition:transform .2s cubic-bezier(.4,0,.2,1);transition:transform .2s cubic-bezier(.4,0,.2,1);-webkit-transform:scale(0) translateX(-50%);transform:scale(0) translateX(-50%);-webkit-transform-origin:top left;transform-origin:top left}.theme__tooltip___3uHDc.theme__tooltipActive___3FruK{-webkit-transform:scale(1) translateX(-50%);transform:scale(1) translateX(-50%)}.theme__tooltip___3uHDc.theme__tooltipTop___2JE6v{-webkit-transform:scale(0) translateX(-50%) translateY(-100%);transform:scale(0) translateX(-50%) translateY(-100%)}.theme__tooltip___3uHDc.theme__tooltipTop___2JE6v.theme__tooltipActive___3FruK{-webkit-transform:scale(1) translateX(-50%) translateY(-100%);transform:scale(1) translateX(-50%) translateY(-100%)}.theme__tooltip___3uHDc.theme__tooltipLeft___3S-DF{-webkit-transform:scale(0) translateX(-100%) translateY(-50%);transform:scale(0) translateX(-100%) translateY(-50%)}.theme__tooltip___3uHDc.theme__tooltipLeft___3S-DF.theme__tooltipActive___3FruK{-webkit-transform:scale(1) translateX(-100%) translateY(-50%);transform:scale(1) translateX(-100%) translateY(-50%)}.theme__tooltip___3uHDc.theme__tooltipRight___DIPzx{-webkit-transform:scale(0) translateX(0) translateY(-50%);transform:scale(0) translateX(0) translateY(-50%)}.theme__tooltip___3uHDc.theme__tooltipRight___DIPzx.theme__tooltipActive___3FruK{-webkit-transform:scale(1) translateX(0) translateY(-50%);transform:scale(1) translateX(0) translateY(-50%)}.theme__tooltipInner___3yZfk{display:block;padding:.8rem;color:#fff;background:rgba(97,97,97,.9);border-radius:.2rem}.style__appbar___2QTMv{z-index:200;display:-webkit-box;display:-ms-flexbox;display:flex;min-height:6.4rem;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;box-shadow:0 1px hsla(0,0%,100%,.65);background-color:#37474f}.style__appTitle___14TWh{text-transform:uppercase}.style__companySettings___xBM6u,.style__topBarOptions___mSQNO{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;text-align:right}.style__companySettings___xBM6u>span{text-transform:uppercase;font-size:1.4rem;font-weight:500}.style__menu___19mUU>div{margin-top:4rem;margin-right:1rem}.style__menu___19mUU button>span{color:#fff}.style__root___1OFQ4{display:-webkit-box;display:-ms-flexbox;display:flex;width:22rem;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;background-color:#fff}.style__navigation___VosYm{position:fixed;top:6.4rem;bottom:0;left:0;z-index:300;box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);-webkit-transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:-webkit-transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1);transition:transform .35s cubic-bezier(.4,0,.2,1),-webkit-transform .35s cubic-bezier(.4,0,.2,1)}.style__list___iyZve{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;overflow-y:auto}.style__list___iyZve::-webkit-scrollbar{width:0;height:0}.style__item___3fG-k>span{padding:1.2rem 2.4rem}.style__item___3fG-k [data-react-toolbox=list-item-text]{font-size:1.4rem;font-weight:500}.style__active___2e1_p{background:#eee}.style__active___2e1_p span:before{position:absolute;bottom:0;left:0;display:block;width:.3rem;height:100%;content:"";background-color:#ff5722}.style__footer___UuQo4{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;padding:2.4rem;overflow:hidden;text-align:center;font-size:1.4rem;color:#757575;border-top:1px solid #e0e0e0}.style__footer___UuQo4>*{display:block}.style__footerTitle___UML2d{color:#fd7348;font-weight:500;padding-bottom:.5rem}/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}html{font-size:62.5%}body{position:absolute;width:100%;height:100%;padding:0;margin:0;font-family:Roboto,sans-serif;font-size:1.6rem;-webkit-touch-callout:none}body *{-webkit-tap-highlight-color:rgba(255,255,255,0)}a,abbr,address,article,aside,audio,b,blockquote,body,caption,cite,code,dd,del,dfn,dialog,div,dl,dt,em,fieldset,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,p,pre,q,samp,section,small,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,time,tr,ul,var,video{padding:0;margin:0;border:0;outline:0}*,:after,:before{box-sizing:border-box;padding:0;margin:0}a,abbr,button,h1,h2,h3,h4,h5,h6,label,p,small,span{font-smoothing:antialiased;-webkit-font-smoothing:antialiased;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}a{text-decoration:none;-webkit-tap-highlight-color:transparent}button,input:not([type=checkbox]):not([type=radio]){outline:none;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:rgba(255,255,255,0)}input[required]:-moz-ui-invalid{box-shadow:none}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{opacity:.54}h1,h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-size:5.6rem;line-height:1.35;letter-spacing:-.02em}h1,h1 small,h2,h2 small,h3 small,h4 small,h5 small,h6 small{font-family:Roboto,Helvetica,Arial,sans-serif;font-weight:400}h2{font-size:4.5rem;line-height:4.8rem}h3{font-size:3.4rem;line-height:4rem}h3,h4{font-family:Roboto,Helvetica,Arial,sans-serif;font-weight:400}h4{font-size:2.4rem;line-height:3.2rem;-moz-osx-font-smoothing:grayscale}h5{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:2rem;font-weight:500;line-height:1;letter-spacing:.02em}h6{font-family:Roboto,Helvetica,Arial,sans-serif;font-size:1.6rem;letter-spacing:.04em}h6,p{font-weight:400;line-height:2.4rem}p{font-size:1.4rem;letter-spacing:0}.style__mainPage___3-2ms{margin-top:6.4rem;margin-left:22rem}.style__mainContent___cQjt4{padding:2rem}.style__mainBreadcrumbs___3oSTT{padding-bottom:2rem;color:#abacac}.style__mainBreadcrumbs___3oSTT a{-webkit-transition:color .4s;transition:color .4s;color:#37474f}.style__mainBreadcrumbs___3oSTT a:link,.style__mainBreadcrumbs___3oSTT a:visited{color:#37474f}.style__mainBreadcrumbs___3oSTT a:active,.style__mainBreadcrumbs___3oSTT a:hover{color:#2e3339}.style__showbox___2_rzn{position:absolute;top:0;bottom:0;left:0;right:0;z-index:1000001;height:100%;width:100%;background:none repeat scroll 0 0 #000;position:fixed;display:block;opacity:.5}.style__loader___2nW0b{position:relative;top:5.4rem}.style__notificationSnackbar___1QypG{width:60%;text-align:center}hgroup{text-align:center;margin-top:8rem}hgroup h3{color:#37474f}hgroup .style__subtitle___iA-iX{margin-top:1rem;color:#fd7348;font-weight:200}.style__group___eZldG{position:relative;margin-bottom:2rem}.style__dashboardCard___3-5mX{width:40rem;margin:4em auto;padding:3em 2em 2em}.style__cardActions___29Swh{padding-top:2rem;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.style__welcome___3aHN5 .style__title___3ayCw{margin-top:3rem;color:#fd7348}.style__welcome___3aHN5 .style__subtitle___2Mmn8{margin-top:2rem;letter-spacing:.3em;color:#abacac}.style__commentForm___txxPA{padding:1rem}.style__toolbar___ySVYb{padding-bottom:1rem}.style__bottomOptions___1DDQN{margin-top:2rem}.style__pageNotFound___3-Ggj>p{font-size:2.4rem;font-weight:400;padding-bottom:2rem}body{background:#f6f6f6} 2 | /*# sourceMappingURL=main.098aa9ee0d410b880d633a4523eae478.css.map*/ -------------------------------------------------------------------------------- /dist_server/index.html: -------------------------------------------------------------------------------- 1 | react-redux-starter
-------------------------------------------------------------------------------- /dist_server/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const path = require('path'); 3 | // const compression = require('compression'); 4 | 5 | const port = process.env.PORT || 3000; 6 | const app = express(); 7 | 8 | // app.use(compression()); 9 | app.use(express.static(__dirname)); 10 | 11 | app.get('/', (_req, res) => { 12 | res.sendFile(path.join(__dirname, 'index.html')); 13 | }); 14 | 15 | /* eslint-disable no-console */ 16 | 17 | app.listen(port, (err) => { 18 | if (err) { 19 | console.log(err); 20 | } else { 21 | console.log(`server started port: ${port}`); 22 | } 23 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-starter", 3 | "version": "0.1.0", 4 | "author": "Ricardo Reis", 5 | "homepage": "https://github.com/rjmreis/react-redux-starter#readme", 6 | "description": "React/Redux starter with login and basic CRUD functionality", 7 | "bugs": { 8 | "url": "https://github.com/rjmreis/react-redux-starter/issues" 9 | }, 10 | "engines": { 11 | "npm": ">=6.0.0" 12 | }, 13 | "scripts": { 14 | "start-message": "babel-node tools/startMessage.js", 15 | "prestart": "npm-run-all --parallel start-message remove-dist", 16 | "start": "npm-run-all --parallel test:watch open:src lint:watch", 17 | "open:src": "babel-node tools/srcServer.js", 18 | "open:dist": "babel-node tools/distServer.js", 19 | "dist-server": "node dist_server/server.js", 20 | "lint": "esw webpack.config.* src tools --color", 21 | "lint:watch": "npm run lint -- --watch", 22 | "clean-dist": "npm run remove-dist && mkdir dist", 23 | "remove-dist": "rimraf ./dist", 24 | "prebuild": "npm run clean-dist && npm run lint && npm run test", 25 | "build": "babel-node tools/build.js && npm run open:dist", 26 | "test": "mocha tools/testSetup.js \"src/**/*.spec.js\" --reporter progress", 27 | "test:cover": "babel-node node_modules/isparta/bin/isparta cover --root src --report html node_modules/mocha/bin/_mocha -- --require ./tools/testSetup.js \"src/**/*.spec.js\" --reporter progress", 28 | "test:cover:travis": "babel-node node_modules/isparta/bin/isparta cover --root src --report lcovonly _mocha -- --require ./tools/testSetup.js \"src/**/*.spec.js\" && cat ./coverage/lcov.info | node_modules/coveralls/bin/coveralls.js", 29 | "test:watch": "npm run test -- --watch", 30 | "open:cover": "npm run test:cover && open coverage/index.html" 31 | }, 32 | "license": "MIT", 33 | "dependencies": { 34 | "babel-cli": "6.18.0", 35 | "babel-core": "6.21.0", 36 | "express": "^4.14.0", 37 | "immutability-helper": "^2.0.0", 38 | "normalize.css": "^5.0.0", 39 | "object-assign": "4.1.0", 40 | "react": "15.4.1", 41 | "react-addons-css-transition-group": "^15.4.1", 42 | "react-breadcrumbs": "^1.5.1", 43 | "react-dom": "15.4.1", 44 | "react-redux": "5.0.1", 45 | "react-router": "3.0.0", 46 | "react-router-redux": "4.0.7", 47 | "react-toolbox": "^1.3.3", 48 | "redux": "3.6.0", 49 | "redux-thunk": "2.1.0", 50 | "validate.js": "^0.11.1" 51 | }, 52 | "devDependencies": { 53 | "autoprefixer": "6.5.4", 54 | "babel-eslint": "^7.1.1", 55 | "babel-loader": "6.2.10", 56 | "babel-plugin-react-display-name": "2.0.0", 57 | "babel-plugin-transform-react-constant-elements": "6.9.1", 58 | "babel-plugin-transform-react-remove-prop-types": "0.2.11", 59 | "babel-preset-latest": "6.16.0", 60 | "babel-preset-react": "6.16.0", 61 | "babel-preset-react-hmre": "1.1.1", 62 | "babel-preset-stage-1": "6.16.0", 63 | "babel-register": "6.18.0", 64 | "browser-sync": "2.18.5", 65 | "chai": "3.5.0", 66 | "chalk": "1.1.3", 67 | "connect-history-api-fallback": "1.3.0", 68 | "coveralls": "2.11.15", 69 | "cross-env": "3.1.3", 70 | "css-loader": "0.26.1", 71 | "enzyme": "2.6.0", 72 | "eslint": "3.12.2", 73 | "eslint-plugin-babel": "^4.0.0", 74 | "eslint-plugin-import": "2.2.0", 75 | "eslint-plugin-jsx-a11y": "3.0.2", 76 | "eslint-plugin-react": "6.8.0", 77 | "eslint-watch": "2.1.14", 78 | "extract-text-webpack-plugin": "1.0.1", 79 | "file-loader": "0.9.0", 80 | "html-webpack-plugin": "2.24.1", 81 | "isparta": "4.0.0", 82 | "json-loader": "^0.5.4", 83 | "mocha": "3.2.0", 84 | "mockdate": "2.0.1", 85 | "node-sass": "4.1.0", 86 | "npm-run-all": "3.1.2", 87 | "open": "0.0.5", 88 | "postcss-loader": "1.2.1", 89 | "prompt": "1.0.0", 90 | "react-addons-test-utils": "15.4.1", 91 | "redux-immutable-state-invariant": "1.2.4", 92 | "replace": "0.3.0", 93 | "rimraf": "2.5.4", 94 | "sass-loader": "4.1.0", 95 | "sinon": "1.17.6", 96 | "sinon-chai": "2.8.0", 97 | "style-loader": "0.13.1", 98 | "url-loader": "0.5.7", 99 | "webpack": "1.14.0", 100 | "webpack-dev-middleware": "1.9.0", 101 | "webpack-hot-middleware": "2.13.2", 102 | "webpack-md5-hash": "0.0.5" 103 | }, 104 | "keywords": [ 105 | "react", 106 | "redux", 107 | "material" 108 | ], 109 | "repository": { 110 | "type": "git", 111 | "url": "" 112 | } 113 | } -------------------------------------------------------------------------------- /src/actions/ajaxStatusActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | 3 | export function beginAjaxCall() { 4 | return { type: types.BEGIN_AJAX_CALL }; 5 | } 6 | 7 | export function ajaxCallError() { 8 | return { type: types.AJAX_CALL_ERROR }; 9 | } 10 | -------------------------------------------------------------------------------- /src/actions/authActions.js: -------------------------------------------------------------------------------- 1 | import { browserHistory } from 'react-router'; 2 | import * as types from '../constants/actionTypes'; 3 | import api from '../api'; 4 | import { beginAjaxCall, ajaxCallError } from './ajaxStatusActions'; 5 | 6 | const requestLogin = creds => { 7 | return { 8 | type: types.LOGIN_REQUEST, 9 | isAuthenticated: false, 10 | creds 11 | }; 12 | }; 13 | 14 | const receiveLogin = auth => { 15 | return { 16 | type: types.LOGIN_SUCCESS, 17 | isAuthenticated: true, 18 | user: auth.user 19 | }; 20 | }; 21 | 22 | const loginError = message => { 23 | return { 24 | type: types.LOGIN_FAILURE, 25 | isAuthenticated: false, 26 | message 27 | }; 28 | }; 29 | 30 | const requestLogout = () => { 31 | return { 32 | type: types.LOGOUT_REQUEST, 33 | isAuthenticated: true 34 | }; 35 | }; 36 | 37 | const receiveLogout = () => { 38 | return { 39 | type: types.LOGOUT_SUCCESS, 40 | isAuthenticated: false 41 | }; 42 | }; 43 | 44 | // Calls the API to get a token and 45 | // dispatches actions along the way 46 | export const loginUser = creds => ( 47 | 48 | dispatch => { 49 | dispatch(beginAjaxCall()); 50 | 51 | // We dispatch requestLogin to kickoff the call to the API 52 | dispatch(requestLogin(creds)); 53 | 54 | return api.auth.authenticate(creds) 55 | .then(auth => { 56 | // If login was successful, set the token in local storage 57 | localStorage.setItem('id_token', auth.id_token); 58 | localStorage.setItem('user', JSON.stringify(auth.user)); 59 | 60 | // Dispatch the success action 61 | dispatch(receiveLogin(auth)); 62 | }).catch(error => { 63 | dispatch(ajaxCallError(error)); 64 | dispatch(loginError(error.message)); 65 | throw error; 66 | }); 67 | } 68 | ); 69 | 70 | // Logs the user out 71 | export const logoutUser = () => { 72 | return dispatch => { 73 | dispatch(requestLogout()); 74 | localStorage.removeItem('id_token'); 75 | localStorage.removeItem('user'); 76 | dispatch(receiveLogout()); 77 | browserHistory.push('/'); 78 | }; 79 | }; 80 | -------------------------------------------------------------------------------- /src/actions/commentActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import api from '../api'; 3 | import { beginAjaxCall } from './ajaxStatusActions'; 4 | import { handleAjaxError } from '../utils/ajax'; 5 | 6 | export const listComments = () => ( 7 | (dispatch) => { 8 | dispatch(beginAjaxCall()); 9 | 10 | return api.comments.listComments() 11 | .then(comments => { 12 | dispatch({ type: types.LIST_COMMENTS_SUCCESS, comments: comments }); 13 | }).catch(error => { 14 | handleAjaxError(dispatch, error); 15 | throw error; 16 | }); 17 | } 18 | ); 19 | 20 | export const saveComment = (comment) => ( 21 | (dispatch) => { 22 | dispatch(beginAjaxCall()); 23 | 24 | return api.comments.saveComment(comment) 25 | .then(savedComment => { 26 | comment.id ? dispatch({ type: types.UPDATE_COMMENT_SUCCESS, comment: savedComment }) : 27 | dispatch({ type: types.CREATE_COMMENT_SUCCESS, comment: savedComment }); 28 | }).catch(error => { 29 | handleAjaxError(dispatch, error); 30 | throw (error); 31 | }); 32 | } 33 | ); 34 | 35 | export const deleteComment = comment => ( 36 | (dispatch) => { 37 | dispatch(beginAjaxCall()); 38 | 39 | let commentId = comment.id; 40 | return api.comments.deleteComment(comment) 41 | .then(() => { 42 | dispatch({ type: types.DELETE_COMMENT_SUCCESS, commentId: commentId }); 43 | }).catch(error => { 44 | handleAjaxError(dispatch, error); 45 | throw (error); 46 | }); 47 | } 48 | ); 49 | -------------------------------------------------------------------------------- /src/actions/notificationActions.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | 3 | export const showNotification = message => ( 4 | (dispatch) => { 5 | return dispatch({ type: types.SHOW_NOTIFICATION, message }); 6 | } 7 | ); 8 | 9 | export const hideNotification = () => ( 10 | (dispatch) => { 11 | return dispatch({ type: types.HIDE_NOTIFICATION }); 12 | } 13 | ); -------------------------------------------------------------------------------- /src/api/auth.js: -------------------------------------------------------------------------------- 1 | const auth = { 2 | authenticate: creds => new Promise(function (resolve, reject) { 3 | if (creds.username === 'admin' && creds.password === 'password') { 4 | resolve({ 5 | id_token: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9obiBEb2UifQ.xuEv8qrfXu424LZk8bVgr9MQJUIrp1rHcPyZw_KSsds', 6 | user: { 7 | name: 'Admin' 8 | } 9 | }); 10 | } else { 11 | reject(); 12 | } 13 | }) 14 | }; 15 | 16 | export default auth; 17 | -------------------------------------------------------------------------------- /src/api/comments.js: -------------------------------------------------------------------------------- 1 | /** 2 | * PROXY API - AJAX calls should be implemented at this layer. 3 | * For demo purposes localStorage is used instead 4 | */ 5 | const comments = { 6 | listComments: () => new Promise(function (resolve) { 7 | let comments = JSON.parse(localStorage.getItem('comments')) || []; 8 | 9 | resolve(comments); 10 | }), 11 | 12 | saveComment: (comment) => { 13 | let comments = JSON.parse(localStorage.getItem('comments')) || []; 14 | 15 | if (comment.id) { 16 | // Update array with new object 17 | let newComments = [...comments.filter(_comment => _comment.id !== comment.id), Object.assign({}, comment)]; 18 | localStorage.setItem('comments', JSON.stringify(newComments)); 19 | 20 | return new Promise(function (resolve) { 21 | resolve(comment); 22 | }); 23 | } else { 24 | // Create comment 25 | let newComment = Object.assign({}, comment); 26 | newComment.id = Math.floor((Date.now() + Math.random()) * 0x10000); // Generate random id 27 | 28 | // Update array with new object 29 | let newComments = [...comments, Object.assign({}, newComment)]; 30 | localStorage.setItem('comments', JSON.stringify(newComments)); 31 | 32 | return new Promise(function (resolve) { 33 | resolve(newComment); 34 | }); 35 | } 36 | }, 37 | 38 | deleteComment: (comment) => { 39 | let comments = JSON.parse(localStorage.getItem('comments')) || []; 40 | let newComments = comments.filter(_comment => _comment.id !== comment.id); 41 | localStorage.setItem('comments', JSON.stringify(newComments)); 42 | 43 | return new Promise(function (resolve) { 44 | resolve(true); 45 | }); 46 | } 47 | }; 48 | 49 | export default comments; 50 | -------------------------------------------------------------------------------- /src/api/index.js: -------------------------------------------------------------------------------- 1 | import auth from './auth'; 2 | import comments from './comments'; 3 | 4 | // Reference to all API definitions 5 | const api = { 6 | auth, 7 | comments 8 | }; 9 | 10 | export default api; 11 | -------------------------------------------------------------------------------- /src/components/App.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Layout } from 'react-toolbox'; 4 | import Main from './Main'; 5 | import LoginPage from './Auth/LoginPage'; 6 | 7 | const App = (props) => ( 8 | 9 | {props.isAuthenticated ?
{props.children}
: } 10 |
11 | ); 12 | 13 | App.propTypes = { 14 | children: PropTypes.element.isRequired, 15 | routes: PropTypes.array.isRequired, 16 | isAuthenticated: PropTypes.bool.isRequired 17 | }; 18 | 19 | const mapStateToProps = state => ({ 20 | isAuthenticated: state.auth.isAuthenticated 21 | }); 22 | 23 | export default connect(mapStateToProps)(App); 24 | -------------------------------------------------------------------------------- /src/components/Auth/LoginForm.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Card, CardActions } from 'react-toolbox/lib/card'; 3 | import { Button } from 'react-toolbox/lib/button'; 4 | import { Input } from 'react-toolbox/lib/input'; 5 | import style from './style.scss'; // eslint-disable-line 6 | 7 | const LoginForm = ({creds, login, onChange}) => { 8 | 9 | return ( 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 |
21 |
22 | ); 23 | }; 24 | 25 | LoginForm.propTypes = { 26 | creds: React.PropTypes.object.isRequired, 27 | login: React.PropTypes.func.isRequired, 28 | onChange: React.PropTypes.func.isRequired 29 | }; 30 | 31 | export default LoginForm; 32 | -------------------------------------------------------------------------------- /src/components/Auth/LoginPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { bindActionCreators } from 'redux'; 3 | import { connect } from 'react-redux'; 4 | import { Panel } from 'react-toolbox'; 5 | import Notifications from '../Notifications'; 6 | import LoginForm from './LoginForm'; 7 | import User from '../../models/User'; 8 | import * as actions from '../../actions/authActions'; 9 | import { showNotification } from '../../actions/notificationActions'; 10 | import style from './style.scss'; // eslint-disable-line 11 | 12 | class Login extends Component { 13 | constructor(props) { 14 | super(props); 15 | 16 | this.state = { 17 | creds: new User(), 18 | showValidationErrors: false 19 | }; 20 | 21 | this.handleChange = this.handleChange.bind(this); 22 | this.login = this.login.bind(this); 23 | } 24 | 25 | handleChange(value, event) { 26 | let field = event.target.name; 27 | let creds = this.state.creds; 28 | creds[field] = value.trim(); 29 | return this.setState({ creds: creds }); 30 | } 31 | 32 | login(event) { 33 | event.preventDefault(); 34 | 35 | let creds = { username: this.state.creds.username, password: this.state.creds.password }; 36 | this.props.actions.loginUser(creds) 37 | .catch(() => { 38 | this.props.showNotification('Authentication failed'); 39 | }); 40 | } 41 | 42 | render() { 43 | return ( 44 | 45 |
46 |

react-redux-starter

47 |
by Ricardo Reis
48 |
49 | 50 | 51 | 52 | 53 |
54 | ); 55 | } 56 | } 57 | 58 | Login.propTypes = { 59 | actions: PropTypes.object.isRequired, 60 | showNotification: PropTypes.func.isRequired 61 | }; 62 | 63 | const mapStateToProps = state => ({ 64 | isAuthenticated: state.auth.isAuthenticated 65 | }); 66 | 67 | const mapDispatchToProps = (dispatch) => ({ 68 | actions: bindActionCreators(actions, dispatch), 69 | showNotification: bindActionCreators(showNotification, dispatch) 70 | }); 71 | 72 | export default connect(mapStateToProps, mapDispatchToProps)(Login); 73 | -------------------------------------------------------------------------------- /src/components/Auth/style.scss: -------------------------------------------------------------------------------- 1 | @import '../globals'; 2 | 3 | hgroup { 4 | text-align:center; 5 | margin-top: 8rem; 6 | 7 | h3 { 8 | color: $appbar-color; 9 | } 10 | 11 | .subtitle { 12 | margin-top: 1rem; 13 | color: $coral; 14 | font-weight: 200; 15 | } 16 | } 17 | 18 | .group { 19 | position: relative; 20 | margin-bottom: 2rem; 21 | } 22 | 23 | .dashboardCard { 24 | width: 40rem; 25 | margin: 4em auto; 26 | padding: 3em 2em 2em 2em; 27 | } 28 | 29 | .cardActions { 30 | padding-top: 2rem; 31 | justify-content: flex-end; 32 | } -------------------------------------------------------------------------------- /src/components/Comments/CommentForm.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { browserHistory } from 'react-router'; 3 | import Input from 'react-toolbox/lib/input'; 4 | import { Card, CardTitle } from 'react-toolbox/lib/card'; 5 | import { Button } from 'react-toolbox/lib/button'; 6 | import classnames from 'classnames'; 7 | import style from './style.scss'; // eslint-disable-line 8 | 9 | const CommentForm = ({ comment, onSave, onChange, onDelete, saving, errors }) => { 10 | 11 | return ( 12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 | 23 | 24 |
25 | 28 | 31 |
32 |
33 | {(comment.id ? 34 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | ); 49 | }; 50 | 51 | CommentForm.propTypes = { 52 | comment: React.PropTypes.object, 53 | onSave: React.PropTypes.func.isRequired, 54 | onChange: React.PropTypes.func.isRequired, 55 | onDelete: React.PropTypes.func.isRequired, 56 | saving: React.PropTypes.bool, 57 | errors: React.PropTypes.object 58 | }; 59 | 60 | export default CommentForm; 61 | -------------------------------------------------------------------------------- /src/components/Comments/CommentList.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { browserHistory } from 'react-router'; 3 | import { Card, CardText } from 'react-toolbox/lib/card'; 4 | import { List, ListItem, ListSubHeader } from 'react-toolbox/lib/list'; 5 | 6 | const CommentList = ({ comments }) => { 7 | 8 | return ( 9 | 10 | {(comments.length > 0 ? 11 | (
12 | 13 | 14 | {comments.map(comment => 15 | browserHistory.push('/comments/' + comment.id)} 20 | rightIcon="assignment" /> 21 | )} 22 | 23 |
24 | ) : 25 | No Comments yet! 26 | )} 27 |
28 | ); 29 | }; 30 | 31 | CommentList.propTypes = { 32 | comments: PropTypes.array.isRequired 33 | }; 34 | 35 | export default CommentList; 36 | -------------------------------------------------------------------------------- /src/components/Comments/CommentMain.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { browserHistory } from 'react-router'; 3 | import { Button } from 'react-toolbox/lib/button'; 4 | import classnames from 'classnames'; 5 | import CommentList from './CommentList'; 6 | import style from './style.scss'; // eslint-disable-line 7 | 8 | const Comments = ({ comments }) => { 9 | 10 | return ( 11 |
12 |
13 |
14 |

Comments

15 |
16 |
17 |
19 |
20 |
21 |
22 | 23 |
24 |
25 |
26 | ); 27 | }; 28 | 29 | Comments.propTypes = { 30 | comments: PropTypes.array.isRequired 31 | }; 32 | 33 | export default Comments; 34 | -------------------------------------------------------------------------------- /src/components/Comments/CommentPage.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import * as actions from '../../actions/commentActions'; 5 | import CommentMain from './CommentMain'; 6 | 7 | class CommentsPage extends Component { 8 | constructor(props) { 9 | super(props); 10 | } 11 | 12 | componentWillMount() { 13 | const { listComments } = this.props.actions; 14 | listComments(); 15 | } 16 | 17 | render() { 18 | const { comments } = this.props; 19 | 20 | return ( 21 | 22 | ); 23 | } 24 | } 25 | 26 | CommentsPage.propTypes = { 27 | actions: PropTypes.object.isRequired, 28 | comments: PropTypes.array.isRequired 29 | }; 30 | 31 | const mapStateToProps = (state) => ({ 32 | comments: state.comments 33 | }); 34 | 35 | const mapDispatchToProps = (dispatch) => ({ 36 | actions: bindActionCreators(actions, dispatch) 37 | }); 38 | 39 | export default connect(mapStateToProps, mapDispatchToProps)(CommentsPage); 40 | -------------------------------------------------------------------------------- /src/components/Comments/ManageCommentPage.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import { browserHistory } from 'react-router'; 5 | import * as actions from '../../actions/commentActions'; 6 | import { showNotification } from '../../actions/notificationActions'; 7 | import CommentForm from './CommentForm'; 8 | import Comment from '../../models/Comment'; 9 | 10 | class ManageCommentPage extends React.Component { 11 | constructor(props) { 12 | super(props); 13 | 14 | this.state = { 15 | comment: Object.assign({}, props.comment), 16 | errors: {}, 17 | saving: false 18 | }; 19 | 20 | this.handleChange = this.handleChange.bind(this); 21 | this.saveComment = this.saveComment.bind(this); 22 | this.deleteComment = this.deleteComment.bind(this); 23 | } 24 | 25 | componentWillMount() { 26 | const { listComments } = this.props.actions; 27 | 28 | if (!this.state.comments) { 29 | listComments(); 30 | } 31 | } 32 | 33 | componentWillReceiveProps(nextProps) { 34 | if (nextProps.comment !== null && this.props.comment.id !== nextProps.comment.id) { 35 | // Necessary to populate form when an existing comment is loaded 36 | this.setState({ comment: Object.assign({}, nextProps.comment) }); 37 | } 38 | } 39 | 40 | handleChange(value, event) { 41 | const field = event.target.name; 42 | let comment = this.state.comment; 43 | comment[field] = value; 44 | return this.setState({ comment: comment }); 45 | } 46 | 47 | saveComment(event) { 48 | event.preventDefault(); 49 | 50 | this.setState({ saving: true }); 51 | 52 | this.props.actions.saveComment(this.state.comment) 53 | .then(() => { 54 | this.props.showNotification('Comment saved successfully'); 55 | browserHistory.push('/comments'); 56 | }) 57 | .catch(error => { 58 | this.setState({ saving: false }); 59 | this.props.showNotification(error.message); 60 | }); 61 | } 62 | 63 | deleteComment(event) { 64 | event.preventDefault(); 65 | 66 | this.setState({ saving: true }); 67 | 68 | this.props.actions.deleteComment(this.state.comment) 69 | .then(() => { 70 | this.setState({ saving: false }); 71 | this.props.showNotification('Comment deleted successfully'); 72 | browserHistory.push('/comments'); 73 | }) 74 | .catch(error => { 75 | this.setState({ saving: false }); 76 | this.props.showNotification(error.message); 77 | }); 78 | } 79 | 80 | render() { 81 | return ( 82 |
83 | 91 |
92 | ); 93 | } 94 | } 95 | 96 | ManageCommentPage.propTypes = { 97 | comment: PropTypes.object, 98 | actions: PropTypes.object.isRequired, 99 | showNotification: PropTypes.func.isRequired 100 | }; 101 | 102 | const getCommentById = (comments, id) => { 103 | const comment = comments.filter(comment => comment.id == id); 104 | if (comment.length) return comment[0]; //since filter returns an array, have to grab the first. 105 | return null; 106 | }; 107 | 108 | const mapStateToProps = (state, ownProps) => { 109 | const commentId = ownProps.params.id; 110 | 111 | let comment = new Comment(); 112 | 113 | if (commentId && state.comments.length > 0) { 114 | comment = getCommentById(state.comments, commentId); 115 | } 116 | 117 | return { 118 | comment: comment 119 | }; 120 | }; 121 | 122 | const mapDispatchToProps = (dispatch) => ({ 123 | actions: bindActionCreators(actions, dispatch), 124 | showNotification: bindActionCreators(showNotification, dispatch) 125 | }); 126 | 127 | export default connect(mapStateToProps, mapDispatchToProps)(ManageCommentPage); 128 | -------------------------------------------------------------------------------- /src/components/Comments/style.scss: -------------------------------------------------------------------------------- 1 | @import "./globals"; 2 | 3 | .commentForm { 4 | padding: 1rem 1rem 1rem 1rem; 5 | } 6 | 7 | .toolbar { 8 | padding-bottom: 1rem; 9 | } 10 | 11 | .bottomOptions { 12 | margin-top: 2rem; 13 | } -------------------------------------------------------------------------------- /src/components/Home/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import Welcome from './Welcome'; 4 | 5 | export const HomePage = () => { 6 | return ( 7 | 8 | ); 9 | }; 10 | 11 | export default connect()(HomePage); 12 | -------------------------------------------------------------------------------- /src/components/Home/Welcome.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import style from './style.scss'; // eslint-disable-line 3 | 4 | const Welcome = () => ( 5 |
6 |
7 |
8 |

Welcome to react-redux-starter

9 |
A React/Redux starter project with login and basic CRUD functionality in a Material flavor
10 |
11 |
12 |
13 | ); 14 | 15 | export default Welcome; 16 | -------------------------------------------------------------------------------- /src/components/Home/style.scss: -------------------------------------------------------------------------------- 1 | @import '../globals'; 2 | 3 | .welcome { 4 | .title { 5 | margin-top: 3rem; 6 | color: $coral; 7 | } 8 | 9 | .subtitle { 10 | margin-top: 2rem; 11 | letter-spacing: 0.3em; 12 | color: $hit-grey; 13 | } 14 | } -------------------------------------------------------------------------------- /src/components/Main.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { bindActionCreators } from 'redux'; 4 | import { Panel } from 'react-toolbox'; 5 | import TopAppBar from './TopAppBar'; 6 | import SideNavigation from './SideNavigation'; 7 | import MainContent from './MainContent'; 8 | import Preloader from './common/Preloader'; 9 | import Notifications from './Notifications'; 10 | import { logoutUser } from '../actions/authActions'; 11 | 12 | const Main = (props) => ( 13 | 14 | 15 | 16 | {props.children} 17 | 18 | 19 | 20 | ); 21 | 22 | Main.propTypes = { 23 | children: PropTypes.element, 24 | routes: PropTypes.array, 25 | isLoading: PropTypes.bool.isRequired, 26 | actions: PropTypes.object.isRequired, 27 | auth: PropTypes.object.isRequired 28 | }; 29 | 30 | const mapStateToProps = (state) => ({ 31 | isLoading: state.ajaxCallsInProgress > 0, 32 | auth: state.auth 33 | }); 34 | 35 | const mapDispatchToProps = (dispatch) => ({ 36 | actions: { 37 | logoutUser: bindActionCreators(logoutUser, dispatch) 38 | } 39 | }); 40 | 41 | export default connect(mapStateToProps, mapDispatchToProps)(Main); -------------------------------------------------------------------------------- /src/components/MainContent/index.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import 'react-toolbox/lib/commons.scss'; 3 | import Breadcrumbs from 'react-breadcrumbs'; 4 | import style from './style.scss'; // eslint-disable-line 5 | 6 | const MainContent = (props) => ( 7 |
8 |
9 |
10 | 11 |
12 | {props.children} 13 |
14 |
15 | ); 16 | 17 | MainContent.propTypes = { 18 | children: PropTypes.element, 19 | routes: PropTypes.array 20 | }; 21 | 22 | export default MainContent; 23 | -------------------------------------------------------------------------------- /src/components/MainContent/style.scss: -------------------------------------------------------------------------------- 1 | @import "./globals"; 2 | 3 | .mainPage { 4 | margin-top: $appbar-height; 5 | margin-left: $navigation-width; 6 | } 7 | 8 | .mainContent { 9 | padding: 2rem 2rem 2rem 2rem; 10 | } 11 | 12 | .mainBreadcrumbs { 13 | padding-bottom: 2rem; 14 | color: $hit-grey; 15 | 16 | a { 17 | transition: color .4s; 18 | color: $appbar-color; 19 | } 20 | a:link, a:visited { color: $appbar-color; } 21 | a:active, a:hover { color: $ebony; } 22 | } -------------------------------------------------------------------------------- /src/components/Notifications/index.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { bindActionCreators } from 'redux'; 3 | import { connect } from 'react-redux'; 4 | import { Snackbar } from 'react-toolbox'; 5 | import * as actions from '../../actions/notificationActions'; 6 | import style from './style.scss'; // eslint-disable-line 7 | 8 | class Notifications extends React.Component { 9 | constructor(props) { 10 | super(props); 11 | 12 | this.hideNotification = this.hideNotification.bind(this); 13 | } 14 | 15 | hideNotification() { 16 | this.props.actions.hideNotification(); 17 | } 18 | 19 | render() { 20 | const { notifications } = this.props; 21 | 22 | return ( 23 | this.hideNotification()} 29 | /> 30 | ); 31 | } 32 | } 33 | 34 | Notifications.propTypes = { 35 | notifications: PropTypes.object.isRequired, 36 | actions: PropTypes.object.isRequired 37 | }; 38 | 39 | const mapStateToProps = (state) => ({ 40 | notifications: state.notifications 41 | }); 42 | 43 | const mapDispatchToProps = (dispatch) => ({ 44 | actions: bindActionCreators(actions, dispatch) 45 | }); 46 | 47 | export default connect(mapStateToProps, mapDispatchToProps)(Notifications); -------------------------------------------------------------------------------- /src/components/Notifications/style.scss: -------------------------------------------------------------------------------- 1 | .notificationSnackbar { 2 | width: 60%; 3 | text-align: center; 4 | } -------------------------------------------------------------------------------- /src/components/PageNotFound.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import { Button } from 'react-toolbox/lib/button'; 4 | import style from './style.scss'; // eslint-disable-line 5 | 6 | const PageNotFound = () => { 7 | return ( 8 |
9 |
10 |

Page Not Found

11 | 12 |
15 |
16 | ); 17 | }; 18 | 19 | export default PageNotFound; 20 | -------------------------------------------------------------------------------- /src/components/SideNavigation/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { List, ListItem } from 'react-toolbox'; 3 | import { Link, IndexLink } from 'react-router'; 4 | import classnames from 'classnames'; 5 | import style from './style.scss'; // eslint-disable-line 6 | 7 | const SideNavigation = () => { 8 | 9 | const components = { 10 | comments: { 11 | name: 'Comments', 12 | path: '/comments', 13 | icon: 'assignment' 14 | } 15 | }; 16 | 17 | const drawerItems = Object.keys(components).map((key) => { 18 | return ( 19 | 20 | 26 | 27 | ); 28 | }); 29 | 30 | return ( 31 | 43 | ); 44 | }; 45 | 46 | export default SideNavigation; 47 | -------------------------------------------------------------------------------- /src/components/SideNavigation/style.scss: -------------------------------------------------------------------------------- 1 | @import '../globals'; 2 | 3 | .root { 4 | display: flex; 5 | width: $navigation-width; 6 | flex-direction: column; 7 | background-color: $color-background; 8 | } 9 | 10 | .navigation { 11 | position: fixed; 12 | top: $appbar-height; 13 | bottom: 0; 14 | left: 0; 15 | z-index: $z-index-highest; 16 | box-shadow: $documentation-left-shadow; 17 | transition: transform $animation-duration $animation-curve-default; 18 | } 19 | 20 | .list { 21 | @include no-webkit-scrollbar; 22 | flex-grow: 1; 23 | overflow-y: auto; 24 | } 25 | 26 | .item { 27 | > span{ 28 | padding: $navigation-v-padding $navigation-h-padding; 29 | } 30 | [data-react-toolbox="list-item-text"] { 31 | font-size: $font-size-small; 32 | font-weight: $font-weight-semi-bold; 33 | } 34 | } 35 | 36 | .active { 37 | background: $color-divider; 38 | 39 | span:before { 40 | position: absolute; 41 | bottom: 0; 42 | left: 0; 43 | display: block; 44 | width: .3rem; 45 | height: 100%; 46 | content: ''; 47 | background-color: $color-primary; 48 | } 49 | } 50 | 51 | .footer { 52 | flex-grow: 0; 53 | padding: $navigation-h-padding; 54 | overflow: hidden; 55 | text-align: center; 56 | font-size: $font-size-small; 57 | color: $color-text-secondary; 58 | border-top: $navigation-footer-border; 59 | > * { 60 | display: block; 61 | } 62 | } 63 | 64 | .footerTitle { 65 | color: $coral; 66 | font-weight: 500; 67 | padding-bottom: 0.5rem; 68 | } -------------------------------------------------------------------------------- /src/components/TopAppBar/index.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import { Link } from 'react-router'; 3 | import { AppBar } from 'react-toolbox/lib/app_bar'; 4 | import { IconMenu, MenuItem } from 'react-toolbox/lib/menu'; 5 | import style from './style.scss'; // eslint-disable-line 6 | 7 | const TopAppBar = ({actions, auth}) => { 8 | 9 | const userName = auth.user.name; 10 | 11 | return ( 12 | 13 | 14 | react-redux-starter 15 | 16 |
17 | {userName} 18 | 19 | 20 | 21 |
22 |
23 | ); 24 | }; 25 | 26 | TopAppBar.propTypes = { 27 | children: PropTypes.node, 28 | actions: PropTypes.object.isRequired, 29 | auth: PropTypes.object.isRequired 30 | }; 31 | 32 | export default TopAppBar; 33 | -------------------------------------------------------------------------------- /src/components/TopAppBar/style.scss: -------------------------------------------------------------------------------- 1 | @import "../globals"; 2 | 3 | .appbar { 4 | z-index: $z-index-higher; 5 | display: flex; 6 | min-height: $appbar-height; 7 | flex-direction: row; 8 | align-items: center; 9 | justify-content: flex-start; 10 | box-shadow: $appbar-shadow; 11 | background-color: $appbar-color; 12 | } 13 | 14 | .appTitle { 15 | text-transform: uppercase; 16 | } 17 | 18 | .topBarOptions { 19 | flex-grow: 1; 20 | text-align: right; 21 | } 22 | 23 | .companySettings { 24 | flex-grow: 1; 25 | text-align: right; 26 | 27 | > span { 28 | text-transform: uppercase; 29 | font-size: 1.4rem; 30 | font-weight: 500; 31 | } 32 | } 33 | 34 | .menu { 35 | > div { 36 | margin-top: 4rem; 37 | margin-right: 1rem; 38 | } 39 | 40 | button > span { 41 | color: #ffffff; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/components/_globals.scss: -------------------------------------------------------------------------------- 1 | @import "~react-toolbox/lib/colors"; 2 | @import "~react-toolbox/lib/globals"; 3 | @import "~react-toolbox/lib/mixins"; 4 | 5 | $unit: 1rem; 6 | $color-content: #fafafa; 7 | $navigation-width: 22 * $unit; 8 | $navigation-h-padding: 2.4 * $unit; 9 | $navigation-v-padding: 1.2 * $unit; 10 | $navigation-footer-border: solid 1px rgb(224, 224, 224); 11 | $documentation-left-shadow: 0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2); 12 | $documentation-right-shadow: -2px 0 4px rgba(0,0,0,.14); 13 | 14 | $appbar-height: 6.4 * $unit; 15 | $appbar-logo-size: 15 * $unit; 16 | $appbar-shadow: 0 1px rgba(255,255,255,.65); 17 | $appbar-navigation-offset: 6.5 * $unit; 18 | 19 | $appbar-color: #37474F; 20 | $white-smoke: #F6F6F6; 21 | $ebony: #2E3339; 22 | $very-light-grey: #CCCCCC; 23 | $coral: #FD7348; 24 | $hit-grey: #ABACAC; 25 | $pattens-blue: #D7E8F7; 26 | -------------------------------------------------------------------------------- /src/components/common/Preloader.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import ProgressBar from 'react-toolbox/lib/progress_bar'; 3 | import style from './style.scss'; 4 | 5 | class Preloader extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | } 9 | 10 | render() { 11 | const { isLoading } = this.props; 12 | 13 | if (!isLoading) { 14 | return false; 15 | } 16 | 17 | return ( 18 |
19 |
20 | 21 |
22 |
23 | ); 24 | } 25 | } 26 | 27 | Preloader.propTypes = { 28 | isLoading: PropTypes.bool.isRequired 29 | }; 30 | 31 | export default Preloader; 32 | -------------------------------------------------------------------------------- /src/components/common/style.scss: -------------------------------------------------------------------------------- 1 | @import '../globals'; 2 | 3 | .showbox { 4 | position: absolute; 5 | top: 0; 6 | bottom: 0; 7 | left: 0; 8 | right: 0; 9 | z-index: 1000001; 10 | height: 100%; 11 | width: 100%; 12 | background: none repeat scroll 0 0 black; 13 | position: fixed; 14 | display: block; 15 | opacity: 0.5; 16 | } 17 | 18 | .loader { 19 | position: relative; 20 | top: $appbar-height - 1rem; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/style.scss: -------------------------------------------------------------------------------- 1 | @import "./globals"; 2 | 3 | .pageNotFound { 4 | > p { 5 | font-size: 2.4rem; 6 | font-weight: 400; 7 | padding-bottom: 2rem; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/theme/_config.scss: -------------------------------------------------------------------------------- 1 | @import "~react-toolbox/lib/colors"; 2 | 3 | $color-primary: $palette-deep-orange-500; 4 | $color-primary-dark: $palette-deep-orange-600; 5 | $color-accent: $palette-blue-grey-600; 6 | $color-accent-dark: $palette-blue-grey-700; 7 | $color-primary-contrast: $color-dark-contrast; 8 | $color-accent-contrast: $color-dark-contrast; -------------------------------------------------------------------------------- /src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | // AUTH 2 | export const LOGIN_REQUEST = 'LOGIN_REQUEST'; 3 | export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; 4 | export const LOGIN_FAILURE = 'LOGIN_FAILURE'; 5 | export const LOGOUT_REQUEST = 'LOGOUT_REQUEST'; 6 | export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; 7 | export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'; 8 | 9 | // AJAX 10 | export const BEGIN_AJAX_CALL = 'BEGIN_AJAX_CALL'; 11 | export const AJAX_CALL_ERROR = 'AJAX_CALL_ERROR'; 12 | 13 | // COMMENTS 14 | export const LIST_COMMENTS_SUCCESS = 'LIST_COMMENTS_SUCCESS'; 15 | export const CREATE_COMMENT_SUCCESS = 'CREATE_COMMENT_SUCCESS'; 16 | export const UPDATE_COMMENT_SUCCESS = 'UPDATE_COMMENT_SUCCESS'; 17 | export const DELETE_COMMENT_SUCCESS = 'DELETE_COMMENT_SUCCESS'; 18 | 19 | // NOTIFICATIONS 20 | export const SHOW_NOTIFICATION = 'SHOW_NOTIFICATION'; 21 | export const HIDE_NOTIFICATION = 'HIDE_NOTIFICATION'; -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rjmreis/react-redux-starter/d87e7ab57c6404f9140b518c6576708b9bcca7af/src/favicon.ico -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 11 | react-redux-starter 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/default */ 2 | import React from 'react'; 3 | import { render } from 'react-dom'; 4 | import { Provider } from 'react-redux'; 5 | import { Router, browserHistory } from 'react-router'; 6 | import { syncHistoryWithStore } from 'react-router-redux'; 7 | import routes from './routes'; 8 | import configureStore from './store/configureStore'; 9 | import './style.scss'; 10 | 11 | const store = configureStore(); 12 | const history = syncHistoryWithStore(browserHistory, store); 13 | 14 | render( 15 | 16 | 17 | , 18 | document.getElementById('app') 19 | ); 20 | -------------------------------------------------------------------------------- /src/models/Comment.js: -------------------------------------------------------------------------------- 1 | export default class Comment { 2 | constructor() { 3 | this.title = ''; 4 | this.description = ''; 5 | } 6 | } -------------------------------------------------------------------------------- /src/models/User.js: -------------------------------------------------------------------------------- 1 | import validate from 'validate.js'; 2 | 3 | export default class User { 4 | constructor() { 5 | this.username = ''; 6 | this.password = ''; 7 | 8 | this.constraints = { 9 | username: { 10 | presence: true 11 | }, 12 | password: { 13 | presence: true 14 | } 15 | }; 16 | } 17 | 18 | isValid() { 19 | return validate(this, this.constraints) === undefined; 20 | } 21 | 22 | getError(key) { 23 | let message = validate({ [key]: this[key] }, this.constraints); 24 | 25 | return message[key] ? message[key][0] : ''; 26 | } 27 | } -------------------------------------------------------------------------------- /src/reducers/ajaxStatusReducer.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import initialState from './initialState'; 3 | 4 | function actionTypeEndsInSuccess(type) { 5 | return type.substring(type.length - 8) === '_SUCCESS'; 6 | } 7 | 8 | export default function ajaxStatusReducer(state = initialState.ajaxCallsInProgress, action) { 9 | if (action.type === types.BEGIN_AJAX_CALL) { 10 | return state + 1; 11 | } else if (action.type === types.AJAX_CALL_ERROR || actionTypeEndsInSuccess(action.type)) { 12 | return state - 1; 13 | } 14 | 15 | return state; 16 | } 17 | -------------------------------------------------------------------------------- /src/reducers/authReducer.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import initialState from './initialState'; 3 | 4 | export default function auth(state = initialState.auth, action) { 5 | switch (action.type) { 6 | case types.LOGIN_REQUEST: 7 | return Object.assign({}, state, { 8 | isAuthenticated: false 9 | }); 10 | case types.LOGIN_SUCCESS: 11 | return Object.assign({}, state, { 12 | isAuthenticated: true, 13 | user: action.user, 14 | errorMessage: '' 15 | }); 16 | case types.LOGIN_FAILURE: 17 | return Object.assign({}, state, { 18 | isAuthenticated: false, 19 | errorMessage: action.message 20 | }); 21 | case types.LOGOUT_SUCCESS: 22 | return Object.assign({}, state, { 23 | isAuthenticated: false, 24 | user: {} 25 | }); 26 | default: 27 | return state; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/reducers/commentReducer.js: -------------------------------------------------------------------------------- 1 | // import objectAssign from 'object-assign'; 2 | import * as types from '../constants/actionTypes'; 3 | import initialState from './initialState'; 4 | 5 | // IMPORTANT: Note that with Redux, state should NEVER be changed. 6 | // State is considered immutable. Instead, 7 | // create a copy of the state passed and set new values on the copy. 8 | // Note the use of the spread operator and Object.assign to create a copy of current state. 9 | export default function commentsReducer(state = initialState.comments, action) { 10 | switch (action.type) { 11 | case types.LIST_COMMENTS_SUCCESS: 12 | return action.comments; 13 | 14 | case types.CREATE_COMMENT_SUCCESS: 15 | return [...state, Object.assign({}, action.comment)]; 16 | 17 | case types.UPDATE_COMMENT_SUCCESS: 18 | return [...state.filter(comment => comment.id !== action.comment.id), Object.assign({}, action.comment)]; 19 | 20 | case types.DELETE_COMMENT_SUCCESS: { 21 | return state.filter(comment => comment.id !== action.commentId); 22 | } 23 | 24 | default: 25 | return state; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { routerReducer } from 'react-router-redux'; 3 | import authReducer from './authReducer'; 4 | import commentReducer from './commentReducer'; 5 | import ajaxStatusReducer from './ajaxStatusReducer'; 6 | import notificationsReducer from './notificationsReducer'; 7 | 8 | const rootReducer = combineReducers({ 9 | routing: routerReducer, 10 | auth: authReducer, 11 | comments: commentReducer, 12 | ajaxCallsInProgress: ajaxStatusReducer, 13 | notifications: notificationsReducer 14 | }); 15 | 16 | export default rootReducer; -------------------------------------------------------------------------------- /src/reducers/initialState.js: -------------------------------------------------------------------------------- 1 | export default { 2 | auth: { 3 | isAuthenticated: localStorage.getItem('id_token') ? true : false, 4 | user: localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')) : {} 5 | }, 6 | comments: [], 7 | ajaxCallsInProgress: 0, 8 | notifications: { 9 | active: false, 10 | message: '' 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/reducers/notificationsReducer.js: -------------------------------------------------------------------------------- 1 | import * as types from '../constants/actionTypes'; 2 | import initialState from './initialState'; 3 | 4 | export default function notificationsReducer(state = initialState.notifications, action) { 5 | if (action.type === types.SHOW_NOTIFICATION) { 6 | return { active: true, message: action.message }; 7 | } else if (action.type === types.HIDE_NOTIFICATION) { 8 | return { active: false, message: state.message }; 9 | } 10 | 11 | return state; 12 | } 13 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-named-as-default */ 2 | 3 | import React from 'react'; 4 | import { Route, IndexRoute } from 'react-router'; 5 | 6 | import App from './components/App.js'; 7 | import HomePage from './components/Home/HomePage.js'; 8 | import CommentPage from './components/Comments/CommentPage.js'; 9 | import ManageCommentPage from './components/Comments/ManageCommentPage.js'; 10 | import PageNotFound from './components/PageNotFound.js'; 11 | 12 | export default ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /src/store/configureStore.dev.js: -------------------------------------------------------------------------------- 1 | // This file merely configures the store for hot reloading. 2 | // This boilerplate file is likely to be the same for each project that uses Redux. 3 | // With Redux, the actual stores are in /reducers. 4 | 5 | import { createStore, compose, applyMiddleware } from 'redux'; 6 | import reduxImmutableStateInvariant from 'redux-immutable-state-invariant'; 7 | import thunkMiddleware from 'redux-thunk'; 8 | import rootReducer from '../reducers'; 9 | 10 | export default function configureStore(initialState) { 11 | const middewares = [ 12 | // Add other middleware on this line... 13 | 14 | // Redux middleware that spits an error on you when you try to mutate your state either inside a dispatch or between dispatches. 15 | reduxImmutableStateInvariant(), 16 | 17 | // thunk middleware can also accept an extra argument to be passed to each thunk action 18 | // https://github.com/gaearon/redux-thunk#injecting-a-custom-argument 19 | thunkMiddleware 20 | ]; 21 | 22 | const store = createStore(rootReducer, initialState, compose( 23 | applyMiddleware(...middewares), 24 | window.devToolsExtension ? window.devToolsExtension() : f => f // add support for Redux dev tools 25 | ) 26 | ); 27 | 28 | if (module.hot) { 29 | // Enable Webpack hot module replacement for reducers 30 | module.hot.accept('../reducers', () => { 31 | const nextReducer = require('../reducers').default; // eslint-disable-line global-require 32 | store.replaceReducer(nextReducer); 33 | }); 34 | } 35 | 36 | return store; 37 | } -------------------------------------------------------------------------------- /src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./configureStore.prod'); 3 | } else { 4 | module.exports = require('./configureStore.dev'); 5 | } 6 | -------------------------------------------------------------------------------- /src/store/configureStore.prod.js: -------------------------------------------------------------------------------- 1 | import { createStore, compose, applyMiddleware } from 'redux'; 2 | import thunkMiddleware from 'redux-thunk'; 3 | import rootReducer from '../reducers'; 4 | 5 | export default function configureStore(initialState) { 6 | const middewares = [ 7 | // Add other middleware on this line... 8 | 9 | // thunk middleware can also accept an extra argument to be passed to each thunk action 10 | // https://github.com/gaearon/redux-thunk#injecting-a-custom-argument 11 | thunkMiddleware, 12 | ]; 13 | 14 | return createStore(rootReducer, initialState, compose( 15 | applyMiddleware(...middewares) 16 | ) 17 | ); 18 | } -------------------------------------------------------------------------------- /src/style.scss: -------------------------------------------------------------------------------- 1 | @import './components/globals'; 2 | 3 | body { 4 | background: $white-smoke; 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/ajax.js: -------------------------------------------------------------------------------- 1 | import { ajaxCallError } from '../actions/ajaxStatusActions'; 2 | 3 | export const handleAjaxError = (dispatch, error) => { 4 | dispatch(ajaxCallError(error)); 5 | }; 6 | -------------------------------------------------------------------------------- /src/utils/dateHelper.js: -------------------------------------------------------------------------------- 1 | export default class DateHelper { 2 | // See tests for desired format. 3 | static getFormattedDateTime(date = new Date()) { 4 | return `${date.getMonth() + 1}/${date.getDate()} ${date.getHours()}:${this.padLeadingZero(date.getMinutes())}:${this.padLeadingZero(date.getSeconds())}`; 5 | } 6 | 7 | static padLeadingZero(value) { 8 | return value > 9 ? value : `0${value}`; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/utils/dateHelper.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import DateHelper from './dateHelper'; 3 | 4 | describe('Date Helper', () => { 5 | describe('getFormattedDateTime', () => { 6 | it('returns mm/dd hh:mm:ss formatted time when passed a date', () => { 7 | // arrange 8 | // The 7 numbers specify the year, month, day, hour, minute, second, and millisecond, in that order 9 | const date = new Date(99, 0, 24, 11, 33, 30, 0); 10 | 11 | // assert 12 | expect(DateHelper.getFormattedDateTime(date)).to.equal('1/24 11:33:30'); 13 | }); 14 | 15 | it('pads single digit minute and second values with leading zeros', () => { 16 | // arrange 17 | // The 7 numbers specify the year, month, day, hour, minute, second, and millisecond, in that order 18 | const date = new Date(99, 0, 4, 11, 3, 2, 0); 19 | 20 | // assert 21 | expect(DateHelper.getFormattedDateTime(date)).to.equal('1/4 11:03:02'); 22 | }); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /src/webpack-public-path.js: -------------------------------------------------------------------------------- 1 | // Dynamically set the webpack public path at runtime below 2 | // This magic global is used by webpack to set the public path at runtime. 3 | // The public path is set dynamically to avoid the following issues: 4 | // 1. https://github.com/coryhouse/react-slingshot/issues/205 5 | // 2. https://github.com/coryhouse/react-slingshot/issues/181 6 | // 3. https://github.com/coryhouse/react-slingshot/pull/125 7 | // Documentation: http://webpack.github.io/docs/configuration.html#output-publicpath 8 | // eslint-disable-next-line no-undef 9 | __webpack_public_path__ = window.location.protocol + "//" + window.location.host + "/"; 10 | -------------------------------------------------------------------------------- /tools/build.js: -------------------------------------------------------------------------------- 1 | // More info on Webpack's Node API here: https://webpack.github.io/docs/node.js-api.html 2 | // Allowing console calls below since this is a build file. 3 | /* eslint-disable no-console */ 4 | import webpack from 'webpack'; 5 | import config from '../webpack.config.prod'; 6 | import { chalkError, chalkSuccess, chalkWarning, chalkProcessing } from './chalkConfig'; 7 | 8 | process.env.NODE_ENV = 'production'; // this assures React is built in prod mode and that the Babel dev config doesn't apply. 9 | 10 | console.log(chalkProcessing('Generating minified bundle for production via Webpack. This will take a moment...')); 11 | 12 | webpack(config).run((error, stats) => { 13 | if (error) { // so a fatal error occurred. Stop here. 14 | console.log(chalkError(error)); 15 | return 1; 16 | } 17 | 18 | const jsonStats = stats.toJson(); 19 | 20 | if (jsonStats.hasErrors) { 21 | return jsonStats.errors.map(error => console.log(chalkError(error))); 22 | } 23 | 24 | if (jsonStats.hasWarnings) { 25 | console.log(chalkWarning('Webpack generated the following warnings: ')); 26 | jsonStats.warnings.map(warning => console.log(chalkWarning(warning))); 27 | } 28 | 29 | console.log(`Webpack stats: ${stats}`); 30 | 31 | console.log(chalkSuccess('Your app is compiled in production mode in /dist. It\'s ready to roll!')); 32 | 33 | return 0; 34 | }); 35 | -------------------------------------------------------------------------------- /tools/chalkConfig.js: -------------------------------------------------------------------------------- 1 | // Centralized configuration for chalk, which is used to add color to console.log statements. 2 | import chalk from 'chalk'; 3 | export const chalkError = chalk.red; 4 | export const chalkSuccess = chalk.green; 5 | export const chalkWarning = chalk.yellow; 6 | export const chalkProcessing = chalk.blue; 7 | -------------------------------------------------------------------------------- /tools/distServer.js: -------------------------------------------------------------------------------- 1 | // This file configures a web server for testing the production build 2 | // on your local machine. 3 | 4 | import browserSync from 'browser-sync'; // eslint-disable-line 5 | import historyApiFallback from 'connect-history-api-fallback'; 6 | import {chalkProcessing} from './chalkConfig'; 7 | 8 | /* eslint-disable no-console */ 9 | 10 | console.log(chalkProcessing('Opening production build...')); 11 | 12 | // Run Browsersync 13 | browserSync({ 14 | port: process.env.PORT || 3000, 15 | ui: { 16 | port: process.env.UI || 3001 17 | }, 18 | server: { 19 | baseDir: 'dist' 20 | }, 21 | 22 | files: [ 23 | 'src/*.html' 24 | ], 25 | 26 | middleware: [historyApiFallback()] 27 | }); 28 | -------------------------------------------------------------------------------- /tools/srcServer.js: -------------------------------------------------------------------------------- 1 | // This file configures the development web server 2 | // which supports hot reloading and synchronized testing. 3 | 4 | // Require Browsersync along with webpack and middleware for it 5 | import browserSync from 'browser-sync'; // eslint-disable-line 6 | // Required for react-router browserHistory 7 | // see https://github.com/BrowserSync/browser-sync/issues/204#issuecomment-102623643 8 | import historyApiFallback from 'connect-history-api-fallback'; 9 | import webpack from 'webpack'; 10 | import webpackDevMiddleware from 'webpack-dev-middleware'; 11 | import webpackHotMiddleware from 'webpack-hot-middleware'; 12 | import config from '../webpack.config.dev'; 13 | 14 | const bundler = webpack(config); 15 | 16 | // Run Browsersync and use middleware for Hot Module Replacement 17 | browserSync({ 18 | port: 3000, 19 | ui: { 20 | port: 3001 21 | }, 22 | server: { 23 | baseDir: 'src', 24 | 25 | middleware: [ 26 | historyApiFallback(), 27 | 28 | webpackDevMiddleware(bundler, { 29 | // Dev middleware can't access config, so we provide publicPath 30 | publicPath: config.output.publicPath, 31 | 32 | // These settings suppress noisy webpack output so only errors are displayed to the console. 33 | noInfo: false, 34 | quiet: false, 35 | stats: { 36 | assets: false, 37 | colors: true, 38 | version: false, 39 | hash: false, 40 | timings: false, 41 | chunks: false, 42 | chunkModules: false 43 | }, 44 | 45 | // for other settings see 46 | // http://webpack.github.io/docs/webpack-dev-middleware.html 47 | }), 48 | 49 | // bundler should be the same as above 50 | webpackHotMiddleware(bundler) 51 | ] 52 | }, 53 | 54 | // no need to watch '*.js' here, webpack will take care of it for us, 55 | // including full page reloads if HMR won't work 56 | files: [ 57 | 'src/*.html' 58 | ] 59 | }); 60 | -------------------------------------------------------------------------------- /tools/startMessage.js: -------------------------------------------------------------------------------- 1 | import { chalkSuccess } from './chalkConfig'; 2 | 3 | /* eslint-disable no-console */ 4 | 5 | console.log(chalkSuccess('Starting app in dev mode...')); 6 | -------------------------------------------------------------------------------- /tools/testSetup.js: -------------------------------------------------------------------------------- 1 | // Tests are placed alongside files under test. 2 | // This file does the following: 3 | // 1. Sets the environment to 'test' so that 4 | // dev-specific babel config in .babelrc doesn't run. 5 | // 2. Disables Webpack-specific features that Mocha doesn't understand. 6 | // 3. Registers babel for transpiling our code for testing. 7 | 8 | // This assures the .babelrc dev config (which includes 9 | // hot module reloading code) doesn't apply for tests. 10 | // Setting NODE_ENV to test instead of production because setting it to production will suppress error messaging 11 | // and propType validation warnings. 12 | process.env.NODE_ENV = 'test'; 13 | 14 | // Disable webpack-specific features for tests since 15 | // Mocha doesn't know what to do with them. 16 | ['.css', '.scss', '.png', '.jpg'].forEach(ext => { 17 | require.extensions[ext] = () => null; 18 | }); 19 | 20 | // Register babel so that it will transpile ES6 to ES5 21 | // before our tests run. 22 | require('babel-register')(); 23 | -------------------------------------------------------------------------------- /webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | import webpack from 'webpack'; 3 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 4 | import autoprefixer from 'autoprefixer'; 5 | 6 | export default { 7 | resolve: { 8 | extensions: ['', '.js', '.jsx'], 9 | modulesDirectories: [ 10 | 'node_modules', 11 | path.resolve(__dirname, './node_modules') 12 | ] 13 | }, 14 | debug: true, 15 | devtool: 'eval-source-map', // more info:https://webpack.github.io/docs/build-performance.html#sourcemaps and https://webpack.github.io/docs/configuration.html#devtool 16 | noInfo: true, // set to false to see a list of every file being bundled. 17 | entry: [ 18 | // must be first entry to properly set public path 19 | './src/webpack-public-path', 20 | 'webpack-hot-middleware/client?reload=true', 21 | './src/index' 22 | ], 23 | target: 'web', // necessary per https://webpack.github.io/docs/testing.html#compile-and-test 24 | output: { 25 | path: `${__dirname}/src`, // Note: Physical files are only output by the production build task `npm run build`. 26 | publicPath: '/', 27 | filename: 'bundle.js' 28 | }, 29 | plugins: [ 30 | new webpack.DefinePlugin({ 31 | 'process.env': { 32 | 'NODE_ENV': JSON.stringify('development'), // Tells React to build in either dev or prod modes. https://facebook.github.io/react/downloads.html (See bottom) 33 | 'API': JSON.stringify(process.env.API) 34 | }, 35 | __DEV__: true 36 | }), 37 | new webpack.HotModuleReplacementPlugin(), 38 | new webpack.NoErrorsPlugin(), 39 | new HtmlWebpackPlugin({ // Create HTML file that includes references to bundled CSS and JS. 40 | template: 'src/index.ejs', 41 | minify: { 42 | removeComments: true, 43 | collapseWhitespace: true 44 | }, 45 | inject: true 46 | }) 47 | ], 48 | module: { 49 | loaders: [ 50 | { test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel'] }, 51 | { test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'file' }, 52 | { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url?limit=10000&mimetype=application/font-woff" }, 53 | { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream' }, 54 | { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml' }, 55 | { test: /\.(jpe?g|png|gif)$/i, loader: 'file?name=[name].[ext]' }, 56 | { test: /\.ico$/, loader: 'file?name=[name].[ext]' }, 57 | { test: /(\.css|\.scss)$/, loaders: ['style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]', 'postcss', 'sass?sourceMap'] }, 58 | { test: /\.json$/, exclude: /node_modules/, loader: 'json' }, 59 | ] 60 | }, 61 | postcss: () => [autoprefixer], 62 | sassLoader: { 63 | data: '@import "theme/_config.scss";', 64 | includePaths: [path.resolve(__dirname, './src/components')] 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | // For info about this file refer to webpack and webpack-hot-middleware documentation 2 | // For info on how we're generating bundles with hashed filenames for cache busting: https://medium.com/@okonetchnikov/long-term-caching-of-static-assets-with-webpack-1ecb139adb95#.w99i89nsz 3 | const path = require('path'); 4 | import webpack from 'webpack'; 5 | import ExtractTextPlugin from 'extract-text-webpack-plugin'; 6 | import WebpackMd5Hash from 'webpack-md5-hash'; 7 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 8 | import autoprefixer from 'autoprefixer'; 9 | 10 | export default { 11 | resolve: { 12 | extensions: ['', '.js', '.jsx'], 13 | modulesDirectories: [ 14 | 'node_modules', 15 | path.resolve(__dirname, './node_modules') 16 | ] 17 | }, 18 | debug: true, 19 | devtool: 'source-map', // more info:https://webpack.github.io/docs/build-performance.html#sourcemaps and https://webpack.github.io/docs/configuration.html#devtool 20 | noInfo: true, // set to false to see a list of every file being bundled. 21 | entry: './src/index', 22 | target: 'web', // necessary per https://webpack.github.io/docs/testing.html#compile-and-test 23 | output: { 24 | path: `${__dirname}/dist`, 25 | publicPath: '/', 26 | filename: '[name].[chunkhash].js' 27 | }, 28 | plugins: [ 29 | // Hash the files using MD5 so that their names change when the content changes. 30 | new WebpackMd5Hash(), 31 | 32 | // Optimize the order that items are bundled. This assures the hash is deterministic. 33 | new webpack.optimize.OccurenceOrderPlugin(), 34 | 35 | // Tells React to build in prod mode. https://facebook.github.io/react/downloads.html 36 | new webpack.DefinePlugin({ 37 | 'process.env': { 38 | 'NODE_ENV': JSON.stringify('production'), // Tells React to build in either dev or prod modes. https://facebook.github.io/react/downloads.html (See bottom) 39 | 'API': JSON.stringify(process.env.API) 40 | }, 41 | __DEV__: false 42 | }), 43 | 44 | // Generate an external css file with a hash in the filename 45 | new ExtractTextPlugin('[name].[contenthash].css'), 46 | 47 | // Generate HTML file that contains references to generated bundles. See here for how this works: https://github.com/ampedandwired/html-webpack-plugin#basic-usage 48 | new HtmlWebpackPlugin({ 49 | template: 'src/index.ejs', 50 | minify: { 51 | removeComments: true, 52 | collapseWhitespace: true, 53 | removeRedundantAttributes: true, 54 | useShortDoctype: true, 55 | removeEmptyAttributes: true, 56 | removeStyleLinkTypeAttributes: true, 57 | keepClosingSlash: true, 58 | minifyJS: true, 59 | minifyCSS: true, 60 | minifyURLs: true 61 | }, 62 | inject: true 63 | }), 64 | 65 | // Eliminate duplicate packages when generating bundle 66 | new webpack.optimize.DedupePlugin(), 67 | 68 | // Minify JS 69 | new webpack.optimize.UglifyJsPlugin() 70 | ], 71 | module: { 72 | loaders: [ 73 | { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel' }, 74 | { test: /\.eot(\?v=\d+.\d+.\d+)?$/, loader: 'url?name=[name].[ext]' }, 75 | { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "url?limit=10000&mimetype=application/font-woff&name=[name].[ext]" }, 76 | { test: /\.ttf(\?v=\d+.\d+.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream&name=[name].[ext]' }, 77 | { test: /\.svg(\?v=\d+.\d+.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml&name=[name].[ext]' }, 78 | { test: /\.(jpe?g|png|gif)$/i, loader: 'file?name=[name].[ext]' }, 79 | { test: /\.ico$/, loader: 'file?name=[name].[ext]' }, 80 | { test: /(\.css|\.scss)$/, loader: ExtractTextPlugin.extract('css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass?sourceMap') } 81 | ] 82 | }, 83 | postcss: () => [autoprefixer], 84 | sassLoader: { 85 | data: '@import "theme/_config.scss";', 86 | includePaths: [path.resolve(__dirname, './src/components')] 87 | } 88 | }; 89 | --------------------------------------------------------------------------------