add loader bar
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
28
resources/css/progressbar.scss
Normal file
28
resources/css/progressbar.scss
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
Reference in New Issue
Block a user