104 lines
2.7 KiB
Vue
104 lines
2.7 KiB
Vue
<template>
|
|
<div class="fixed left-1/2 top-30 z-999 -translate-x-1/2">
|
|
<transition
|
|
name="alert"
|
|
enter-active-class="alert-enter-active"
|
|
leave-active-class="alert-leave-active"
|
|
enter-from-class="alert-enter-from"
|
|
enter-to-class="alert-enter-to"
|
|
leave-from-class="alert-leave-from"
|
|
leave-to-class="alert-leave-to"
|
|
>
|
|
<div
|
|
v-if="alertStore?.alertState.value.visible"
|
|
:class="alertClasses"
|
|
class="alert"
|
|
>
|
|
<div class="flex items-center gap-2">
|
|
<!-- Icons for different alert types -->
|
|
<CheckCircle
|
|
v-if="alertStore?.alertState.value.type === 'success'"
|
|
class="h-6 w-6 shrink-0 stroke-current"
|
|
/>
|
|
<XCircle
|
|
v-else-if="alertStore?.alertState.value.type === 'error'"
|
|
class="h-6 w-6 shrink-0 stroke-current"
|
|
/>
|
|
<AlertTriangle
|
|
v-else-if="alertStore?.alertState.value.type === 'warning'"
|
|
class="h-6 w-6 shrink-0 stroke-current"
|
|
/>
|
|
<Info v-else class="h-6 w-6 shrink-0 stroke-current" />
|
|
<span>{{ alertStore?.alertState.value.message }}</span>
|
|
</div>
|
|
<div class="flex-none">
|
|
<button
|
|
class="btn btn-sm btn-circle btn-ghost"
|
|
@click="alertStore?.hide"
|
|
>
|
|
<X class="h-4 w-4" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from "vue";
|
|
import { CheckCircle, XCircle, AlertTriangle, Info, X } from "lucide-vue-next";
|
|
import { useAlertStore } from ".";
|
|
import { useRequiredInjection } from "@/utils/Common";
|
|
|
|
const alertStore = useRequiredInjection(useAlertStore);
|
|
|
|
// Computed classes for different alert types
|
|
const alertClasses = computed(() => {
|
|
const baseClasses = "shadow-lg max-w-sm";
|
|
|
|
switch (alertStore.alertState.value.type) {
|
|
case "success":
|
|
return `${baseClasses} alert-success`;
|
|
case "error":
|
|
return `${baseClasses} alert-error`;
|
|
case "warning":
|
|
return `${baseClasses} alert-warning`;
|
|
case "info":
|
|
default:
|
|
return `${baseClasses} alert-info`;
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* 进入和离开的过渡动画持续时间 */
|
|
.alert-enter-active,
|
|
.alert-leave-active {
|
|
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
}
|
|
|
|
/* 进入的起始状态 */
|
|
.alert-enter-from {
|
|
opacity: 0;
|
|
transform: translateY(-20px) scale(0.95);
|
|
}
|
|
|
|
/* 进入的结束状态 */
|
|
.alert-enter-to {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
}
|
|
|
|
/* 离开的起始状态 */
|
|
.alert-leave-from {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
}
|
|
|
|
/* 离开的结束状态 */
|
|
.alert-leave-to {
|
|
opacity: 0;
|
|
transform: translateY(-10px) scale(0.98);
|
|
}
|
|
</style>
|