├── .audit
└── README.md
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── LICENSE
└── images
│ └── pwafireappreport.png
├── .gitignore
├── LICENSE
├── README.md
├── README1.md
├── _config.yml
├── app
├── .firebaserc
├── .gitignore
├── firebase.json
├── firestore.indexes.json
├── firestore.rules
├── functions
│ ├── .eslintrc.json
│ ├── index.js
│ ├── package-lock.json
│ └── package.json
├── package-lock.json
├── package.json
├── server.js
├── service-worker-config.js
└── src
│ ├── 404.html
│ ├── add-article
│ └── index.html
│ ├── app.webmanifest
│ ├── assets
│ ├── css
│ │ ├── article.css
│ │ ├── auth.css
│ │ └── main.css
│ └── js
│ │ ├── addfirestore.js
│ │ ├── app.js
│ │ ├── article.js
│ │ ├── auth.js
│ │ ├── display.js
│ │ ├── login.js
│ │ ├── render.js
│ │ ├── sync.js
│ │ ├── test.js
│ │ ├── update.js
│ │ └── view.js
│ ├── auth
│ └── index.html
│ ├── images
│ ├── banners
│ │ └── pwafireappbanner.gif
│ ├── home
│ │ ├── pwafireapp-frog-icon.svg
│ │ └── pwafireapp-frog-icon1.gif
│ ├── icons
│ │ ├── icon-128x128.png
│ │ ├── icon-144x144.png
│ │ ├── icon-152x152.png
│ │ ├── icon-192x192.png
│ │ ├── icon-384x384.png
│ │ ├── icon-48x48.png
│ │ ├── icon-512x512.png
│ │ ├── icon-72x72.png
│ │ └── icon-96x96.png
│ ├── others
│ │ ├── latest.svg
│ │ ├── pwafireapp.svg
│ │ ├── pwafireapp1.svg
│ │ ├── round-hot_tub-24px.svg
│ │ └── round-trending_up-24px.svg
│ ├── pwafireapp-frog-icon.gif
│ ├── pwafireapp.svg
│ ├── sample.gif
│ ├── sample.jpg
│ ├── sample.png
│ ├── sample.svg
│ └── vectors
│ │ └── pwafireappbanner.psd
│ ├── index.html
│ ├── latest
│ ├── index.html
│ └── sport1.html
│ ├── profile
│ ├── index.html
│ └── share.html
│ └── service-worker.js
└── docs
└── README.md
/.audit/README.md:
--------------------------------------------------------------------------------
1 |
2 | ### [100% Audit Pass]()
3 |
4 | 
5 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | app/src/index.html/* linguist-vendored
2 | app/src/pages/index.html/* linguist-vendored
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 PWAFire.Org
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/images/pwafireappreport.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/.github/images/pwafireappreport.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.cache
3 | build/
4 | *.log
5 | app/node_modules/
6 | app/src/assets/js/firestore.js
7 | functions/
8 | %RESOURCE_DIR%/
9 | *.rules
10 | *.rules
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 PWAFire.Org
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## We are creating a new version
2 |
3 | Check the [codelab available here](https://pwafire.org/developer/codelabs/get-started-with-pwafireapp/) to use the previous version of the sample app
4 |
--------------------------------------------------------------------------------
/README1.md:
--------------------------------------------------------------------------------
1 | ### [PWA Fire App *Beta*](https://pwafire.org/developer/app/)
2 |
3 | Project [PWA Fire Bundle](https://github.com/mayeedwin/pwafire) is an open source javascript and json bundle that allows you to convert your existing website into a progressive web app or build one in a few.
4 |
5 | ***
6 |
7 | ### [What is PWA Fire App?](https://github.com/mayeedwin/pwafireapp)
8 |
9 | Progressive Web App starter App designed with [progressive web app best practices](https://developers.google.com/web/progressive-web-apps/checklist) and packaged ready for your [PWA Project](https://pwafire.org/developer/app/)
10 |
11 | It has two versions;
12 |
13 | 1. For project with build process, npm ; [as in this guide here](https://github.com/mayeedwin/pwafireapp/tree/master/docs)
14 |
15 | 2. For project without any build process; [config guide is here](https://pwafire.org/developer/pwa/started/)
16 |
17 | - [PWA Fire App Demo App](https://pwafireapp.firebaseapp.com/) has a 100% Audit Pass for Progressive Web App, Best Practices, Perfomance, Accessbility and SEO as shown in the [.audit dir here](https://github.com/mayeedwin/pwafireapp/tree/master/.audit)
18 |
19 | ***
20 |
21 | ### [App Structure]()
22 |
23 | Here is the basic skeleton for **PWA Fire App** that each of the two starter PWA Kits will conform to:
24 |
25 | - [ ] **For node-module or build process**
26 |
27 | For **node modules,** follow the setup guide as curated in [the doc folder here](https://github.com/mayeedwin/pwafireapp/tree/master/docs) to get started building a scalable progressive web app with **PWA Fire App.**
28 |
29 | ```b
30 | ├── app
31 | │ ├── build
32 | │ ├── node_modules
33 | │ ├── src
34 | │ ├── assets
35 | | ├── css
36 | | ├── js
37 | | ├── scss
38 | │ ├── images
39 | | ├── icons
40 | | ├── others
41 | | ├── pages
42 | │ ├── index.html
43 | │ ├── app.webmanifest
44 | │ ├── service-worker.js
45 | │ ├── package-lock.json
46 | │ ├── package.json
47 | │ ├── server.js
48 | │ └── sw-config.js
49 |
50 | ```
51 |
52 | - [ ] **For without any build process like npm**
53 |
54 | If you do not have or do not want to use any build process such as ** npm**, make sure to
55 | remove all other files and that your app structure looks as below. Configure your **service-worker.js**
56 | file as in [this codelab here](https://pwafire.org/developer/pwa/started/#sw-config)
57 |
58 | ```bash
59 | ├── app
60 | │ ├── src
61 | │ ├── assets
62 | | ├── css
63 | | ├── js
64 | | ├── scss
65 | │ ├── images
66 | | ├── icons
67 | | ├── others
68 | | ├── pages
69 | │ ├── index.html
70 | │ ├── app.webmanifest
71 | │ ├── service-worker.js
72 |
73 | ```
74 |
75 | ***
76 |
77 | #### [Getting started](https://pwafire.org/developer/codelabs/cloud-firestore-for-web)
78 | Get started on how to set up PWA Fire App [ in this setup guide ](https://github.com/mayeedwin/pwafireapp/tree/master/docs).
79 |
80 | ***
81 |
82 | #### [Engage us](https://twitter.com/pwafire)
83 | Donate a star, like, follow and contribute in any way. If you use [PWA Fire Developer Resources](https://pwafire.org/developer), kindly let us know. JUST simply [Tweet us](https://twitter.com/pwafire).
84 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/app/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "pwafireapp"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 |
9 | # Firebase cache
10 | .firebase/
11 |
12 | # Firebase config
13 |
14 | # Uncomment this if you'd like others to create their own Firebase project.
15 | # For a team working on the same Firebase project(s), it is recommended to leave
16 | # it commented so all members can deploy to the same project(s) in .firebaserc.
17 | # .firebaserc
18 |
19 | # Runtime data
20 | pids
21 | *.pid
22 | *.seed
23 | *.pid.lock
24 |
25 | # Directory for instrumented libs generated by jscoverage/JSCover
26 | lib-cov
27 |
28 | # Coverage directory used by tools like istanbul
29 | coverage
30 |
31 | # nyc test coverage
32 | .nyc_output
33 |
34 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
35 | .grunt
36 |
37 | # Bower dependency directory (https://bower.io/)
38 | bower_components
39 |
40 | # node-waf configuration
41 | .lock-wscript
42 |
43 | # Compiled binary addons (http://nodejs.org/api/addons.html)
44 | build/Release
45 |
46 | # Dependency directories
47 | node_modules/
48 |
49 | # Optional npm cache directory
50 | .npm
51 |
52 | # Optional eslint cache
53 | .eslintcache
54 |
55 | # Optional REPL history
56 | .node_repl_history
57 |
58 | # Output of 'npm pack'
59 | *.tgz
60 |
61 | # Yarn Integrity file
62 | .yarn-integrity
63 |
64 | # dotenv environment variables file
65 | .env
66 |
--------------------------------------------------------------------------------
/app/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ]
9 | },
10 | "firestore": {
11 | "rules": "firestore.rules",
12 | "indexes": "firestore.indexes.json"
13 | },
14 | "functions": {
15 | "predeploy": [
16 | "npm --prefix \"%RESOURCE_DIR%\" run lint"
17 | ],
18 | "source": "functions"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/firestore.indexes.json:
--------------------------------------------------------------------------------
1 | {
2 | "indexes": [],
3 | "fieldOverrides": []
4 | }
5 |
--------------------------------------------------------------------------------
/app/firestore.rules:
--------------------------------------------------------------------------------
1 | // Allow read/write access on all documents to any user signed in to the application
2 | service cloud.firestore {
3 | match /databases/{database}/documents {
4 | match /{document=**} {
5 | allow write: if request.auth.uid != null;
6 | allow read;
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/app/functions/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "parserOptions": {
3 | // Required for certain syntax usages
4 | "ecmaVersion": 6
5 | },
6 | "plugins": [
7 | "promise"
8 | ],
9 | "extends": "eslint:recommended",
10 | "rules": {
11 | // Removed rule "disallow the use of console" from recommended eslint rules
12 | "no-console": "off",
13 |
14 | // Removed rule "disallow multiple spaces in regular expressions" from recommended eslint rules
15 | "no-regex-spaces": "off",
16 |
17 | // Removed rule "disallow the use of debugger" from recommended eslint rules
18 | "no-debugger": "off",
19 |
20 | // Removed rule "disallow unused variables" from recommended eslint rules
21 | "no-unused-vars": "off",
22 |
23 | // Removed rule "disallow mixed spaces and tabs for indentation" from recommended eslint rules
24 | "no-mixed-spaces-and-tabs": "off",
25 |
26 | // Removed rule "disallow the use of undeclared variables unless mentioned in /*global */ comments" from recommended eslint rules
27 | "no-undef": "off",
28 |
29 | // Warn against template literal placeholder syntax in regular strings
30 | "no-template-curly-in-string": 1,
31 |
32 | // Warn if return statements do not either always or never specify values
33 | "consistent-return": 1,
34 |
35 | // Warn if no return statements in callbacks of array methods
36 | "array-callback-return": 1,
37 |
38 | // Require the use of === and !==
39 | "eqeqeq": 2,
40 |
41 | // Disallow the use of alert, confirm, and prompt
42 | "no-alert": 2,
43 |
44 | // Disallow the use of arguments.caller or arguments.callee
45 | "no-caller": 2,
46 |
47 | // Disallow null comparisons without type-checking operators
48 | "no-eq-null": 2,
49 |
50 | // Disallow the use of eval()
51 | "no-eval": 2,
52 |
53 | // Warn against extending native types
54 | "no-extend-native": 1,
55 |
56 | // Warn against unnecessary calls to .bind()
57 | "no-extra-bind": 1,
58 |
59 | // Warn against unnecessary labels
60 | "no-extra-label": 1,
61 |
62 | // Disallow leading or trailing decimal points in numeric literals
63 | "no-floating-decimal": 2,
64 |
65 | // Warn against shorthand type conversions
66 | "no-implicit-coercion": 1,
67 |
68 | // Warn against function declarations and expressions inside loop statements
69 | "no-loop-func": 1,
70 |
71 | // Disallow new operators with the Function object
72 | "no-new-func": 2,
73 |
74 | // Warn against new operators with the String, Number, and Boolean objects
75 | "no-new-wrappers": 1,
76 |
77 | // Disallow throwing literals as exceptions
78 | "no-throw-literal": 2,
79 |
80 | // Require using Error objects as Promise rejection reasons
81 | "prefer-promise-reject-errors": 2,
82 |
83 | // Enforce “for” loop update clause moving the counter in the right direction
84 | "for-direction": 2,
85 |
86 | // Enforce return statements in getters
87 | "getter-return": 2,
88 |
89 | // Disallow await inside of loops
90 | "no-await-in-loop": 2,
91 |
92 | // Disallow comparing against -0
93 | "no-compare-neg-zero": 2,
94 |
95 | // Warn against catch clause parameters from shadowing variables in the outer scope
96 | "no-catch-shadow": 1,
97 |
98 | // Disallow identifiers from shadowing restricted names
99 | "no-shadow-restricted-names": 2,
100 |
101 | // Enforce return statements in callbacks of array methods
102 | "callback-return": 2,
103 |
104 | // Require error handling in callbacks
105 | "handle-callback-err": 2,
106 |
107 | // Warn against string concatenation with __dirname and __filename
108 | "no-path-concat": 1,
109 |
110 | // Prefer using arrow functions for callbacks
111 | "prefer-arrow-callback": 1,
112 |
113 | // Return inside each then() to create readable and reusable Promise chains.
114 | // Forces developers to return console logs and http calls in promises.
115 | "promise/always-return": 2,
116 |
117 | //Enforces the use of catch() on un-returned promises
118 | "promise/catch-or-return": 2,
119 |
120 | // Warn against nested then() or catch() statements
121 | "promise/no-nesting": 1
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/app/functions/index.js:
--------------------------------------------------------------------------------
1 | const functions = require('firebase-functions');
2 | const admin = require('firebase-admin');
3 |
4 | admin.initializeApp();
5 | const db = admin.firestore();
6 |
7 | // // Create and Deploy Your First Cloud Functions
8 | // // https://firebase.google.com/docs/functions/write-firebase-functions
9 | //
10 | // exports.helloWorld = functions.https.onRequest((request, response) => {
11 | // response.send("Hello from Firebase!");
12 | // });
13 |
14 | const addUser = (userData, context) => {
15 | return db.collection('users').doc(userData.uid).set({
16 | email: userData.email,
17 | displayName: userData.displayName,
18 | }).catch(console.error);
19 | };
20 |
21 | module.exports = {
22 | authOnCreate: functions.auth.user().onCreate(addUser),
23 | };
24 |
--------------------------------------------------------------------------------
/app/functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "description": "Cloud Functions for Firebase",
4 | "scripts": {
5 | "lint": "eslint .",
6 | "serve": "firebase serve --only functions",
7 | "shell": "firebase functions:shell",
8 | "start": "npm run shell",
9 | "deploy": "firebase deploy --only functions",
10 | "logs": "firebase functions:log"
11 | },
12 | "dependencies": {
13 | "firebase-admin": "~6.0.0",
14 | "firebase-functions": "^2.1.0"
15 | },
16 | "devDependencies": {
17 | "eslint": "^4.12.0",
18 | "eslint-plugin-promise": "^3.6.0"
19 | },
20 | "private": true
21 | }
22 |
--------------------------------------------------------------------------------
/app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Maye Edwin",
3 | "scripts": {
4 | "copy": "copyfiles -u 1 src/**/**/* src/**/* src/* build",
5 | "build": "npm run copy && workbox injectManifest service-worker-config.js",
6 | "start": "node server.js"
7 | },
8 | "dependencies": {
9 | "express": "^4.15.4"
10 | },
11 | "devDependencies": {
12 | "copyfiles": "^1.2.0",
13 | "workbox-cli": "^4.0.0"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/server.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google Inc.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 | */
8 | const express = require('express');
9 | const app = express();
10 |
11 | // This serves static files from the specified directory
12 | app.use(express.static(__dirname + '/build'));
13 |
14 | const server = app.listen(8081, () => {
15 |
16 | const host = server.address().address;
17 | const port = server.address().port;
18 |
19 | console.log('App listening at http://%s:%s', host, port);
20 | });
21 |
--------------------------------------------------------------------------------
/app/service-worker-config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | /* The base directory you wish to match globPatterns against,
3 | relative to the current working directory
4 | */
5 | "globDirectory": "build/",
6 | "globPatterns": [
7 | /* Edit to add all file to pre-cache; configure for your project as shown below
8 | e.g cache all .css files in the root folder
9 | */
10 | "index.html",
11 | "app.webmanifest",
12 | "images/home/*.gif",
13 | // Pre-cache the default app icon needed for app installation
14 | "images/icons/icon-144x144.png",
15 | // Pre-cache app assets i.e css, scss, js
16 | "assets/js/*.js",
17 | "assets/css/*.css"
18 | ],
19 | /* The path and filename of the service worker file that will
20 | be created by the build process
21 | */
22 | "swSrc": "src/service-worker.js",
23 | /* The path to the source service worker file that can contain
24 | your own customized code e.g cache strategies for different app resources
25 | */
26 | "swDest": "build/service-worker.js",
27 | /* In addition to containing a match for
28 | injectionPointRegexp
29 | */
30 | "globIgnores": [
31 | "../service-worker-config.js"
32 | ]
33 | };
--------------------------------------------------------------------------------
/app/src/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Page Not Found
7 |
8 |
23 |
24 |
25 |
26 |
404
27 |
Page Not Found
28 |
The specified file was not found on this app. Please check the URL for mistakes and try again.
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/add-article/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | PWA Fire App - Latest Progressive Web Apps News
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
41 |
42 |
43 |
44 |
47 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
67 |
68 |
75 |
76 |
97 |
98 |
101 |
102 |
103 | Share
104 |
105 |
106 | Install
107 |
108 |
109 |
110 |
111 |
117 |
118 |
119 | This page must be served over HTTPS. Please reload this page via HTTPS .
120 |
121 |
122 |
123 |
124 |
127 |
128 |
130 |
131 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/app/src/app.webmanifest:
--------------------------------------------------------------------------------
1 | {
2 | "background_color": "#fff",
3 | "display": "standalone",
4 | "orientation":"portrait",
5 | "theme_color": "#fff",
6 | "short_name": "PWA Fire App",
7 | "name": "PWA Fire App",
8 | "description": "description or purpose of your progressive web app",
9 | "lang": "en-US",
10 | "share_target": {
11 | "action": "index.html",
12 | "params": {
13 | "title": "title",
14 | "text": "text",
15 | "url": "url"
16 | }
17 | },
18 | "icons": [
19 | {
20 | "src": "images/icons/icon-72x72.png",
21 | "sizes": "72x72",
22 | "type": "image/png"
23 | },
24 | {
25 | "src": "images/icons/icon-96x96.png",
26 | "sizes": "96x96",
27 | "type": "image/png"
28 | },
29 | {
30 | "src": "images/icons/icon-128x128.png",
31 | "sizes": "128x128",
32 | "type": "image/png"
33 | },
34 | {
35 | "src": "images/icons/icon-144x144.png",
36 | "sizes": "144x144",
37 | "type": "image/png"
38 | },
39 | {
40 | "src": "images/icons/icon-152x152.png",
41 | "sizes": "152x152",
42 | "type": "image/png"
43 | },
44 | {
45 | "src": "images/icons/icon-192x192.png",
46 | "sizes": "192x192",
47 | "type": "image/png"
48 | },
49 | {
50 | "src": "images/icons/icon-384x384.png",
51 | "sizes": "384x384",
52 | "type": "image/png"
53 | },
54 | {
55 | "src": "images/icons/icon-512x512.png",
56 | "sizes": "512x512",
57 | "type": "image/png"
58 | }
59 | ],
60 | "start_url": "index.html?launcher=true",
61 | "scope": "/"
62 | }
--------------------------------------------------------------------------------
/app/src/assets/css/article.css:
--------------------------------------------------------------------------------
1 | /* add some
2 | styles
3 | */
4 | form {
5 | margin-top: 10px;
6 | }
7 |
8 | .row {
9 | margin: 25px 0; /* need some nice spacing here */
10 | position: relative; /* this one is important */
11 | }
12 |
13 | /*make label absolute and position it on input area*/
14 | label {
15 | font-size: 13px;
16 | position: absolute;
17 | top: 15px;
18 | left: 2px;
19 | -webkit-transition: .1s;
20 | -o-transition: .1s;
21 | transition: .1s;
22 | }
23 |
24 | input {
25 | padding: 10px 0 10px;
26 | width: 100%;
27 | border: none;
28 | border-bottom: 1px solid #34495e;
29 | font-size: 13px;
30 | background: #ecf0f1;
31 | text-align: center;
32 | }
33 |
34 | /*magic happens here */
35 | input:focus{
36 | outline: none;
37 | border-color: #2980b9;
38 | }
39 |
40 | input:valid ~ label, /*detects if input has valid input*/
41 | input:focus ~ label{
42 | top: -20px;
43 | font-weight: 0;
44 | }
45 |
46 |
47 | .submitButton {
48 | background-color: inherit;
49 | border: 1px solid #c7c0c0;
50 | font-size: 1em;
51 | padding: 0.60em;
52 | border-radius: 25px;
53 | width: 150px;
54 | }
--------------------------------------------------------------------------------
/app/src/assets/css/auth.css:
--------------------------------------------------------------------------------
1 |
2 | .auth
3 |
4 | {
5 | margin: 250px auto;
6 |
7 | }
8 |
9 | .firebaseui-tos {
10 | color: #757575;
11 | direction: ltr;
12 | font-size: 13px;
13 | line-height: 16px;
14 | margin-bottom: 24px;
15 | margin-top: 0;
16 | text-align: left;
17 | }
18 |
19 | .firebaseui-idp-button {
20 | direction: ltr;
21 | font-weight: 500;
22 | height: auto;
23 | line-height: normal;
24 | max-width: 190px;
25 | min-height: 40px;
26 | padding: 8px 16px;
27 | text-align: center;
28 | width: 100%;
29 | border-radius: 25px;
30 | }
--------------------------------------------------------------------------------
/app/src/assets/css/main.css:
--------------------------------------------------------------------------------
1 | /** replace or + add your css**/
2 | @import url('https://fonts.googleapis.com/css?family=Roboto');
3 |
4 | body {
5 | display: block;
6 | margin: 0px;
7 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
8 | }
9 |
10 | .pwafireapp {
11 | height: 100%;
12 | min-height: 100%;
13 | }
14 |
15 | .navbar {
16 | display: flex;
17 | background: #fff;
18 | border-bottom: 0.75px solid #c7c0c0;
19 | padding: 15px;
20 | justify-content: center;
21 | position: fixed;
22 | flex-wrap: wrap;
23 | top: 0;
24 | left: 0;
25 | right: 0;
26 | z-index: 1000;
27 | }
28 |
29 | .main-div {
30 | min-height: 100%;
31 | width: 100%;
32 | display: flex;
33 | -webkit-box-pack: center;
34 | justify-content: center;
35 | -webkit-box-align: center;
36 | align-items: center;
37 | -webkit-box-orient: vertical;
38 | -webkit-box-direction: normal;
39 | -ms-flex-direction: column;
40 | flex-direction: column;
41 | text-align: center;
42 | }
43 |
44 | .app-logo {
45 | width: 50px;
46 | margin-top: 75px;
47 | }
48 |
49 | h3 {
50 | font-weight: 500;
51 | }
52 |
53 | #title {
54 | font-size: 18px;
55 | font-weight: 500;
56 | }
57 |
58 | #desc {
59 | text-align: center;
60 | text-decoration: wavy;
61 | text-rendering: optimizeSpeed;
62 | flood-color: rgb(49, 47, 47);
63 | }
64 |
65 | .hidden {
66 | display: none !important;
67 | }
68 |
69 | .share-par {
70 | display: none !important;
71 | }
72 |
73 | button[disabled] {
74 | opacity: 0.5;
75 | border: 1px solid rgba(74, 20, 140, 0.5) !important;
76 | }
77 |
78 | #installContainer {
79 | display: inline-flex;
80 | justify-content: center;
81 | width: 100%;
82 | margin-top: 25px;
83 | }
84 |
85 | #installContainer button {
86 | background-color: inherit;
87 | border: 1px solid #c7c0c0;
88 | font-size: 1em;
89 | padding: 0.60em;
90 | border-radius: 25px;
91 | width: 150px;
92 | }
93 |
94 | #customButton {
95 | background-color: inherit;
96 | border: 1px solid #c7c0c0;
97 | font-size: 0.75em;
98 | padding: 0.60em;
99 | border-radius: 25px;
100 | width: 100px;
101 | display: inline-block;
102 | margin: 7px;
103 | }
104 |
105 | #auth_in {
106 | background-color: inherit;
107 | border: 1px solid #c7c0c0;
108 | font-size: 0.75em;
109 | padding: 0.60em;
110 | border-radius: 25px;
111 | width: 100px;
112 | display: inline-block;
113 | margin: 7px;
114 | }
115 |
116 | *,
117 | ::after,
118 | ::before {
119 | box-sizing: unset;
120 | }
121 |
122 | /** set what happens on focus **/
123 | #customButton {
124 | outline: 0px dotted;
125 | color: rgb(49, 47, 47);
126 | outline: 0px auto -webkit-focus-ring-color;
127 | }
128 |
129 | #auth_in:focus {
130 | outline: 0px dotted;
131 | color: rgb(49, 47, 47);
132 | outline: 0px auto -webkit-focus-ring-color;
133 | }
134 |
135 |
136 | button:focus {
137 | outline: 0px dotted;
138 | color: rgb(49, 47, 47);
139 | outline: 0px auto -webkit-focus-ring-color;
140 | }
141 |
142 |
143 | a {
144 | text-decoration: none;
145 | }
146 |
147 | .navigate {
148 | display: flex;
149 | justify-content: center;
150 | width: 100%;
151 | }
152 |
153 | #buttonInstall {
154 | margin-left: 1em;
155 | }
156 |
157 |
158 | /* snackbar.css by
159 | https://pwafire.org/developer/ */
160 |
161 | /* The snackbar - position it at the bottom and in the middle
162 | of the screen */
163 |
164 |
165 | #snackbar {
166 | visibility: hidden;
167 | background-color: rgb(68, 66, 66);
168 | color: #fff;
169 | text-align: center;
170 | border-radius: 7px;
171 | padding: 8px;
172 | z-index: 1;
173 | bottom: 30px;
174 | font-size: 14px;
175 | width: 295px;
176 | display: block;
177 | margin: 0 auto;
178 | }
179 |
180 |
181 | /* Show the snackbar when clicking on a button
182 | (class added with JavaScript) */
183 |
184 | #snackbar.show {
185 | visibility: visible;
186 | /* Show the snackbar */
187 |
188 | /* Add animation: Take 0.5 seconds to fade in and out the snackbar.
189 | However, delay the fade out process for 2.5 seconds */
190 |
191 | -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
192 | animation: fadein 0.5s, fadeout 0.5s 2.5s;
193 | text-align: center;
194 | }
195 |
196 | /* Animations to fade the snackbar in and out */
197 | @-webkit-keyframes fadein {
198 | from {
199 | bottom: 0;
200 | opacity: 0;
201 | }
202 |
203 | to {
204 | bottom: 30px;
205 | opacity: 1;
206 | }
207 | }
208 |
209 | @keyframes fadein {
210 | from {
211 | bottom: 0;
212 | opacity: 0;
213 | }
214 |
215 | to {
216 | bottom: 30px;
217 | opacity: 1;
218 | }
219 | }
220 |
221 | @-webkit-keyframes fadeout {
222 | from {
223 | bottom: 30px;
224 | opacity: 1;
225 | }
226 |
227 | to {
228 | bottom: 0;
229 | opacity: 0;
230 | }
231 | }
232 |
233 | @keyframes fadeout {
234 | from {
235 | bottom: 30px;
236 | opacity: 1;
237 | }
238 |
239 | to {
240 | bottom: 0;
241 | opacity: 0;
242 | }
243 | }
244 |
245 | .footer {
246 | display: block;
247 | background: inherit;
248 | border-bottom: 0.50px solid #c7c0c0;
249 | padding: 10px;
250 | text-align: center;
251 | font-size: 12px;
252 | }
253 |
254 | .latest-news {
255 | align-items: center;
256 | text-align: left;
257 | margin: auto;
258 | padding-left: 10px;
259 | padding-right: 10px;
260 | overflow-y: scroll;
261 | height: 225px;
262 | border-radius: 10px;
263 | width: 75%;
264 | }
265 |
266 | .post-article {
267 | padding-left: 20px;
268 | padding-right: 20px;
269 | width: 75%;
270 | margin: 0 auto;
271 | }
272 |
273 | /* Portrait and Landscape */
274 | @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) {
275 | .main-div {
276 | margin: 0 auto;
277 | text-align: center;
278 | width: auto;
279 | padding-left: 20px;
280 | padding-right: 20px;
281 | }
282 |
283 | .latest-news {
284 | width: auto;
285 | margin: 10px;
286 | height: 250px;
287 | }
288 |
289 | .desktop {
290 | display: none;
291 | }
292 |
293 | .mobile {
294 | display: block;
295 | }
296 |
297 | .post-article {
298 | width: auto;
299 | }
300 | }
301 |
302 | .mobile {
303 | display: none;
304 | }
305 |
306 | /* Portrait and Landscape */
307 | @media only screen and (-Webkit-min-device-pixel-ratio:1.5),
308 | only screen and (-moz-min-device-pixel-ratio:1.5),
309 | only screen and (min-device-pixel-ratio:1.5) {
310 |
311 | .main-div {
312 | margin: 0 auto;
313 | text-align: center;
314 | width: auto;
315 | padding-left: 5px;
316 | padding-right: 5px;
317 | }
318 |
319 | .header-intro {
320 | padding: 5px;
321 | display: block;
322 |
323 | }
324 |
325 | .latest-news {
326 | width: auto;
327 | margin: 10px;
328 | height: 250px;
329 | }
330 |
331 | .desktop {
332 | display: none;
333 | }
334 |
335 | .mobile {
336 | display: block;
337 | }
338 |
339 | #installContainer button {
340 | width: 120px;
341 | }
342 |
343 | #snackbar {
344 | width: auto;
345 | }
346 |
347 | .post-article {
348 | width: auto;
349 | }
350 |
351 | }
352 |
353 | /* ----------- iPad 3, 4 and Pro 9.7" ----------- */
354 |
355 | /* Portrait and Landscape */
356 | @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) {
357 |
358 | .latest-news {
359 | margin-left: 75px;
360 | margin-right: 75px;
361 | }
362 |
363 | #snackbar {
364 | width: 350px;
365 | }
366 |
367 | }
368 |
369 |
370 | .latest-news h2 {
371 | font-size: 15px;
372 | font-weight: 500;
373 | }
374 |
375 | .latest-news p {
376 | font-size: 13px;
377 | }
378 |
379 | article {
380 |
381 | border-bottom: 0.50px solid #c7c0c0;
382 |
383 | }
384 |
385 | /* Let's get this party started */
386 | ::-webkit-scrollbar {
387 | width: 7px;
388 | }
389 |
390 | /* track */
391 | ::-webkit-scrollbar-track {
392 | -webkit-border-radius: 10px;
393 | border-radius: 10px;
394 | }
395 |
396 | /* handle */
397 | ::-webkit-scrollbar-thumb {
398 | -webkit-border-radius: 10px;
399 | border-radius: 10px;
400 | background: rgba(113, 122, 116, 0.4);
401 | }
402 |
403 | ::-webkit-scrollbar-thumb:window-inactive {
404 | background: rgba(113, 122, 116, 0.4);
405 | }
--------------------------------------------------------------------------------
/app/src/assets/js/addfirestore.js:
--------------------------------------------------------------------------------
1 | // Initialize Firebase
2 | let config = {
3 | apiKey: "apiKey",
4 | authDomain: "authDomain",
5 | databaseURL: "databaseURL",
6 | projectId: "projectId",
7 | storageBucket: "storageBucket",
8 | messagingSenderId: "messagingSenderId"
9 | };
10 |
11 | firebase.initializeApp(config);
12 | let firestore = firebase.firestore();
13 | console.log("Cloud Firestore Loaded");
14 |
15 | var db = firebase.firestore();
16 |
17 | const timestamps = firebase.firestore();
18 | const settings = {
19 | timestampsInSnapshots: true
20 | };
21 | firestore.settings(settings);
22 |
23 | // Enable offline capabilities
24 | firebase.firestore().enablePersistence()
25 | .then(function() {
26 | // Initialize Cloud Firestore through firebase
27 | var db = firebase.firestore();
28 | })
29 | .catch(function(err) {
30 | if (err.code == 'failed-precondition') {
31 | // Multiple tabs open, persistence can only be enabled in one tab at a a time.
32 |
33 | } else if (err.code == 'unimplemented') {
34 | // The current browser does not support all of the
35 | // features required to enable persistence
36 | // ...
37 | }
38 | });
39 |
40 | /*
41 | var docRef = db.collection('rate').doc('feedback');
42 | // Update the timestamp field with the value from the server
43 | var updateTimestamp = docRef.update({
44 | timestamp: firebase.firestore.FieldValue.serverTimestamp()
45 | });
46 | console.log(updateTimestamp);
47 |
48 | */
49 |
--------------------------------------------------------------------------------
/app/src/assets/js/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | Your Javascript
3 | */
4 |
5 | console.log("I am a Beta version of PWA Fire App 🐹");
6 |
7 | const divResult = document.getElementById('result');
8 | const divInstall = document.getElementById('installContainer');
9 | const buttonInstall = document.getElementById('buttonInstall');
10 | const buttonShare = document.getElementById('buttonShare');
11 |
12 | window.addEventListener('beforeinstallprompt', (event) => {
13 | console.log('👍', 'beforeinstallprompt', event);
14 | // Stash the event so it can be triggered later.
15 | window.deferredPrompt = event;
16 | // Remove the 'hidden' class from the install button container
17 | buttonInstall.removeAttribute('disabled');
18 | });
19 |
20 | buttonInstall.addEventListener('click', () => {
21 | console.log('👍', 'buttonInstall-clicked');
22 | const promptEvent = window.deferredPrompt;
23 | if (!promptEvent) {
24 | // The deferred prompt isn't available.
25 | return;
26 | }
27 | // Show the install prompt.
28 | promptEvent.prompt();
29 | // Log the result
30 | promptEvent.userChoice.then((result) => {
31 | console.log('👍', 'userChoice', result);
32 | // Reset the deferred prompt variable, since
33 | // prompt() can only be called once.
34 | window.deferredPrompt = null;
35 | // Hide the install button.
36 | buttonInstall.setAttribute('disabled', true);
37 | });
38 | });
39 |
40 | window.addEventListener('appinstalled', (event) => {
41 | console.log('👍', 'app successfully installed', event);
42 | });
43 |
44 | if ('share' in navigator) {
45 | console.log('👍', 'navigator.share is supported');
46 | buttonShare.removeAttribute('disabled');
47 | buttonShare.addEventListener('click', (e) => {
48 | console.log('👍', 'buttonShare-clicked', e);
49 | e.preventDefault();
50 | const shareOpts = {
51 | title: 'PWA Fire App',
52 | text: 'Starter Web App Designed With Progressive Web App Best Practices And Packaged Ready For Your PWA Project #pwafireapp #pwafiredev #pwafire #pwa',
53 | url: 'https://pwafire.org/developer/app/',
54 | };
55 | navigator.share(shareOpts)
56 | .then((e) => {
57 | const msg = 'navigator.share succeeded.';
58 | divResult.textContent = msg;
59 | console.log('👍', msg, e);
60 | })
61 | .catch((err) => {
62 | const msg = 'navigator.share failed';
63 | divResult.textContent = `${msg}\n${JSON.stringify(err)}`;
64 | console.error('👎', msg, err);
65 | });
66 | });
67 | }
68 | else {
69 | console.warn('👎', 'navigator.share is not supported');
70 | // const divNotSup = document.getElementById('shareNotSupported');
71 | // divNotSup.classList.toggle('hidden', false);
72 |
73 | // Add the snackbar to show no support [2]
74 | document.getElementById("snackbar").innerHTML = "navigator.share is not supported in this browser";
75 | var snackbar = document.getElementById("snackbar");
76 | // Add the "show" class to div
77 | snackbar.className = "show";
78 | // After 5 seconds, remove the show class from div
79 | setTimeout(function(){ snackbar.className = snackbar.className.replace("show", ""); }, 3000);
80 | // divResult.classList.toggle('hidden', true);
81 | }
82 |
83 | /*
84 | * Warn the page must be served over HTTPS
85 | * The `beforeinstallprompt` event won't fire if the page is served over HTTP.
86 | * Installability requires a service worker with a fetch event handler, and
87 | * if the page isn't served over HTTPS, the service worker won't load.
88 |
89 | if (window.location.protocol === 'http:') {
90 | const requireHTTPS = document.getElementById('requireHTTPS');
91 | const link = requireHTTPS.querySelector('a');
92 | link.href = window.location.href.replace('http://', 'https://');
93 | requireHTTPS.classList.remove('hidden');
94 | }
95 |
96 |
97 | // add a new version update prompt for users
98 | self.addEventListener('message', (event) => {
99 | if (!event.data){
100 | return;
101 | }
102 |
103 | switch (event.data) {
104 | case 'skipWaiting':
105 | self.skipWaiting();
106 | break;
107 | default:
108 | // NOOP
109 | break;
110 | }
111 | });
112 |
113 | */
--------------------------------------------------------------------------------
/app/src/assets/js/article.js:
--------------------------------------------------------------------------------
1 |
2 | console.log("Loading Article");
3 | function postArticle()
4 | {
5 | var article_url = document.getElementById('article_url').value;
6 | var article_title = document.getElementById('article_title').value;
7 | var article_caption = document.getElementById('article_caption').value;
8 | console.log(article_url);
9 | console.log(article_title);
10 | console.log(article_caption);
11 |
12 | // Add a new document with a generated id.
13 | db.collection("posts").add({
14 | article_url: article_url,
15 | article_title: article_title,
16 | article_caption: article_caption
17 | })
18 |
19 | .then(function(docRef) {
20 | console.log("Document written with ID: ", docRef.id);
21 | })
22 | .catch(function(error) {
23 | console.error("Error adding document: ", error);
24 | });
25 |
26 | }
27 |
28 | // redirect to homepage on sending article_title
29 | document
30 | .getElementById("formRedirect")
31 | .addEventListener("submit", function(e) {
32 | e.preventDefault();
33 | window.location.href = "../latest";
34 | });
35 |
--------------------------------------------------------------------------------
/app/src/assets/js/auth.js:
--------------------------------------------------------------------------------
1 |
2 | // Initialize the FirebaseUI Widget using Firebase.
3 | var ui = new firebaseui.auth.AuthUI(firebase.auth());
4 |
5 | ui.start('#firebaseui-auth-container', {
6 | signInOptions: [
7 | // List of OAuth providers supported.
8 | firebase.auth.GoogleAuthProvider.PROVIDER_ID,
9 | firebase.auth.GithubAuthProvider.PROVIDER_ID,
10 | ],
11 | // Other config options...
12 | });
13 |
14 |
15 | firebase.auth().setPersistence(firebase.auth.Auth.Persistence.SESSION)
16 | .then(function() {
17 | // Existing and future Auth states are now persisted in the current
18 | // session only. Closing the window would clear any existing state even
19 | // if a user forgets to sign out.
20 | // ...
21 | // New sign-in will be persisted with session persistence.
22 | return firebase.auth.GoogleAuthProvider();
23 | })
24 | .catch(function(error) {
25 | // Handle Errors here.
26 | var errorCode = error.code;
27 | var errorMessage = error.message;
28 | });
29 |
30 | var uiConfig = {
31 | callbacks: {
32 | signInSuccessWithAuthResult: function(authResult, redirectUrl) {
33 | // User successfully signed in.
34 | // Return type determines whether we continue the redirect automatically
35 | // or whether we leave that to developer to handle.
36 | return true;
37 |
38 | },
39 | uiShown: function() {
40 | // The widget is rendered.
41 | // Hide the loader.
42 | document.getElementById('loader').style.display = 'none';
43 | }
44 | },
45 | // Will use popup for IDP Providers sign-in flow instead of the default, redirect.
46 | signInFlow: 'popup',
47 | signInSuccessUrl: '../add-article',
48 | signInOptions: [
49 | // Leave the lines as is for the providers you want to offer your users.
50 | firebase.auth.GoogleAuthProvider.PROVIDER_ID,
51 | firebase.auth.GithubAuthProvider.PROVIDER_ID,
52 | ],
53 | // Terms of service url.
54 | tosUrl: '../',
55 | // Privacy policy url.
56 | privacyPolicyUrl: '../'
57 | };
58 |
59 | // The start method will wait until the DOM is loaded.
60 | ui.start('#firebaseui-auth-container', uiConfig);
61 |
62 | firebase.auth().signOut().then(function() {
63 | // Sign-out successful.
64 | }).catch(function(error) {
65 | // An error happened.
66 | });
67 |
--------------------------------------------------------------------------------
/app/src/assets/js/display.js:
--------------------------------------------------------------------------------
1 | /*
2 | var postsRef;
3 | var postArticle;
4 | // Read firestore data from database in the posts collection
5 | db.collection("posts").get().then(function(querySnapshot) {
6 | querySnapshot.forEach(function(doc) {
7 | // doc.data() is never undefined for query doc snapshots
8 | console.log(doc.id, " => ", doc.data());
9 | const posts = doc.data();
10 | article_url.href = posts.article_url;
11 | article_title.innerText = posts.article_title;
12 | article_caption.innerText = posts.article_caption;
13 | });
14 | });
15 | */
16 |
17 | const cafeList = document.querySelector('#cafe-list');
18 |
19 | // create element and render cafe to the dom
20 | function renderCafe(doc) {
21 | let li = document.createElement('li');
22 | let article_title = document.createElement('span');
23 | let article_caption = document.createElement('span');
24 |
25 | li.setAttribute('data-id', doc.id);
26 | article_title.textContent = doc.data().article_title;
27 | article_caption.textContent = doc.data().article_caption;
28 |
29 | li.appendChild(article_title);
30 | li.appendChild(article_caption);
31 |
32 | cafeList.appendChild(li);
33 |
34 | }
35 |
36 | db.collection('posts').get().then((snapshot) => {
37 | snapshot.docs.forEach(doc => {
38 | console.log(doc.data());
39 | // call the render function
40 | renderCafe(doc);
41 | } ) ;
42 | });
43 |
44 |
--------------------------------------------------------------------------------
/app/src/assets/js/login.js:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | if logged in
4 | */
5 |
6 | firebase.auth().onAuthStateChanged(function(user) {
7 | if (user) {
8 |
9 | // Add the snackbar to show guide
10 | document.getElementById("snackbar").innerHTML = "Share an amazing trendy article : )";
11 | var snackbar = document.getElementById("snackbar");
12 |
13 | // Add the "show" class to div
14 | snackbar.className = "show";
15 |
16 | // After 5 seconds, remove the show class from div
17 | setTimeout(function(){ snackbar.className = snackbar.className.replace("show", ""); }, 5000);
18 |
19 | // Add user is logged in
20 | document.getElementById("auth_in").innerHTML = "Logged in : )";
21 | var auth_in = document.getElementById("auth_in");
22 |
23 | // Add the "show" class to div
24 | auth_in.className = "auth-in";
25 | // After 5 seconds, remove the auth-in class from div
26 | setTimeout(function(){ auth_in.className = auth_in.className.replace("auth_in", ""); });
27 |
28 | } else {
29 | // User is signed out.
30 | // ...
31 | console.log("You are signed out!");
32 | }
33 | // ...
34 | });
35 |
--------------------------------------------------------------------------------
/app/src/assets/js/render.js:
--------------------------------------------------------------------------------
1 |
2 | var render = function (template, node) {
3 |
4 | if (!node) return;
5 | node.innerHTML = template;
6 |
7 | };
8 |
9 | var template = 'Hello world! ';
10 | render(template, document.querySelector('#main'));
11 |
12 | /*
13 |
14 | var data = {
15 | animals:[
16 | {name: 'mouse'},
17 | {name: 'cat'},
18 | {name: 'bird'},
19 | {name: 'dog'}
20 | ]
21 | };
22 | var directive = {
23 | 'li':{
24 | 'animal<-animals':{ //for each entry in animales name the element 'animal'
25 | 'span': 'animal.name' //the dot selector, means the current node (here a LI)
26 | }
27 | }
28 | };
29 | $p( 'ul' ).render( data, directive );
30 | */
--------------------------------------------------------------------------------
/app/src/assets/js/sync.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | Copyright 2018 PWAFire.Org Authored. All Rights Reserved.
4 | **/
5 | (function (window) {
6 | 'use strict';
7 |
8 | // Add background sync on page load
9 |
10 | document.addEventListener("DOMContentLoaded", function() {
11 | window.registerBGSync();
12 | });
13 | //To register `BG Sync` and check 'push notification' support
14 | //Exposing `registerSync()` globally for only development purpose
15 | window.registerBGSync = function() {
16 | //If `serviceWorker` is registered and ready
17 | navigator.serviceWorker.ready
18 | .then(function (registration) {
19 | //Registering `background sync` event
20 | return registration.sync.register('Comments') //`Comments` is sync tag name
21 | .then(function (rs) {
22 | console.info('Background sync registered!');
23 | // bgSyncElement.classList.add('hide');
24 | // bgSyncTextElement.removeAttribute('hidden'); //Show registered text to user
25 | }, function () {
26 | console.error('Background sync registered failed.');
27 | });
28 |
29 | });
30 | }
31 | })(window);
32 |
--------------------------------------------------------------------------------
/app/src/assets/js/test.js:
--------------------------------------------------------------------------------
1 | const cafeList = document.querySelector('#cafe-list');
2 |
3 | // create element and render cafe to the dom
4 | function renderCafe(doc) {
5 | let li = document.createElement('li');
6 | let article_title = document.createElement('span');
7 | let article_caption = document.createElement('span');
8 |
9 | li.setAttribute('data-id', doc.id);
10 | article_title.textContent = doc.data().article_title;
11 | article_caption.textContent = doc.data().article_caption;
12 |
13 | li.appendChild(article_title);
14 | li.appendChild(article_caption);
15 |
16 | cafeList.appendChild(li);
17 |
18 | }
19 |
20 | db.collection('posts').get().then((snapshot) => {
21 | snapshot.docs.forEach(doc => {
22 | console.log(doc.data());
23 | // call the render function
24 | renderCafe(doc);
25 | } ) ;
26 | });
27 |
--------------------------------------------------------------------------------
/app/src/assets/js/update.js:
--------------------------------------------------------------------------------
1 | function showRefreshUI(registration) {
2 | // TODO: Display a toast or refresh UI.
3 |
4 | // This demo creates and injects a button.
5 |
6 | var button = document.createElement('button');
7 | button.style.position = 'absolute';
8 | button.style.bottom = '24px';
9 | button.style.left = '24px';
10 | button.textContent = 'This site has updated. Please click to see changes.';
11 |
12 | button.addEventListener('click', function() {
13 | if (!registration.waiting) {
14 | // Just to ensure registration.waiting is available before
15 | // calling postMessage()
16 | return;
17 | }
18 |
19 | button.disabled = true;
20 |
21 | registration.waiting.postMessage('skipWaiting');
22 | });
23 |
24 | document.body.appendChild(button);
25 | }
26 |
27 | function onNewServiceWorker(registration, callback) {
28 | if (registration.waiting) {
29 | // service-worker is waiting to activate. Can occur if multiple clients open and
30 | // one of the clients is refreshed.
31 | return callback();
32 | }
33 |
34 | function listenInstalledStateChange() {
35 | registration.installing.addEventListener('statechange', function(event) {
36 | if (event.target.state === 'installed') {
37 | // A new service worker is available, inform the user
38 | callback();
39 | }
40 | });
41 | }
42 |
43 | if (registration.installing) {
44 | return listenInstalledStateChange();
45 | }
46 |
47 | // We are currently controlled so a new service-worker may be found...
48 | // Add a listener in case a new service-worker is found,
49 | registration.addEventListener('updatefound', listenInstalledStateChange);
50 | }
51 |
52 | window.addEventListener('load', function() {
53 | navigator.serviceWorker.register('../../service-worker.js')
54 | .then(function (registration) {
55 | // Track updates to the Service Worker.
56 | if (!navigator.serviceWorker.controller) {
57 | // The window client isn't currently controlled so it's a new service
58 | // worker that will activate immediately
59 | return;
60 | }
61 |
62 | // When the user asks to refresh the UI, we'll need to reload the window
63 | var preventDevToolsReloadLoop;
64 | navigator.serviceWorker.addEventListener('controllerchange', function(event) {
65 | // Ensure refresh is only called once.
66 | // This works around a bug in "force update on reload".
67 | if (preventDevToolsReloadLoop) return;
68 | preventDevToolsReloadLoop = true;
69 | console.log('Controller loaded');
70 | window.location.reload();
71 | });
72 |
73 | onNewServiceWorker(registration, function() {
74 | showRefreshUI(registration);
75 | });
76 | });
77 | });
--------------------------------------------------------------------------------
/app/src/assets/js/view.js:
--------------------------------------------------------------------------------
1 | // Display data into our web app
2 | const article_title=document.querySelector("#article_title");
3 | const article_caption=document.querySelector("#article_caption");
4 |
--------------------------------------------------------------------------------
/app/src/auth/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Latest PWA News : Authentication
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/images/banners/pwafireappbanner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/banners/pwafireappbanner.gif
--------------------------------------------------------------------------------
/app/src/images/home/pwafireapp-frog-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/home/pwafireapp-frog-icon1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/home/pwafireapp-frog-icon1.gif
--------------------------------------------------------------------------------
/app/src/images/icons/icon-128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-128x128.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-144x144.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-152x152.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-192x192.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-384x384.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-384x384.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-48x48.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-512x512.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-72x72.png
--------------------------------------------------------------------------------
/app/src/images/icons/icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/icons/icon-96x96.png
--------------------------------------------------------------------------------
/app/src/images/others/latest.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/others/pwafireapp.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/others/pwafireapp1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/others/round-hot_tub-24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/others/round-trending_up-24px.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/pwafireapp-frog-icon.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/pwafireapp-frog-icon.gif
--------------------------------------------------------------------------------
/app/src/images/pwafireapp.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/src/images/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/sample.gif
--------------------------------------------------------------------------------
/app/src/images/sample.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/sample.jpg
--------------------------------------------------------------------------------
/app/src/images/sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/sample.png
--------------------------------------------------------------------------------
/app/src/images/sample.svg:
--------------------------------------------------------------------------------
1 | arrow
--------------------------------------------------------------------------------
/app/src/images/vectors/pwafireappbanner.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pwafire/pwafireapp/a49ae8313b6c041514e211d1e0bbe4b12a8c683a/app/src/images/vectors/pwafireappbanner.psd
--------------------------------------------------------------------------------
/app/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
16 |
17 | PWA Fire App - Workbox Progressive Web App Demo And Starter App
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
51 |
52 |
53 |
54 |
57 |
58 |
59 |
62 |
63 |
64 |
65 |
66 |
80 |
81 | Getting set up?
82 |
83 |
84 | You need basic HTML, CSS and JavaScript skills Have fun with me!
85 | Man's got to code better and relaxed 😋 😎
86 |
87 |
88 |
96 |
97 |
100 |
101 |
102 | Share
103 |
104 |
105 | Install
106 |
107 |
108 |
109 |
110 |
116 |
117 |
118 | This page must be served over HTTPS. Please reload this page via HTTPS .
119 |
120 |
121 |
122 |
123 |
126 |
127 |
129 |
130 |
141 |
142 |
143 |
144 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/app/src/latest/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | PWA Fire App - Latest Progressive Web Apps News
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
46 |
47 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
64 |
65 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
100 |
104 |
105 |
106 |
107 |
108 |
111 |
112 |
113 | Share
114 |
115 |
116 | Install
117 |
118 |
119 |
120 |
121 |
127 |
128 |
129 | This page must be served over HTTPS. Please reload this page via HTTPS .
130 |
131 |
132 |
133 |
134 |
137 |
138 |
140 |
141 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/latest/sport1.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [ PWA Fire App - Page 2 ]
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/profile/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | [ PWA Fire App - Page 2 ]
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
76 |
77 |
78 |
79 |
80 |
83 |
84 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/profile/share.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | PWA Fire App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
43 |
44 | Web Share Target Handler
45 |
46 |
47 | href:
48 |
49 |
50 | Query String Parameters:
51 | title:
52 | text:
53 | url:
54 |
55 |
56 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/service-worker.js:
--------------------------------------------------------------------------------
1 |
2 | // Authored by Maye Edwin : https://twitter.com/MayeEdwin1
3 | // Add custom cache strategies and routing methods
4 | // pwafire v4.0.1
5 |
6 | importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.1.1/workbox-sw.js');
7 |
8 | if (workbox) {
9 | console.log('Yay! Workbox is loaded ! Cheers to PWA Fire 🐹');
10 | workbox.precaching.precacheAndRoute([]);
11 |
12 | /* cache images in the e.g others folder; edit to other folders you got
13 | and config in the sw-config.js file
14 |
15 | -- notes --
16 | if you are using *networkFirst* cache strategies,
17 | they should come first as in this app
18 | */
19 | workbox.routing.registerRoute(
20 | /(.*)others(.*)\.(?:|svg|png|gif|jpg)/,
21 | new workbox.strategies.NetworkFirst({
22 | cacheName: 'images-cache',
23 | plugins: [
24 | new workbox.expiration.Plugin({
25 | maxEntries: 50, // max number of images to cache
26 | maxAgeSeconds: 7 * 24 * 60 * 60, // 7 Days
27 | })
28 | ]
29 | })
30 | );
31 |
32 | // cache google fonts
33 | workbox.routing.registerRoute(
34 | new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
35 | new workbox.strategies.NetworkFirst({
36 | cacheName: 'google-fonts',
37 | plugins: [
38 | new workbox.cacheableResponse.Plugin({
39 | statuses: [0, 200],
40 | }),
41 | ],
42 | })
43 | );
44 |
45 | /* cache resources from a specific subdirectory
46 | -- notes --
47 | add url for other sub-directories that a user visits depending
48 | on his or her needs "/subdirectory/" as shown below ; *subdirectory*
49 | could be any name eg *latest* if a user shows interest in *latest* categ of a news app;
50 | this means all .html articles in the *latest* route that the user reads, get cached
51 | */
52 | workbox.routing.registerRoute(
53 | new RegExp('/latest/'),
54 | new workbox.strategies.StaleWhileRevalidate({
55 | // use a custom cache name
56 | cacheName: 'latest-cache',
57 | plugins: [
58 | new workbox.expiration.Plugin({
59 | // max number of items to be cached
60 | maxEntries: 20,
61 | maxAgeSeconds: 7 * 24 * 60 * 60, // 7 Days
62 | }),
63 | ]
64 | })
65 | );
66 |
67 | /* Make your JS and CSS ⚡ fast by returning the assets from the cache,
68 | while making sure they are updated in the background for the next use.
69 | */
70 | workbox.routing.registerRoute(
71 | // cache js, css, scc files
72 | /.*\.(?:css|js|scss|)/,
73 | // use cache but update in the background ASAP
74 | new workbox.strategies.StaleWhileRevalidate({
75 | // use a custom cache name
76 | cacheName: 'assets-cache',
77 | plugins: [
78 | new workbox.expiration.Plugin({
79 | // max number of items to be cached
80 | maxEntries: 20,
81 | }),
82 | ]
83 | })
84 | );
85 |
86 | // add offline analytics
87 | workbox.googleAnalytics.initialize();
88 |
89 | /* Install a new service worker and have it update
90 | and control a web page as soon as possible
91 | */
92 |
93 | workbox.core.skipWaiting();
94 | workbox.core.clientsClaim();
95 |
96 | } else {
97 | console.log("Oops! Workbox didn't load 👺");
98 | }
99 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ### PWA Fire App
2 |
3 | Before we get started; let us make sure everything is ready and we have all tools needed.
4 |
5 | #### [What you should already know]()
6 |
7 | - Basic HTML, CSS, and JavaScript (ofcourse you are)
8 | - How to run commands from the command line
9 | - Some familiarity with service workers is recommended
10 | - Familiarity with Node.js is recommended
11 |
12 | **NOTE** All the code is commented BTW; Read through to understand each line. It is good to do so!
13 |
14 | #### [What you will need]()
15 |
16 | [PWA Fire App](https://pwafire.org/developer/app) requires Node.js. [Install](https://nodejs.org/en/) the latest long term support (LTS) version if you have not already.
17 |
18 | Make sure you have all this checked before we start;
19 |
20 | - Connection to the internet
21 | - A browser that [supports service worker](https://pwafire.org/developer/tools/browser-test/)
22 | - A text editor; like [VS Code](https://code.visualstudio.com/)
23 | - [Node.js](https://nodejs.org/en/) installed
24 | - [Firebase](https://pwafire.org/developer/codelabs/firebase-hosting-web/) if you need to deploy it
25 |
26 | #### [Get the app](https://github.com/mayeedwin/pwafireapp/archive/master.zip)
27 |
28 | The important directory for our web app is going to be the **src** folder in which you will place all of your project files or start your new progressive web app project from.
29 |
30 | Download [PWA Fire App here](https://github.com/mayeedwin/pwafireapp/archive/master.zip)
31 |
32 | #### [Install project dependencies and start the server]()
33 |
34 | 1. Navigate to the app directory via the command line:
35 |
36 | cd pwafireapp-master
37 | cd app
38 |
39 | 2. Run the following commands to install the project dependencies:
40 |
41 | npm install
42 |
43 | 3. Then build and serve the app with these commands:
44 |
45 | npm run build
46 | npm run start
47 |
48 | The *npm install* command installs the project dependencies based on the configuration in **package.json.** Open **../app/package.json** and examine its contents. Get the [explanation here](https://pwafire.org/developer/pwa/started/#sw-config-for-node)
49 |
50 | NOTE : Checkout for the latest workbox release here and update the importScripts below say 3.6.1 to 3.6.2 if it's available and update the service-worker.js file in the src folder.
51 |
52 | Once you have started the server, open the browser and navigate to http://localhost:8081/ to view the app. The app is a simple one page progressive web app which just showcases a working PWA Fire App.
53 |
54 | #### [Add your project source files or start a new project]()
55 |
56 | Open the **src** folder in your text editor. The **src** folder is where you will be building your progressive web app or copy all your projects source files as in the app structure.
57 |
58 | Find demo [PWA Fire App here](https://pwafireapp.firebaseapp.com)
59 |
60 | 1. Add or create your source files as in the **app structure** shown below. For example, you will place all **.css** files in the **css** folder.
61 |
62 | ```bash
63 |
64 | │ ├── src
65 | │ ├── assets
66 | | ├── css
67 | | ├── js
68 | | ├── scss
69 | │ ├── images
70 | | ├── icons
71 | | ├── others
72 | | ├── pages
73 | │ ├── index.html
74 | │ ├── app.webmanifest
75 | │ ├── service-worker.js
76 |
77 | ```
78 |
79 | 2. For the **images** folder, make sure you have all your app icons in your project as shown below and copy all images to it; The **icons** should be of sizes as in the **app.webmanifest** file. Atleast have an icon size of 144x144 is required for our progressive web app to install.
80 |
81 | 3. **Generate** your progressive [web app icons here](https://app-manifest.firebaseapp.com/). Unzip the icons and copy them to the **icons** folder of the [PWA Fire App](https://pwafire.org/developer/app). Open **app.webmanifest** and configure your web app name, short name and theme color **(must be the same as specified in the *index.html*).**
82 |
83 | 4. For the **others** folder; You could rename it to say **team** and add images to it but make sure to update that in the **service-worker.js** as shown below; Just an example of extra folders you may want to add to your project or your project has.
84 |
85 | ```javascript
86 |
87 | /* cache images in the e.g others folder; edit to other folders you got
88 | and config in the sw-config.js file
89 | */
90 | workbox.routing.registerRoute(
91 | /(.*)others(.*)\.(?:png|gif|jpg)/,
92 | workbox.strategies.cacheFirst({
93 | cacheName: 'images',
94 | plugins: [
95 | new workbox.expiration.Plugin({
96 | maxEntries: 50,
97 | maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
98 | })
99 | ]
100 | })
101 | );
102 |
103 | ```
104 |
105 | 5. To make your progressive web app more discoverable and your pages built with best web practices, configure your pages as in the **head** tag of the default **index.html** in the **src** folder.
106 |
107 | ### [Build your progressive web app]()
108 |
109 | After configuring your project to the app structure above; let us build and even deploy it!
110 | Then build and serve the app with these commands:
111 |
112 | npm run build
113 | npm run start
114 |
115 | The web app files are copied over to the **build** folder when the **npm run build** command is run, and the server (is started with **npm run start**) serves these files from the **build** directory.
116 |
117 | **Alternatively**, you can test your web app by running `firebase serve` in the app root folder and host with [firebase](https://firebase.google.com/docs/web/setup) as in [this codelab](https://pwafire.org/developer/codelabs/firebase-hosting-web/).
118 |
119 | You are done! Welcome to PWAs World!
120 |
121 | ### [Engage us](https://twitter.com/pwafire)
122 | Donate a star, like, follow and contribute in any way. You got any **bug?** Report it [here for support.](https://github.com/mayeedwin/pwafireapp/issues/new) You want to contribute? Create your [feature here.](https://github.com/mayeedwin/pwafireapp/issues/new)
123 |
--------------------------------------------------------------------------------