116 lines
3.3 KiB
Vue
116 lines
3.3 KiB
Vue
<template>
|
|
<BaseModal
|
|
:modelValue="modelValue"
|
|
@update:modelValue="$emit('update:modelValue', $event)"
|
|
:modalTitle="false"
|
|
>
|
|
<div class="confirm-modal-body p-4 text-center">
|
|
<div v-if="variant === 'danger'" class="icon-circle bg-soft-danger text-danger mb-3 mx-auto">
|
|
<i class="fas fa-exclamation-triangle fa-2x"></i>
|
|
</div>
|
|
<div v-else-if="variant === 'warning'" class="icon-circle bg-soft-warning text-warning mb-3 mx-auto">
|
|
<i class="fas fa-exclamation-circle fa-2x"></i>
|
|
</div>
|
|
<div v-else class="icon-circle bg-soft-primary text-primary mb-3 mx-auto">
|
|
<i class="fas fa-info-circle fa-2x"></i>
|
|
</div>
|
|
|
|
<h3 class="fw_8 mb-2">{{ title }}</h3>
|
|
<p class="text-muted mb-0">{{ message }}</p>
|
|
</div>
|
|
|
|
<template #footer>
|
|
<div class="d-flex w-100 gap-2 mb-2 px-2">
|
|
<button type="button" class="btn btn-light flex-fill rounded-pill py-2 fw_6" @click="handleCancel">
|
|
{{ cancelText }}
|
|
</button>
|
|
<button type="button" :class="confirmBtnClass" class="btn flex-fill rounded-pill py-2 fw_6" @click="handleConfirm">
|
|
{{ confirmText }}
|
|
</button>
|
|
</div>
|
|
</template>
|
|
</BaseModal>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue';
|
|
import BaseModal from './BaseModal.vue';
|
|
|
|
const props = defineProps({
|
|
modelValue: { type: Boolean, required: true },
|
|
title: { type: String, default: 'Confirm Action' },
|
|
message: { type: String, default: 'Are you sure you want to proceed?' },
|
|
confirmText: { type: String, default: 'Confirm' },
|
|
cancelText: { type: String, default: 'Cancel' },
|
|
variant: { type: String, default: 'info' } // danger, warning, info
|
|
});
|
|
|
|
const emit = defineEmits(['update:modelValue', 'confirm', 'cancel']);
|
|
|
|
const confirmBtnClass = computed(() => {
|
|
if (props.variant === 'danger') return 'btn-danger shadow-danger';
|
|
if (props.variant === 'warning') return 'btn-warning shadow-warning';
|
|
return 'btn-primary shadow-primary';
|
|
});
|
|
|
|
const handleCancel = () => {
|
|
emit('cancel');
|
|
emit('update:modelValue', false);
|
|
};
|
|
|
|
const handleConfirm = () => {
|
|
emit('confirm');
|
|
emit('update:modelValue', false);
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.confirm-modal-body {
|
|
min-height: 180px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
}
|
|
|
|
.icon-circle {
|
|
width: 70px;
|
|
height: 70px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
}
|
|
|
|
.confirm-modal-body:hover .icon-circle {
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
.bg-soft-danger { background-color: rgba(231, 76, 60, 0.1); }
|
|
.bg-soft-warning { background-color: rgba(243, 156, 18, 0.1); }
|
|
.bg-soft-primary { background-color: rgba(52, 152, 219, 0.1); }
|
|
|
|
.shadow-danger {
|
|
background-color: #e74c3c !important;
|
|
border-color: #e74c3c !important;
|
|
color: white !important;
|
|
box-shadow: 0 4px 14px rgba(231, 76, 60, 0.4);
|
|
}
|
|
.shadow-warning {
|
|
background-color: #f39c12 !important;
|
|
border-color: #f39c12 !important;
|
|
color: white !important;
|
|
box-shadow: 0 4px 14px rgba(243, 156, 18, 0.4);
|
|
}
|
|
.shadow-primary {
|
|
background-color: #3498db !important;
|
|
border-color: #3498db !important;
|
|
color: white !important;
|
|
box-shadow: 0 4px 14px rgba(52, 152, 219, 0.4);
|
|
}
|
|
|
|
:global(.dark-mode) .icon-circle {
|
|
filter: brightness(1.2);
|
|
}
|
|
</style>
|