From be7763d38deefd5e5f2a3970e6e0d75ec78db2e9 Mon Sep 17 00:00:00 2001 From: williamg1750 Date: Thu, 18 Mar 2021 07:58:41 -0400 Subject: [PATCH] done --- .firebaserc | 5 + .github/workflows/firebase-hosting-merge.yml | 21 ++ .../firebase-hosting-pull-request.yml | 17 ++ .gitignore | 66 ++++++ firebase.json | 10 + index.html | 212 +++++++++--------- js/app.js | 11 +- js/db.js | 50 +++++ js/ui.js | 33 ++- pages/about.html | 108 +++++---- pages/contact.html | 113 +++++----- pages/fallback.html | 98 ++++---- public/404.html | 33 +++ public/index.html | 89 ++++++++ sw.js | 70 +++--- 15 files changed, 647 insertions(+), 289 deletions(-) create mode 100644 .firebaserc create mode 100644 .github/workflows/firebase-hosting-merge.yml create mode 100644 .github/workflows/firebase-hosting-pull-request.yml create mode 100644 .gitignore create mode 100644 firebase.json create mode 100644 js/db.js create mode 100644 public/404.html create mode 100644 public/index.html diff --git a/.firebaserc b/.firebaserc new file mode 100644 index 0000000..d34a1e8 --- /dev/null +++ b/.firebaserc @@ -0,0 +1,5 @@ +{ + "projects": { + "default": "food-ninja-pwa-13cac" + } +} diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml new file mode 100644 index 0000000..c377025 --- /dev/null +++ b/.github/workflows/firebase-hosting-merge.yml @@ -0,0 +1,21 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on merge +'on': + push: + branches: + - master +jobs: + build_and_deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: '${{ secrets.GITHUB_TOKEN }}' + firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_FOOD_NINJA_PWA_13CAC }}' + channelId: live + projectId: food-ninja-pwa-13cac + env: + FIREBASE_CLI_PREVIEWS: hostingchannels diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml new file mode 100644 index 0000000..02a6b7f --- /dev/null +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -0,0 +1,17 @@ +# This file was auto-generated by the Firebase CLI +# https://github.com/firebase/firebase-tools + +name: Deploy to Firebase Hosting on PR +'on': pull_request +jobs: + build_and_preview: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: FirebaseExtended/action-hosting-deploy@v0 + with: + repoToken: '${{ secrets.GITHUB_TOKEN }}' + firebaseServiceAccount: '${{ secrets.FIREBASE_SERVICE_ACCOUNT_FOOD_NINJA_PWA_13CAC }}' + projectId: food-ninja-pwa-13cac + env: + FIREBASE_CLI_PREVIEWS: hostingchannels diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbb58ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,66 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +firebase-debug.log* +firebase-debug.*.log* + +# Firebase cache +.firebase/ + +# Firebase config + +# Uncomment this if you'd like others to create their own Firebase project. +# For a team working on the same Firebase project(s), it is recommended to leave +# it commented so all members can deploy to the same project(s) in .firebaserc. +# .firebaserc + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env diff --git a/firebase.json b/firebase.json new file mode 100644 index 0000000..e782939 --- /dev/null +++ b/firebase.json @@ -0,0 +1,10 @@ +{ + "hosting": { + "public": "public", + "ignore": [ + "firebase.json", + "**/.*", + "**/node_modules/**" + ] + } +} diff --git a/index.html b/index.html index e87254a..fc5647c 100644 --- a/index.html +++ b/index.html @@ -1,113 +1,113 @@ - - - - - Food Ninja - - - - - - - - - - - - - - - + + + + + Food Ninja + + + + + + + + + + + + + + - - + + - -
-
- recipe thumb -
-
Edame Noodles
-
Edame Beans, Noodels, Garlic oil
-
-
- delete_outline -
+ +
+
William's Recipes
-
- recipe thumb -
-
Edame Noodles
-
Edame Beans, Noodels, Garlic oil
-
-
- delete_outline -
-
-
- recipe thumb -
-
Edame Noodles
-
Edame Beans, Noodels, Garlic oil
-
-
- delete_outline -
-
-
- recipe thumb -
-
Edame Noodles
-
Edame Beans, Noodels, Garlic oil
-
-
- delete_outline -
-
-
- + - -
-
-
New Recipe
-
-
- - -
-
- - -
-
- -
-
-
+ +
+
+
New Recipe
+
+
+ + +
+
+ + +
+
+ +
+
+
+ + + - - - - \ No newline at end of file + + + + + + diff --git a/js/app.js b/js/app.js index 12ded7a..36800c1 100644 --- a/js/app.js +++ b/js/app.js @@ -1,5 +1,6 @@ -if('serviceWorker' in navigator){ - navigator.serviceWorker.register('/sw.js') - .then(reg => console.log('service worker registered')) - .catch(err => console.log('service worker not registered', err)); -} \ No newline at end of file +if ('serviceWorker' in navigator) { + navigator.serviceWorker + .register('/sw.js') + .then((reg) => console.log('service worker registered')) + .catch((err) => console.log('service worker not registered', err)); +} diff --git a/js/db.js b/js/db.js new file mode 100644 index 0000000..50d0299 --- /dev/null +++ b/js/db.js @@ -0,0 +1,50 @@ +// enable offline data +db.enablePersistence().catch(function (err) { + if (err.code == 'failed-precondition') { + // probably multible tabs open at once + console.log('persistance failed'); + } else if (err.code == 'unimplemented') { + // lack of browser support for the feature + console.log('persistance not available'); + } +}); + +// real-time listener +db.collection('recipes').onSnapshot((snapshot) => { + snapshot.docChanges().forEach((change) => { + if (change.type === 'added') { + renderRecipe(change.doc.data(), change.doc.id); + } + if (change.type === 'removed') { + removeRecipe(change.doc.id); + } + }); +}); + +// add new recipe +const form = document.querySelector('form'); +form.addEventListener('submit', (evt) => { + evt.preventDefault(); + + const recipe = { + title: form.title.value, + ingredients: form.ingredients.value, + }; + + db.collection('recipes') + .add(recipe) + .catch((err) => console.log(err)); + + form.title.value = ''; + form.ingredients.value = ''; +}); + +// remove a recipe +const recipeContainer = document.querySelector('.recipes'); +recipeContainer.addEventListener('click', (evt) => { + if (evt.target.tagName === 'I') { + const id = evt.target.getAttribute('data-id'); + //console.log(id); + db.collection('recipes').doc(id).delete(); + } +}); diff --git a/js/ui.js b/js/ui.js index 2f45663..52dbb1c 100644 --- a/js/ui.js +++ b/js/ui.js @@ -1,8 +1,33 @@ -document.addEventListener('DOMContentLoaded', function() { +const recipes = document.querySelector('.recipes'); + +document.addEventListener('DOMContentLoaded', function () { // nav menu const menus = document.querySelectorAll('.side-menu'); - M.Sidenav.init(menus, {edge: 'right'}); + M.Sidenav.init(menus, { edge: 'right' }); // add recipe form const forms = document.querySelectorAll('.side-form'); - M.Sidenav.init(forms, {edge: 'left'}); -}); \ No newline at end of file + M.Sidenav.init(forms, { edge: 'left' }); +}); + +// render recipe data +const renderRecipe = (data, id) => { + const html = ` +
+ recipe thumb +
+
${data.name}
+
${data.ingredients}
+
+
+ delete_outline +
+
+ `; + recipes.innerHTML += html; +}; + +// remove recipe +const removeRecipe = (id) => { + const recipe = document.querySelector(`.recipe[data-id=${id}]`); + recipe.remove(); +}; diff --git a/pages/about.html b/pages/about.html index 421973d..68acab2 100644 --- a/pages/about.html +++ b/pages/about.html @@ -1,50 +1,66 @@ - - - - - Food Ninja - - - - - - - - - - - + + + + + Food Ninja + + + + + + + + + + + + + - - - - - + + - -
-
About Food Ninja
-

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ducimus, porro voluptatum illum veniam eaque sunt sit labore provident eligendi! Voluptate amet suscipit inventore unde maxime atque impedit officia nobis laboriosam!

-

Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam voluptatibus omnis, ea doloremque exercitationem id necessitatibus. Voluptatem officiis cupiditate commodi totam, hic laborum est ducimus amet iure, non dignissimos illo.

-
+ +
+
About Food Ninja
+

+ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ducimus, porro + voluptatum illum veniam eaque sunt sit labore provident eligendi! + Voluptate amet suscipit inventore unde maxime atque impedit officia + nobis laboriosam! +

+

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam + voluptatibus omnis, ea doloremque exercitationem id necessitatibus. + Voluptatem officiis cupiditate commodi totam, hic laborum est ducimus + amet iure, non dignissimos illo. +

+
- - - - \ No newline at end of file + + + + diff --git a/pages/contact.html b/pages/contact.html index b6b232c..4155050 100644 --- a/pages/contact.html +++ b/pages/contact.html @@ -1,55 +1,66 @@ - - - - - Food Ninja - - - - - - - - - - - + + + + + Food Ninja + + + + + + + + + + + + + - - - - - - - -
-
Contact Us
-

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ducimus, porro voluptatum illum veniam eaque sunt sit labore provident eligendi! Voluptate amet suscipit inventore unde maxime atque impedit officia nobis laboriosam!

-
-
Find us at:
-
- - - - \ No newline at end of file + +
+
Contact Us
+

+ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Ducimus, porro + voluptatum illum veniam eaque sunt sit labore provident eligendi! + Voluptate amet suscipit inventore unde maxime atque impedit officia + nobis laboriosam! +

+
+
Find us at:
+
    +
  • 123 Spicy Noodle Road
  • +
  • Manchester, UK
  • +
+
+ + + + + diff --git a/pages/fallback.html b/pages/fallback.html index ea7e057..0131bc7 100644 --- a/pages/fallback.html +++ b/pages/fallback.html @@ -1,50 +1,56 @@ - - - - - Food Ninja - - - - - - - - - - - + + + + + Food Ninja + + + + + + + + + + + + + - - - - - + + - -
-
OOPS!
-

Currently you can't view this page without a connection.

- Go to the Homepage -
+ +
+
OOPS!
+

Currently you can't view this page without a connection.

+ Go to the Homepage +
- - - - \ No newline at end of file + + + + diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..829eda8 --- /dev/null +++ b/public/404.html @@ -0,0 +1,33 @@ + + + + + + Page Not Found + + + + +
+

404

+

Page Not Found

+

The specified file was not found on this website. Please check the URL for mistakes and try again.

+

Why am I seeing this?

+

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

+
+ + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..6fa829d --- /dev/null +++ b/public/index.html @@ -0,0 +1,89 @@ + + + + + + Welcome to Firebase Hosting + + + + + + + + + + + + + + + + + + + +
+

Welcome

+

Firebase Hosting Setup Complete

+

You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!

+ Open Hosting Documentation +
+

Firebase SDK Loading…

+ + + + diff --git a/sw.js b/sw.js index f31de97..666372c 100644 --- a/sw.js +++ b/sw.js @@ -1,5 +1,5 @@ -const staticCacheName = 'site-static-v2'; -const dynamicCacheName = 'site-dynamic-v1'; +const staticCacheName = 'site-static-v4'; +const dynamicCacheName = 'site-dynamic-v4'; const assets = [ '/', '/index.html', @@ -11,14 +11,14 @@ const assets = [ '/img/dish.png', 'https://fonts.googleapis.com/icon?family=Material+Icons', 'https://fonts.gstatic.com/s/materialicons/v47/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2', - '/pages/fallback.html' + '/pages/fallback.html', ]; // cache size limit function const limitCacheSize = (name, size) => { - caches.open(name).then(cache => { - cache.keys().then(keys => { - if(keys.length > size){ + caches.open(name).then((cache) => { + cache.keys().then((keys) => { + if (keys.length > size) { cache.delete(keys[0]).then(limitCacheSize(name, size)); } }); @@ -26,7 +26,7 @@ const limitCacheSize = (name, size) => { }; // install event -self.addEventListener('install', evt => { +self.addEventListener('install', (evt) => { //console.log('service worker installed'); evt.waitUntil( caches.open(staticCacheName).then((cache) => { @@ -37,36 +37,44 @@ self.addEventListener('install', evt => { }); // activate event -self.addEventListener('activate', evt => { +self.addEventListener('activate', (evt) => { //console.log('service worker activated'); evt.waitUntil( - caches.keys().then(keys => { + caches.keys().then((keys) => { //console.log(keys); - return Promise.all(keys - .filter(key => key !== staticCacheName && key !== dynamicCacheName) - .map(key => caches.delete(key)) + return Promise.all( + keys + .filter((key) => key !== staticCacheName && key !== dynamicCacheName) + .map((key) => caches.delete(key)) ); }) ); }); -// fetch event -self.addEventListener('fetch', evt => { - //console.log('fetch event', evt); - evt.respondWith( - caches.match(evt.request).then(cacheRes => { - return cacheRes || fetch(evt.request).then(fetchRes => { - return caches.open(dynamicCacheName).then(cache => { - cache.put(evt.request.url, fetchRes.clone()); - // check cached items size - limitCacheSize(dynamicCacheName, 15); - return fetchRes; +// fetch events +self.addEventListener('fetch', (evt) => { + if (evt.request.url.indexOf('firestore.googleapis.com') === -1) { + evt.respondWith( + caches + .match(evt.request) + .then((cacheRes) => { + return ( + cacheRes || + fetch(evt.request).then((fetchRes) => { + return caches.open(dynamicCacheName).then((cache) => { + cache.put(evt.request.url, fetchRes.clone()); + // check cached items size + limitCacheSize(dynamicCacheName, 15); + return fetchRes; + }); + }) + ); }) - }); - }).catch(() => { - if(evt.request.url.indexOf('.html') > -1){ - return caches.match('/pages/fallback.html'); - } - }) - ); -}); \ No newline at end of file + .catch(() => { + if (evt.request.url.indexOf('.html') > -1) { + return caches.match('/pages/fallback.html'); + } + }) + ); + } +});