├── .babelrc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .firebaserc
├── .gitignore
├── __mocks__
└── fileMock.js
├── database.rules.json
├── favicon.ico
├── firebase.json
├── functions
├── index.js
└── package.json
├── index.html
├── manifest.json
├── package.json
├── public
├── app.js
├── favicon.ico
├── images
│ ├── icon-128x128.png
│ ├── icon-144x144.png
│ ├── icon-152x152.png
│ ├── icon-192x192.png
│ ├── icon-384x384.png
│ ├── icon-512x512.png
│ ├── icon-72x72.png
│ └── icon-96x96.png
├── index.html
├── manifest.js
├── manifest.json
├── styles.css
├── sw.js
└── vendor.js
├── src
├── components
│ ├── App.js
│ ├── App.spec.js
│ ├── __snapshots__
│ │ └── App.spec.js.snap
│ ├── card-item
│ │ ├── CardItem.js
│ │ ├── CardItem.spec.js
│ │ ├── __snapshots__
│ │ │ └── CardItem.spec.js.snap
│ │ └── styles.scss
│ ├── cards
│ │ ├── Cards.js
│ │ ├── Cards.spec.js
│ │ ├── __snapshots__
│ │ │ └── Cards.spec.js.snap
│ │ └── styles.scss
│ ├── header
│ │ ├── Header.js
│ │ ├── Header.spec.js
│ │ ├── __snapshots__
│ │ │ └── Header.spec.js.snap
│ │ └── styles.scss
│ └── styles.scss
├── images
│ ├── icons
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ ├── icon-384x384.png
│ │ ├── icon-512x512.png
│ │ ├── icon-72x72.png
│ │ └── icon-96x96.png
│ └── svgs
│ │ ├── back.svg
│ │ ├── logo-white.svg
│ │ └── logo.svg
└── index.js
├── sw.js
├── webpack.config.babel.js
├── webpack.dev.config.babel.js
└── webpack.prod.config.babel.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react"]
3 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{js,py}]
8 | charset = utf-8
9 |
10 | indent_style = space
11 | indent_size = 2
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*.spec.js
2 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": "airbnb",
4 | "rules": {
5 | "react/jsx-filename-extension": 0,
6 | "linebreak-style": "off",
7 | "class-methods-use-this": "off"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "planning-poker-5ea54"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/__mocks__/fileMock.js:
--------------------------------------------------------------------------------
1 | module.exports = 'test-file-stub';
2 |
--------------------------------------------------------------------------------
/database.rules.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | ".read": "auth != null",
4 | ".write": "auth != null"
5 | }
6 | }
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/favicon.ico
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "database": {
3 | "rules": "database.rules.json"
4 | },
5 | "hosting": {
6 | "public": "public",
7 | "rewrites": [
8 | {
9 | "source": "**",
10 | "destination": "/index.html"
11 | }
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/functions/index.js:
--------------------------------------------------------------------------------
1 | var functions = require('firebase-functions');
2 |
3 | // // Start writing Firebase Functions
4 | // // https://firebase.google.com/functions/write-firebase-functions
5 | //
6 | // exports.helloWorld = functions.https.onRequest((request, response) => {
7 | // response.send("Hello from Firebase!");
8 | // })
9 |
--------------------------------------------------------------------------------
/functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "description": "Cloud Functions for Firebase",
4 | "dependencies": {
5 | "firebase-admin": "^4.1.2",
6 | "firebase-functions": "^0.5"
7 | },
8 | "private": true
9 | }
10 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Agile Poker
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "AgilePoker",
3 | "short_name": "AgilePoker",
4 | "theme_color": "#2a0044",
5 | "background_color": "#2a0044",
6 | "display": "standalone",
7 | "start_url": "/",
8 | "icons": [
9 | {
10 | "src": "images/icon-72x72.png",
11 | "sizes": "72x72",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "images/icon-96x96.png",
16 | "sizes": "96x96",
17 | "type": "image/png"
18 | },
19 | {
20 | "src": "images/icon-128x128.png",
21 | "sizes": "128x128",
22 | "type": "image/png"
23 | },
24 | {
25 | "src": "images/icon-144x144.png",
26 | "sizes": "144x144",
27 | "type": "image/png"
28 | },
29 | {
30 | "src": "images/icon-152x152.png",
31 | "sizes": "152x152",
32 | "type": "image/png"
33 | },
34 | {
35 | "src": "images/icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image/png"
38 | },
39 | {
40 | "src": "images/icon-384x384.png",
41 | "sizes": "384x384",
42 | "type": "image/png"
43 | },
44 | {
45 | "src": "images/icon-512x512.png",
46 | "sizes": "512x512",
47 | "type": "image/png"
48 | }
49 | ],
50 | "splash_pages": null
51 | }
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pwa-planning-poker",
3 | "version": "1.0.0",
4 | "description": "A Planning Poker Progressive Web Apps for Agile meetings",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack-dev-server --inline --hot",
8 | "build": "webpack",
9 | "test": "jest",
10 | "lint": "eslint src",
11 | "check": "npm run test && npm run lint"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "dependencies": {
16 | "classnames": "^2.2.5",
17 | "preact": "^7.2.0",
18 | "preact-compat": "^3.14.0",
19 | "react": "^15.4.2",
20 | "react-dom": "^15.4.2"
21 | },
22 | "devDependencies": {
23 | "babel-core": "^6.21.0",
24 | "babel-eslint": "^7.1.1",
25 | "babel-jest": "^19.0.0",
26 | "babel-loader": "^6.2.10",
27 | "babel-preset-es2015": "^6.18.0",
28 | "babel-preset-react": "^6.16.0",
29 | "clean-webpack-plugin": "^0.1.15",
30 | "copy-webpack-plugin": "^4.0.1",
31 | "css-loader": "^0.26.1",
32 | "eslint": "^3.13.1",
33 | "eslint-config-airbnb": "^14.0.0",
34 | "eslint-loader": "^1.6.1",
35 | "eslint-plugin-import": "^2.2.0",
36 | "eslint-plugin-jsx-a11y": "^3.0.2",
37 | "eslint-plugin-react": "^6.9.0",
38 | "extract-text-webpack-plugin": "^1.0.1",
39 | "html-webpack-plugin": "^2.26.0",
40 | "identity-obj-proxy": "^3.0.0",
41 | "jest": "^19.0.2",
42 | "react-test-renderer": "^15.4.2",
43 | "sass-loader": "^4.1.1",
44 | "style-loader": "^0.13.1",
45 | "url-loader": "^0.5.7",
46 | "webpack": "^1.14.0",
47 | "webpack-dev-server": "^1.16.2"
48 | },
49 | "jest": {
50 | "moduleNameMapper": {
51 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js",
52 | "\\.(css|scss)$": "identity-obj-proxy"
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/public/app.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([0,2],[function(M,e,u){"use strict";function t(M){return M&&M.__esModule?M:{default:M}}var j=u(1),A=t(j),I=u(1),g=t(I),a=u(5),D=t(a);g.default.render(A.default.createElement(D.default,null),document.getElementById("app"))},,,,,function(M,e,u){"use strict";function t(M){return M&&M.__esModule?M:{default:M}}Object.defineProperty(e,"__esModule",{value:!0});var j=u(1),A=t(j),I=u(6),g=t(I),a=u(12),D=t(a);u(21);var n=function(){return A.default.createElement("div",null,A.default.createElement(g.default,null),A.default.createElement(D.default,null))};e.default=n},function(M,e,u){"use strict";function t(M){return M&&M.__esModule?M:{default:M}}Object.defineProperty(e,"__esModule",{value:!0});var j=u(1),A=t(j),I=u(7),g=t(I),a=u(8),D=t(a),n=function(){return A.default.createElement("header",{className:D.default.header},A.default.createElement("div",{className:D.default.content},A.default.createElement("figure",null,A.default.createElement("img",{src:g.default,alt:"Logo brand"})),A.default.createElement("h1",null,"AgilePoker")))};e.default=n},function(M,e){M.exports="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjYiIGhlaWdodD0iMjYiIHZpZXdCb3g9IjAgMCAyNiAyNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48dGl0bGU+QzQ5NTVGNUMtMEE2NS00RTNCLUE4ODctMDE0QzY0NTEzRDdFPC90aXRsZT48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik05LjczNSAxNC4zNzlhMS43OTcgMS43OTcgMCAwIDEtMS41MDQuODI2Yy0uNjEyIDAtMS4xOC0uMzIxLTEuNTA0LS44MjZoMy4wMDh6bS0xLjUwNCAxLjI4N2MuODY3IDAgMS42NjMtLjUxIDIuMDMtMS4yODdoLjE5OWEuMjMuMjMgMCAxIDAgMC0uNDYySDYuMDAzYS4yMy4yMyAwIDAgMCAwIC40NjJoLjE5OGEyLjI2MSAyLjI2MSAwIDAgMCAyLjAzIDEuMjg3ek0xNy43NzUgMTUuMjA1Yy0uNjEyIDAtMS4xOC0uMzIxLTEuNTA0LS44MjZoMy4wMDhhMS43OTcgMS43OTcgMCAwIDEtMS41MDQuODI2bTIuMjI4LTEuMjg4aC00LjQ1N2EuMjMuMjMgMCAwIDAgMCAuNDYyaC4xOThhMi4yNjEgMi4yNjEgMCAwIDAgMi4wMyAxLjI4OGMuODY3IDAgMS42NjQtLjUxMiAyLjAzMS0xLjI4OGguMTk4YS4yMy4yMyAwIDAgMCAwLS40NjIiLz48cGF0aCBkPSJNOS44MDYgMTguNDIzaC4zNTlhLjIzLjIzIDAgMCAwIC4yMy0uMjMuOTUuOTUgMCAwIDEgLjk1LS45NWgzLjMxN2EuOTUuOTUgMCAwIDEgLjk0OS45NWMwIC4xMjcuMTAzLjIzLjIzLjIzaC4zNmEuOTUuOTUgMCAwIDEgLjkyLjcxOEg4Ljg4NWEuOTUuOTUgMCAwIDEgLjkyLS43MThtOC45NjcuNzE4aC0xLjE4YTEuNDEyIDEuNDEyIDAgMCAwLTEuMzkyLTEuMThoLS4xNDdhMS40MTMgMS40MTMgMCAwIDAtMS4zOTEtMS4xNzloLTEuNDI4VjguMDUxaDQuMjJsLTEuNzc3IDUuMzE2YS4yMzEuMjMxIDAgMCAwIC40MzguMTQ2bDEuNjYtNC45NjUgMS42NiA0Ljk2NWEuMjMuMjMgMCAwIDAgLjQzOC0uMTQ2bC0xLjc3OC01LjMxNmguMzc4YS4yMy4yMyAwIDEgMCAwLS40NjJoLTUuMjRWNi4yMzhoMS4xMjljLjM2MiAwIC42NTcuMjk1LjY1Ny42NTcgMCAuMTI4LjEwMy4yMy4yMy4yM2guN2EuMjMuMjMgMCAwIDAgMC0uNDZoLS40OTNhMS4xMiAxLjEyIDAgMCAwLTEuMDk0LS44ODhoLTEuMTI4di0uMjQyYS4yMy4yMyAwIDAgMC0uNDYyIDB2LjI0MmgtMS4xMjdhMS4xMiAxLjEyIDAgMCAwLTEuMDk1Ljg4N2gtLjQ5MmEuMjMuMjMgMCAwIDAgMCAuNDYyaC42OTlhLjIzLjIzIDAgMCAwIC4yMy0uMjNjMC0uMzYzLjI5NS0uNjU4LjY1OC0uNjU4aDEuMTI3djEuMzUxaC01LjI0YS4yMy4yMyAwIDAgMCAwIC40NjJoLjM3OWwtMS43NzcgNS4zMTZhLjIzLjIzIDAgMCAwIC40MzcuMTQ2bDEuNjYtNC45NjUgMS42NiA0Ljk2NWEuMjMuMjMgMCAwIDAgLjQzOC0uMTQ2TDguNTUyIDguMDUxaDQuMjJ2OC43MzFoLTEuNDI4Yy0uNjk5IDAtMS4yOC41MTEtMS4zOTEgMS4xOGgtLjE0N2MtLjcgMC0xLjI4MS41MTEtMS4zOTEgMS4xOEg3LjIzNGEuMjMuMjMgMCAwIDAgMCAuNDZoMTEuNTM4YS4yMy4yMyAwIDAgMCAwLS40NiIvPjxwYXRoIGQ9Ik0xMyAuNjE1YTEyLjMwMyAxMi4zMDMgMCAwIDAtOC43NTcgMy42MjhBMTIuMzAzIDEyLjMwMyAwIDAgMCAuNjE1IDEzYzAgMy4zMDggMS4yODkgNi40MTggMy42MjggOC43NTdBMTIuMzAzIDEyLjMwMyAwIDAgMCAxMyAyNS4zODVjMy4zMDggMCA2LjQxOC0xLjI4OSA4Ljc1Ny0zLjYyOEExMi4zMDMgMTIuMzAzIDAgMCAwIDI1LjM4NSAxM2MwLTMuMzA4LTEuMjg5LTYuNDE4LTMuNjI4LTguNzU3QTEyLjMwMyAxMi4zMDMgMCAwIDAgMTMgLjYxNU0xMyAyNmExMi45MTUgMTIuOTE1IDAgMCAxLTkuMTkyLTMuODA4QTEyLjkxNSAxMi45MTUgMCAwIDEgMCAxM2MwLTMuNDcyIDEuMzUyLTYuNzM3IDMuODA4LTkuMTkyQTEyLjkxNSAxMi45MTUgMCAwIDEgMTMgMGMzLjQ3MiAwIDYuNzM3IDEuMzUyIDkuMTkyIDMuODA4QTEyLjkxNSAxMi45MTUgMCAwIDEgMjYgMTNjMCAzLjQ3Mi0xLjM1MiA2LjczNy0zLjgwOCA5LjE5MkExMi45MTUgMTIuOTE1IDAgMCAxIDEzIDI2Ii8+PC9nPjwvc3ZnPg=="},function(M,e){M.exports={header:"fyeEC",content:"_35nvu"}},,,,function(M,e,u){"use strict";function t(M){return M&&M.__esModule?M:{default:M}}function j(M,e){if(!(M instanceof e))throw new TypeError("Cannot call a class as a function")}function A(M,e){if(!M)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?M:e}function I(M,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);M.prototype=Object.create(e&&e.prototype,{constructor:{value:M,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(M,e):M.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var g=function(){function M(M,e){for(var u=0;u
2 |
3 |
4 |
5 |
6 |
7 | Agile Poker
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/public/manifest.js:
--------------------------------------------------------------------------------
1 | !function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={exports:{},id:n,loaded:!1};return e[n].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n=window.webpackJsonp;window.webpackJsonp=function(o,p){for(var l,c,s=0,i=[];sfigure{margin:0 1em;float:left}._35nvu img{width:2em}._35nvu>h1{color:#fff;font-weight:300;font-size:1.4em}._1Oqix{position:relative;display:inline-block;background-color:#fafafa;border-radius:4px;width:5em;height:8em;cursor:pointer;margin:.4em;border:1px solid rgba(41,0,68,.7);box-shadow:0 0 2px 0 rgba(0,0,0,.5)}._1Oqix:hover{opacity:.75}._3Q6ZY{width:9.5em;height:15em;box-shadow:0 0 10px 0 rgba(0,0,0,.2)}._1Oqix>span{position:absolute;font-size:2.5em;color:#2a0044;top:50%;left:50%;transform:translate(-50%,-60%)}._17if_{bottom:0;left:-1.5em}._2vUUx,._17if_{position:absolute}._2vUUx{margin:0 auto;left:0;right:0;top:11em}._3Q6ZY>span{font-size:5.5em;font-weight:300}._1E2AT{display:flex;flex-flow:row wrap;max-width:28em;padding:3em 0;margin:0 auto;animation:_3IFwn .7s ease-in-out}.hLcrF{margin:2em;text-align:center}._1Udwa{animation:_3IFwn 1s ease-in-out}._2kd9t{animation:hvgzA 1s ease-in-out}.SEHnH{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.Rykdh{position:relative;line-height:.5;width:165px;margin:0 auto}.Rykdh>p{font-size:14px;font-weight:700;font-style:oblique;color:#2a0044}.h4aMm{padding-top:2em}.h4aMm:before{position:absolute;left:-.5em;top:.2em;content:"\201C";font-size:60px;font-weight:700;color:#999}.h4aMm:after{content:""}@keyframes _3IFwn{0%{opacity:0}to{opacity:1}}@keyframes hvgzA{0%{opacity:0}to{opacity:1}}body{background-color:#f0f0f0;font-family:Helvetica Neue,Helvetica,Arial,sans-serif}
--------------------------------------------------------------------------------
/public/sw.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var CACHE_NAME = 'static-v1';
4 |
5 | self.addEventListener('install', function (event) {
6 | event.waitUntil(
7 | caches.open(CACHE_NAME).then(function (cache) {
8 | return cache.addAll([
9 | '/',
10 | '/index.html',
11 | '/styles.css',
12 | '/app.js',
13 | '/manifest.js',
14 | '/vendor.js',
15 | ]);
16 | })
17 | )
18 | });
19 |
20 | self.addEventListener('activate', function activator(event) {
21 | event.waitUntil(
22 | caches.keys().then(function (keys) {
23 | return Promise.all(keys
24 | .filter(function (key) {
25 | return key.indexOf(CACHE_NAME) !== 0;
26 | })
27 | .map(function (key) {
28 | return caches.delete(key);
29 | })
30 | );
31 | })
32 | );
33 | });
34 |
35 | self.addEventListener('fetch', function (event) {
36 | event.respondWith(
37 | caches.match(event.request).then(function (cachedResponse) {
38 | return cachedResponse || fetch(event.request);
39 | })
40 | );
41 | });
42 |
--------------------------------------------------------------------------------
/public/vendor.js:
--------------------------------------------------------------------------------
1 | webpackJsonp([1,2],[function(e,t,n){n(1),e.exports=n(1)},function(e,t,n){(function(t){!function(t,r){e.exports=r(n(3),n(4))}(this,function(e,n){function r(){return null}function o(e){var t=e.nodeName,n=e.attributes;e.attributes={},t.defaultProps&&_(e.attributes,t.defaultProps),n&&_(e.attributes,n)}function i(e,t){var n,r,o;if(t){for(o in t)if(n=B.test(o))break;if(n){r=e.attributes={};for(o in t)t.hasOwnProperty(o)&&(r[B.test(o)?o.replace(/([A-Z0-9])/,"-$1").toLowerCase():o]=t[o])}}}function a(e,t,r){var o=t&&t._preactCompatRendered&&t._preactCompatRendered.base;o&&o.parentNode!==t&&(o=null),o||(o=t.children[0]);for(var i=t.childNodes.length;i--;)t.childNodes[i]!==o&&t.removeChild(t.childNodes[i]);var a=n.render(e,t,o);return t&&(t._preactCompatRendered=a&&(a._component||{base:a})),"function"==typeof r&&r(),a&&a._component||a}function u(e,t,r,o){var i=n.h(J,{context:e.context},t),u=a(i,r);return o&&o(u),u._component||u.base}function l(e){var t=e._preactCompatRendered&&e._preactCompatRendered.base;return!(!t||t.parentNode!==e)&&(n.render(n.h(r),e,t),!0)}function c(e){return h.bind(null,e)}function s(e,t){for(var n=t||0;n0;)r[o]=arguments[o+2];if(!y(e))return e;var i=e.attributes||e.props,a=n.h(e.nodeName||e.type,i,e.children||i&&i.children),u=[a,t];return r&&r.length?u.push(r):t&&t.children&&u.push(t.children),m(n.cloneElement.apply(void 0,u))}function y(e){return e&&(e instanceof H||e.$$typeof===L)}function b(e,t){return t._refProxies[e]||(t._refProxies[e]=function(n){t&&t.refs&&(t.refs[e]=n,null===n&&(delete t._refProxies[e],t=null))})}function g(e){var t=e.nodeName,n=e.attributes;if(n&&"string"==typeof t){var r={};for(var o in n)r[o.toLowerCase()]=o;if(r.ondoubleclick&&(n.ondblclick=n[r.ondoubleclick],delete n[r.ondoubleclick]),r.onchange&&("textarea"===t||"input"===t.toLowerCase()&&!/^fil|che|rad/i.test(n.type))){var i=r.oninput||"oninput";n[i]||(n[i]=A([n[i],n[r.onchange]]),delete n[r.onchange])}}}function x(e){var t=e.attributes;if(t){var n=t.className||t.class;n&&(t.className=n)}}function _(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function C(e,t){for(var n in e)if(!(n in t))return!0;for(var r in t)if(e[r]!==t[r])return!0;return!1}function N(e){return e&&e.base||e}function w(){}function k(e){function t(e,t){E(this),I.call(this,e,t,$),O.call(this,e,t)}return e=_({constructor:t},e),e.mixins&&S(e,P(e.mixins)),e.statics&&_(t,e.statics),e.propTypes&&(t.propTypes=e.propTypes),e.defaultProps&&(t.defaultProps=e.defaultProps),e.getDefaultProps&&(t.defaultProps=e.getDefaultProps()),w.prototype=I.prototype,t.prototype=_(new w,e),t.displayName=e.displayName||"Component",t}function P(e){for(var t={},n=0;n1)for(var n=1;n>",P={array:o("array"),bool:o("boolean"),func:o("function"),number:o("number"),object:o("object"),string:o("string"),symbol:o("symbol"),any:i(),arrayOf:a,element:u(),instanceOf:l,node:p(),objectOf:s,oneOf:c,oneOfType:f,shape:d};t.exports=P})},function(e,t,n){!function(e,n){n(t)}(this,function(e){function t(e,t,n){this.nodeName=e,this.attributes=t,this.children=n,this.key=t&&t.key}function n(e,n){var r,o,i,a,u;for(u=arguments.length;u-- >2;)L.push(arguments[u]);for(n&&n.children&&(L.length||L.push(n.children),delete n.children);L.length;)if((i=L.pop())instanceof Array)for(u=i.length;u--;)L.push(i[u]);else null!=i&&i!==!0&&i!==!1&&("number"==typeof i&&(i=String(i)),a="string"==typeof i,a&&o?r[r.length-1]+=i:((r||(r=[])).push(i),o=a));var l=new t(e,n||void 0,r||V);return M.vnode&&M.vnode(l),l}function r(e,t){if(t)for(var n in t)e[n]=t[n];return e}function o(e){return r({},e)}function i(e,t){for(var n=t.split("."),r=0;r2?[].slice.call(arguments,2):e.children)}function s(e,t,n){var r=t.split(".");return function(t){for(var o=t&&t.target||this,a={},l=a,c=u(n)?i(t,n):o.nodeName?o.type.match(/^che|rad/)?o.checked:o.value:t,s=0;s=h?e.appendChild(l):l!==c[g]&&(l===c[g+1]&&b(c[g]),e.insertBefore(l,c[g]||null)))}if(p)for(var g in f)f[g]&&E(f[g]);for(;d<=v;)l=s[v--],l&&E(l)}function E(e,t){var n=e._component;if(n)I(n,!t);else{e[q]&&e[q].ref&&e[q].ref(null),t||C(e);for(var r;r=e.lastChild;)E(r,t)}}function T(e,t,n){var r;for(r in n)t&&r in t||null==n[r]||g(e,r,n[r],n[r]=void 0,Y);if(t)for(r in t)"children"===r||"innerHTML"===r||r in n&&t[r]===("value"===r||"checked"===r?e[r]:n[r])||g(e,r,n[r],n[r]=t[r],Y)}function A(e){var t=e.constructor.name,n=te[t];n?n.push(e):te[t]=[e]}function O(e,t,n){var r=new e(t,n),o=te[e.name];if(W.call(r,t,n),o)for(var i=o.length;i--;)if(o[i].constructor===e){r.nextBase=o[i].nextBase,o.splice(i,1);break}return r}function U(e,t,n,r,o){e._disable||(e._disable=!0,(e.__ref=t.ref)&&delete t.ref,(e.__key=t.key)&&delete t.key,!e.base||o?e.componentWillMount&&e.componentWillMount():e.componentWillReceiveProps&&e.componentWillReceiveProps(t,r),r&&r!==e.context&&(e.prevContext||(e.prevContext=e.context),e.context=r),e.prevProps||(e.prevProps=e.props),e.props=t,e._disable=!1,0!==n&&(1!==n&&M.syncComponentUpdates===!1&&e.base?f(e):j(e,1,o)),e.__ref&&e.__ref(e))}function j(e,t,n,i){if(!e._disable){var u,l,c,s,f=e.props,p=e.state,m=e.context,v=e.prevProps||f,b=e.prevState||p,g=e.prevContext||m,x=e.base,_=e.nextBase,C=x||_,N=e._component;if(x&&(e.props=v,e.state=b,e.context=g,2!==t&&e.shouldComponentUpdate&&e.shouldComponentUpdate(f,p,m)===!1?u=!0:e.componentWillUpdate&&e.componentWillUpdate(f,p,m),e.props=f,e.state=p,e.context=m),e.prevProps=e.prevState=e.prevContext=e.nextBase=null,e._dirty=!1,!u){for(e.render&&(l=e.render(f,p,m)),e.getChildContext&&(m=r(o(m),e.getChildContext()));d(l);)l=h(l,m);var P,S,T=l&&l.nodeName;if(a(T)){var A=y(l);c=N,c&&c.constructor===T&&A.key==c.__key?U(c,A,1,m):(P=c,c=O(T,A,m),c.nextBase=c.nextBase||_,c._parentComponent=e,e._component=c,U(c,A,0,m),j(c,1,n,!0)),S=c.base}else s=C,P=N,P&&(s=e._component=null),(C||1===t)&&(s&&(s._component=null),S=k(s,l,m,n||!x,C&&C.parentNode,!0));if(C&&S!==C&&c!==N){var R=C.parentNode;R&&S!==R&&(R.replaceChild(S,C),P||(C._component=null,E(C)))}if(P&&I(P,S!==C),e.base=S,S&&!i){for(var W=e,D=e;D=D._parentComponent;)(W=D).base=S;S._component=W,S._componentConstructor=W.constructor}}!x||n?Q.unshift(e):u||(e.componentDidUpdate&&e.componentDidUpdate(v,b,g),M.afterUpdate&&M.afterUpdate(e));var L,V=e._renderCallbacks;if(V)for(;L=V.pop();)L.call(e);X||i||w()}}function R(e,t,n,r){for(var o=e&&e._component,i=o,a=e,u=o&&e._componentConstructor===t.nodeName,l=u,c=y(t);o&&!l&&(o=o._parentComponent);)l=o.constructor===t.nodeName;return o&&l&&(!r||o._component)?(U(o,c,3,n,r),e=o.base):(i&&!u&&(I(i,!0),e=a=null),o=O(t.nodeName,c,n),e&&!o.nextBase&&(o.nextBase=e,a=null),U(o,c,1,n,r),e=o.base,a&&e!==a&&(a._component=null,E(a))),e}function I(e,t){M.beforeUnmount&&M.beforeUnmount(e);var n=e.base;e._disable=!0,e.componentWillUnmount&&e.componentWillUnmount(),e.base=null;var r=e._component;if(r)I(r,t);else if(n){n[q]&&n[q].ref&&n[q].ref(null),e.nextBase=n,t&&(b(n),A(e));for(var o;o=n.lastChild;)E(o,!t)}e.__ref&&e.__ref(null),e.componentDidUnmount&&e.componentDidUnmount()}function W(e,t){this._dirty=!0,this.context=t,this.props=e,this.state||(this.state={})}function D(e,t,n){return k(n,e,{},!1,t)}var M={},L=[],V=[],z={},B=function(e){return z[e]||(z[e]=e.toLowerCase())},$="undefined"!=typeof Promise&&Promise.resolve(),G=$?function(e){$.then(e)}:setTimeout,H={},q="undefined"!=typeof Symbol?Symbol.for("preactattr"):"__preactattr_",F={boxFlex:1,boxFlexGroup:1,columnCount:1,fillOpacity:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,fontWeight:1,lineClamp:1,lineHeight:1,opacity:1,order:1,orphans:1,strokeOpacity:1,widows:1,zIndex:1,zoom:1},J={blur:1,error:1,focus:1,load:1,resize:1,scroll:1},Z=[],K={},Q=[],X=0,Y=!1,ee=!1,te={};r(W.prototype,{linkState:function(e,t){var n=this._linkedStates||(this._linkedStates={});return n[e+t]||(n[e+t]=s(this,e,t))},setState:function(e,t){var n=this.state;this.prevState||(this.prevState=o(n)),r(n,a(e)?e(n,this.props):e),t&&(this._renderCallbacks=this._renderCallbacks||[]).push(t),f(this)},forceUpdate:function(){j(this,2)},render:function(){}}),e.h=n,e.cloneElement=c,e.Component=W,e.render=D,e.rerender=p,e.options=M})}]);
--------------------------------------------------------------------------------
/src/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Header from './header/Header';
4 | import Cards from './cards/Cards';
5 | import './styles.scss';
6 |
7 | const App = () => (
8 |
9 |
10 |
11 |
12 | );
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/src/components/App.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import App from './App';
5 |
6 | test('Snapshot', () => {
7 | const component = renderer.create(
8 |
9 | );
10 | let tree = component.toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 |
--------------------------------------------------------------------------------
/src/components/__snapshots__/App.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Snapshot 1`] = `
4 |
5 |
8 |
11 |
12 |
16 |
17 |
18 | AgilePoker
19 |
20 |
21 |
22 |
25 |
28 |
31 |
35 |
36 | ?
37 |
38 |
39 |
43 |
44 | 0
45 |
46 |
47 |
51 |
52 | 1/2
53 |
54 |
55 |
59 |
60 | 1
61 |
62 |
63 |
67 |
68 | 2
69 |
70 |
71 |
75 |
76 | 3
77 |
78 |
79 |
83 |
84 | 5
85 |
86 |
87 |
91 |
92 | 8
93 |
94 |
95 |
99 |
100 | 13
101 |
102 |
103 |
107 |
108 | 21
109 |
110 |
111 |
115 |
116 | 34
117 |
118 |
119 |
123 |
124 | 55
125 |
126 |
127 |
128 |
129 |
130 |
131 | `;
132 |
--------------------------------------------------------------------------------
/src/components/card-item/CardItem.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable jsx-a11y/no-static-element-interactions */
2 |
3 | import React from 'react';
4 | import cx from 'classnames';
5 |
6 | import logo from '../../images/svgs/logo.svg';
7 | import back from '../../images/svgs/back.svg';
8 | import styles from './styles.scss';
9 |
10 | const onClick = (value, openedCard, toggleCard) => {
11 | if (openedCard) {
12 | return toggleCard(null);
13 | }
14 | return toggleCard(value);
15 | };
16 |
17 | const getContainerStyles = (openedCard) => {
18 | if (openedCard) {
19 | return cx(styles.container, styles.opened);
20 | }
21 | return styles.container;
22 | };
23 |
24 | const renderBrandLogo = (openedCard) => {
25 | if (openedCard) {
26 | return (
27 |
28 |
29 |
30 | );
31 | }
32 | return null;
33 | };
34 |
35 | const renderBackButton = (openedCard) => {
36 | if (openedCard) {
37 | return (
38 |
39 |
40 |
41 | );
42 | }
43 | return null;
44 | };
45 |
46 | const CardItem = ({ value, openedCard, toggleCard }) => (
47 | onClick(value, openedCard, toggleCard)}
49 | className={getContainerStyles(openedCard)}
50 | >
51 | {value}
52 | {renderBrandLogo(openedCard)}
53 | {renderBackButton(openedCard)}
54 |
55 | );
56 |
57 | CardItem.defaultProps = {
58 | openedCard: null,
59 | };
60 |
61 | CardItem.propTypes = {
62 | value: React.PropTypes.string.isRequired,
63 | openedCard: React.PropTypes.string,
64 | toggleCard: React.PropTypes.func.isRequired,
65 | };
66 |
67 | export default CardItem;
68 |
--------------------------------------------------------------------------------
/src/components/card-item/CardItem.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import CardItem from './CardItem';
5 |
6 | const props = {
7 | value: 'value',
8 | toggleCard: () => {},
9 | };
10 |
11 | test('Snapshot', () => {
12 | const component = renderer.create(
13 |
14 | );
15 | let tree = component.toJSON();
16 | expect(tree).toMatchSnapshot();
17 | });
18 |
--------------------------------------------------------------------------------
/src/components/card-item/__snapshots__/CardItem.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Snapshot 1`] = `
4 |
8 |
9 | value
10 |
11 |
12 | `;
13 |
--------------------------------------------------------------------------------
/src/components/card-item/styles.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | position: relative;
3 | display: inline-block;
4 | background-color: #fafafa;
5 | border-radius: 4px;
6 | width: 5em;
7 | height: 8em;
8 | cursor: pointer;
9 | margin: .4em;
10 | border: solid 1px rgba(41, 0, 68, 0.7);
11 | box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5);
12 | }
13 |
14 | .container:hover {
15 | opacity: 0.75;
16 | }
17 |
18 | .opened {
19 | width: 9.5em;
20 | height: 15em;
21 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.2);
22 | }
23 |
24 | .container > span {
25 | position: absolute;
26 | font-size: 2.5em;
27 | color: #2a0044;
28 | top: 50%;
29 | left: 50%;
30 | transform: translate(-50%, -60%);
31 | }
32 |
33 | .backButton {
34 | position: absolute;
35 | bottom: 0;
36 | left: -1.5em;
37 | }
38 |
39 | .brandLogo {
40 | position: absolute;
41 | margin: 0 auto;
42 | left: 0;
43 | right: 0;
44 | top: 11em;
45 | }
46 |
47 | .opened > span {
48 | font-size: 5.5em;
49 | font-weight: 300;
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/cards/Cards.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import CardItem from '../card-item/CardItem';
4 | import styles from './styles.scss';
5 |
6 | class Cards extends Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.state = {
11 | openedCard: null,
12 | };
13 |
14 | this.cards = [
15 | '?', '0', '1/2', '1', '2', '3', '5', '8', '13', '21', '34', '55',
16 | ];
17 |
18 | this.toggleCard = this.toggleCard.bind(this);
19 | this.renderCards = this.renderCards.bind(this);
20 | }
21 |
22 | toggleCard(card) {
23 | this.setState({ openedCard: card });
24 | }
25 |
26 | renderCards() {
27 | if (this.state.openedCard) {
28 | return (
29 |
30 |
35 |
36 |
If there is no struggle,
37 |
there is no progress.
38 |
39 |
40 | );
41 | }
42 | return this.cards.map(card =>
43 | ,
49 | );
50 | }
51 |
52 | render() {
53 | const animationStyles = this.state.openedCard ?
54 | styles.opened : styles.closed;
55 |
56 | return (
57 |
58 |
59 |
60 | {this.renderCards()}
61 |
62 |
63 |
64 | );
65 | }
66 | }
67 |
68 | export default Cards;
69 |
--------------------------------------------------------------------------------
/src/components/cards/Cards.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import Cards from './Cards';
5 |
6 | test('Snapshot', () => {
7 | const component = renderer.create(
8 |
9 | );
10 | let tree = component.toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 |
--------------------------------------------------------------------------------
/src/components/cards/__snapshots__/Cards.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Snapshot 1`] = `
4 |
7 |
10 |
13 |
17 |
18 | ?
19 |
20 |
21 |
25 |
26 | 0
27 |
28 |
29 |
33 |
34 | 1/2
35 |
36 |
37 |
41 |
42 | 1
43 |
44 |
45 |
49 |
50 | 2
51 |
52 |
53 |
57 |
58 | 3
59 |
60 |
61 |
65 |
66 | 5
67 |
68 |
69 |
73 |
74 | 8
75 |
76 |
77 |
81 |
82 | 13
83 |
84 |
85 |
89 |
90 | 21
91 |
92 |
93 |
97 |
98 | 34
99 |
100 |
101 |
105 |
106 | 55
107 |
108 |
109 |
110 |
111 |
112 | `;
113 |
--------------------------------------------------------------------------------
/src/components/cards/styles.scss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-flow: row wrap;
4 | max-width: 28em;
5 | padding: 3em 0;
6 | margin: 0 auto;
7 | animation: show .7s ease-in-out;
8 | }
9 |
10 | .content {
11 | margin: 2em;
12 | text-align: center;
13 | }
14 |
15 | .opened {
16 | animation: show 1s ease-in-out;
17 | }
18 |
19 | .closed {
20 | animation: hide 1s ease-in-out;
21 | }
22 |
23 | .card {
24 | position: absolute;
25 | top: 50%;
26 | left: 50%;
27 | transform: translate(-50%, -50%);
28 | }
29 |
30 | .quotes {
31 | position: relative;
32 | line-height: 0.5;
33 | width: 165px;
34 | margin: 0 auto;
35 | }
36 |
37 | .quotes > p {
38 | font-size: 14px;
39 | font-weight: bold;
40 | font-style: oblique;
41 | color: #2a0044;
42 | }
43 |
44 | .firstText {
45 | padding-top: 2em;
46 | }
47 |
48 | .firstText::before{
49 | position: absolute;
50 | left: -0.5em;
51 | top: 0.2em;
52 | content: "\201C";
53 | font-size: 60px;
54 | font-weight: bold;
55 | color: #999;
56 | }
57 |
58 | .firstText::after{
59 | content: "";
60 | }
61 |
62 | @keyframes show {
63 | 0% { opacity: 0; }
64 | 100% { opacity: 1; }
65 | }
66 |
67 | @keyframes hide {
68 | 0% { opacity: 0; }
69 | 100% { opacity: 1; }
70 | }
71 |
--------------------------------------------------------------------------------
/src/components/header/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import logo from '../../images/svgs/logo-white.svg';
4 | import styles from './styles.scss';
5 |
6 | const Header = () => (
7 |
8 |
9 |
10 |
11 |
12 |
AgilePoker
13 |
14 |
15 | );
16 |
17 | export default Header;
18 |
--------------------------------------------------------------------------------
/src/components/header/Header.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import Header from './Header';
5 |
6 | test('Snapshot', () => {
7 | const component = renderer.create(
8 |
9 | );
10 | let tree = component.toJSON();
11 | expect(tree).toMatchSnapshot();
12 | });
13 |
--------------------------------------------------------------------------------
/src/components/header/__snapshots__/Header.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Snapshot 1`] = `
4 |
7 |
10 |
11 |
15 |
16 |
17 | AgilePoker
18 |
19 |
20 |
21 | `;
22 |
--------------------------------------------------------------------------------
/src/components/header/styles.scss:
--------------------------------------------------------------------------------
1 | .header {
2 | position: fixed;
3 | background-color: #2a0044;
4 | height: 3.4em;
5 | box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.5);
6 | top: 0;
7 | left: 0;
8 | right: 0;
9 | width: 100%;
10 | z-index: 1;
11 | }
12 |
13 | .content {
14 | display: flex;
15 | justify-content: flex-start;
16 | align-items: center;
17 | }
18 |
19 | .content > figure {
20 | margin: 0 1em;
21 | float: left;
22 | }
23 |
24 | .content img {
25 | width: 2em;
26 | }
27 |
28 | .content > h1 {
29 | color: #fff;
30 | font-weight: 300;
31 | font-size: 1.4em;
32 | }
33 |
--------------------------------------------------------------------------------
/src/components/styles.scss:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #f0f0f0;
3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
4 | }
5 |
--------------------------------------------------------------------------------
/src/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/src/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/src/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/src/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/src/images/icons/icon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-384x384.png
--------------------------------------------------------------------------------
/src/images/icons/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-512x512.png
--------------------------------------------------------------------------------
/src/images/icons/icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-72x72.png
--------------------------------------------------------------------------------
/src/images/icons/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matheusml/pwa-planning-poker/77ecd2c63c62fd53d041d4d8b15a48d6d2bba7bb/src/images/icons/icon-96x96.png
--------------------------------------------------------------------------------
/src/images/svgs/back.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/images/svgs/logo-white.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/images/svgs/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import App from './components/App';
5 |
6 | ReactDOM.render(, document.getElementById('app')); // eslint-disable-line no-undef
7 |
--------------------------------------------------------------------------------
/sw.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | var CACHE_NAME = 'static-v1';
4 |
5 | self.addEventListener('install', function (event) {
6 | event.waitUntil(
7 | caches.open(CACHE_NAME).then(function (cache) {
8 | return cache.addAll([
9 | '/',
10 | '/index.html',
11 | '/styles.css',
12 | '/app.js',
13 | '/manifest.js',
14 | '/vendor.js',
15 | ]);
16 | })
17 | )
18 | });
19 |
20 | self.addEventListener('activate', function activator(event) {
21 | event.waitUntil(
22 | caches.keys().then(function (keys) {
23 | return Promise.all(keys
24 | .filter(function (key) {
25 | return key.indexOf(CACHE_NAME) !== 0;
26 | })
27 | .map(function (key) {
28 | return caches.delete(key);
29 | })
30 | );
31 | })
32 | );
33 | });
34 |
35 | self.addEventListener('fetch', function (event) {
36 | event.respondWith(
37 | caches.match(event.request).then(function (cachedResponse) {
38 | return cachedResponse || fetch(event.request);
39 | })
40 | );
41 | });
42 |
--------------------------------------------------------------------------------
/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import devConfig from './webpack.dev.config.babel.js';
4 | import prodConfig from './webpack.prod.config.babel.js';
5 |
6 | let config;
7 |
8 | switch (process.env.npm_lifecycle_event) {
9 | case 'build':
10 | config = prodConfig;
11 | break;
12 | default:
13 | config = devConfig;
14 | break;
15 | }
16 |
17 | module.exports = config;
18 |
--------------------------------------------------------------------------------
/webpack.dev.config.babel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ template: 'index.html' });
5 |
6 | module.exports = {
7 | entry: './src/index.js',
8 | output: {
9 | filename: 'bundle.js',
10 | },
11 | eslint: {
12 | configFile: './.eslintrc',
13 | },
14 | module: {
15 | preLoaders: [
16 | {
17 | test: /\.js$/,
18 | exclude: /node_modules/,
19 | loader: 'eslint-loader',
20 | },
21 | ],
22 | loaders: [
23 | {
24 | test: /\.js$/,
25 | exclude: /node_modules/,
26 | loader: 'babel',
27 | },
28 | {
29 | test: /\.scss$/,
30 | loader: 'style!css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
31 | },
32 | {
33 | test: /.(png|woff(2)?|eot|otf|ttf|svg)(\?[a-z0-9=\.]+)?$/,
34 | loader: 'url-loader?limit=100000',
35 | },
36 | ],
37 | },
38 | plugins: [HTMLWebpackPluginConfig],
39 | };
40 |
--------------------------------------------------------------------------------
/webpack.prod.config.babel.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable import/no-extraneous-dependencies */
2 |
3 | const webpack = require('webpack');
4 | const HtmlWebpackPlugin = require('html-webpack-plugin');
5 | const CleanWebpackPlugin = require('clean-webpack-plugin');
6 | const CopyWebpackPlugin = require('copy-webpack-plugin');
7 | const ExtractTextPlugin = require('extract-text-webpack-plugin');
8 |
9 | const DefinePlugin = new webpack.DefinePlugin({
10 | 'process.env': {
11 | NODE_ENV: JSON.stringify('production'),
12 | },
13 | });
14 | const CleanPlugin = new CleanWebpackPlugin(['public']);
15 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ template: 'index.html' });
16 | const UglifyPlugin = new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } });
17 | const DedupePlugin = new webpack.optimize.DedupePlugin();
18 | const CommonChunksPlugin = new webpack.optimize.CommonsChunkPlugin({ names: ['vendor', 'manifest'] });
19 |
20 | const CopyWebpackPluginConfig = new CopyWebpackPlugin([
21 | { from: 'manifest.json' },
22 | { from: 'favicon.ico' },
23 | { from: 'sw.js' },
24 | { from: 'src/images/icons', to: 'images' },
25 | ]);
26 |
27 | const ExtractText = new ExtractTextPlugin('styles.css');
28 |
29 | module.exports = {
30 | entry: {
31 | vendor: ['react', 'react-dom'],
32 | app: './src/index.js',
33 | },
34 | output: {
35 | path: 'public',
36 | filename: '[name].js',
37 | },
38 | resolve: {
39 | alias: {
40 | react: 'preact-compat',
41 | 'react-dom': 'preact-compat',
42 | },
43 | },
44 | module: {
45 | loaders: [
46 | {
47 | test: /\.js$/,
48 | exclude: /node_modules/,
49 | loader: 'babel',
50 | },
51 | {
52 | test: /\.scss$/,
53 | loader: ExtractText.extract(
54 | 'style',
55 | 'css?modules&importLoaders=1&localIdentName=[hash:base64:5]',
56 | ),
57 | },
58 | {
59 | test: /.(png|woff(2)?|eot|otf|ttf|svg)(\?[a-z0-9=\.]+)?$/,
60 | loader: 'url-loader?limit=100000',
61 | },
62 | ],
63 | },
64 | plugins: [CleanPlugin, DefinePlugin, HTMLWebpackPluginConfig, UglifyPlugin, DedupePlugin,
65 | ExtractText, CopyWebpackPluginConfig, CommonChunksPlugin],
66 | };
67 |
--------------------------------------------------------------------------------