59 lines
1.6 KiB
Vue
59 lines
1.6 KiB
Vue
<script setup lang="ts">
|
|
import { useResumesStore } from '@/stores/resume';
|
|
import { computed, ref, watch } from 'vue';
|
|
import { CloudCheck, LoaderCircle, CircleAlert } from 'lucide-vue-next';
|
|
|
|
const resumeStore = useResumesStore();
|
|
|
|
const DISAPPEAR_DELAY = 5000;
|
|
|
|
const isSaving = computed(() => resumeStore.isSaving);
|
|
|
|
const error = ref<string | null>(null);
|
|
watch(() => resumeStore.savingError, (newError) => {
|
|
error.value = newError;
|
|
if (newError) {
|
|
showSaved.value = false;
|
|
}
|
|
});
|
|
|
|
const showSaved = ref(false);
|
|
let showSavedTimeout: ReturnType<typeof setTimeout>;
|
|
watch(isSaving, (newIsSaving: boolean) => {
|
|
if (!newIsSaving && !error.value) {
|
|
if (showSavedTimeout) {
|
|
clearTimeout(showSavedTimeout);
|
|
}
|
|
showSaved.value = true;
|
|
showSavedTimeout = setTimeout(() => {
|
|
showSaved.value = false;
|
|
}, DISAPPEAR_DELAY);
|
|
} else {
|
|
showSaved.value = false;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex justify-between gap-2 items-center p-3 h-4">
|
|
<p class="text-red-400">{{ error }}</p>
|
|
<Transition mode="out-in" appear>
|
|
<CircleAlert class="w-4 h-4 text-red-500" v-if="error"/>
|
|
<LoaderCircle class="w-4 h-4 animate-spin" v-else-if="isSaving"/>
|
|
<CloudCheck class="w-4 h-4" v-else-if="showSaved" title="Sauvegardé"/>
|
|
</Transition>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="css" scoped>
|
|
.v-enter-active,
|
|
.v-leave-active {
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.v-enter-from,
|
|
.v-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style>
|