web-frontend/src/components/SuspenseRouterView.vue

60 lines
No EOL
1.2 KiB
Vue

<template>
<router-view v-slot="{ Component }">
<template v-if="Component">
<suspense @pending="loading = true" @resolve="loading = false">
<!-- The key makes that components are not reused if only params changed -->
<component :is="Component" :key="JSON.stringify($route.params)"/>
</suspense>
</template>
</router-view>
<div
class="pt-10 absolute inset-0 bg-background"
:class="$style.loadingOverlay"
:data-is-visible="loading || forceLoading"
>
<div class="flex justify-center gap-3 text-2xl p-8" :class="$style.loadingIndicator">
<LoadingIcon/>
<span>{{ loadingText }}</span>
</div>
</div>
</template>
<style module lang="scss">
.loadingOverlay {
opacity: 0;
transition: 100ms ease opacity;
&[data-is-visible="true"] {
opacity: 100%;
transition-duration: 200ms;
.loadingIndicator {
opacity: 100%;
}
}
&[data-is-visible="false"] {
pointer-events: none;
}
}
.loadingIndicator {
opacity: 0;
transition: 200ms ease opacity;
}
</style>
<script setup lang="ts">
import { ref } from "vue"
import LoadingIcon from "./LoadingIcon.vue"
defineProps({
loadingText: {
type: String,
default: "Loading…"
},
forceLoading: Boolean
})
const loading = ref(false)
</script>