forked from nikita/muzika-gromche
93 lines
2.4 KiB
Vue
93 lines
2.4 KiB
Vue
<script setup lang="ts">
|
|
import { TransitionPresets, useTransition, watchDebounced } from "@vueuse/core";
|
|
import { computed, shallowRef, useId } from "vue";
|
|
import ScreenTransition from "./ScreenTransition.vue";
|
|
|
|
const {
|
|
visible,
|
|
message = "Loading…",
|
|
progress = undefined,
|
|
} = defineProps<{
|
|
visible: boolean,
|
|
message?: string,
|
|
// loading progress, range 0..1
|
|
progress?: number | undefined,
|
|
}>();
|
|
|
|
// CSS transition on width does not work in Firefox
|
|
const zeroProgress = computed(() => progress ?? 0);
|
|
const easedProgress = useTransition(zeroProgress, {
|
|
duration: 400,
|
|
easing: TransitionPresets.easeInOutQuad,
|
|
});
|
|
|
|
const progressId = useId();
|
|
// Let the progress animation finish before cutting it off of updates
|
|
const actuallyVisible = shallowRef(visible);
|
|
watchDebounced(() => visible, () => {
|
|
actuallyVisible.value = visible;
|
|
}, { debounce: 600 })
|
|
</script>
|
|
<template>
|
|
<ScreenTransition :visible="actuallyVisible">
|
|
<div class="tw:h-full tw:flex tw:flex-col tw:gap-8 tw:items-center tw:justify-center tw:text-2xl">
|
|
<label :for="progressId">
|
|
{{ message }}
|
|
</label>
|
|
<progress :id="progressId" class="progress" max="1" :value="easedProgress">
|
|
<template v-if="progress !== undefined">
|
|
{{ Math.floor(progress * 100) }} %
|
|
</template>
|
|
</progress>
|
|
</div>
|
|
</ScreenTransition>
|
|
</template>
|
|
|
|
<style scoped>
|
|
label {
|
|
user-select: none;
|
|
}
|
|
|
|
.progress {
|
|
appearance: none;
|
|
background-color: #1a1a1a;
|
|
height: 24px;
|
|
padding: 5px;
|
|
width: 350px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 1px 5px #000 inset, 0 1px 0 #444;
|
|
}
|
|
|
|
.progress::-webkit-progress-bar {
|
|
appearance: none;
|
|
background: none;
|
|
}
|
|
|
|
/* for some reason combining these two selector via comma breaks Chromium */
|
|
.progress::-webkit-progress-value {
|
|
appearance: none;
|
|
height: 100%;
|
|
border-radius: 3px;
|
|
background-color: #444;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
|
|
|
|
background-image: -webkit-linear-gradient(135deg,
|
|
transparent 33%, rgba(0, 0, 0, .1) 33%,
|
|
rgba(0, 0, 0, .1) 66%, transparent 66%);
|
|
background-size: 35px 20px;
|
|
}
|
|
|
|
.progress::-moz-progress-bar {
|
|
appearance: none;
|
|
background-color: #444;
|
|
height: 100%;
|
|
border-radius: 3px;
|
|
box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
|
|
|
|
background-image: repeating-linear-gradient(135deg,
|
|
transparent 0%, transparent 33%,
|
|
rgba(0, 0, 0, .1) 33%, rgba(0, 0, 0, .1) 66%);
|
|
background-size: 35px 100%;
|
|
}
|
|
</style>
|