├── .editorconfig ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── public ├── assets │ ├── img │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── avatar.svg │ │ └── splashscreen-icon-384x384.png │ └── translations │ │ ├── de.json │ │ └── en.json ├── favicon.ico └── manifest.json ├── scripts ├── graphql │ ├── generated │ │ └── README.md │ ├── index.js │ └── templates │ │ ├── entitiesReducer.ejs │ │ └── entityReducer.ejs └── intl │ ├── index.js │ └── webpack.config.js ├── src ├── actions.js ├── component.js ├── components │ ├── demo-button │ │ ├── component.js │ │ └── styles.scss │ ├── demo-card │ │ ├── component.js │ │ └── styles.scss │ ├── demo-checkbox │ │ ├── component.js │ │ └── styles.scss │ ├── demo-drawer │ │ ├── component.js │ │ └── styles.scss │ ├── demo-icon-toggle │ │ ├── component.js │ │ └── styles.scss │ ├── demo-list │ │ ├── component.js │ │ └── styles.scss │ ├── demo-snackbar │ │ ├── component.js │ │ └── styles.scss │ ├── demo-switch │ │ ├── component.js │ │ └── styles.scss │ ├── demo-text-field │ │ ├── component.js │ │ └── styles.scss │ └── demo-theme │ │ ├── component.js │ │ └── styles.scss ├── containers │ ├── about │ │ └── component.js │ ├── demo │ │ ├── component.js │ │ └── styles.scss │ └── home │ │ ├── component.js │ │ └── styles.scss ├── entities │ ├── README.md │ ├── addressReducer.js │ ├── cardReducer.js │ ├── cardTransactionReducer.js │ ├── colorReducer.js │ ├── commerceReducer.js │ ├── companyReducer.js │ ├── createdByReducer.js │ ├── currencyReducer.js │ ├── databaseReducer.js │ ├── dateTimeReducer.js │ ├── entitiesReducer.js │ ├── fakeReducer.js │ ├── financeReducer.js │ ├── hackerReducer.js │ ├── imageReducer.js │ ├── internetReducer.js │ ├── loremReducer.js │ ├── meetingReducer.js │ ├── messageReducer.js │ ├── metaReducer.js │ ├── miscReducer.js │ ├── numbersReducer.js │ ├── personReducer.js │ ├── phoneReducer.js │ ├── queryReducer.js │ ├── systemReducer.js │ ├── transactionReducer.js │ ├── updatedByReducer.js │ ├── userAddressReducer.js │ └── userReducer.js ├── epic.js ├── graphql │ ├── index.js │ └── types.json ├── index.client.js ├── index.ejs ├── index.server.js ├── preact-dom-renderer.js ├── reducer.js ├── server.js ├── serverless.js └── styles.scss ├── translations ├── mastercard │ ├── de.po │ └── en.po └── visa │ ├── de.po │ └── en.po └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | certificates 3 | dist 4 | node_modules 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | ### Version 0.1.0 3 | - First commit 4 | ### Version 0.2.0 5 | - Changed material design to `preact-mdc` 6 | ### Version 0.3.0 7 | - Latest preact-compat is now compatible with latest react-router 8 | - https://github.com/developit/preact-compat/issues/358#issuecomment-294604085 9 | ### Version 0.4.0 10 | - Added PO translation file import and export feature with whitelabel support 11 | ### Version 0.5.0 12 | - Added GraphQL entity generator scripts and example implementation 13 | - Example GraphQL server currently not responding to calls from epic because of CORS issue - will be resolved soon, or replace with your own! 14 | ### Version 0.6.0 15 | - Added AWS Lambda support for serverless rendering within a Lamda for SEO Websites. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017 Bernd Wessels 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # preact-redux-isomorphic 2 | 3 | ## Overview 4 | 5 | This is an opinionated isomorphic preact and redux starter-kit. 6 | 7 | It includes all your favourite libraries and can be as little as `24kB` but most likely less than `80kB` for the client to load your entire app! 8 | It depends on how many of the great stuff you actually need for your app. 9 | 10 | The goal is to use the same code to achieve 11 | - a PWA (progressive web app) 12 | - a SPA (single page application) that can be serverless and hosted on a CDN 13 | - a SSR (server-side rendered) app with SEO (search engine optimization) support 14 | - a serverless SSR (running in AWS Lambda and static resources in AWS S3) 15 | 16 | ### Latest and greatest 17 | 18 | #### preact v7 19 | 20 | `preact` is `react` in only `3kB` 21 | 22 | We also added `preact-compat` in case you need it, otherwise just get rid of it. 23 | 24 | #### react-router v4 25 | 26 | Routing done right with components. `ConnectedRouter` on the client and `StaticRouter` on the server 27 | allow for perfect isomorphic routing. 28 | 29 | #### redux v3 and ramda 30 | 31 | Single immutable state, reducers and actions to structure and master even the biggest apps. 32 | 33 | Use `rambda` to mutate state - this allows your state to be POJO (Plain Old JavaScript Objects) 34 | and make development so much more fun. 35 | 36 | #### rxjs v5 37 | 38 | Reactive programming of your actions allows for easy composition of even the most complex 39 | async action stream flows. 40 | This can replace all the other redux middleware you used so far. 41 | 42 | #### react-intl v2 43 | 44 | Internationalization that uses standards and works client and server-side. 45 | With support for all the stuff you need like genderization, pluralization, date and time. 46 | 47 | There are even some helper scripts to export/import PO files to communicate with your translators. 48 | 49 | ##### `npm run po:export` 50 | 51 | This will extract all translations from your code and merge them into PO files. 52 | It will NOT override already existing translations but only add new translations to the PO files. 53 | You then send the PO files to your translator and he will use his tools to only translate the new untranslated translations. 54 | 55 | ##### `npm run po:import visa` 56 | 57 | This will import all translations from the PO files within the given whitelabel. 58 | You do this after you received all translations back from the translator and before you build. 59 | 60 | ##### Whitelabel 61 | 62 | If you are building just for your own company, then just have only a single whitelabel and that's totally fine. 63 | 64 | But we also want to enable you to build for multiple whitelabels. 65 | This allows you to have different translations for different whitelabels. 66 | It is a very common thing in enterprise applications and translations really differ between whitelabels (believe me). 67 | 68 | #### webpack v2 with HMR (hot module replacement) 69 | 70 | Obviously the latest and greatest webpack with all the bells and whistles to achieve 71 | highly optimized builds. 72 | 73 | #### server-side rendering without the need for `preact-render-to-string` 74 | 75 | With a huge thanks to @developit we can now run the preact app on the server without the need 76 | for complex pre-render state calculations and render-to-string. 77 | 78 | This gives us very clean code that is almost identical on server and client-side and performs 79 | great. 80 | 81 | You can find [all the details here](ttps://github.com/developit/preact-render-to-string/issues/30#issuecomment-288752733). 82 | 83 | #### PWA (progressive web app) Service Worker 84 | 85 | 100/100 Lighthouse rating if you decide to use this repo to build a PWA. 86 | 87 | Otherwise just get rid of the service worker at the end of `index.client.js`. 88 | 89 | #### preact-mdc (material design components) 90 | 91 | Isomorphic modular lightweight preact material design based on the [material-components-web](https://github.com/material-components/material-components-web) sass styles. 92 | 93 | Replace it with your own front-end components if you like. Just make sure they are isomorphic. 94 | 95 | #### Normalized GraphQL Entity Redux State 96 | 97 | You can replace this easily with whatever data fetching technology you like but we really 98 | encourage you to embrace GraphQL. 99 | 100 | If you are using `GraphQL` and `Redux` you are most likely to normalize any `GraphQL Query` 101 | into a `normalized entity store`. 102 | 103 | To make this as simple and easy to use as possible we provide a script that can extract all 104 | `GraphQL Entities` from a given `GraphQL Endpoint` and automatically create the `Entity Reducers` 105 | for you. 106 | 107 | You run this script initially and then whenever the `GraphQL Schema` is about to change. 108 | 109 | ##### Usage 110 | 111 | ###### Override 112 | 113 | If you don't make any manual changes to any of the `Entity Reducers` you can just run 114 | 115 | `npm run graphql:override` 116 | 117 | This will generate and override your `Entity Reducers` automatically and you are ready to go. 118 | 119 | ###### Merge 120 | 121 | If you are extending the `Entity Reducers` with additional functionality you must run 122 | 123 | `npm run graphql:merge` 124 | 125 | This will generate all the `Entity Reducers` in the `scripts/graphql/generated` folder. 126 | 127 | You can now manually merge the generated 128 | 129 | `...Reducer.js` files into `src/entities` 130 | 131 | and 132 | 133 | `types.json` file into `src/graphql` 134 | 135 | without losing any of the extensions you've previously added to the `Entity Reducers`. 136 | 137 | ## Getting started 138 | 139 | ### Preparations 140 | 141 | - Either provide your own ssl certificates of change the code to use http instead of https! 142 | - To get a response from the GraphQL API you need to run your own GraphQL server, 143 | adjust the query and create the `Entity Reducers` (see above for details)! 144 | Otherwise just replace it with your ordinary REST APIs. 145 | - Fork and clone this repo. 146 | - `npm install` 147 | 148 | #### npm run-commands in `package.json` 149 | 150 | You might want to change the following parameters within the dev and build run-commands: 151 | 152 | - `BASEURL` will be injected into the `index.html` and the `router history` 153 | - `PORT` is the port to be used by the development server 154 | - `HOST` is the host to be used by the development server 155 | 156 | ```js 157 | "build:client": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=web BASEURL=/ webpack", 158 | "build:server": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=node BASEURL=/ webpack", 159 | "dev": "cross-env NODE_ENV=development TARGET=web BASEURL=/ PORT=8080 HOST=localhost webpack-dev-server --inline --hot --progress", 160 | "dev:secure": "cross-env NODE_ENV=development TARGET=web BASEURL=/ PORT=8080 HOST=my-domain.com webpack-dev-server --inline --hot --progress --https", 161 | ``` 162 | 163 | #### SSL 164 | 165 | You can run development with `http` or `https`. Production is served only with `https`. 166 | 167 | To do so you have to provide your own SSL certificates as `certificates/domain.key` and `certificates/domain.cert`. 168 | 169 | Make sure you don't check those in to GIT!!! 170 | 171 | ### Development 172 | 173 | `npm run dev` runs the development version via `http` 174 | 175 | `npm run dev:secure` runs the development version via `https` in which case you have to provide 176 | your own ssl certificate in the `certificates` folder. 177 | 178 | ### Production 179 | 180 | `npm run build` 181 | 182 | `node dist/server/main` 183 | 184 | This serves via https and requires you to provide your own certificates since it is intended to be for production. 185 | 186 | ### Server Side Rendering (SSR) 187 | 188 | The server will only render and serve the site to the client when the `ROOT_STATE_READY_TO_RENDER` action has been dispatched. 189 | 190 | This example dispatches this action once the first `GraphQL Query` had a successful response. 191 | 192 | You can replace that easily with your own custom logic. Just make sure you dispatch the `ROOT_STATE_READY_TO_RENDER` action 193 | when you are ready to render and serve the site to the client. 194 | 195 | ### Serverless SSR on AWS 196 | 197 | To build for a real serverless SSR just run `npm run build:serverless` 198 | 199 | - This will give you a `client` folder. 200 | - Create a `S3` bucket that will host your `static resources`. 201 | - Create a subfolder called `_` within that bucket. 202 | - Copy everything within the `client` folder into the `_` subfolder in the `S3` bucket. 203 | - This will also give you the server files. 204 | - Create a `Lambda` function. 205 | - Zip the `index.js` and `client` folder together into an archive and upload it into your `Lambda` function. 206 | - Now create a `CloudFront Distribution` with 2 `origins`. 207 | - The `default origin` will point to the `API Gateway Endpoint` that calls the `Lambda Function`. 208 | - The resource `origin` uses the `_` path to point to the `S3` static resources bucket. 209 | 210 | If you have no idea what all this is or you like more details, please contact me. I have `terraform` scripts that build 211 | all of this infrastructure automatically. 212 | 213 | # Contributing 214 | 215 | You are very welcome to report issues, PRs and become a contributor. 216 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-redux-isomorphic", 3 | "version": "0.6.0", 4 | "description": "preact-redux-isomorphic", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "npm run build:client & npm run build:server", 8 | "build:client": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=web BASEURL=/ webpack", 9 | "build:server": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=node BASEURL=/ webpack", 10 | "build:serverless": "npm run build:serverless:server & npm run build:serverless:client", 11 | "build:serverless:client": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=web RESOURCEPATH=_/ BASEURL=/ webpack", 12 | "build:serverless:server": "cross-env NODE_ENV=production BABEL_ENV=production TARGET=serverless RESOURCEPATH=_/ BASEURL=/ webpack", 13 | "dev": "cross-env NODE_ENV=development TARGET=web BASEURL=/ PORT=8080 HOST=localhost webpack-dev-server --inline --hot --progress", 14 | "dev:secure": "cross-env NODE_ENV=development TARGET=web BASEURL=/ PORT=8080 HOST=my-domain.com webpack-dev-server --inline --hot --progress --https", 15 | "po:export": "node ./scripts/intl export", 16 | "po:import": "node ./scripts/intl import", 17 | "graphql:merge": "node ./scripts/graphql --mode=merge --endpoint=http://159.203.96.223/graphql", 18 | "graphql:override": "node ./scripts/graphql --mode=override --endpoint=http://159.203.96.223/graphql", 19 | "test": "echo \"Error: no test specified\" && exit 1" 20 | }, 21 | "author": "Bernd Wessels", 22 | "license": "MIT", 23 | "devDependencies": { 24 | "autoprefixer": "^7.0.0", 25 | "aws-serverless-express": "^3.0.0", 26 | "babel-core": "^6.0.0", 27 | "babel-loader": "^6.0.0", 28 | "babel-plugin-react-intl": "^2.0.0", 29 | "babel-plugin-transform-class-properties": "^6.0.0", 30 | "babel-plugin-transform-object-rest-spread": "^6.0.0", 31 | "babel-plugin-transform-react-jsx": "^6.0.0", 32 | "babel-preset-es2015": "^6.0.0", 33 | "bundle-loader": "^0.5.0", 34 | "clean-webpack-plugin": "^0.1.0", 35 | "copy-webpack-plugin": "^4.0.0", 36 | "cross-env": "^5.0.0", 37 | "css-loader": "^0.28.0", 38 | "ejs": "^2.0.0", 39 | "extract-text-webpack-plugin": "^2.0.0", 40 | "file-loader": "^0.11.0", 41 | "glob": "^7.0.0", 42 | "html-webpack-plugin": "^2.0.0", 43 | "node-sass": "^4.0.0", 44 | "postcss-loader": "^2.0.0", 45 | "request": "^2.0.0", 46 | "resolve-url-loader": "^2.0.0", 47 | "sass-loader": "^6.0.0", 48 | "style-loader": "^0.17.0", 49 | "sw-precache-webpack-plugin": "^0.11.0", 50 | "webpack": "^2.0.0", 51 | "webpack-dev-server": "^2.0.0", 52 | "yargs": "^8.0.0" 53 | }, 54 | "dependencies": { 55 | "classnames": "^2.0.0", 56 | "history": "^4.0.0", 57 | "material-components-web": "^0.10.0", 58 | "material-design-icons": "^3.0.0", 59 | "preact": "^8.0.0", 60 | "preact-compat": "^3.0.0", 61 | "preact-mdc": "^0.1.0", 62 | "preact-redux": "^2.0.0", 63 | "ramda": "^0.23.0", 64 | "react-intl": "^2.0.0", 65 | "react-router": "^4.0.0", 66 | "react-router-redux": "^5.0.0-alpha.6", 67 | "redux": "^3.0.0", 68 | "redux-observable": "^0.14.0", 69 | "roboto-fontface": "^0.7.0", 70 | "rxjs": "^5.0.0", 71 | "undom": "^0.3.0", 72 | "xhr2": "^0.1.0" 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /public/assets/img/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/assets/img/android-chrome-144x144.png -------------------------------------------------------------------------------- /public/assets/img/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/assets/img/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/assets/img/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/assets/img/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /public/assets/img/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/assets/img/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /public/assets/img/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/img/splashscreen-icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/assets/img/splashscreen-icon-384x384.png -------------------------------------------------------------------------------- /public/assets/translations/de.json: -------------------------------------------------------------------------------- 1 | {"demoTitle":"Preact Material Design Components Web (preact-mdc) [visa/de]"} -------------------------------------------------------------------------------- /public/assets/translations/en.json: -------------------------------------------------------------------------------- 1 | {"demoTitle":"Preact Material Design Components Web (preact-mdc) [visa/en]"} -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BerndWessels/preact-redux-isomorphic/b7dc6f6d2b956821a50469eaaf0c20cb286976a6/public/favicon.ico -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-redux-isomorphic", 3 | "short_name": "PRI", 4 | "icons": [ 5 | { 6 | "src": "assets/img/apple-touch-icon-120x120.png", 7 | "sizes": "120x120", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "assets/img/apple-touch-icon-152x152.png", 12 | "sizes": "152x152", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "assets/img/android-chrome-144x144.png", 17 | "sizes": "144x144", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "assets/img/android-chrome-192x192.png", 22 | "sizes": "192x192", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "assets/img/splashscreen-icon-384x384.png", 27 | "sizes": "384x384", 28 | "type": "image/png" 29 | } 30 | ], 31 | "start_url": "/", 32 | "display": "standalone", 33 | "theme_color": "#333", 34 | "background_color": "#222" 35 | } 36 | -------------------------------------------------------------------------------- /scripts/graphql/generated/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | If you are using `GraphQL` and `Redux` you are most likely to normalize any `GraphQL Query` 4 | into a `normalized entity store`. 5 | 6 | To make this as simple and easy to use as possible we provide a script that can extract all 7 | `GraphQL Entities` from a given `GraphQL Endpoint` and automatically create the `Entity Reducers` 8 | for you. 9 | 10 | You run this script initially and then whenever the `GraphQL Schema` is about to change. 11 | 12 | # Usage 13 | 14 | ## Override 15 | 16 | If you don't make any manual changes to any of the `Entity Reducers` you can just run 17 | 18 | `npm run graphql:override` 19 | 20 | This will generate and override your `Entity Reducers` automatically and you are ready to go. 21 | 22 | ## Merge 23 | 24 | If you are extending the `Entity Reducers` with additional functionality you must run 25 | 26 | `npm run graphql:merge` 27 | 28 | This will generate all the `Entity Reducers` in the `scripts/graphql/generated` folder. 29 | 30 | You can now manually merge the generated 31 | 32 | `...Reducer.js` files into `src/entities` 33 | 34 | and 35 | 36 | `types.json` file into `src/graphql` 37 | 38 | without losing any of the extensions you've previously added to the `Entity Reducers`. 39 | -------------------------------------------------------------------------------- /scripts/graphql/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | const ejs = require('ejs'); 13 | const fs = require('fs'); 14 | const path = require('path'); 15 | const request = require('request'); 16 | const argv = require('yargs').argv; 17 | 18 | /** 19 | * Check 20 | */ 21 | if(argv.mode !== 'merge' && argv.mode !== 'override') { 22 | console.log('Please provide a mode (merge|override)!'); 23 | return -1; 24 | } 25 | 26 | if(!argv.endpoint) { 27 | console.log('Please provide an endpoint!'); 28 | return -1; 29 | } 30 | 31 | /** 32 | * Request the GraphQL schema from the server. 33 | */ 34 | request({ 35 | rejectUnauthorized: false, 36 | headers: { 37 | 'Content-Type': 'application/json; charset=UTF-8' 38 | }, 39 | uri: argv.endpoint, 40 | body: JSON.stringify({ 41 | query: ` 42 | { 43 | __schema { 44 | types { 45 | name 46 | kind 47 | ofType { 48 | name 49 | kind 50 | } 51 | fields { 52 | name 53 | type { 54 | name 55 | kind 56 | ofType { 57 | name 58 | kind 59 | ofType { 60 | name 61 | kind 62 | } 63 | } 64 | possibleTypes { 65 | name 66 | kind 67 | } 68 | } 69 | } 70 | } 71 | } 72 | }` 73 | }), 74 | method: 'POST' 75 | }, function (err, _res, body) { 76 | if (err) { 77 | console.log(err); 78 | return; 79 | } 80 | const schema = JSON.parse(body).data.__schema; 81 | 82 | /** 83 | * Create the types.json file. 84 | */ 85 | const typesObject = schema.types.reduce((prev, curr) => { 86 | if (curr.kind === 'OBJECT') { 87 | curr.fields = curr.fields.reduce((prev, curr) => { 88 | prev[curr.name] = curr; 89 | return prev; 90 | }, {}); 91 | } 92 | prev[curr.name] = curr; 93 | return prev; 94 | }, {}); 95 | fs.writeFile(path.join(__dirname, argv.mode === 'override' ? '../../src/graphql/types.json' : './generated/types.json'), JSON.stringify(typesObject, null, 2), (err) => { 96 | if (err) { 97 | console.log(err) 98 | } 99 | }); 100 | 101 | /** 102 | * Extend the schema. 103 | */ 104 | let types = Object.keys(typesObject).map((k) => typesObject[k]); 105 | 106 | types.forEach(type => { 107 | type.Name = type.name; 108 | type.name = type.name.charAt(0).toLowerCase() + type.name.slice(1); 109 | }); 110 | 111 | /** 112 | * Create the [entity]Reducer.js files. 113 | */ 114 | types.filter(t => t.kind === 'OBJECT' && t.name.charAt(0) !== '_' && t.name !== 'Query').forEach(type => { 115 | ejs.renderFile(path.join(__dirname, './templates/entityReducer.ejs'), type, (err, compiled) => { 116 | if (err) { 117 | console.log(err); 118 | } else { 119 | fs.writeFile(path.join(__dirname, `${argv.mode === 'override' ? '../../src/entities' : './generated'}/${type.name}Reducer.js`), compiled, (err) => { 120 | if (err) { 121 | console.log(err); 122 | } 123 | }); 124 | } 125 | }); 126 | }); 127 | 128 | /** 129 | * Create the reducer.js file. 130 | */ 131 | ejs.renderFile(path.join(__dirname, './templates/entitiesReducer.ejs'), {types: types.filter(t => t.kind === 'OBJECT' && t.name.charAt(0) !== '_' && t.name !== 'Query')}, (err, compiled) => { 132 | if (err) { 133 | console.log(err); 134 | } else { 135 | fs.writeFile(path.join(__dirname, argv.mode === 'override' ? '../../src/entities/entitiesReducer.js' : './generated/entitiesReducer.js'), compiled, (err) => { 136 | if (err) { 137 | console.log(err); 138 | } 139 | }); 140 | } 141 | }); 142 | 143 | }); 144 | -------------------------------------------------------------------------------- /scripts/graphql/templates/entitiesReducer.ejs: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {combineReducers} from 'redux'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | <% for(var i=0; iimport {<%= types[i].name %>Reducer} from './<%= types[i].name %>Reducer'; 19 | <% } %> 20 | 21 | /** 22 | * Export the entities store. 23 | */ 24 | export const entitiesReducer = combineReducers({ 25 | <% for(var i=0; i <%= types[i].Name %>: <%= types[i].name %>Reducer, 26 | <% } %> 27 | }); 28 | -------------------------------------------------------------------------------- /scripts/graphql/templates/entityReducer.ejs: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default <%= Name %> entities state. 24 | */ 25 | const <%= name %>DefaultState = {}; 26 | 27 | /** 28 | * Export the <%= Name %> entities store. 29 | */ 30 | export function <%= name %>Reducer(state = <%= name %>DefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.<%= Name %>); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /scripts/intl/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2017 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | /** 13 | * Import dependencies. 14 | */ 15 | const fs = require('fs'); 16 | const path = require('path'); 17 | const globSync = require('glob').sync; 18 | const rimraf = require('rimraf'); 19 | const webpack = require('webpack'); 20 | const config = require('./webpack.config'); 21 | const R = require('ramda'); 22 | 23 | /** 24 | * Read already existing PO files. 25 | */ 26 | function readPO(filename) { 27 | const file = fs.readFileSync(filename, 'utf8'); 28 | let lines = file.trim().match(/\S.*\r?\n?|[\r?\n].*?/g); 29 | if (!lines) { 30 | return {}; 31 | } 32 | let translations = [{ 33 | msgctxt: null, 34 | prevMsgctxt: null, 35 | lines: { 36 | translatorComments: [], 37 | extractedComments: [], 38 | reference: [], 39 | msgid: [], 40 | msgstr: [], 41 | prevMsgid: null 42 | } 43 | }]; 44 | for (let i = 0, j = 0; i < lines.length; i++) { 45 | if (lines[i][0] === '\n') { 46 | j++; 47 | translations.push({ 48 | msgctxt: null, 49 | prevMsgctxt: null, 50 | lines: { 51 | translatorComments: [], 52 | extractedComments: [], 53 | reference: [], 54 | msgid: [], 55 | msgstr: [], 56 | prevMsgid: null 57 | } 58 | }); 59 | while (lines[++i][0] === '\n'); 60 | } 61 | if (/^#\s\s?(\S.*)/g.test(lines[i])) { 62 | translations[j].lines.translatorComments.push(/^#\s\s?(\S.*)/g.exec(lines[i])[1]); 63 | continue; 64 | } 65 | if (/^#\. (\S.*)/g.test(lines[i])) { 66 | translations[j].lines.extractedComments.push(/^#\. (\S.*)/g.exec(lines[i])[1]); 67 | continue; 68 | } 69 | if (/^#: (\S.*)/g.test(lines[i])) { 70 | translations[j].lines.reference.push(/^#: (\S.*)/g.exec(lines[i])[1]); 71 | continue; 72 | } 73 | if (/^msgctxt "(\S.*)"/g.exec(lines[i])) { 74 | translations[j].msgctxt = /^msgctxt "(\S.*)"/g.exec(lines[i])[1]; 75 | continue; 76 | } 77 | let msgid = /^msgid "(\S.*)?"/g.exec(lines[i]); 78 | if (msgid) { 79 | translations[j].lines.msgid.push(!msgid[1] ? "" : msgid[1]); 80 | while (/^\s*"(\S.*)"/g.test(lines[++i])) { 81 | translations[j].lines.msgid.push(/\s*"(\S.*)"/g.exec(lines[i])[1]); 82 | } 83 | } 84 | let msgstr = /^msgstr "(\S.*)?"/g.exec(lines[i]); 85 | if (msgstr) { 86 | translations[j].lines.msgstr.push(!msgstr[1] ? "" : msgstr[1]); 87 | while (/^\s*"(\S.*)"/g.test(lines[++i])) { 88 | translations[j].lines.msgstr.push(/\s*"(\S.*)"/g.exec(lines[i])[1]); 89 | } 90 | i--; 91 | } 92 | } 93 | let reducedTranslations = R.reduce((a, b) => { 94 | if(!b.lines.msgid.length || !b.lines.msgid[0].length) { 95 | console.log('Ignoring empty [msgid]. This was most likely generated as a comment from a translation tool.'); 96 | return a; 97 | } 98 | if (b.msgctxt) 99 | a[b.msgctxt] = b; 100 | else 101 | console.error(`Error! Missing [msgctxt] for [msgid]: ${b.lines.msgid}`); 102 | return a; 103 | }, {}, translations); 104 | 105 | return reducedTranslations; 106 | } 107 | 108 | /** 109 | * Read the extracted translations. 110 | */ 111 | function readExtract() { 112 | let reducedTranslations = {}; 113 | globSync(path.join(__dirname, './src/**/*.json')) 114 | .forEach(filename => { 115 | const reference = path.relative(path.join(__dirname, './src'), filename); 116 | const source = JSON.parse(fs.readFileSync(filename, 'utf8')); 117 | source.map(translation => { 118 | reducedTranslations[translation.id] = { 119 | msgctxt: translation.id, 120 | prevMsgctxt: null, 121 | lines: { 122 | translatorComments: [], 123 | extractedComments: translation.description.match(/\S.*\n?/g).map(m => m.replace('\n', '')), 124 | reference: [reference], 125 | msgid: translation.defaultMessage.match(/\S.*\n?/g).map(m => m.replace('\n', '\\n')), 126 | msgstr: [], 127 | prevMsgid: null, 128 | } 129 | }; 130 | if (reducedTranslations[translation.id].lines.msgid.length > 1) { 131 | reducedTranslations[translation.id].lines.msgid.unshift(""); 132 | } 133 | }); 134 | }); 135 | return reducedTranslations; 136 | } 137 | 138 | /** 139 | * Merge the extracted translations and the existing PO files. 140 | */ 141 | function mergeExtractAndPo(reducedExtract, reducedPo) { 142 | let merged = R.mergeWith((a, b) => { 143 | let m = R.assocPath(['lines', 'translatorComments'], b.lines.translatorComments, a); 144 | m = R.assocPath(['lines', 'msgstr'], b.lines.msgstr, m); 145 | if (!R.equals(m.lines.msgid, b.lines.msgid)) { 146 | // #| msgctxt previous-context 147 | // #| msgid previous-untranslated-string 148 | m = R.assocPath(['lines', 'prevMsgid'], b.lines.msgid, m); 149 | m = R.assoc('prevMsgctxt', b.msgctxt, m); 150 | } 151 | return m; 152 | }, reducedExtract, reducedPo); 153 | return merged; 154 | } 155 | 156 | /** 157 | * Write the merged result into new PO files. 158 | */ 159 | function writePO(merged, filename) { 160 | let output = ''; 161 | output += R.values(merged).map(translation => { 162 | let t = ''; 163 | t += translation.lines.translatorComments.length > 0 ? translation.lines.translatorComments.map(x => `# ${x}`).join('\n') + '\n' : ''; 164 | t += translation.lines.extractedComments.length > 0 ? translation.lines.extractedComments.map(x => `#. ${x}`).join('\n') + '\n' : ''; 165 | t += translation.lines.reference.length > 0 ? translation.lines.reference.map(x => `#: ${x}`).join('\n') + '\n' : ''; 166 | t += translation.prevMsgctxt ? `#| msgctxt "${translation.prevMsgctxt}"\n` : ''; 167 | t += translation.prevMsgctxt ? '#| msgid ' + translation.lines.prevMsgid.map((x, i) => `${i ? '#| ' : ''}"${x}"`).join('\n') + '\n' : ''; 168 | t += `msgctxt "${translation.msgctxt}"\n`; 169 | t += translation.lines.msgid.length > 0 ? 'msgid ' + translation.lines.msgid.map(x => `"${x}"`).join('\n') + '\n' : ''; 170 | t += translation.lines.msgstr.length > 0 ? 'msgstr ' + translation.lines.msgstr.map(x => `"${x}"`).join('\n') + '\n' : 'msgstr ""\n'; 171 | return t; 172 | }).join('\n'); 173 | fs.writeFileSync(filename, output); 174 | } 175 | 176 | /** 177 | * Update all existing PO files. 178 | */ 179 | function updateAllPOs() { 180 | let reducedExtract = readExtract(); 181 | globSync(path.join(__dirname, '../../translations/**/*.po')) 182 | .forEach(filename => writePO(mergeExtractAndPo(reducedExtract, readPO(filename)), filename)); 183 | } 184 | 185 | /** 186 | * Webpack callback. 187 | */ 188 | const callback = function (err, stats) { 189 | if (err) { 190 | console.error(err.toString()); 191 | } else { 192 | updateAllPOs(); 193 | rimraf(path.join(__dirname, './dist'), (err) => { 194 | if (err) { 195 | console.error(err); 196 | } 197 | }); 198 | rimraf(path.join(__dirname, './src'), (err) => { 199 | if (err) { 200 | console.error(err); 201 | } 202 | }); 203 | } 204 | }; 205 | 206 | /** 207 | * Import new translations into the build files. 208 | */ 209 | function importTranslations(theme) { 210 | globSync(path.join(__dirname, `../../translations/${theme}/*.po`)) 211 | .forEach(filename => { 212 | let po = readPO(filename); 213 | let output = R.reduce((a, b) => { 214 | a[b.msgctxt] = b.lines.msgstr.map(s => s.replace('\\n', '')).join('\n'); 215 | return a; 216 | }, {}, R.values(po)); 217 | fs.writeFileSync(path.join(__dirname, `../../public/assets/translations/${path.basename(filename).replace('.po', '.json')}`), JSON.stringify(output)); 218 | }); 219 | } 220 | 221 | /** 222 | * Import: npm run po:export 223 | * Export: npm run po:import visa 224 | */ 225 | if (process.argv.length === 3 && process.argv[2] === 'export') { 226 | webpack(config(), callback); 227 | } else if (process.argv.length === 4 && process.argv[2] === 'import') { 228 | importTranslations(process.argv[3]); 229 | } else { 230 | console.error(`Please specify [export] | [import theme]!`); 231 | } 232 | -------------------------------------------------------------------------------- /scripts/intl/webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2017 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | /** 13 | * Import dependencies. 14 | */ 15 | const fs = require('fs'); 16 | const path = require('path'); 17 | const glob = require('glob'); 18 | const webpack = require('webpack'); 19 | const autoprefixer = require('autoprefixer'); 20 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 21 | 22 | /** 23 | * Export the build configuration. 24 | */ 25 | module.exports = function () { 26 | // Build sass loaders. 27 | function getSassLoaders(modules) { 28 | return [ 29 | { 30 | // https://github.com/webpack-contrib/css-loader 31 | loader: 'css-loader', 32 | options: Object.assign({ 33 | sourceMap: true, 34 | modules: modules, 35 | importLoaders: 2 36 | }, {} 37 | ) 38 | }, 39 | { 40 | // https://github.com/postcss/postcss-loader 41 | loader: 'postcss-loader', 42 | options: { 43 | plugins: function () { 44 | return [ 45 | autoprefixer({browsers: ['last 1 versions']}) 46 | ]; 47 | } 48 | } 49 | }, 50 | { 51 | // https://github.com/bholloway/resolve-url-loader 52 | loader: 'resolve-url-loader' 53 | }, 54 | { 55 | // https://github.com/webpack-contrib/sass-loader 56 | loader: 'sass-loader', 57 | options: { 58 | sourceMap: true, 59 | includePaths: ['../../node_modules', '../../node_modules/@material/*'] 60 | .map((d) => path.join(__dirname, d)) 61 | .map((g) => glob.sync(g)) 62 | .reduce((a, c) => a.concat(c), []) 63 | } 64 | } 65 | ]; 66 | } 67 | 68 | // Build and export the build configuration. 69 | return { 70 | // https://webpack.js.org/configuration/target 71 | target: 'web', 72 | // https://webpack.js.org/configuration/entry-context 73 | entry: { 74 | main: path.resolve(__dirname, '../../src/index.client.js') 75 | }, 76 | // https://webpack.js.org/configuration/output 77 | output: { 78 | filename: '[name].[hash].js', 79 | path: path.resolve(__dirname, './dist/intl'), 80 | publicPath: '' 81 | }, 82 | // https://webpack.js.org/configuration/resolve 83 | resolve: { 84 | alias: { 85 | 'preact': 'preact', 86 | 'react': 'preact-compat', 87 | 'react-dom': 'preact-compat' 88 | }, 89 | extensions: ['.js', '.jsx', '.json', '.scss'], 90 | modules: ['node_modules'] 91 | }, 92 | // https://webpack.js.org/configuration/module 93 | module: { 94 | noParse: /\.min\.js/, 95 | rules: [{ 96 | test: /\.jsx?$/, 97 | exclude: [/node_modules(?![\/\\]preact-mdc)/], 98 | use: [{ 99 | // https://github.com/babel/babel-loader 100 | loader: 'babel-loader', 101 | options: { 102 | presets: [ 103 | ['es2015', {loose: true, modules: false}] 104 | ], 105 | plugins: [ 106 | 'transform-class-properties', 107 | 'transform-object-rest-spread', 108 | ['transform-react-jsx', {pragma: 'h'}], 109 | [ 110 | "react-intl", 111 | { 112 | "messagesDir": path.resolve(path.join(__dirname, './')), 113 | "enforceDescriptions": true 114 | } 115 | ] 116 | ] 117 | }, 118 | }] 119 | }, { 120 | test: /(\.scss|\.css)$/, 121 | exclude: [/node_modules/, /normalize.css/, /icomoon/], 122 | use: getSassLoaders(true) 123 | }, { 124 | test: /(\.scss|\.css)$/, 125 | include: [/node_modules/], 126 | use: getSassLoaders(false) 127 | }, { 128 | // https://github.com/webpack/file-loader 129 | test: /\.(svg|woff|woff2|ttf|eot)$/, 130 | loader: 'file-loader?name=assets/fonts/[name].[hash].[ext]' 131 | }] 132 | }, 133 | // https://webpack.js.org/configuration/plugins 134 | plugins: [ 135 | // https://github.com/johnagan/clean-webpack-plugin 136 | new CleanWebpackPlugin(['dist/intl'], __dirname) 137 | ] 138 | }; 139 | }; 140 | -------------------------------------------------------------------------------- /src/actions.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Export action types. 12 | */ 13 | export const ROOT_STATE_READY_TO_RENDER = 'ROOT_STATE_READY_TO_RENDER'; 14 | 15 | export const ROOT_FETCH_GRAPHQL_QUERY = 'ROOT_FETCH_GRAPHQL_QUERY'; 16 | export const ROOT_FETCH_GRAPHQL_QUERY_CANCEL = 'ROOT_FETCH_GRAPHQL_QUERY_CANCEL'; 17 | export const ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED = 'ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED'; 18 | export const ROOT_FETCH_GRAPHQL_QUERY_FAILED = 'ROOT_FETCH_GRAPHQL_QUERY_FAILED'; 19 | export const ROOT_FETCH_GRAPHQL_QUERY_PENDING = 'ROOT_FETCH_GRAPHQL_QUERY_PENDING'; 20 | 21 | /** 22 | * Export action creators. 23 | */ 24 | export const rootStateReadyToRenderCreator = () => ({type: ROOT_STATE_READY_TO_RENDER}); 25 | 26 | export const fetchGraphQLQueryCreator = (payload) => ({type: ROOT_FETCH_GRAPHQL_QUERY, payload}); 27 | export const fetchGraphQLQueryCancelCreator = () => ({type: ROOT_FETCH_GRAPHQL_QUERY_CANCEL}); 28 | export const fetchGraphQLQuerySucceededCreator = (payload) => ({type: ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED, payload}); 29 | export const fetchGraphQLQueryFailedCreator = (payload) => ({type: ROOT_FETCH_GRAPHQL_QUERY_FAILED, payload}); 30 | export const fetchGraphQLQueryPendingCreator = () => ({type: ROOT_FETCH_GRAPHQL_QUERY_PENDING}); 31 | -------------------------------------------------------------------------------- /src/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import {connect} from 'preact-redux'; 15 | import {push} from 'react-router-redux'; 16 | import {Route} from 'react-router'; 17 | 18 | /** 19 | * Import local dependencies. 20 | */ 21 | import Demo from './containers/demo/component'; 22 | import DemoButton from './components/demo-button/component'; 23 | import DemoCard from './components/demo-card/component'; 24 | import DemoCheckbox from './components/demo-checkbox/component'; 25 | import DemoDrawer from './components/demo-drawer/component'; 26 | import DemoIconToggle from './components/demo-icon-toggle/component'; 27 | import DemoList from './components/demo-list/component'; 28 | import DemoSnackbar from './components/demo-snackbar/component'; 29 | import DemoSwitch from './components/demo-switch/component'; 30 | import DemoTextField from './components/demo-text-field/component'; 31 | import DemoTheme from './components/demo-theme/component'; 32 | 33 | /** 34 | * Import actions. 35 | */ 36 | import {fetchGraphQLQueryCreator} from './actions'; 37 | import {rootStateReadyToRenderCreator} from './actions'; 38 | 39 | /** 40 | * Import styles. 41 | */ 42 | import 'roboto-fontface/css/roboto/sass/roboto-fontface-regular.scss'; 43 | import styles from './styles'; 44 | 45 | /** 46 | * Create the component. 47 | */ 48 | class App extends Component { 49 | 50 | /** 51 | * Initialize local component state. 52 | */ 53 | constructor() { 54 | super(); 55 | this.state = {}; 56 | } 57 | 58 | // Called on server and client. 59 | componentWillMount = () => { 60 | // Load data if necessary. 61 | setTimeout(() => { 62 | if (!this.props.alreadyLoaded) { 63 | this.props.onReady(); 64 | } 65 | }); 66 | }; 67 | 68 | // Render the component. 69 | render({onNavigate, aTest}, {drawerCollapsed}) { 70 | return ( 71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 |
84 | ); 85 | } 86 | } 87 | 88 | /** 89 | * Map state to component properties. 90 | */ 91 | const mapStateToProps = (state) => { 92 | return { 93 | aTest: state.a.test, 94 | alreadyLoaded: state.a.hasOwnProperty('report') 95 | } 96 | }; 97 | 98 | /** 99 | * Map actions to component properties. 100 | */ 101 | const mapDispatchToProps = (dispatch) => { 102 | return { 103 | onNavigate: (path) => dispatch(push(path)), 104 | onReady: () => dispatch(rootStateReadyToRenderCreator()) 105 | // onReady: () => dispatch(fetchGraphQLQueryCreator({ 106 | // query: `{ 107 | // Fake { 108 | // _id 109 | // firstName 110 | // lastName 111 | // Address { 112 | // country 113 | // countryCode 114 | // } 115 | // } 116 | // } 117 | // ` 118 | // }) 119 | // ) 120 | } 121 | }; 122 | 123 | /** 124 | * Export the container component. 125 | */ 126 | export default connect( 127 | mapStateToProps, 128 | mapDispatchToProps, 129 | null, { 130 | pure: false 131 | } 132 | )(App); 133 | -------------------------------------------------------------------------------- /src/components/demo-button/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Button from 'preact-mdc/material-button'; 19 | import Fab from 'preact-mdc/material-fab'; 20 | 21 | /** 22 | * Import styles. 23 | */ 24 | import styles from './styles'; 25 | 26 | /** 27 | * Create the component. 28 | */ 29 | class Demo extends Component { 30 | 31 | constructor() { 32 | super(); 33 | this.state = {}; 34 | } 35 | 36 | render(props, state) { 37 | return ( 38 |
39 | 40 | 41 |
42 | ); 43 | } 44 | } 45 | 46 | /** 47 | * Export the component. 48 | */ 49 | export default Demo; 50 | -------------------------------------------------------------------------------- /src/components/demo-button/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | -------------------------------------------------------------------------------- /src/components/demo-card/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Card from 'preact-mdc/material-card'; 19 | import CardPrimary from 'preact-mdc/material-card-primary'; 20 | import CardTitle from 'preact-mdc/material-card-title'; 21 | import CardSubTitle from 'preact-mdc/material-card-subtitle'; 22 | import CardSupportingText from 'preact-mdc/material-card-supporting-text'; 23 | import CardActions from 'preact-mdc/material-card-actions'; 24 | import CardAction from 'preact-mdc/material-card-action'; 25 | import CardMedia from 'preact-mdc/material-card-media'; 26 | import CardMediaItem from 'preact-mdc/material-card-media-item'; 27 | import CardHorizontalBlock from 'preact-mdc/material-card-horizontal-block'; 28 | 29 | /** 30 | * Import styles. 31 | */ 32 | import styles from './styles'; 33 | 34 | /** 35 | * Create the component. 36 | */ 37 | class Demo extends Component { 38 | 39 | constructor() { 40 | super(); 41 | this.state = {}; 42 | } 43 | 44 | render(props, state) { 45 | return ( 46 |
47 | 48 | 49 | 50 | Title 51 | Subtitle 52 | 53 | 54 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod 55 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim 56 | veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 57 | commodo consequat. 58 | 59 | 60 | Raised 61 | Action 62 | 63 | 64 |
65 | 66 | 67 | 68 | Large Title 69 | Subtitle 70 | 71 | 72 | 73 | 74 | Vertical 75 | Actions 76 | 77 | 78 |
79 | ); 80 | } 81 | } 82 | 83 | /** 84 | * Export the component. 85 | */ 86 | export default Demo; 87 | -------------------------------------------------------------------------------- /src/components/demo-card/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .media { 11 | height: 200px; 12 | background-color: #32007e; 13 | background-image: url("data:image/svg+xml,%3Csvg width='304' height='304' viewBox='0 0 304 304' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M44.1 224c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H0v-2h44.1zm160 48c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H82v-2h122.1zm57.8-46c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H304v2h-42.1zm0 16c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H304v2h-42.1zm6.2-114c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4h-86.2c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h86.2zm-256-48c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H0v-2h12.1zm185.8 34c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h86.2c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4h-86.2zM258 12.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V0h2v12.1zm-64 208c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-54.2c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9v54.2zm48-198.2c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V82h64v-2h-62V21.9zm16 16c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V66h48v-2h-46V37.9zm-128 96c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V210h16v10.1c-2.282.463-4 2.48-4 4.9 0 2.76 2.24 5 5 5s5-2.24 5-5c0-2.42-1.718-4.437-4-4.9V208h-16v-74.1zm-5.9-21.9c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H114v48H85.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H112v-48h12.1zm-6.2 130c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H176v-74.1c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V242h-60.1zm-16-64c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H114v48h10.1c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H112v-48h-10.1zM66 284.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V274H50v30h-2v-32h18v12.1zM236.1 176c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H274v44.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V146h-10.1zm-64 96c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H208v-80h16v-14h-42.1c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H226v18h-16v80h-12.1zm86.2-210c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H272V0h2v32h10.1zM98 101.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V144H53.9c-.463-2.282-2.48-4-4.9-4-2.76 0-5 2.24-5 5s2.24 5 5 5c2.42 0 4.437-1.718 4.9-4H98v-44.1zM53.9 34c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H80V0h2v34H53.9zm60.1 3.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V64H80v64H69.9c-.463-2.282-2.48-4-4.9-4-2.76 0-5 2.24-5 5s2.24 5 5 5c2.42 0 4.437-1.718 4.9-4H82V66h32V37.9zM101.9 82c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H128V37.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V82h-28.1zm16-64c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H146v44.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V18h-26.1zm102.2 270c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H98v14h-2v-16h124.1zM242 149.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V162h16v30h-16v66h48v46h2v-48h-48v-62h16v-34h-16v-10.1zM53.9 18c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H64V2H48V0h18v18H53.9zm112 32c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H192V0h50v2h-48v48h-28.1zm-48-48c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5 0-.342.034-.677.1-1h2.07c-.11.313-.17.65-.17 1 0 1.657 1.343 3 3 3s3-1.343 3-3c0-.35-.06-.687-.17-1H178v34h-18V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V32h14V2h-58.1zm0 96c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H137l32-32h39V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V66h-40.172l-32 32H117.9zm28.1 90.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-76.513L175.586 80H224V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V82h-49.586L146 112.414V188.1zm16 32c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-99.513L184.586 96H300.1c.398-1.96 1.94-3.502 3.9-3.9v2.07c-1.165.413-2 1.524-2 2.83s.835 2.417 2 2.83v2.07c-1.96-.398-3.502-1.94-3.9-3.9H185.414L162 121.414V220.1zm-144-64c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-3.513l48-48V48h32V0h2v50H66v55.413l-48 48v2.687zM50 53.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9v42.686l-48 48V210h28.1c.463 2.282 2.48 4 4.9 4 2.76 0 5-2.24 5-5s-2.24-5-5-5c-2.42 0-4.437 1.718-4.9 4H2v-62.586l48-48V53.9zm-16 16c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9v18.686l-32 32v2.828l34-34V69.9zM12.1 32c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H9.414L0 43.414v-2.828L8.586 32H12.1zm265.8 18c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h18.686L304 40.586v2.828L297.414 50H277.9zm-16 160c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H288V136.587l16-16v2.827l-14 14V210h-28.1zm-208 32c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H64v-22.586L40.586 194H21.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h19.513L66 216.586V242H53.9zm150.2 14c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H96v-56.598L56.598 162H37.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h19.502L98 200.598V256h106.1zm-150.2 2c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H80v-46.586L48.586 178H21.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h27.513L82 208.586V258H53.9zM97 100c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-48 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 96c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-144c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-96 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm96 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-32 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM49 36c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-32 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM33 68c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 240c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm80-176c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm112 176c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM17 180c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM17 84c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 39.793V0h-2v40.586L8.586 64H0v2h9.413L34 41.414v-1.62zM2 300.1V258h14v46h2v-48H0V302.17c.313-.11.65-.17 1-.17 1.306 0 2.417.835 2.83 2H5.9c-.398-1.96-1.94-3.502-3.9-3.9zM34 241v63h-2v-62H0v-2h34v1zM17 18h1V0h-2v16H0v2h17zm273-2V0h-2v18h16v-2h-14zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1c.323-.066.658-.1 1-.1 2.76 0 5 2.24 5 5s-2.24 5-5 5c-.342 0-.677-.034-1-.1v-2.07c.313.11.65.17 1 .17 1.657 0 3-1.343 3-3s-1.343-3-3-3c-.35 0-.687.06-1 .17V92.1zM80 272h2v32h-2v-32zm37.9 32c-.463-2.282-2.48-4-4.9-4-2.42 0-4.437 1.718-4.9 4h2.07c.413-1.165 1.524-2 2.83-2s2.417.835 2.83 2h2.07zM5.9 0c.066.323.1.658.1 1 0 2.76-2.24 5-5 5-.342 0-.677-.034-1-.1V3.83C.313 3.94.65 4 1 4c1.657 0 3-1.343 3-3 0-.35-.06-.687-.17-1H5.9zm294.2 0c-.066.323-.1.658-.1 1 0 2.42 1.718 4.437 4 4.9V3.83c-1.165-.413-2-1.524-2-2.83 0-.35.06-.687.17-1h-2.07zm3.9 300.1c-1.96.398-3.502 1.94-3.9 3.9h2.07c.302-.852.978-1.528 1.83-1.83v-2.07z' fill='%23ffffff' fill-opacity='0.4' fill-rule='evenodd'/%3E%3C/svg%3E"); 14 | } 15 | 16 | .mediaItem { 17 | width: 400px; 18 | background-color: #32007e; 19 | background-image: url("data:image/svg+xml,%3Csvg width='304' height='304' viewBox='0 0 304 304' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M44.1 224c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H0v-2h44.1zm160 48c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H82v-2h122.1zm57.8-46c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H304v2h-42.1zm0 16c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H304v2h-42.1zm6.2-114c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4h-86.2c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h86.2zm-256-48c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H0v-2h12.1zm185.8 34c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h86.2c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4h-86.2zM258 12.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V0h2v12.1zm-64 208c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-54.2c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9v54.2zm48-198.2c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V82h64v-2h-62V21.9zm16 16c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V66h48v-2h-46V37.9zm-128 96c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V210h16v10.1c-2.282.463-4 2.48-4 4.9 0 2.76 2.24 5 5 5s5-2.24 5-5c0-2.42-1.718-4.437-4-4.9V208h-16v-74.1zm-5.9-21.9c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H114v48H85.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H112v-48h12.1zm-6.2 130c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H176v-74.1c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V242h-60.1zm-16-64c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H114v48h10.1c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H112v-48h-10.1zM66 284.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V274H50v30h-2v-32h18v12.1zM236.1 176c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H226v94h48v32h-2v-30h-48v-98h12.1zm25.8-30c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H274v44.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V146h-10.1zm-64 96c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H208v-80h16v-14h-42.1c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H226v18h-16v80h-12.1zm86.2-210c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H272V0h2v32h10.1zM98 101.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V144H53.9c-.463-2.282-2.48-4-4.9-4-2.76 0-5 2.24-5 5s2.24 5 5 5c2.42 0 4.437-1.718 4.9-4H98v-44.1zM53.9 34c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H80V0h2v34H53.9zm60.1 3.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V64H80v64H69.9c-.463-2.282-2.48-4-4.9-4-2.76 0-5 2.24-5 5s2.24 5 5 5c2.42 0 4.437-1.718 4.9-4H82V66h32V37.9zM101.9 82c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H128V37.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V82h-28.1zm16-64c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H146v44.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9V18h-26.1zm102.2 270c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H98v14h-2v-16h124.1zM242 149.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9V162h16v30h-16v66h48v46h2v-48h-48v-62h16v-34h-16v-10.1zM53.9 18c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H64V2H48V0h18v18H53.9zm112 32c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H192V0h50v2h-48v48h-28.1zm-48-48c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5 0-.342.034-.677.1-1h2.07c-.11.313-.17.65-.17 1 0 1.657 1.343 3 3 3s3-1.343 3-3c0-.35-.06-.687-.17-1H178v34h-18V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V32h14V2h-58.1zm0 96c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H137l32-32h39V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V66h-40.172l-32 32H117.9zm28.1 90.1c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-76.513L175.586 80H224V21.9c-2.282-.463-4-2.48-4-4.9 0-2.76 2.24-5 5-5s5 2.24 5 5c0 2.42-1.718 4.437-4 4.9V82h-49.586L146 112.414V188.1zm16 32c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-99.513L184.586 96H300.1c.398-1.96 1.94-3.502 3.9-3.9v2.07c-1.165.413-2 1.524-2 2.83s.835 2.417 2 2.83v2.07c-1.96-.398-3.502-1.94-3.9-3.9H185.414L162 121.414V220.1zm-144-64c2.282.463 4 2.48 4 4.9 0 2.76-2.24 5-5 5s-5-2.24-5-5c0-2.42 1.718-4.437 4-4.9v-3.513l48-48V48h32V0h2v50H66v55.413l-48 48v2.687zM50 53.9c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9v42.686l-48 48V210h28.1c.463 2.282 2.48 4 4.9 4 2.76 0 5-2.24 5-5s-2.24-5-5-5c-2.42 0-4.437 1.718-4.9 4H2v-62.586l48-48V53.9zm-16 16c2.282-.463 4-2.48 4-4.9 0-2.76-2.24-5-5-5s-5 2.24-5 5c0 2.42 1.718 4.437 4 4.9v18.686l-32 32v2.828l34-34V69.9zM12.1 32c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H9.414L0 43.414v-2.828L8.586 32H12.1zm265.8 18c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h18.686L304 40.586v2.828L297.414 50H277.9zm-16 160c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H288V136.587l16-16v2.827l-14 14V210h-28.1zm-208 32c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H64v-22.586L40.586 194H21.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h19.513L66 216.586V242H53.9zm150.2 14c.463-2.282 2.48-4 4.9-4 2.76 0 5 2.24 5 5s-2.24 5-5 5c-2.42 0-4.437-1.718-4.9-4H96v-56.598L56.598 162H37.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h19.502L98 200.598V256h106.1zm-150.2 2c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4H80v-46.586L48.586 178H21.9c-.463 2.282-2.48 4-4.9 4-2.76 0-5-2.24-5-5s2.24-5 5-5c2.42 0 4.437 1.718 4.9 4h27.513L82 208.586V258H53.9zM97 100c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-48 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 96c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-144c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-96 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm96 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-32 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM49 36c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-32 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM33 68c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 240c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm80-176c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 48c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm112 176c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm-16 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM17 180c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0 16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm0-32c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16 0c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM17 84c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm32 64c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm16-16c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 39.793V0h-2v40.586L8.586 64H0v2h9.413L34 41.414v-1.62zM2 300.1V258h14v46h2v-48H0V302.17c.313-.11.65-.17 1-.17 1.306 0 2.417.835 2.83 2H5.9c-.398-1.96-1.94-3.502-3.9-3.9zM34 241v63h-2v-62H0v-2h34v1zM17 18h1V0h-2v16H0v2h17zm273-2V0h-2v18h16v-2h-14zm-32 273v15h-2v-14h-14v14h-2v-16h18v1zM0 92.1c.323-.066.658-.1 1-.1 2.76 0 5 2.24 5 5s-2.24 5-5 5c-.342 0-.677-.034-1-.1v-2.07c.313.11.65.17 1 .17 1.657 0 3-1.343 3-3s-1.343-3-3-3c-.35 0-.687.06-1 .17V92.1zM80 272h2v32h-2v-32zm37.9 32c-.463-2.282-2.48-4-4.9-4-2.42 0-4.437 1.718-4.9 4h2.07c.413-1.165 1.524-2 2.83-2s2.417.835 2.83 2h2.07zM5.9 0c.066.323.1.658.1 1 0 2.76-2.24 5-5 5-.342 0-.677-.034-1-.1V3.83C.313 3.94.65 4 1 4c1.657 0 3-1.343 3-3 0-.35-.06-.687-.17-1H5.9zm294.2 0c-.066.323-.1.658-.1 1 0 2.42 1.718 4.437 4 4.9V3.83c-1.165-.413-2-1.524-2-2.83 0-.35.06-.687.17-1h-2.07zm3.9 300.1c-1.96.398-3.502 1.94-3.9 3.9h2.07c.302-.852.978-1.528 1.83-1.83v-2.07z' fill='%23ffffff' fill-opacity='0.4' fill-rule='evenodd'/%3E%3C/svg%3E"); 20 | } 21 | -------------------------------------------------------------------------------- /src/components/demo-checkbox/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Checkbox from 'preact-mdc/material-checkbox'; 19 | import CheckboxLabel from 'preact-mdc/material-checkbox-label'; 20 | import FormField from 'preact-mdc/material-form-field'; 21 | import Radio from 'preact-mdc/material-radio'; 22 | 23 | /** 24 | * Import styles. 25 | */ 26 | import styles from './styles'; 27 | 28 | /** 29 | * Create the component. 30 | */ 31 | class Demo extends Component { 32 | 33 | constructor() { 34 | super(); 35 | this.state = {}; 36 | } 37 | 38 | render(props, state) { 39 | return ( 40 |
41 | 42 | 43 | Disabled 44 | 45 | 46 | 47 | Radio 1 48 | 49 | 50 | 51 | Radio 2 52 | 53 | 54 | 55 | Radio 3 56 | 57 |
58 | ); 59 | } 60 | } 61 | 62 | /** 63 | * Export the component. 64 | */ 65 | export default Demo; 66 | -------------------------------------------------------------------------------- /src/components/demo-checkbox/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | -------------------------------------------------------------------------------- /src/components/demo-drawer/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Button from 'preact-mdc/material-button'; 19 | import Drawer from 'preact-mdc/material-drawer'; 20 | import DrawerToolbarSpacer from 'preact-mdc/material-drawer-toolbar-spacer'; 21 | import DrawerHeader from 'preact-mdc/material-drawer-header'; 22 | import DrawerContent from 'preact-mdc/material-drawer-content'; 23 | import FormField from 'preact-mdc/material-form-field'; 24 | import Checkbox from 'preact-mdc/material-checkbox'; 25 | import CheckboxLabel from 'preact-mdc/material-checkbox-label'; 26 | import Toolbar from 'preact-mdc/material-toolbar'; 27 | import ToolbarRow from 'preact-mdc/material-toolbar-row'; 28 | import ToolbarSection from 'preact-mdc/material-toolbar-section'; 29 | import ToolbarTitle from 'preact-mdc/material-toolbar-title'; 30 | 31 | /** 32 | * Import styles. 33 | */ 34 | import '@material/theme/mdc-theme.scss'; 35 | import '@material/typography/mdc-typography.scss'; 36 | import styles from './styles'; 37 | 38 | /** 39 | * Create the component. 40 | */ 41 | class Demo extends Component { 42 | 43 | constructor() { 44 | super(); 45 | this.state = { 46 | open: true, 47 | permanent: false 48 | }; 49 | } 50 | 51 | render(props, {open, permanent}) { 52 | return ( 53 |
54 | { 55 | this.setState({open: false}) 56 | }}> 57 | {permanent && 58 | 59 | } 60 | {!permanent && 61 | Header 63 | } 64 | 65 | 66 | 67 | 68 |
69 | 70 | 71 | 72 | {!permanent && 73 | 76 | } 77 | Title 78 | 79 | 80 | alarm 81 | 82 | 83 | 84 | 85 | this.setState({permanent: e.target.checked})}/> 86 | Permanent Drawer 87 | 88 |
89 |
90 | ); 91 | } 92 | } 93 | 94 | /** 95 | * Export the component. 96 | */ 97 | export default Demo; 98 | -------------------------------------------------------------------------------- /src/components/demo-drawer/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | display: flex; 12 | flex-direction: row; 13 | padding: 0; 14 | margin: 0; 15 | box-sizing: border-box; 16 | height: 100%; 17 | width: 100%; 18 | } 19 | 20 | .main { 21 | flex: 1; 22 | } 23 | 24 | :global(.mdc-toolbar) { 25 | button:global(.material-icons) { 26 | height: auto !important; 27 | width: auto !important; 28 | min-width: 24px !important; 29 | padding: 0 8px 0 0 !important; 30 | color: white !important; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/demo-icon-toggle/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import IconToggle from 'preact-mdc/material-icon-toggle'; 19 | 20 | /** 21 | * Import styles. 22 | */ 23 | import styles from './styles'; 24 | 25 | /** 26 | * Create the component. 27 | */ 28 | class Demo extends Component { 29 | 30 | render(state, props) { 31 | 32 | return ( 33 | 74 | ); 75 | } 76 | } 77 | 78 | /** 79 | * Export the component. 80 | */ 81 | export default Demo; 82 | -------------------------------------------------------------------------------- /src/components/demo-icon-toggle/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | -------------------------------------------------------------------------------- /src/components/demo-list/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import classnames from 'classnames/dedupe'; 15 | 16 | /** 17 | * Import local dependencies. 18 | */ 19 | import List from 'preact-mdc/material-list'; 20 | import ListDivider from 'preact-mdc/material-list-divider'; 21 | import ListGroup from 'preact-mdc/material-list-group'; 22 | import ListGroupDivider from 'preact-mdc/material-list-group-divider'; 23 | import ListGroupHeader from 'preact-mdc/material-list-group-header'; 24 | import ListItem from 'preact-mdc/material-list-item'; 25 | import ListItemDetail from 'preact-mdc/material-list-item-detail'; 26 | import ListItemText from 'preact-mdc/material-list-item-text'; 27 | import ListItemTextPrimary from 'preact-mdc/material-list-item-text-primary'; 28 | import ListItemTextSecondary from 'preact-mdc/material-list-item-text-secondary'; 29 | 30 | /** 31 | * Import styles. 32 | */ 33 | import '@material/typography/mdc-typography.scss'; 34 | import styles from './styles'; 35 | 36 | /** 37 | * Create the component. 38 | */ 39 | class Demo extends Component { 40 | 41 | constructor() { 42 | super(); 43 | this.state = {}; 44 | } 45 | 46 | render(props, state) { 47 | let classes = classnames(styles.root, 'mdc-typography'); 48 | return ( 49 |
50 |

Simple List

51 | 52 | Single-line item 53 | Single-line item 54 | 55 | Single-line item 56 | 57 |

Simple List (dense)

58 | 59 | Single-line item 60 | Single-line item 61 | Single-line item 62 | 63 |

Two-line list

64 | 65 | 66 | 67 | Two-line item 68 | Secondary text 69 | 70 | 71 | 72 | 73 | Two-line item 74 | Secondary text 75 | 76 | 77 | 78 |

List with details

79 | 80 | 81 | network_wifi 82 | Wi-Fi 83 | 84 | 85 | bluetooth 86 | Bluetooth 87 | 88 | 89 | 90 | data_usage 91 | Data Usage 92 | 93 | 94 |

List with details (end)

95 | 96 | 97 | Peter 98 | favorite 99 | 100 | 101 | Paul 102 | favorite_border 103 | 104 | 105 |

List with avatar

106 | 107 | 108 | avatar 109 | Avatar 110 | 111 | 112 | avatar 113 | Avatar 114 | 115 | 116 |

List Groups

117 | 118 | Folders 119 | 120 | 121 | 122 | 123 | 124 | 125 | Photos 126 | 1/1/2000 127 | 128 | info 129 | 130 | 131 | 132 | 133 | 134 | 135 | Documents 136 | 9/9/2009 137 | 138 | info 139 | 140 | 141 | 142 | Files 143 | 144 | 145 | 146 | 147 | 148 | 149 | House on fire 150 | 1/1/2000 151 | 152 | 153 | info 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | Our new house 162 | 9/9/2009 163 | 164 | info 165 | 166 | 167 | 168 |
169 | ); 170 | } 171 | } 172 | 173 | /** 174 | * Export the component. 175 | */ 176 | export default Demo; 177 | -------------------------------------------------------------------------------- /src/components/demo-list/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | flex: 1; 12 | overflow-y: auto; 13 | padding: 20px; 14 | .hover { 15 | :global(.mdc-list-item) { 16 | &:hover { 17 | background-color: #f8f8f8; 18 | } 19 | } 20 | } 21 | } 22 | 23 | .fileAvatar { 24 | background-color: lightgray; 25 | display: inline-flex; 26 | align-items: center; 27 | justify-content: center; 28 | color: white; 29 | } 30 | -------------------------------------------------------------------------------- /src/components/demo-snackbar/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Button from 'preact-mdc/material-button'; 19 | import Checkbox from 'preact-mdc/material-checkbox'; 20 | import CheckboxLabel from 'preact-mdc/material-checkbox-label'; 21 | import FormField from 'preact-mdc/material-form-field'; 22 | import Snackbar from 'preact-mdc/material-snackbar'; 23 | 24 | /** 25 | * Import styles. 26 | */ 27 | import styles from './styles'; 28 | 29 | /** 30 | * Create the component. 31 | */ 32 | class Demo extends Component { 33 | 34 | constructor() { 35 | super(); 36 | this.state = { 37 | active: false, 38 | multiline: false, 39 | actionOnBottom: false 40 | }; 41 | } 42 | 43 | handleClick = () => { 44 | this.setState({active: true}); 45 | setTimeout(() => { 46 | this.setState({active: false}) 47 | }, 2000); 48 | }; 49 | 50 | render(props, {active, multiline, actionOnBottom}, context) { 51 | return ( 52 |
53 | 54 | 55 | this.setState({multiline: e.target.checked})}/> 56 | Multiline 57 | 58 | 59 | this.setState({actionOnBottom: e.target.checked})}/> 60 | Action on bottom 61 | 62 | 63 | 64 | 65 | 66 |
67 | ); 68 | } 69 | } 70 | 71 | /** 72 | * Export the component. 73 | */ 74 | export default Demo; 75 | -------------------------------------------------------------------------------- /src/components/demo-snackbar/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | padding: 20px; 12 | flex: 1; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: flex-start; 16 | 17 | > :global(.mdc-form-field) { 18 | margin: 20px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/components/demo-switch/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import CheckboxLabel from 'preact-mdc/material-checkbox-label'; 19 | import FormField from 'preact-mdc/material-form-field'; 20 | import Switch from 'preact-mdc/material-switch'; 21 | 22 | /** 23 | * Import styles. 24 | */ 25 | import styles from './styles'; 26 | 27 | /** 28 | * Create the component. 29 | */ 30 | class Demo extends Component { 31 | 32 | constructor() { 33 | super(); 34 | this.state = {}; 35 | } 36 | 37 | render(props, state) { 38 | return ( 39 |
40 | 41 | console.log(e.target.checked)}/> 42 | Switch me 43 | 44 | 45 | 46 | Disabled 47 | 48 |
49 | ); 50 | } 51 | } 52 | 53 | /** 54 | * Export the component. 55 | */ 56 | export default Demo; 57 | -------------------------------------------------------------------------------- /src/components/demo-switch/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | flex: 1; 12 | display: flex; 13 | flex-direction: column; 14 | 15 | > :global(.mdc-form-field) { 16 | margin: 20px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/demo-text-field/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import Button from 'preact-mdc/material-button'; 19 | import Checkbox from 'preact-mdc/material-checkbox'; 20 | import CheckboxLabel from 'preact-mdc/material-checkbox-label'; 21 | import FormField from 'preact-mdc/material-form-field'; 22 | import TextField from 'preact-mdc/material-text-field'; 23 | 24 | /** 25 | * Import styles. 26 | */ 27 | import styles from './styles'; 28 | 29 | /** 30 | * Create the component. 31 | */ 32 | class Demo extends Component { 33 | 34 | constructor() { 35 | super(); 36 | this.state = { 37 | type: 'text', 38 | value: null, 39 | label: 'Label', 40 | placeholder: 'Placeholder', 41 | disabled: false, 42 | rtl: false, 43 | dense: false, 44 | required: false, 45 | pattern: '.{8,}', 46 | helpText: null, 47 | helpTextPersistent: false, 48 | helpTextValidation: false 49 | }; 50 | } 51 | 52 | render(props, { 53 | disabled, 54 | rtl, 55 | dense, 56 | required, 57 | helpText, 58 | helpTextPersistent, 59 | helpTextValidation, 60 | ...state 61 | }, context) { 62 | return ( 63 |
64 | 66 | 67 | this.setState({disabled: e.target.checked})}/> 68 | Disabled 69 | 70 | 71 | this.setState({rtl: e.target.checked})}/> 72 | RTL 73 | 74 | 75 | this.setState({dense: e.target.checked})}/> 76 | Dense 77 | 78 | 79 | this.setState({required: e.target.checked})}/> 80 | Required 81 | 82 | 83 | this.setState({helpText: e.target.checked ? 'Helptext' : null})}/> 85 | Help Text 86 | 87 | 88 | this.setState({helpTextPersistent: e.target.checked})}/> 90 | Help Text Persistent 91 | 92 | 93 | this.setState({helpTextValidation: e.target.checked})}/> 95 | Help Text Validation 96 | 97 |
98 | this.setState({value: e.target.value})}/> 107 |
108 |
109 | ); 110 | } 111 | } 112 | 113 | /** 114 | * Export the component. 115 | */ 116 | export default Demo; 117 | -------------------------------------------------------------------------------- /src/components/demo-text-field/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | -------------------------------------------------------------------------------- /src/components/demo-theme/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import classnames from 'classnames/dedupe'; 15 | 16 | /** 17 | * Import local dependencies. 18 | */ 19 | import Button from 'preact-mdc/material-button'; 20 | 21 | /** 22 | * Import styles. 23 | */ 24 | import '@material/theme/mdc-theme.scss'; 25 | import '@material/typography/mdc-typography.scss'; 26 | import styles from './styles'; 27 | 28 | /** 29 | * Create the component. 30 | */ 31 | class Demo extends Component { 32 | 33 | constructor() { 34 | super(); 35 | this.state = {}; 36 | } 37 | 38 | render(props, state) { 39 | let root = classnames('mdc-typography', styles.root); 40 | let dark = classnames('mdc-theme--dark', styles.darkBg); 41 | return ( 42 |
43 |

Light Theme

44 |
45 | 46 |
47 |

Dark Theme

48 |
49 | 50 |
51 |
52 | ); 53 | } 54 | } 55 | 56 | /** 57 | * Export the component. 58 | */ 59 | export default Demo; 60 | -------------------------------------------------------------------------------- /src/components/demo-theme/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | flex: 1; 12 | } 13 | 14 | .darkBg { 15 | background-color: darkslategrey; 16 | } 17 | -------------------------------------------------------------------------------- /src/containers/about/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import {connect} from 'preact-redux'; 15 | import {FormattedMessage} from 'react-intl'; 16 | 17 | /** 18 | * Import local dependencies. 19 | */ 20 | 21 | /** 22 | * Create the component. 23 | */ 24 | class About extends Component { 25 | render(props, state) { 26 | return ( 27 |

28 | 29 |

30 | ); 31 | } 32 | } 33 | 34 | /** 35 | * Map state to component properties. 36 | */ 37 | const mapStateToProps = (state) => { 38 | return {} 39 | }; 40 | 41 | /** 42 | * Map actions to component properties. 43 | */ 44 | const mapDispatchToProps = (dispatch) => { 45 | return {} 46 | }; 47 | 48 | /** 49 | * Export the container component. 50 | */ 51 | export default connect( 52 | mapStateToProps, 53 | mapDispatchToProps, 54 | null, { 55 | pure: false 56 | } 57 | )(About); 58 | -------------------------------------------------------------------------------- /src/containers/demo/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import classnames from 'classnames/dedupe'; 15 | import {connect} from 'preact-redux'; 16 | import {push} from 'react-router-redux'; 17 | import {FormattedMessage} from 'react-intl'; 18 | 19 | /** 20 | * Import local dependencies. 21 | */ 22 | import List from 'preact-mdc/material-list'; 23 | import ListItem from 'preact-mdc/material-list-item'; 24 | 25 | /** 26 | * Import actions. 27 | */ 28 | import {rootStateReadyToRenderCreator} from '../../actions'; 29 | 30 | /** 31 | * Import styles. 32 | */ 33 | import '@material/typography/mdc-typography.scss'; 34 | import styles from './styles'; 35 | 36 | /** 37 | * Create the component. 38 | */ 39 | class Demo extends Component { 40 | 41 | componentDidMount = () => { 42 | this.props.onReady(); // TODO Usually a GraphQL response would trigger the SSR to render. 43 | }; 44 | 45 | render({onNavigate}, state) { 46 | let classes = classnames(styles.root, 'mdc-typography'); 47 | return ( 48 |
49 |

50 | 53 |

54 | 55 | onNavigate(e, '/button')}>Button Demo 56 | onNavigate(e, '/card')}>Card Demo 57 | onNavigate(e, '/checkbox')}>Checkbox / Radio Demo 58 | onNavigate(e, '/drawer')}>Drawer / Toolbar Demo 59 | onNavigate(e, '/icon-toggle')}>Icon Toggle Demo 60 | onNavigate(e, '/list')}>List Demo 61 | onNavigate(e, '/snackbar')}>Snackbar Demo 62 | onNavigate(e, '/switch')}>Switch Demo 63 | onNavigate(e, '/text-field')}>Text field Demo 64 | onNavigate(e, '/theme')}>Theme Demo 65 | 66 |
67 | ); 68 | } 69 | } 70 | 71 | /** 72 | * Map state to component properties. 73 | */ 74 | const mapStateToProps = (state) => { 75 | return {} 76 | }; 77 | 78 | /** 79 | * Map actions to component properties. 80 | */ 81 | const mapDispatchToProps = (dispatch) => { 82 | return { 83 | onNavigate: (e, path) => { 84 | e.preventDefault(); 85 | dispatch(push(path)); 86 | }, 87 | onReady: () => dispatch(rootStateReadyToRenderCreator()) 88 | }; 89 | }; 90 | 91 | /** 92 | * Export the container component. 93 | */ 94 | export default connect( 95 | mapStateToProps, 96 | mapDispatchToProps, 97 | null, { 98 | pure: false 99 | } 100 | )(Demo); 101 | -------------------------------------------------------------------------------- /src/containers/demo/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | flex: 1; 12 | overflow-y: auto; 13 | padding: 20px; 14 | :global(.mdc-list-item) { 15 | &:hover { 16 | background-color: #f8f8f8; 17 | } 18 | } 19 | } 20 | 21 | .fileAvatar { 22 | background-color: lightgray; 23 | display: inline-flex; 24 | align-items: center; 25 | justify-content: center; 26 | color: white; 27 | } 28 | -------------------------------------------------------------------------------- /src/containers/home/component.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, Component} from 'preact'; 14 | import {connect} from 'preact-redux'; 15 | import {FormattedMessage} from 'react-intl'; 16 | import {Button, Icon, Card, CardTitle, CardText, CardActions, CardMenu, Grid, Cell} from 'preact-mdl'; 17 | import classnames from 'classnames'; 18 | 19 | /** 20 | * Import local dependencies. 21 | */ 22 | 23 | /** 24 | * Import styles. 25 | */ 26 | import styles from './styles'; 27 | 28 | /** 29 | * Create the component. 30 | */ 31 | class Home extends Component { 32 | render(props, state) { 33 | let rootStyles = classnames(styles.root); 34 | return ( 35 | 36 | 37 | 38 | Welcome 43 | 44 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 45 | Mauris sagittis pellentesque lacus eleifend lacinia... 46 | 47 | 48 | 49 | 50 | 51 | 54 | 55 | 56 | 57 | 58 | 59 | Welcome 64 | 65 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 66 | Mauris sagittis pellentesque lacus eleifend lacinia... 67 | 68 | 69 | 70 | 71 | 72 | 75 | 76 | 77 | 78 | 79 | 80 | Welcome 85 | 86 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 87 | Mauris sagittis pellentesque lacus eleifend lacinia... 88 | 89 | 90 | 91 | 92 | 93 | 96 | 97 | 98 | 99 | 100 | ); 101 | } 102 | } 103 | 104 | /** 105 | * Map state to component properties. 106 | */ 107 | const mapStateToProps = (state) => { 108 | return {} 109 | }; 110 | 111 | /** 112 | * Map actions to component properties. 113 | */ 114 | const mapDispatchToProps = (dispatch) => { 115 | return {} 116 | }; 117 | 118 | /** 119 | * Export the container component. 120 | */ 121 | export default connect( 122 | mapStateToProps, 123 | mapDispatchToProps, 124 | null, { 125 | pure: false 126 | } 127 | )(Home); 128 | -------------------------------------------------------------------------------- /src/containers/home/styles.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | .root { 11 | padding: 15px; 12 | } 13 | 14 | :global { 15 | .mdl-card { 16 | width: auto !important; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/entities/README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This folder contains the `Entity Reducers` for all `GraphQL Entities`. 4 | 5 | See the main `README` for details. 6 | -------------------------------------------------------------------------------- /src/entities/addressReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Address entities state. 24 | */ 25 | const addressDefaultState = {}; 26 | 27 | /** 28 | * Export the Address entities store. 29 | */ 30 | export function addressReducer(state = addressDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Address); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/cardReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Card entities state. 24 | */ 25 | const cardDefaultState = {}; 26 | 27 | /** 28 | * Export the Card entities store. 29 | */ 30 | export function cardReducer(state = cardDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Card); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/cardTransactionReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default CardTransaction entities state. 24 | */ 25 | const cardTransactionDefaultState = {}; 26 | 27 | /** 28 | * Export the CardTransaction entities store. 29 | */ 30 | export function cardTransactionReducer(state = cardTransactionDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.CardTransaction); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/colorReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Color entities state. 24 | */ 25 | const colorDefaultState = {}; 26 | 27 | /** 28 | * Export the Color entities store. 29 | */ 30 | export function colorReducer(state = colorDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Color); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/commerceReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Commerce entities state. 24 | */ 25 | const commerceDefaultState = {}; 26 | 27 | /** 28 | * Export the Commerce entities store. 29 | */ 30 | export function commerceReducer(state = commerceDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Commerce); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/companyReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Company entities state. 24 | */ 25 | const companyDefaultState = {}; 26 | 27 | /** 28 | * Export the Company entities store. 29 | */ 30 | export function companyReducer(state = companyDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Company); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/createdByReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default CreatedBy entities state. 24 | */ 25 | const createdByDefaultState = {}; 26 | 27 | /** 28 | * Export the CreatedBy entities store. 29 | */ 30 | export function createdByReducer(state = createdByDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.CreatedBy); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/currencyReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Currency entities state. 24 | */ 25 | const currencyDefaultState = {}; 26 | 27 | /** 28 | * Export the Currency entities store. 29 | */ 30 | export function currencyReducer(state = currencyDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Currency); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/databaseReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Database entities state. 24 | */ 25 | const databaseDefaultState = {}; 26 | 27 | /** 28 | * Export the Database entities store. 29 | */ 30 | export function databaseReducer(state = databaseDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Database); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/dateTimeReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default DateTime entities state. 24 | */ 25 | const dateTimeDefaultState = {}; 26 | 27 | /** 28 | * Export the DateTime entities store. 29 | */ 30 | export function dateTimeReducer(state = dateTimeDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.DateTime); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/entitiesReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {combineReducers} from 'redux'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import {queryReducer} from './queryReducer'; 19 | import {addressReducer} from './addressReducer'; 20 | import {fakeReducer} from './fakeReducer'; 21 | import {cardReducer} from './cardReducer'; 22 | import {colorReducer} from './colorReducer'; 23 | import {commerceReducer} from './commerceReducer'; 24 | import {companyReducer} from './companyReducer'; 25 | import {databaseReducer} from './databaseReducer'; 26 | import {dateTimeReducer} from './dateTimeReducer'; 27 | import {financeReducer} from './financeReducer'; 28 | import {currencyReducer} from './currencyReducer'; 29 | import {hackerReducer} from './hackerReducer'; 30 | import {imageReducer} from './imageReducer'; 31 | import {internetReducer} from './internetReducer'; 32 | import {loremReducer} from './loremReducer'; 33 | import {meetingReducer} from './meetingReducer'; 34 | import {personReducer} from './personReducer'; 35 | import {miscReducer} from './miscReducer'; 36 | import {numbersReducer} from './numbersReducer'; 37 | import {phoneReducer} from './phoneReducer'; 38 | import {systemReducer} from './systemReducer'; 39 | import {cardTransactionReducer} from './cardTransactionReducer'; 40 | import {messageReducer} from './messageReducer'; 41 | import {metaReducer} from './metaReducer'; 42 | import {createdByReducer} from './createdByReducer'; 43 | import {userAddressReducer} from './userAddressReducer'; 44 | import {updatedByReducer} from './updatedByReducer'; 45 | import {transactionReducer} from './transactionReducer'; 46 | import {userReducer} from './userReducer'; 47 | 48 | 49 | /** 50 | * Export the entities store. 51 | */ 52 | export const entitiesReducer = combineReducers({ 53 | Query: queryReducer, 54 | Address: addressReducer, 55 | Fake: fakeReducer, 56 | Card: cardReducer, 57 | Color: colorReducer, 58 | Commerce: commerceReducer, 59 | Company: companyReducer, 60 | Database: databaseReducer, 61 | DateTime: dateTimeReducer, 62 | Finance: financeReducer, 63 | Currency: currencyReducer, 64 | Hacker: hackerReducer, 65 | Image: imageReducer, 66 | Internet: internetReducer, 67 | Lorem: loremReducer, 68 | Meeting: meetingReducer, 69 | Person: personReducer, 70 | Misc: miscReducer, 71 | Numbers: numbersReducer, 72 | Phone: phoneReducer, 73 | System: systemReducer, 74 | CardTransaction: cardTransactionReducer, 75 | Message: messageReducer, 76 | Meta: metaReducer, 77 | CreatedBy: createdByReducer, 78 | UserAddress: userAddressReducer, 79 | UpdatedBy: updatedByReducer, 80 | Transaction: transactionReducer, 81 | User: userReducer, 82 | 83 | }); 84 | -------------------------------------------------------------------------------- /src/entities/fakeReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Fake entities state. 24 | */ 25 | const fakeDefaultState = {}; 26 | 27 | /** 28 | * Export the Fake entities store. 29 | */ 30 | export function fakeReducer(state = fakeDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Fake); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/financeReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Finance entities state. 24 | */ 25 | const financeDefaultState = {}; 26 | 27 | /** 28 | * Export the Finance entities store. 29 | */ 30 | export function financeReducer(state = financeDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Finance); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/hackerReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Hacker entities state. 24 | */ 25 | const hackerDefaultState = {}; 26 | 27 | /** 28 | * Export the Hacker entities store. 29 | */ 30 | export function hackerReducer(state = hackerDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Hacker); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/imageReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Image entities state. 24 | */ 25 | const imageDefaultState = {}; 26 | 27 | /** 28 | * Export the Image entities store. 29 | */ 30 | export function imageReducer(state = imageDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Image); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/internetReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Internet entities state. 24 | */ 25 | const internetDefaultState = {}; 26 | 27 | /** 28 | * Export the Internet entities store. 29 | */ 30 | export function internetReducer(state = internetDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Internet); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/loremReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Lorem entities state. 24 | */ 25 | const loremDefaultState = {}; 26 | 27 | /** 28 | * Export the Lorem entities store. 29 | */ 30 | export function loremReducer(state = loremDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Lorem); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/meetingReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Meeting entities state. 24 | */ 25 | const meetingDefaultState = {}; 26 | 27 | /** 28 | * Export the Meeting entities store. 29 | */ 30 | export function meetingReducer(state = meetingDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Meeting); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/messageReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Message entities state. 24 | */ 25 | const messageDefaultState = {}; 26 | 27 | /** 28 | * Export the Message entities store. 29 | */ 30 | export function messageReducer(state = messageDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Message); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/metaReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Meta entities state. 24 | */ 25 | const metaDefaultState = {}; 26 | 27 | /** 28 | * Export the Meta entities store. 29 | */ 30 | export function metaReducer(state = metaDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Meta); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/miscReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Misc entities state. 24 | */ 25 | const miscDefaultState = {}; 26 | 27 | /** 28 | * Export the Misc entities store. 29 | */ 30 | export function miscReducer(state = miscDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Misc); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/numbersReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Numbers entities state. 24 | */ 25 | const numbersDefaultState = {}; 26 | 27 | /** 28 | * Export the Numbers entities store. 29 | */ 30 | export function numbersReducer(state = numbersDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Numbers); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/personReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Person entities state. 24 | */ 25 | const personDefaultState = {}; 26 | 27 | /** 28 | * Export the Person entities store. 29 | */ 30 | export function personReducer(state = personDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Person); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/phoneReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Phone entities state. 24 | */ 25 | const phoneDefaultState = {}; 26 | 27 | /** 28 | * Export the Phone entities store. 29 | */ 30 | export function phoneReducer(state = phoneDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Phone); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/queryReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Query entities state. 24 | */ 25 | const queryDefaultState = {}; 26 | 27 | /** 28 | * Export the Query entities store. 29 | */ 30 | export function queryReducer(state = queryDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Query); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/systemReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default System entities state. 24 | */ 25 | const systemDefaultState = {}; 26 | 27 | /** 28 | * Export the System entities store. 29 | */ 30 | export function systemReducer(state = systemDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.System); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/transactionReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default Transaction entities state. 24 | */ 25 | const transactionDefaultState = {}; 26 | 27 | /** 28 | * Export the Transaction entities store. 29 | */ 30 | export function transactionReducer(state = transactionDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.Transaction); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/updatedByReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default UpdatedBy entities state. 24 | */ 25 | const updatedByDefaultState = {}; 26 | 27 | /** 28 | * Export the UpdatedBy entities store. 29 | */ 30 | export function updatedByReducer(state = updatedByDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.UpdatedBy); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/userAddressReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default UserAddress entities state. 24 | */ 25 | const userAddressDefaultState = {}; 26 | 27 | /** 28 | * Export the UserAddress entities store. 29 | */ 30 | export function userAddressReducer(state = userAddressDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.UserAddress); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/entities/userReducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {merge} from 'ramda'; 14 | 15 | /** 16 | * Import local dependencies. 17 | */ 18 | import { 19 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED 20 | } from '../actions'; 21 | 22 | /** 23 | * Default User entities state. 24 | */ 25 | const userDefaultState = {}; 26 | 27 | /** 28 | * Export the User entities store. 29 | */ 30 | export function userReducer(state = userDefaultState, action) { 31 | switch (action.type) { 32 | case ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED: 33 | return merge(state, action.payload.User); 34 | default: 35 | return state; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/epic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {combineEpics} from 'redux-observable'; 14 | import {Observable} from 'rxjs/Observable'; 15 | import 'rxjs/add/observable/dom/ajax'; 16 | import 'rxjs/add/observable/from'; 17 | import 'rxjs/add/observable/of'; 18 | import 'rxjs/add/operator/mergeMap'; 19 | import 'rxjs/add/operator/map'; 20 | import 'rxjs/add/operator/catch'; 21 | import 'rxjs/add/operator/startWith'; 22 | import 'rxjs/add/operator/retry'; 23 | import 'rxjs/add/operator/take'; 24 | import 'rxjs/add/operator/takeUntil'; 25 | 26 | /** 27 | * Import local dependencies. 28 | */ 29 | import { 30 | ROOT_FETCH_GRAPHQL_QUERY, 31 | ROOT_FETCH_GRAPHQL_QUERY_CANCEL, 32 | ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED, 33 | fetchGraphQLQuerySucceededCreator, 34 | fetchGraphQLQueryFailedCreator, 35 | fetchGraphQLQueryPendingCreator, 36 | rootStateReadyToRenderCreator 37 | } from './actions'; 38 | import {normalizeGraphQLQueryResponse} from './graphql'; 39 | // TODO import your other epics here if you have any. 40 | // import {demoPageEpic} from './containers/demo-page/epic'; 41 | 42 | /** 43 | * Isomorphic Observable.ajax request. TODO maybe make it an npm package. 44 | */ 45 | const request = function request(options) { 46 | if (process.env.WEB) { 47 | return Observable.ajax(options); 48 | } else { 49 | return Observable.ajax({ 50 | createXHR: () => { 51 | const https = require('https'); 52 | const XHR2 = require('xhr2'); 53 | const xhr = new XHR2(); 54 | const agent = new https.Agent({rejectUnauthorized: false}); 55 | xhr.nodejsSet({httpsAgent: agent}); 56 | return xhr; 57 | }, ...options 58 | }); 59 | } 60 | }; 61 | 62 | /** 63 | * This epic fetches a GraphQL query. 64 | */ 65 | const fetchGraphQLQueryEpic = action$ => 66 | action$.ofType(ROOT_FETCH_GRAPHQL_QUERY) 67 | .mergeMap(action => 68 | request({ 69 | url: 'http://159.203.96.223/graphql', 70 | body: action.payload, 71 | method: 'POST', 72 | headers: { 73 | 'Accept': 'application/json', 74 | 'Authorization': 'Bearer ', // + accessToken, 75 | 'Content-Type': 'application/json; charset=UTF-8' 76 | } 77 | }) 78 | // TODO supply identifier mappings here if necessary , {Param: 'name', Something: 'key'})) 79 | .map((payload) => normalizeGraphQLQueryResponse(payload.response.data)) 80 | .takeUntil(action$.ofType(ROOT_FETCH_GRAPHQL_QUERY_CANCEL)) 81 | .map(fetchGraphQLQuerySucceededCreator) 82 | .retry(2) 83 | .catch(({xhr}) => Observable.of(fetchGraphQLQueryFailedCreator(xhr))) 84 | .startWith(fetchGraphQLQueryPendingCreator()) 85 | ); 86 | 87 | /** 88 | * This epic takes the first GraphQL query success and assumes that the state is now ready to be rendered. 89 | */ 90 | const stateReadyToRenderEpic = action$ => action$.ofType(ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED).map(rootStateReadyToRenderCreator).take(1); 91 | 92 | /** 93 | * Export the root epic. 94 | */ 95 | export default combineEpics( 96 | // TODO import your other epics here if you have any. 97 | // demoPageEpic, 98 | stateReadyToRenderEpic, 99 | fetchGraphQLQueryEpic 100 | ); 101 | -------------------------------------------------------------------------------- /src/graphql/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | 14 | /** 15 | * Import local dependencies. 16 | */ 17 | import types from './types.json'; 18 | 19 | /** 20 | * Export the GraphQL response normalizer helper function. 21 | */ 22 | export const normalizeGraphQLQueryResponse = (response, identifiers = {}) => { 23 | // received entities will be flattend into this payload. 24 | let entities = {}; 25 | // start processing the query response. 26 | normalizeGraphQLQueryResponseNode(entities, identifiers, response, 'Query', 'Query'); 27 | // return the received and flattened payload to the reducers. 28 | return entities; 29 | }; 30 | 31 | // parse each node recursively. 32 | function normalizeGraphQLQueryResponseNode(entities, identifiers, node, path, nodeTypeName) { 33 | // initialize empty nodes with null. 34 | if (!node) { 35 | return null; 36 | } 37 | // get the node type either from the schema or the union type itself. 38 | let nodeType = node.hasOwnProperty('__typename') ? types[node.__typename] : types[nodeTypeName]; 39 | // get the identifier for the node. 40 | let identifier = identifiers.hasOwnProperty(nodeType.name) ? identifiers[nodeType.name] : 'id'; 41 | // start building the entity for the node. 42 | let entity = {}; 43 | // Compute identifier for nodes without id. 44 | if (node.hasOwnProperty(identifier) && node[identifier] !== null) { 45 | // Apply the valid id to the entity. 46 | entity[identifier] = node[identifier]; 47 | // Calculate the base path for the child properties. 48 | path = nodeType.name + '.' + node[identifier]; 49 | } 50 | else { 51 | // Apply the path as the identifier for this entity. 52 | entity[identifier] = path; 53 | } 54 | // iterate through each property of the node. 55 | for (let nodePropName in node) { 56 | // Be nice. 57 | if (node.hasOwnProperty(nodePropName)) { 58 | // id is handled already. 59 | if (nodePropName === identifier) { 60 | continue; 61 | } 62 | // simply copy the __typename property if available. 63 | if (nodePropName === '__typename') { 64 | entity[nodePropName] = node[nodePropName]; 65 | continue; 66 | } 67 | // get the properties type and value. 68 | let nodePropType = nodeType.fields[nodePropName].type; 69 | let nodePropValue = node[nodePropName]; 70 | // process the property based on its type. 71 | switch (nodePropType.kind) { 72 | case 'SCALAR': 73 | case 'ENUM': 74 | entity[nodePropName] = nodePropValue; 75 | break; 76 | case 'OBJECT': 77 | entity[nodePropName] = normalizeGraphQLQueryResponseNode(entities, identifiers, nodePropValue, `${path}.${nodePropName}`, nodePropType.name); 78 | break; 79 | case 'UNION': 80 | // TODO make sure there is a __typename and handle more than just UNIONs of OBJECTs here 81 | entity[nodePropName] = normalizeGraphQLQueryResponseNode(entities, identifiers, nodePropValue, `${path}.${nodePropName}`); 82 | break; 83 | case 'LIST': 84 | switch (nodePropType.ofType.kind) { 85 | case 'SCALAR': 86 | case 'ENUM': 87 | entity[nodePropName] = nodePropValue; 88 | break; 89 | case 'OBJECT': { 90 | let list = []; 91 | if (nodePropValue) { 92 | nodePropValue.forEach((listItem, i) => { 93 | list.push(normalizeGraphQLQueryResponseNode(entities, identifiers, listItem, `${path}.${nodePropName}.${i}`, nodePropType.ofType.name)); 94 | }); 95 | } 96 | entity[nodePropName] = list; 97 | break; 98 | } 99 | case 'UNION': { 100 | let list = []; 101 | if (nodePropValue) { 102 | nodePropValue.forEach(listItem => { 103 | // TODO include the type here, id is not enough 104 | list.push(normalizeGraphQLQueryResponseNode(entities, identifiers, listItem, `${path}.${nodePropName}`)); 105 | }); 106 | } 107 | entity[nodePropName] = list; 108 | break; 109 | } 110 | case 'LIST': { 111 | switch (nodePropType.ofType.ofType.kind) { 112 | case 'SCALAR': 113 | case 'ENUM': 114 | let list = []; 115 | if (nodePropValue) { 116 | nodePropValue.forEach(listItem => { 117 | list.push(listItem); 118 | }); 119 | } 120 | entity[nodePropName] = list; 121 | break; 122 | // TODO support more than just SCALARs in LIST of LISTs 123 | } 124 | break; 125 | } 126 | } 127 | break; 128 | } 129 | } 130 | } 131 | // Entities always have to have an id, even if they are local properties only. 132 | if (!entity.hasOwnProperty(identifier)) { 133 | throw `Entity of type ${nodeType.name} has neither a natural nor a computed id! This should never happen!`; 134 | } 135 | // Create the entity type store if it doesn't exist yet. 136 | if (!entities.hasOwnProperty(nodeType.name)) { 137 | entities[nodeType.name] = {}; 138 | } 139 | // Get the entity's id. 140 | const id = entity[identifier]; 141 | // Add the entity to the response store. Note: entities is processed "withMutations". 142 | entities[nodeType.name][id] = entity; 143 | // Return a reference to the entity. 144 | return {id, __typename: nodeType.name}; 145 | } 146 | -------------------------------------------------------------------------------- /src/index.client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h, render} from 'preact'; 14 | import {Provider} from 'preact-redux'; 15 | import {applyMiddleware, compose, createStore} from 'redux'; 16 | import {createEpicMiddleware} from 'redux-observable'; 17 | import createHistory from 'history/createBrowserHistory' 18 | import {ConnectedRouter, routerMiddleware} from 'react-router-redux' 19 | import {addLocaleData, IntlProvider} from 'react-intl'; 20 | import {head, split} from 'ramda'; 21 | 22 | /** 23 | * Import local dependencies. 24 | */ 25 | import rootReducer from './reducer'; 26 | import rootEpic from './epic'; 27 | 28 | import intlDE from 'bundle-loader?lazy!react-intl/locale-data/de.js'; 29 | import intlEN from 'bundle-loader?lazy!react-intl/locale-data/en.js'; 30 | import intlMessagesDE from 'bundle-loader?lazy!../public/assets/translations/de.json'; 31 | import intlMessagesEN from 'bundle-loader?lazy!../public/assets/translations/en.json'; 32 | 33 | /** 34 | * Load the locale data for the users language. 35 | */ 36 | 37 | function getQueryStringValue (key) { 38 | return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1")); 39 | } 40 | 41 | // Get the users language. 42 | const locale = getQueryStringValue('language') ? head(split('-', getQueryStringValue('language'))) : 'de'; // TODO support en-gb fallback to en? 43 | const locales = { 44 | de: {data: intlDE, messages: intlMessagesDE}, 45 | en: {data: intlEN, messages: intlMessagesEN} 46 | }; 47 | 48 | // Load the locale data for the users language asynchronously. 49 | locales[locale].data((localeData) => { 50 | 51 | // Set the locale data. 52 | addLocaleData(localeData); 53 | 54 | // Load the locale messages for the users language asynchronously. 55 | locales[locale].messages((localeMessages) => { 56 | 57 | /** 58 | * Create the browser history access. 59 | */ 60 | const history = createHistory({ 61 | basename: process.env.BASE_URL 62 | }); 63 | 64 | /** 65 | * Create the epic middleware. 66 | */ 67 | const epicMiddleware = createEpicMiddleware(rootEpic); 68 | 69 | /** 70 | * Create the store. 71 | */ 72 | let store; 73 | if (process.env.NODE_ENV === 'development') { 74 | // Development mode with Redux DevTools support enabled. 75 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ 76 | // Prevents Redux DevTools from re-dispatching all previous actions. 77 | shouldHotReload: false 78 | }) : compose; 79 | // Create the redux store. 80 | store = createStore( 81 | rootReducer, 82 | composeEnhancers(applyMiddleware(routerMiddleware(history), epicMiddleware)) 83 | ); 84 | } else { 85 | // Production mode. 86 | store = window.__INITIAL_STATE__ ? createStore( 87 | rootReducer, 88 | window.__INITIAL_STATE__, 89 | applyMiddleware(routerMiddleware(history), epicMiddleware) 90 | ) : createStore( 91 | rootReducer, 92 | applyMiddleware(routerMiddleware(history), epicMiddleware) 93 | ); 94 | // TODO delete initial state for garbage collection? 95 | } 96 | 97 | /** 98 | * Render the application. 99 | */ 100 | let root = document.body.lastElementChild; 101 | const renderRoot = () => { 102 | let Root = require('./component').default; 103 | requestAnimationFrame(() => { 104 | root = render( 105 | 106 | 107 | 108 | 109 | 110 | 111 | , 112 | document.body, 113 | root 114 | ); 115 | }); 116 | }; 117 | 118 | /** 119 | * Enable hot module reloading in development mode. 120 | */ 121 | if (process.env.NODE_ENV === 'development') { 122 | if (module.hot) { 123 | // Handle updates to the components. 124 | module.hot.accept('./component', () => { 125 | console.log('Updated components'); 126 | renderRoot(); 127 | }); 128 | // Handle updates to the reducers. 129 | module.hot.accept('./reducer', () => { 130 | console.log('Updated reducers'); 131 | let rootReducer = require('./reducer').default; 132 | store.replaceReducer(rootReducer); 133 | }); 134 | // Handle updates to the epics. 135 | module.hot.accept('./epic', () => { 136 | console.log('Updated epics'); 137 | let rootEpic = require('./epic').default; 138 | epicMiddleware.replaceEpic(rootEpic); 139 | }); 140 | } 141 | } 142 | 143 | /** 144 | * Finally render the app. 145 | */ 146 | renderRoot(); 147 | 148 | /** 149 | * Register the service worker in production. 150 | */ 151 | if (process.env.NODE_ENV === 'production') { 152 | if ('serviceWorker' in navigator) { 153 | // Your service-worker.js *must* be located at the top-level directory relative to your site. 154 | // It won't be able to control pages unless it's located at the same level or higher than them. 155 | // *Don't* register service worker file in, e.g., a scripts/ sub-directory! 156 | // See https://github.com/slightlyoff/ServiceWorker/issues/468 157 | navigator.serviceWorker.register('service-worker.js').then(function(reg) { 158 | // updatefound is fired if service-worker.js changes. 159 | reg.onupdatefound = function() { 160 | // The updatefound event implies that reg.installing is set; see 161 | // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event 162 | let installingWorker = reg.installing; 163 | 164 | installingWorker.onstatechange = function() { 165 | switch (installingWorker.state) { 166 | case 'installed': 167 | if (navigator.serviceWorker.controller) { 168 | // At this point, the old content will have been purged and the fresh content will 169 | // have been added to the cache. 170 | // It's the perfect time to display a "New content is available; please refresh." 171 | // message in the page's interface. 172 | console.log('New or updated content is available.'); 173 | } else { 174 | // At this point, everything has been precached. 175 | // It's the perfect time to display a "Content is cached for offline use." message. 176 | console.log('Content is now available offline!'); 177 | } 178 | break; 179 | 180 | case 'redundant': 181 | console.error('The installing service worker became redundant.'); 182 | break; 183 | } 184 | }; 185 | }; 186 | }).catch(function(e) { 187 | console.error('Error during service worker registration:', e); 188 | }); 189 | } 190 | } 191 | }); 192 | }); 193 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= htmlWebpackPlugin.options.title %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | <% for (var css in htmlWebpackPlugin.files.css) { %> 29 | 32 | <% } %><% for (var chunk in htmlWebpackPlugin.files.chunks) { %> 33 | <% } %> 34 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/index.server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {h} from 'preact'; 14 | import createRenderer from './preact-dom-renderer'; 15 | import {Provider} from 'preact-redux'; 16 | import {applyMiddleware, createStore} from 'redux'; 17 | import {createEpicMiddleware} from 'redux-observable'; 18 | import {StaticRouter} from 'react-router'; 19 | import {addLocaleData, IntlProvider} from 'react-intl'; 20 | import {head, split} from 'ramda'; 21 | 22 | /** 23 | * Import local dependencies. 24 | */ 25 | import Root from './component'; 26 | import {rootReducer} from './reducer'; 27 | import rootEpic from './epic'; 28 | import {ROOT_STATE_READY_TO_RENDER} from './actions'; 29 | 30 | import intlDE from 'react-intl/locale-data/de.js'; 31 | import intlEN from 'react-intl/locale-data/en.js'; 32 | import intlMessagesDE from '../public/assets/translations/de.json'; 33 | import intlMessagesEN from '../public/assets/translations/en.json'; 34 | 35 | /** 36 | * Export the promise factory. 37 | */ 38 | export default function (req) { 39 | 40 | /** 41 | * Create a new promise for the current request. 42 | */ 43 | return new Promise((resolve) => { 44 | 45 | /** 46 | * Injected reducer to process the "ready to render" action. 47 | */ 48 | const serverReducer = (state = {}, action) => { 49 | 50 | if (action.type === ROOT_STATE_READY_TO_RENDER) { 51 | setTimeout(() => { 52 | let state = store.getState(); 53 | delete state._server_; 54 | delete state.router; 55 | let html = renderer.html(); 56 | renderer.tearDown(); 57 | resolve({context, html, state}); 58 | }, 1); 59 | } 60 | return state; 61 | }; 62 | 63 | /** 64 | * Load the locale data for the users language. 65 | */ 66 | const locale = req.query.language ? head(split('-', req.query.language)) : 'de'; // TODO support en-gb fallback to en? 67 | const locales = { 68 | de: {data: intlDE, messages: intlMessagesDE}, 69 | en: {data: intlEN, messages: intlMessagesEN} 70 | }; 71 | 72 | // Set the locale data. 73 | addLocaleData(locales[locale].data); 74 | 75 | /** 76 | * Create the epic middleware. 77 | */ 78 | const epicMiddleware = createEpicMiddleware(rootEpic); 79 | 80 | /** 81 | * Create the store. 82 | */ 83 | let store = createStore( 84 | rootReducer(serverReducer), 85 | applyMiddleware(epicMiddleware) 86 | ); 87 | 88 | /** 89 | * Now we can run the app on the server. 90 | * https://github.com/developit/preact-render-to-string/issues/30#issuecomment-288752733 91 | */ 92 | const renderer = createRenderer(); 93 | 94 | // Router context for capturing redirects. 95 | let context = {}; 96 | 97 | try { 98 | // Run the app on the server. 99 | renderer.render( 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | ); 108 | } catch (e) { 109 | console.log(JSON.stringify(e)); 110 | } 111 | }); 112 | } 113 | -------------------------------------------------------------------------------- /src/preact-dom-renderer.js: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact'; 2 | import undom from 'undom'; 3 | 4 | const VOID_ELEMENTS = [ 5 | 'area', 6 | 'base', 7 | 'br', 8 | 'col', 9 | 'embed', 10 | 'hr', 11 | 'img', 12 | 'input', 13 | 'link', 14 | 'meta', 15 | 'param', 16 | 'source', 17 | 'track', 18 | 'wbr', 19 | ]; 20 | 21 | const ESC = { 22 | '&': 'amp', 23 | '<': 'lt', 24 | '>': 'gt', 25 | '"': 'quot', 26 | "'": 'apos', 27 | }; 28 | 29 | const enc = s => s.replace(/[&'"<>]/g, a => `&${ESC[a]};`); 30 | const attr = (a) => { 31 | if (a.name === 'class' && a.value === '') { 32 | return ''; 33 | } 34 | return ` ${a.name.replace(/^html/, '')}${a.value === 'true' || a.value === '' ? '' : `="${enc(a.value)}"`}`; 35 | }; 36 | 37 | const serializeHtml = (el) => { 38 | const { nodeType, nodeName, textContent, attributes, childNodes, innerHTML } = el; 39 | const normalizedNodeName = nodeName.toLowerCase(); 40 | if (nodeType === 3) { 41 | return enc(textContent); 42 | } 43 | const start = `<${normalizedNodeName}${attributes.map(attr).join('')}`; 44 | if (VOID_ELEMENTS.indexOf(normalizedNodeName) > -1) { 45 | return `${start} />`; 46 | } 47 | return `${start}>${innerHTML || childNodes.map(serializeHtml).join('')}`; 48 | }; 49 | 50 | let doc; 51 | const preactDomRenderer = () => { 52 | if (!doc) { 53 | doc = undom(); 54 | Object.assign(global, doc.defaultView); 55 | } 56 | 57 | let root; 58 | const parent = doc.createElement('x-root'); 59 | doc.body.appendChild(parent); 60 | 61 | const renderer = { 62 | render: (jsx) => { 63 | root = render(jsx, parent, root); 64 | return renderer; 65 | }, 66 | html: () => serializeHtml(root), 67 | tearDown: () => render(, parent, root).remove(), 68 | }; 69 | return renderer; 70 | }; 71 | 72 | export default preactDomRenderer; 73 | -------------------------------------------------------------------------------- /src/reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | /** 11 | * Import dependencies. 12 | */ 13 | import {combineReducers} from 'redux'; 14 | import {routerReducer} from 'react-router-redux'; 15 | 16 | /** 17 | * Import local dependencies. 18 | */ 19 | import {ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED} from './actions'; 20 | 21 | // TODO import other reducers here 22 | const aReducer = (state = {test: 'wessels yeah!'}, action) => { 23 | if (action.type === ROOT_FETCH_GRAPHQL_QUERY_SUCCEEDED) { 24 | // TODO just a test 25 | return Object.assign({}, state, {report: action.payload.report.name}); 26 | } 27 | return state; 28 | }; 29 | 30 | /** 31 | * Collect all reducers. 32 | */ 33 | const reducers = { 34 | a: aReducer, 35 | router: routerReducer 36 | }; 37 | 38 | /** 39 | * Export the root reducer for server-side rendering. 40 | */ 41 | export function rootReducer(serverReducer) { 42 | return combineReducers({...reducers, _server_: serverReducer}); 43 | } 44 | 45 | /** 46 | * Export the root reducer. 47 | */ 48 | export default combineReducers(reducers); 49 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | /** 13 | * Import dependencies. 14 | */ 15 | import fs from 'fs'; 16 | import path from 'path'; 17 | import net from 'net'; 18 | import http from 'http'; 19 | import https from 'https'; 20 | import express from 'express'; 21 | import compression from 'compression'; 22 | 23 | /** 24 | * Import local dependencies. 25 | */ 26 | import root from './index.server'; 27 | 28 | /** 29 | * Crazy way to redirect http to https. 30 | * TODO This is not for production. 31 | */ 32 | 33 | const basePort = process.env.PORT || 8080; 34 | const redirectPort = basePort + 1; 35 | const httpsPort = basePort + 2; 36 | 37 | function tcpConnection(conn) { 38 | conn.once('data', function (buf) { 39 | // A TLS handshake record starts with byte 22. 40 | const address = (buf[0] === 22) ? httpsPort : redirectPort; 41 | const proxy = net.createConnection(address, function () { 42 | proxy.write(buf); 43 | conn.pipe(proxy).pipe(conn); 44 | }); 45 | }); 46 | } 47 | 48 | net.createServer(tcpConnection).listen(basePort); 49 | http.createServer(httpConnection).listen(redirectPort); 50 | 51 | function httpConnection(req, res) { 52 | const host = req.headers['host']; 53 | res.writeHead(301, { "Location": "https://" + host + req.url }); 54 | res.end(); 55 | } 56 | 57 | /** 58 | * Read the index.html template. 59 | */ 60 | const indexHtml = fs.readFileSync(path.join(__dirname, '../client/index.html'), 'utf8'); 61 | 62 | /** 63 | * Create the express server. 64 | */ 65 | const app = express(); 66 | 67 | // Log incoming requests. 68 | app.use((req, res, next) => { 69 | console.log(req.url); 70 | next() 71 | }); 72 | 73 | // Remove unnecessary headers. 74 | app.disable('x-powered-by'); 75 | 76 | // Enable compression. 77 | app.use(compression()); 78 | 79 | // Serve all static content apart from the index.html. 80 | // TODO Static content should be hosted and requested from a CDN and not from here. 81 | app.use('/', express.static(path.join(__dirname, '../client'), {index: false, maxAge: '365d'})); 82 | 83 | // Serve the PWA service worker. 84 | //app.use('/service-worker.js', express.static('build/public/service-worker.js')); 85 | 86 | // Serve the index.html for everything else. 87 | app.get('*', (req, res, next) => { 88 | try { 89 | root(req).then(({context, html, state}) => { 90 | res.send(indexHtml 91 | .replace(/<\/body>/m, `${html}`) 92 | .replace(/window.__INITIAL_STATE__ = null;/m, `window.__INITIAL_STATE__ = ${JSON.stringify(state)};`) 93 | ); 94 | }); 95 | } catch (e) { 96 | // TODO Better error handling/reporting needed. 97 | console.log(e); 98 | next(e); 99 | } 100 | }); 101 | 102 | /** 103 | * Load the ssl certificates. 104 | */ 105 | const privateKey = fs.readFileSync(path.join(__dirname, '../../certificates/localhost.key')); 106 | const certificate = fs.readFileSync(path.join(__dirname, '../../certificates/localhost.crt')); 107 | 108 | /** 109 | * Create and run the server. 110 | */ 111 | const server = https.createServer({ 112 | key: privateKey, 113 | cert: certificate 114 | }, app).listen(httpsPort, () => { 115 | console.log(`[server] app on https://localhost:${server.address().port} - ${app.settings.env}`) 116 | }); 117 | 118 | /** 119 | * Terminate the server on request. 120 | */ 121 | process.on('SIGTERM', () => { 122 | server.close(() => { 123 | process.exit(0) 124 | }) 125 | }); 126 | -------------------------------------------------------------------------------- /src/serverless.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2016 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | /** 13 | * Import dependencies. 14 | */ 15 | import fs from 'fs'; 16 | import path from 'path'; 17 | import express from 'express'; 18 | import awsServerlessExpress from 'aws-serverless-express'; 19 | import awsServerlessExpressMiddleware from 'aws-serverless-express/middleware'; 20 | 21 | /** 22 | * Import local dependencies. 23 | */ 24 | import root from './index.server'; 25 | 26 | /** 27 | * Read the index.html template. 28 | */ 29 | const indexHtml = fs.readFileSync(path.join(__dirname, './client/index.html'), 'utf8'); 30 | 31 | /** 32 | * Create the express server. 33 | */ 34 | const app = express(); 35 | 36 | // Log incoming requests. TODO only for debugging purposes? 37 | app.use((req, res, next) => { 38 | console.log(req.url); 39 | next(); 40 | }); 41 | 42 | // Remove unnecessary headers. 43 | app.disable('x-powered-by'); 44 | 45 | // Enable compression. TODO: Update binaryMimeTypes if you use this. 46 | // app.use(compression()); 47 | 48 | app.use(awsServerlessExpressMiddleware.eventContext()); 49 | 50 | // We only serve the rendered index.html. 51 | // All other resources will be served from an S3 bucket. 52 | app.get('*', (req, res, next) => { 53 | try { 54 | root(req).then(({context, html, state}) => { 55 | let renderedHtml = indexHtml 56 | .replace(/<\/body>/m, `${html}`) 57 | .replace(/window.__INITIAL_STATE__ = null;/m, `window.__INITIAL_STATE__ = ${JSON.stringify(state)};`); 58 | res.set({ 59 | 'Content-Type': 'text/html', 60 | 'Content-Length': Buffer.byteLength(renderedHtml) 61 | }); 62 | res.status(200).send(renderedHtml); 63 | }); 64 | } catch (e) { 65 | // TODO Better error handling/reporting needed. 66 | console.log(e); 67 | next(e); 68 | } 69 | }); 70 | 71 | // NOTE: If you get ERR_CONTENT_DECODING_FAILED in your browser, this is likely 72 | // due to a compressed response (e.g. gzip) which has not been handled correctly 73 | // by aws-serverless-express and/or API Gateway. Add the necessary MIME types to 74 | // binaryMimeTypes, and to the x-amazon-apigateway-binary-media-types array in 75 | // simple-proxy-api.yaml, then redeploy (`npm run package-deploy`) 76 | const binaryMimeTypes = [ 77 | // 'application/javascript', 78 | // 'application/json', 79 | 'application/octet-stream', 80 | // 'application/xml', 81 | 'font/eot', 82 | 'font/opentype', 83 | 'font/otf', 84 | 'image/jpeg', 85 | 'image/png', 86 | 'image/svg+xml', 87 | // 'text/comma-separated-values', 88 | // 'text/css', 89 | // 'text/html', TODO turn this on if you use app.use(compression()); !!!!!!!!!!!!!!!! 90 | // 'text/javascript', 91 | // 'text/plain', 92 | // 'text/text', 93 | // 'text/xml' 94 | ]; 95 | 96 | // Create the AWS Lambda server. 97 | const server = awsServerlessExpress.createServer(app, null, binaryMimeTypes); 98 | 99 | // Export the AWS Lambda server proxy. 100 | exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context); 101 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | display: block; 3 | height: 100%; 4 | margin: 0; 5 | overflow: hidden; 6 | padding: 0; 7 | position: relative; 8 | width: 100%; 9 | } 10 | 11 | @font-face { 12 | font-family: 'Material Icons'; 13 | font-style: normal; 14 | font-weight: 400; 15 | src: url('../node_modules/material-design-icons/iconfont/MaterialIcons-Regular.eot'); /* For IE6-8 */ 16 | src: local('Material Icons'), 17 | local('MaterialIcons-Regular'), 18 | url('../node_modules/material-design-icons/iconfont/MaterialIcons-Regular.woff2') format('woff2'), 19 | url('../node_modules/material-design-icons/iconfont/MaterialIcons-Regular.woff') format('woff'), 20 | url('../node_modules/material-design-icons/iconfont/MaterialIcons-Regular.ttf') format('truetype'); 21 | } 22 | 23 | :global { 24 | .material-icons { 25 | font-family: 'Material Icons'; 26 | font-weight: normal; 27 | font-style: normal; 28 | font-size: 24px; /* Preferred icon size */ 29 | display: inline-block; 30 | line-height: 1; 31 | text-transform: none; 32 | letter-spacing: normal; 33 | word-wrap: normal; 34 | white-space: nowrap; 35 | direction: ltr; 36 | 37 | /* Support for all WebKit browsers. */ 38 | -webkit-font-smoothing: antialiased; 39 | /* Support for Safari and Chrome. */ 40 | text-rendering: optimizeLegibility; 41 | 42 | /* Support for Firefox. */ 43 | -moz-osx-font-smoothing: grayscale; 44 | 45 | /* Support for IE. */ 46 | font-feature-settings: 'liga'; 47 | } 48 | } 49 | 50 | .root { 51 | display: flex; 52 | flex-direction: row; 53 | padding: 0; 54 | margin: 0; 55 | box-sizing: border-box; 56 | height: 100%; 57 | width: 100%; 58 | } 59 | -------------------------------------------------------------------------------- /translations/mastercard/de.po: -------------------------------------------------------------------------------- 1 | # This is an example comment that would come from the translator. 2 | #. This is the title of the demo page. 3 | #: containers\demo\component.json 4 | msgctxt "demoTitle" 5 | msgid "Preact Material Design Components Web (preact-mdc)" 6 | msgstr "Preact Material Design Components Web (preact-mdc) [mastercard/de]" 7 | -------------------------------------------------------------------------------- /translations/mastercard/en.po: -------------------------------------------------------------------------------- 1 | # This is an example comment that would come from the translator. 2 | #. This is the title of the demo page. 3 | #: containers\demo\component.json 4 | msgctxt "demoTitle" 5 | msgid "Preact Material Design Components Web (preact-mdc)" 6 | msgstr "Preact Material Design Components Web (preact-mdc) [mastercard/en]" 7 | -------------------------------------------------------------------------------- /translations/visa/de.po: -------------------------------------------------------------------------------- 1 | # This is an example comment that would come from the translator. 2 | #. This is the title of the demo page. 3 | #: containers\demo\component.json 4 | msgctxt "demoTitle" 5 | msgid "Preact Material Design Components Web (preact-mdc)" 6 | msgstr "Preact Material Design Components Web (preact-mdc) [visa/de]" 7 | -------------------------------------------------------------------------------- /translations/visa/en.po: -------------------------------------------------------------------------------- 1 | # This is an example comment that would come from the translator. 2 | #. This is the title of the demo page. 3 | #: containers\demo\component.json 4 | msgctxt "demoTitle" 5 | msgid "Preact Material Design Components Web (preact-mdc)" 6 | msgstr "Preact Material Design Components Web (preact-mdc) [visa/en]" 7 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bernd Wessels (https://github.com/BerndWessels/) 3 | * 4 | * Copyright © 2017 Bernd Wessels. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | 'use strict'; 11 | 12 | /** 13 | * Import dependencies. 14 | */ 15 | const fs = require('fs'); 16 | const path = require('path'); 17 | const glob = require('glob'); 18 | const webpack = require('webpack'); 19 | const autoprefixer = require('autoprefixer'); 20 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 21 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 22 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 23 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 24 | const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); 25 | const contains = require('ramda/src/contains'); 26 | 27 | /** 28 | * Export the build configuration. 29 | */ 30 | module.exports = function () { 31 | // Get the build environment. 32 | const DEV = process.env.NODE_ENV === 'development'; 33 | const WEB = process.env.TARGET === 'web'; 34 | const AWS = process.env.TARGET === 'serverless'; 35 | const BASEURL = process.env.BASEURL; 36 | const RESOURCEPATH = process.env.RESOURCEPATH || ''; 37 | const HTTPS = contains('--https', process.argv); 38 | // Build sass loaders. 39 | function getSassLoaders(modules) { 40 | return [] 41 | .concat(DEV ? [ 42 | { 43 | //https://github.com/webpack-contrib/style-loader 44 | loader: 'style-loader' 45 | }] : []) 46 | .concat([ 47 | { 48 | // https://github.com/webpack-contrib/css-loader 49 | loader: 'css-loader', 50 | options: Object.assign({ 51 | sourceMap: true, 52 | modules: modules, 53 | importLoaders: 2 54 | }, 55 | DEV ? { 56 | localIdentName: "[path]---[name]---[local]---[hash:base64:5]" 57 | } : {} 58 | ) 59 | }, 60 | { 61 | // https://github.com/postcss/postcss-loader 62 | loader: 'postcss-loader', 63 | options: { 64 | plugins: function () { 65 | return [ 66 | autoprefixer({browsers: ['last 1 versions']}) 67 | ]; 68 | } 69 | } 70 | }, 71 | { 72 | // https://github.com/bholloway/resolve-url-loader 73 | loader: 'resolve-url-loader' 74 | }, 75 | { 76 | // https://github.com/webpack-contrib/sass-loader 77 | loader: 'sass-loader', 78 | options: { 79 | sourceMap: true, 80 | includePaths: ['node_modules', 'node_modules/@material/*'] 81 | .map((d) => path.join(__dirname, d)) 82 | .map((g) => glob.sync(g)) 83 | .reduce((a, c) => a.concat(c), []) 84 | } 85 | } 86 | ]); 87 | } 88 | 89 | // Build and export the build configuration. 90 | return { 91 | // https://webpack.js.org/configuration/target 92 | target: WEB ? 'web' : 'node', 93 | node: { 94 | __dirname: false, 95 | __filename: false, 96 | }, 97 | // https://webpack.js.org/configuration/entry-context 98 | entry: { 99 | index: path.resolve(__dirname, WEB ? './src/index.client.js' : AWS ? './src/serverless.js' : './src/server.js') 100 | }, 101 | // https://webpack.js.org/configuration/output 102 | output: { 103 | filename: WEB ? '[name].[hash].js' : '[name].js', 104 | path: path.resolve(__dirname, WEB ? './dist/client' : AWS ? './dist' : './dist/server'), 105 | publicPath: AWS ? '/_/' : '' 106 | }, 107 | // https://webpack.js.org/configuration/resolve 108 | resolve: { 109 | alias: { 110 | 'preact': 'preact', 111 | 'react': 'preact-compat', 112 | 'react-dom': 'preact-compat', 113 | 'react-redux': 'preact-redux' 114 | }, 115 | extensions: ['.js', '.jsx', '.json', '.scss'], 116 | modules: ['node_modules'] 117 | }, 118 | // https://webpack.js.org/configuration/module 119 | module: { 120 | noParse: /\.min\.js/, 121 | rules: [{ 122 | test: /\.jsx?$/, 123 | exclude: [/node_modules(?!([\/\\]preact-mdc|[\/\\]aws-serverless-express))/], 124 | use: [{ 125 | // https://github.com/babel/babel-loader 126 | loader: 'babel-loader', 127 | options: { 128 | presets: [ 129 | ['es2015', {loose: true, modules: false}] 130 | ], 131 | plugins: [ 132 | 'transform-class-properties', 133 | 'transform-object-rest-spread', 134 | ['transform-react-jsx', {pragma: 'h'}] 135 | ] 136 | }, 137 | }] 138 | }, { 139 | test: /(\.scss|\.css)$/, 140 | exclude: [/node_modules/, /normalize.css/, /icomoon/], 141 | use: DEV ? getSassLoaders(true) : ExtractTextPlugin.extract(getSassLoaders(true)) 142 | }, { 143 | test: /(\.scss|\.css)$/, 144 | include: [/node_modules/], 145 | use: DEV ? getSassLoaders(false) : ExtractTextPlugin.extract(getSassLoaders(false)) 146 | }, { 147 | // https://github.com/webpack/file-loader 148 | test: /\.(svg|woff|woff2|ttf|eot)$/, 149 | loader: 'file-loader?name=assets/fonts/[name].[hash].[ext]' 150 | }] 151 | }, 152 | // https://webpack.js.org/configuration/plugins 153 | plugins: [ 154 | // https://github.com/johnagan/clean-webpack-plugin 155 | new CleanWebpackPlugin(WEB ? ['dist/client'] : AWS ? ['dist'] : ['dist/server'], __dirname), 156 | // https://github.com/kevlened/copy-webpack-plugin 157 | new CopyWebpackPlugin([ 158 | {from: 'public'} 159 | ]), 160 | // https://webpack.js.org/plugins/loader-options-plugin 161 | new webpack.LoaderOptionsPlugin({ 162 | minimize: !DEV, 163 | debug: !DEV 164 | }), 165 | // https://webpack.js.org/plugins/define-plugin 166 | new webpack.DefinePlugin({ 167 | 'process.env': { 168 | NODE_ENV: JSON.stringify(DEV ? 'development' : 'production'), 169 | WEB: JSON.stringify(WEB), 170 | BASE_URL: JSON.stringify(BASEURL) 171 | } 172 | }) 173 | ].concat(WEB ? [ 174 | // https://github.com/ampedandwired/html-webpack-plugin 175 | new HtmlWebpackPlugin(Object.assign({ 176 | template: path.resolve(__dirname, './src/index.ejs'), 177 | inject: false, 178 | baseurl: BASEURL, 179 | manifest: 'manifest.json', 180 | themeColor: '#333', 181 | favIcon: 'favicon.ico', 182 | resourcePath: RESOURCEPATH 183 | }, !DEV ? { 184 | serviceWorker: 'service-worker.js' 185 | } : {})) 186 | ] : []) 187 | .concat(DEV ? [ 188 | // prints more readable module names in the browser console on HMR updates 189 | new webpack.NamedModulesPlugin() 190 | ] : []) 191 | .concat(!DEV ? [ 192 | // https://github.com/webpack-contrib/extract-text-webpack-plugin 193 | new ExtractTextPlugin({ 194 | filename: '[name].[hash].css' 195 | }), 196 | // https://github.com/webpack-contrib/uglifyjs-webpack-plugin 197 | new webpack.optimize.UglifyJsPlugin({ 198 | compress: { 199 | screw_ie8: true, 200 | warnings: false 201 | }, 202 | output: { 203 | comments: false, 204 | screw_ie8: true 205 | }, 206 | mangle: { 207 | screw_ie8: true 208 | }, 209 | sourceMap: true 210 | }) 211 | ] : []) 212 | .concat(!DEV && WEB ? [ 213 | new SWPrecacheWebpackPlugin( 214 | { 215 | cacheId: 'my-project-name', // TODO 216 | filename: 'service-worker.js', 217 | stripPrefix: path.join(__dirname, 'dist/client').replace(/\\/g, "/"), 218 | maximumFileSizeToCacheInBytes: 4194304, 219 | minify: false, 220 | runtimeCaching: [{ 221 | handler: 'cacheFirst', 222 | urlPattern: /[.]mp3$/, 223 | }], 224 | } 225 | ) 226 | ] : []), 227 | // https://webpack.js.org/configuration/devtool 228 | devtool: DEV ? 'cheap-module-eval-source-map' : 'source-map', 229 | // https://webpack.js.org/configuration/other-options/#bail 230 | bail: !DEV, 231 | // https://webpack.js.org/configuration/stats 232 | stats: { 233 | colors: true 234 | }, 235 | // https://webpack.js.org/configuration/dev-server 236 | devServer: HTTPS ? { 237 | port: process.env.PORT, 238 | host: process.env.HOST, 239 | publicPath: '/', 240 | contentBase: './src', 241 | historyApiFallback: true, 242 | key: fs.readFileSync(path.resolve(__dirname, './certificates/domain.key')), 243 | cert: fs.readFileSync(path.resolve(__dirname, './certificates/domain.crt')) 244 | } : { 245 | port: process.env.PORT, 246 | host: process.env.HOST, 247 | publicPath: '/', 248 | contentBase: './src', 249 | historyApiFallback: true 250 | } 251 | }; 252 | }; 253 | --------------------------------------------------------------------------------