73 lines
1.9 KiB
Vue
73 lines
1.9 KiB
Vue
<!-- LoadingCheck.vue -->
|
|
<script setup>
|
|
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
isComplete: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
size: {
|
|
type: Number,
|
|
default: 24
|
|
}
|
|
});
|
|
|
|
const dashOffset = ref(0);
|
|
let animationFrame = null;
|
|
|
|
const circleStyle = computed(() => ({
|
|
strokeDasharray: '60 60',
|
|
strokeDashoffset: props.isComplete ? '60' : String(dashOffset.value),
|
|
transition: props.isComplete ? 'all 0.2s ease-in-out' : 'none',
|
|
transformOrigin: 'center',
|
|
transform: `rotate(${props.isComplete ? -90 : 0}deg)`
|
|
}));
|
|
|
|
const checkStyle = computed(() => ({
|
|
opacity: props.isComplete ? 1 : 0,
|
|
strokeDasharray: 20,
|
|
strokeDashoffset: props.isComplete ? 0 : 20,
|
|
transition: 'all 0.3s ease-in-out',
|
|
transitionDelay: '0.2s'
|
|
}));
|
|
|
|
let startTime = null;
|
|
const animate = (timestamp) => {
|
|
if (!startTime) startTime = timestamp;
|
|
dashOffset.value = (timestamp - startTime) / 10;
|
|
animationFrame = requestAnimationFrame(animate);
|
|
};
|
|
|
|
watch(
|
|
() => props.isComplete,
|
|
(newValue) => {
|
|
if (newValue && animationFrame) {
|
|
cancelAnimationFrame(animationFrame);
|
|
animationFrame = null;
|
|
}
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
if (!props.isComplete) {
|
|
animationFrame = requestAnimationFrame(animate);
|
|
}
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (animationFrame) {
|
|
cancelAnimationFrame(animationFrame);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="inline-flex items-center justify-center">
|
|
<svg :width="size" :height="size" viewBox="0 0 24 24" class="transform transition-transform duration-500">
|
|
<circle cx="12" cy="12" r="8" fill="none" stroke="currentColor" stroke-width="2" class="text-blue-500" :style="circleStyle" />
|
|
<path d="M8 12l3 3l5-5" fill="none" stroke="currentColor" stroke-width="2" class="text-green-500" :style="checkStyle" />
|
|
</svg>
|
|
</div>
|
|
</template>
|