diff --git a/package.json b/package.json
index 7a37613..339ef7b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ludo",
- "version": "v1.2.3",
+ "version": "v1.3.2",
"private": true,
"scripts": {
"start": "yarn serve",
@@ -17,6 +17,7 @@
"mersenne-twister": "1.1.0",
"register-service-worker": "1.6.2",
"sass-rem": "2.0.1",
+ "toastify-js": "https://github.com/mort3za/toastify-js.git",
"vue": "2.6.10",
"vue-class-component": "7.0.2",
"vue-property-decorator": "8.1.0",
diff --git a/src/App.vue b/src/App.vue
index 981d760..2ff1754 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -16,13 +16,13 @@ body,
-
+
diff --git a/src/functions/general-helpers.ts b/src/functions/general-helpers.ts
index 380a111..6037d25 100644
--- a/src/functions/general-helpers.ts
+++ b/src/functions/general-helpers.ts
@@ -1,3 +1,6 @@
+// @ts-ignore
+import Toastify from "toastify-js";
+
import {
PositionInBoard,
Marble,
@@ -12,6 +15,27 @@ import {
import { getPositionAfterMove } from "@/functions/path-helpers.ts";
import store from "@/store/index";
+export function notify(options: any = {}) {
+ if (!options.text) {
+ console.log('No text');
+ return;
+ }
+ Toastify({
+ className: "shadow",
+ text: "",
+ duration: 600000,
+ // destination: undefined,
+ // newWindow: false,
+ // onClick: () => {}
+ close: false,
+ gravity: "bottom", // `top` or `bottom`
+ position: "left", // `left`, `center` or `right`
+ backgroundColor: "white",
+ stopOnFocus: true,
+ ...options
+ }).showToast();
+}
+
// TODO: rename to isSamePosition
export function isSameStep(position1: PositionInBoard, position2: PositionInBoard): boolean {
return position1.row === position2.row && position1.column === position2.column;
diff --git a/src/registerServiceWorker.ts b/src/registerServiceWorker.ts
index ef87577..1f6fe7e 100644
--- a/src/registerServiceWorker.ts
+++ b/src/registerServiceWorker.ts
@@ -1,32 +1,55 @@
/* tslint:disable:no-console */
-import { register } from 'register-service-worker';
+import { register } from "register-service-worker";
+import { notify } from "./functions/general-helpers";
-if (process.env.NODE_ENV === 'production') {
+const notifyUserAboutUpdate = (worker: any) => {
+ notify({
+ text: "New version available 🥳, Click here to run the new version!",
+ close: false,
+ onClick: () => {
+ console.log("upgrade confirmed");
+ worker.postMessage({ action: "skipWaiting" });
+ }
+ });
+};
+
+if (process.env.NODE_ENV === "production") {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
- 'App is being served from cache by a service worker.\n' +
- 'For more details, visit https://goo.gl/AFskqB',
+ "App is being served from cache by a service worker.\n" +
+ "For more details, visit https://goo.gl/AFskqB"
);
},
registered() {
- console.log('Service worker has been registered.');
+ console.log("Service worker has been registered.");
},
cached() {
- console.log('Content has been cached for offline use.');
+ console.log("Content has been cached for offline use.");
},
updatefound() {
- console.log('New content is downloading.');
+ console.log("New content is downloading.");
},
- updated() {
- console.log('New content is available; please refresh.');
+ updated(registration) {
+ console.log("New content is available; please refresh.");
+ notifyUserAboutUpdate(registration.waiting);
},
offline() {
- console.log('No internet connection found. App is running in offline mode.');
+ console.log("No internet connection found. App is running in offline mode.");
},
error(error) {
- console.error('Error during service worker registration:', error);
- },
+ console.error("Error during service worker registration:", error);
+ }
+ });
+
+ let refreshing: any;
+ navigator.serviceWorker.addEventListener("controllerchange", () => {
+ console.log('controllerchange...');
+ if (refreshing) {
+ return;
+ }
+ window.location.reload();
+ refreshing = true;
});
}
diff --git a/src/service-worker.js b/src/service-worker.js
new file mode 100644
index 0000000..e2faa7e
--- /dev/null
+++ b/src/service-worker.js
@@ -0,0 +1,15 @@
+/**
+ * The workboxSW.precacheAndRoute() method efficiently caches and responds to
+ * requests for URLs in the manifest.
+ * See https://goo.gl/S9QRab
+ */
+self.__precacheManifest = [].concat(self.__precacheManifest || []);
+workbox.precaching.suppressWarnings();
+workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
+
+self.addEventListener("message", msg => {
+ if (msg.data.action === "skipWaiting") {
+ console.log('skip waiting...');
+ self.skipWaiting();
+ }
+});
diff --git a/src/styles/global.scss b/src/styles/global.scss
index a9fde48..4b884a8 100644
--- a/src/styles/global.scss
+++ b/src/styles/global.scss
@@ -1,3 +1,4 @@
+@import "./toastify.scss";
@import "./global-ghost.scss";
@import "./bootstrap.scss";
@import "./animations.scss";
diff --git a/src/styles/toastify.scss b/src/styles/toastify.scss
new file mode 100644
index 0000000..05adb3b
--- /dev/null
+++ b/src/styles/toastify.scss
@@ -0,0 +1,82 @@
+/*!
+ * Toastify js 1.6.1
+ * https://github.com/apvarun/toastify-js
+ * @license MIT licensed
+ *
+ * Copyright (C) 2018 Varun A P
+ */
+
+.toastify {
+ padding: rem(12px 20px);
+ color: $dark;
+ display: inline-block;
+ background: white;
+ position: fixed;
+ opacity: 0;
+ transition: all 300ms cubic-bezier(0.215, 0.61, 0.355, 1);
+ border-radius: $border-radius;
+ cursor: pointer;
+ text-decoration: none;
+ max-width: calc(50% - 20px);
+ z-index: 5000;
+}
+
+.toastify.on {
+ opacity: 1;
+}
+
+.toast-close {
+ opacity: 0.4;
+}
+
+.toastify-right {
+ right: rem(16px);
+ .toast-close {
+ padding: rem(0 0 0 16px);
+ }
+}
+
+.toastify-left {
+ left: rem(16px);
+ .toast-close {
+ padding: rem(0 16px 0 0);
+ }
+}
+
+.toastify-top {
+ top: rem(-150px);
+}
+
+.toastify-bottom {
+ bottom: rem(-150px);
+}
+
+// .toastify-rounded {
+// border-radius: 25px;
+// }
+
+// .toastify-avatar {
+// width: 1.5em;
+// height: 1.5em;
+// margin: 0 5px;
+// border-radius: 2px;
+// }
+
+.toastify-center {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+}
+
+@media only screen and (max-width: 360px) {
+ .toastify-right,
+ .toastify-left {
+ margin-left: auto;
+ margin-right: auto;
+ left: 0;
+ right: 0;
+ max-width: fit-content;
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index d247025..52cfe29 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -37,4 +37,4 @@
"exclude": [
"node_modules"
]
-}
+}
\ No newline at end of file
diff --git a/vue.config.js b/vue.config.js
index 243cb38..513a6cc 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -5,6 +5,13 @@ module.exports = {
productionSourceMap: false,
publicPath: process.env.NODE_ENV === "production" ? "/ludo/" : "/",
pwa: {
+ // service worker guides:
+ // https://levelup.gitconnected.com/vue-pwa-example-298a8ea953c9
+ // https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
+ workboxPluginMode: 'InjectManifest',
+ workboxOptions: {
+ swSrc: 'src/service-worker.js'
+ },
name: "Ludo Game",
themeColor: "#00ffbb",
msTileColor: "#2c3939",
diff --git a/yarn.lock b/yarn.lock
index 1cd9da7..242719c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8702,6 +8702,10 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
+"toastify-js@https://github.com/mort3za/toastify-js.git":
+ version "1.6.1"
+ resolved "https://github.com/mort3za/toastify-js.git#39974891c867e58bf476004bd8f31f25d209a477"
+
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
@@ -8872,10 +8876,10 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
-typescript@3.4.3:
- version "3.4.3"
- resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f"
- integrity sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==
+typescript@3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977"
+ integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==
uglify-js@3.4.x:
version "3.4.10"