add loader bar

This commit is contained in:
2023-02-24 10:11:32 +10:00
parent 4261a35ca7
commit 25790d1c45
11 changed files with 53 additions and 86 deletions

6
package-lock.json generated
View File

@@ -5,6 +5,7 @@
"packages": { "packages": {
"": { "": {
"dependencies": { "dependencies": {
"@marcoschulte/vue3-progress": "^0.0.7",
"@tinymce/tinymce-vue": "^4.0.7", "@tinymce/tinymce-vue": "^4.0.7",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",
"@vuepic/vue-datepicker": "^3.6.4", "@vuepic/vue-datepicker": "^3.6.4",
@@ -518,6 +519,11 @@
"@jridgewell/sourcemap-codec": "^1.4.10" "@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": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",

View File

@@ -25,6 +25,7 @@
"vitest": "^0.28.5" "vitest": "^0.28.5"
}, },
"dependencies": { "dependencies": {
"@marcoschulte/vue3-progress": "^0.0.7",
"@tinymce/tinymce-vue": "^4.0.7", "@tinymce/tinymce-vue": "^4.0.7",
"@vitejs/plugin-vue": "^4.0.0", "@vitejs/plugin-vue": "^4.0.0",
"@vuepic/vue-datepicker": "^3.6.4", "@vuepic/vue-datepicker": "^3.6.4",

View File

@@ -3,6 +3,7 @@
@import "data-table.scss"; @import "data-table.scss";
@import "tinymce.scss"; @import "tinymce.scss";
@import "prism.css"; @import "prism.css";
@import "progressbar.scss";
* { * {
box-sizing: border-box; box-sizing: border-box;

View File

@@ -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;
}
}

View File

@@ -2,8 +2,7 @@
<template v-if="loading"> <template v-if="loading">
<transition name="fade"> <transition name="fade">
<div v-if="loading" class="sm-loader"> <div v-if="loading" class="sm-loader">
<SMLoadingIconToolbox v-if="type.toLowerCase() == 'toolbox'" /> <SMLoadingIcon />
<SMLoadingIconBalls v-else />
</div> </div>
</transition> </transition>
</template> </template>
@@ -11,8 +10,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import SMLoadingIconToolbox from "./SMLoadingIconToolbox.vue"; import SMLoadingIcon from "./SMLoadingIcon.vue";
import SMLoadingIconBalls from "./SMLoadingIcon.vue";
defineProps({ defineProps({
loading: { loading: {
@@ -20,11 +18,6 @@ defineProps({
default: false, default: false,
required: true, required: true,
}, },
type: {
type: String,
default: "",
required: false,
},
}); });
</script> </script>

View File

@@ -1,49 +0,0 @@
<template>
<div class="sm-loading-icon-toolbox">
<div class="loading-logo"></div>
<div class="loading-bar"></div>
</div>
</template>
<style lang="scss">
.sm-loading-icon-toolbox {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
.loading-logo {
background-image: url("/img/logo-small.png");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
height: 130px;
width: 130px;
}
.loading-bar {
width: 130px;
height: 10px;
background: #cfcfcf;
position: relative;
overflow: hidden;
border: 1px solid #aaa;
}
.loading-bar::before {
content: "";
width: 68px;
height: 10px;
background: $primary-color;
position: absolute;
left: -34px;
animation: bluebar 1.5s infinite ease;
}
}
@keyframes bluebar {
50% {
left: 96px;
}
}
</style>

View File

@@ -1,7 +1,7 @@
/* https://blog.logrocket.com/axios-vs-fetch-best-http-requests/ */
import { useUserStore } from "../store/UserStore"; import { useUserStore } from "../store/UserStore";
import { ProgressFinisher, useProgress } from "@marcoschulte/vue3-progress";
const progresses = [] as ProgressFinisher[];
interface ApiProgressData { interface ApiProgressData {
loaded: number; loaded: number;
total: number; total: number;
@@ -82,6 +82,8 @@ export const api = {
let receivedData = false; let receivedData = false;
progresses.push(useProgress().start());
fetch(url, fetchOptions) fetch(url, fetchOptions)
.then((response) => { .then((response) => {
receivedData = true; receivedData = true;
@@ -173,6 +175,9 @@ export const api = {
...rest, ...rest,
response: response && response.json(), response: response && response.json(),
}); });
})
.finally(() => {
progresses.pop()?.finish();
}); });
}); });
}, },

View File

@@ -12,6 +12,7 @@ import SMColumn from "./components/SMColumn.vue";
import { PromiseDialog } from "vue3-promise-dialog"; import { PromiseDialog } from "vue3-promise-dialog";
import { VueReCaptcha } from "vue-recaptcha-v3"; import { VueReCaptcha } from "vue-recaptcha-v3";
import "./lib/prism"; import "./lib/prism";
import { Vue3ProgressPlugin } from "@marcoschulte/vue3-progress";
const pinia = createPinia(); const pinia = createPinia();
pinia.use(piniaPluginPersistedstate); pinia.use(piniaPluginPersistedstate);
@@ -27,6 +28,7 @@ createApp(App)
autoHideBadge: true, autoHideBadge: true,
}, },
}) })
.use(Vue3ProgressPlugin)
.component("SMContainer", SMContainer) .component("SMContainer", SMContainer)
.component("SMRow", SMRow) .component("SMRow", SMRow)
.component("SMColumn", SMColumn) .component("SMColumn", SMColumn)

View File

@@ -2,6 +2,9 @@ import { createWebHistory, createRouter } from "vue-router";
import { useUserStore } from "@/store/UserStore"; import { useUserStore } from "@/store/UserStore";
import { useApplicationStore } from "../store/ApplicationStore"; import { useApplicationStore } from "../store/ApplicationStore";
import { api } from "../helpers/api"; import { api } from "../helpers/api";
import { useProgress } from "@marcoschulte/vue3-progress";
const progresses = [];
export const routes = [ export const routes = [
{ {
@@ -371,22 +374,11 @@ const router = createRouter({
// export let activeRoutes = []; // export let activeRoutes = [];
let routerLoadingTimeout = null;
router.beforeEach(async (to, from, next) => { router.beforeEach(async (to, from, next) => {
const userStore = useUserStore(); const userStore = useUserStore();
const applicationStore = useApplicationStore(); const applicationStore = useApplicationStore();
if (routerLoadingTimeout != null) { progresses.push(useProgress().start());
clearTimeout(routerLoadingTimeout);
routerLoadingTimeout = null;
}
routerLoadingTimeout = window.setTimeout(() => {
routerLoadingTimeout = null;
applicationStore.setRouterLoading(true);
}, 1000);
applicationStore.clearDynamicTitle(); applicationStore.clearDynamicTitle();
// Check Token // Check Token
@@ -470,13 +462,7 @@ router.beforeEach(async (to, from, next) => {
}); });
router.afterEach((to, from) => { router.afterEach((to, from) => {
if (routerLoadingTimeout != null) { progresses.pop()?.finish();
clearTimeout(routerLoadingTimeout);
routerLoadingTimeout = null;
}
const applicationStore = useApplicationStore();
applicationStore.setRouterLoading(false);
}); });
export default router; export default router;

View File

@@ -2,14 +2,12 @@ import { defineStore } from "pinia";
export interface ApplicationStore { export interface ApplicationStore {
dynamicTitle: string; dynamicTitle: string;
routerLoading: boolean;
} }
export const useApplicationStore = defineStore({ export const useApplicationStore = defineStore({
id: "application", id: "application",
state: (): ApplicationStore => ({ state: (): ApplicationStore => ({
dynamicTitle: "", dynamicTitle: "",
routerLoading: false,
}), }),
actions: { actions: {

View File

@@ -8,18 +8,14 @@
</router-view> </router-view>
</main> </main>
<SMFooter /> <SMFooter />
<SMLoader type="toolbox" :loading="applicationStore.routerLoading" /> <vue3-progress-bar></vue3-progress-bar>
<DialogWrapper :transition-attrs="{ name: 'fade' }" /> <DialogWrapper :transition-attrs="{ name: 'fade' }" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import SMNavbar from "../components/SMNavbar.vue"; import SMNavbar from "../components/SMNavbar.vue";
import SMFooter from "../components/SMFooter.vue"; import SMFooter from "../components/SMFooter.vue";
import SMLoader from "../components/SMLoader.vue";
import { DialogWrapper } from "vue3-promise-dialog"; import { DialogWrapper } from "vue3-promise-dialog";
import { useApplicationStore } from "../store/ApplicationStore";
const applicationStore = useApplicationStore();
</script> </script>
<style lang="scss"> <style lang="scss">