diff --git a/package-lock.json b/package-lock.json index fa536c3..db9a3a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,6 @@ "packages": { "": { "dependencies": { - "@marcoschulte/vue3-progress": "^0.0.7", "@tinymce/tinymce-vue": "^4.0.7", "@vitejs/plugin-vue": "^4.0.0", "@vuepic/vue-datepicker": "^3.6.4", @@ -520,11 +519,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@marcoschulte/vue3-progress": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@marcoschulte/vue3-progress/-/vue3-progress-0.0.7.tgz", - "integrity": "sha512-gcvZW9gJ/isTD0sjorgvLOuoS2U5r5djMoLOwuN4YvhOvgOyYGWoQF1hubhouE/dVDPvWHmZsD0gvf6YD0x7fg==" - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/package.json b/package.json index 4835f3f..44a54b9 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "vitest": "^0.28.5" }, "dependencies": { - "@marcoschulte/vue3-progress": "^0.0.7", "@tinymce/tinymce-vue": "^4.0.7", "@vitejs/plugin-vue": "^4.0.0", "@vuepic/vue-datepicker": "^3.6.4", diff --git a/resources/js/components/SMProgress.vue b/resources/js/components/SMProgress.vue new file mode 100644 index 0000000..25e61c6 --- /dev/null +++ b/resources/js/components/SMProgress.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/resources/js/helpers/api.ts b/resources/js/helpers/api.ts index 47c9a4a..2bef9d5 100644 --- a/resources/js/helpers/api.ts +++ b/resources/js/helpers/api.ts @@ -1,7 +1,5 @@ import { useUserStore } from "../store/UserStore"; -import { ProgressFinisher, useProgress } from "@marcoschulte/vue3-progress"; - -const progresses = [] as ProgressFinisher[]; +import { useProgressStore } from "../store/ProgressStore"; interface ApiProgressData { loaded: number; total: number; @@ -82,7 +80,8 @@ export const api = { let receivedData = false; - progresses.push(useProgress().start()); + const progressStore = useProgressStore(); + progressStore.start(); fetch(url, fetchOptions) .then((response) => { @@ -177,7 +176,7 @@ export const api = { }); }) .finally(() => { - progresses.pop()?.finish(); + progressStore.finish(); }); }); }, diff --git a/resources/js/router/index.js b/resources/js/router/index.js index 03b5cd1..56bd202 100644 --- a/resources/js/router/index.js +++ b/resources/js/router/index.js @@ -1,8 +1,8 @@ import { createWebHistory, createRouter } from "vue-router"; import { useUserStore } from "@/store/UserStore"; import { useApplicationStore } from "../store/ApplicationStore"; +import { useProgressStore } from "../store/ProgressStore"; import { api } from "../helpers/api"; -import { useProgress } from "@marcoschulte/vue3-progress"; const progresses = []; @@ -377,8 +377,11 @@ const router = createRouter({ router.beforeEach(async (to, from, next) => { const userStore = useUserStore(); const applicationStore = useApplicationStore(); + const progressStore = useProgressStore(); + + // progressStore.reset(); + progressStore.start(); - progresses.push(useProgress().start()); applicationStore.clearDynamicTitle(); // Check Token @@ -451,7 +454,7 @@ router.beforeEach(async (to, from, next) => { } if (to.meta.middleware == "authenticated" && !userStore.id) { - progresses.pop()?.finish(); + progressStore.finish(); next({ name: "login", query: { redirect: to.fullPath } }); } else { next(); @@ -459,7 +462,8 @@ router.beforeEach(async (to, from, next) => { }); router.afterEach((to, from) => { - progresses.pop()?.finish(); + const progressStore = useProgressStore(); + progressStore.finish(); }); export default router; diff --git a/resources/js/store/ProgressStore.ts b/resources/js/store/ProgressStore.ts new file mode 100644 index 0000000..ec3bbf3 --- /dev/null +++ b/resources/js/store/ProgressStore.ts @@ -0,0 +1,115 @@ +import { defineStore } from "pinia"; +import { clamp } from "../helpers/utils"; + +export interface ProgressStore { + spinner: number; + status: number; + opacity: number; + queue: number; + timeoutID: number | null; +} + +export const useProgressStore = defineStore({ + id: "progress", + state: (): ProgressStore => ({ + spinner: 0, + status: 0, + opacity: 0, + queue: 0, + timeoutID: null, + }), + + actions: { + start() { + if (this.queue == 0) { + this.set(0); + + const work = () => { + window.setTimeout(() => { + if (this.status != null) { + this._trickle(); + work(); + } + }, 200); + }; + + work(); + + if (this.opacity == 0) { + if (this.timeoutID != null) { + window.clearTimeout(this.timeoutID); + } + + this.timeoutID = window.setTimeout(() => { + this._show(); + this.timeoutID = null; + }, 200); + } + + if (this.spinner == 0) { + this.spinner = 1; + } + } + + ++this.queue; + }, + + set(number: number) { + this.status = clamp(number, 0.08, 1); + }, + + finish() { + if (this.queue > 0) { + --this.queue; + } + }, + + _trickle() { + const n = this.status; + + if (this.queue == 0 && this.timeoutID == null) { + this.timeoutID = window.setTimeout(() => { + this.set(1); + this.timeoutID = null; + + this.timeoutID = window.setTimeout(() => { + this._hide(); + this.timeoutID = null; + }, 500); + }, 200); + } + + if (n == 0) { + this.start(); + } else if (n < 1) { + let amount = 0; + + if (n >= 0 && n < 0.2) { + amount = 0.1; + } else if (n >= 0.2 && n < 0.5) { + amount = 0.04; + } else if (n >= 0.5 && n < 0.8) { + amount = 0.02; + } else if (n >= 0.8 && n < 0.99) { + amount = 0.005; + } else { + amount = 0; + } + + this.set(clamp(n + amount, 0, 0.994)); + } + }, + + _show() { + this.opacity = 1; + }, + + _hide() { + this.opacity = 0; + + if (this.spinner == 1) { + this.spinner = 0; + } + }, + }, +}); diff --git a/resources/js/views/App.vue b/resources/js/views/App.vue index 9446e81..d3d6e25 100644 --- a/resources/js/views/App.vue +++ b/resources/js/views/App.vue @@ -8,13 +8,14 @@ - +