diff --git a/package-lock.json b/package-lock.json index 9344eda..b6a4e5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,6 +5,7 @@ "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", @@ -518,6 +519,11 @@ "@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 7372449..930308b 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "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/css/app.scss b/resources/css/app.scss index 92d8e56..a5d276b 100644 --- a/resources/css/app.scss +++ b/resources/css/app.scss @@ -3,6 +3,7 @@ @import "data-table.scss"; @import "tinymce.scss"; @import "prism.css"; +@import "progressbar.scss"; * { box-sizing: border-box; diff --git a/resources/css/progressbar.scss b/resources/css/progressbar.scss new file mode 100644 index 0000000..b8c2bed --- /dev/null +++ b/resources/css/progressbar.scss @@ -0,0 +1,28 @@ +$vue3-progress-bar-container-z-index: 999999 !default; +$vue3-progress-bar-container-transition: all 500ms ease !default; + +$vue3-progress-bar-color: $primary-color-dark !default; +$vue3-progress-bar-height: 4px !default; +$vue3-progress-bar-transition: all 200ms ease !default; + +.vue3-progress-bar-container { + position: fixed; + z-index: $vue3-progress-bar-container-z-index; + top: 0; + left: 0; + width: 100%; + opacity: 0; + background-color: #eee; + transition: $vue3-progress-bar-container-transition; + &[active="true"] { + opacity: 1; + transition: none; + } + .vue3-progress-bar { + width: 100%; + height: $vue3-progress-bar-height; + transform: translate3d(-100%, 0, 0); + background-color: $vue3-progress-bar-color; + transition: $vue3-progress-bar-transition; + } +} diff --git a/resources/js/components/SMLoader.vue b/resources/js/components/SMLoader.vue index 449862f..1201f4f 100644 --- a/resources/js/components/SMLoader.vue +++ b/resources/js/components/SMLoader.vue @@ -2,8 +2,7 @@ @@ -11,8 +10,7 @@ diff --git a/resources/js/components/SMLoadingIconToolbox.vue b/resources/js/components/SMLoadingIconToolbox.vue deleted file mode 100644 index 28a2252..0000000 --- a/resources/js/components/SMLoadingIconToolbox.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - diff --git a/resources/js/helpers/api.ts b/resources/js/helpers/api.ts index 47b7ec2..47c9a4a 100644 --- a/resources/js/helpers/api.ts +++ b/resources/js/helpers/api.ts @@ -1,7 +1,7 @@ -/* https://blog.logrocket.com/axios-vs-fetch-best-http-requests/ */ - import { useUserStore } from "../store/UserStore"; +import { ProgressFinisher, useProgress } from "@marcoschulte/vue3-progress"; +const progresses = [] as ProgressFinisher[]; interface ApiProgressData { loaded: number; total: number; @@ -82,6 +82,8 @@ export const api = { let receivedData = false; + progresses.push(useProgress().start()); + fetch(url, fetchOptions) .then((response) => { receivedData = true; @@ -173,6 +175,9 @@ export const api = { ...rest, response: response && response.json(), }); + }) + .finally(() => { + progresses.pop()?.finish(); }); }); }, diff --git a/resources/js/main.js b/resources/js/main.js index bc8d48e..e3b9106 100644 --- a/resources/js/main.js +++ b/resources/js/main.js @@ -12,6 +12,7 @@ import SMColumn from "./components/SMColumn.vue"; import { PromiseDialog } from "vue3-promise-dialog"; import { VueReCaptcha } from "vue-recaptcha-v3"; import "./lib/prism"; +import { Vue3ProgressPlugin } from "@marcoschulte/vue3-progress"; const pinia = createPinia(); pinia.use(piniaPluginPersistedstate); @@ -27,6 +28,7 @@ createApp(App) autoHideBadge: true, }, }) + .use(Vue3ProgressPlugin) .component("SMContainer", SMContainer) .component("SMRow", SMRow) .component("SMColumn", SMColumn) diff --git a/resources/js/router/index.js b/resources/js/router/index.js index 1b01eab..ef79495 100644 --- a/resources/js/router/index.js +++ b/resources/js/router/index.js @@ -2,6 +2,9 @@ import { createWebHistory, createRouter } from "vue-router"; import { useUserStore } from "@/store/UserStore"; import { useApplicationStore } from "../store/ApplicationStore"; import { api } from "../helpers/api"; +import { useProgress } from "@marcoschulte/vue3-progress"; + +const progresses = []; export const routes = [ { @@ -371,22 +374,11 @@ const router = createRouter({ // export let activeRoutes = []; -let routerLoadingTimeout = null; - router.beforeEach(async (to, from, next) => { const userStore = useUserStore(); const applicationStore = useApplicationStore(); - if (routerLoadingTimeout != null) { - clearTimeout(routerLoadingTimeout); - routerLoadingTimeout = null; - } - - routerLoadingTimeout = window.setTimeout(() => { - routerLoadingTimeout = null; - applicationStore.setRouterLoading(true); - }, 1000); - + progresses.push(useProgress().start()); applicationStore.clearDynamicTitle(); // Check Token @@ -470,13 +462,7 @@ router.beforeEach(async (to, from, next) => { }); router.afterEach((to, from) => { - if (routerLoadingTimeout != null) { - clearTimeout(routerLoadingTimeout); - routerLoadingTimeout = null; - } - - const applicationStore = useApplicationStore(); - applicationStore.setRouterLoading(false); + progresses.pop()?.finish(); }); export default router; diff --git a/resources/js/store/ApplicationStore.ts b/resources/js/store/ApplicationStore.ts index f34114b..5b16563 100644 --- a/resources/js/store/ApplicationStore.ts +++ b/resources/js/store/ApplicationStore.ts @@ -2,14 +2,12 @@ import { defineStore } from "pinia"; export interface ApplicationStore { dynamicTitle: string; - routerLoading: boolean; } export const useApplicationStore = defineStore({ id: "application", state: (): ApplicationStore => ({ dynamicTitle: "", - routerLoading: false, }), actions: { diff --git a/resources/js/views/App.vue b/resources/js/views/App.vue index 5675b65..9446e81 100644 --- a/resources/js/views/App.vue +++ b/resources/js/views/App.vue @@ -8,18 +8,14 @@ - +