polarpress-pagebuilder/resources/js/components/Toast.vue
Helge-Mikael Nordgård e15d3ae146
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (push) Waiting to run
Transferred and translated the frontend code from L10 to L12
2025-05-05 19:01:27 +02:00

139 lines
5.0 KiB
Vue

<script setup>
import { ref, watch, computed } from 'vue';
import { usePage } from '@inertiajs/vue3';
import { toastMessage } from '@/Composables/useToast';
const show = ref(false);
const message = ref('');
const type = ref('success');
const page = usePage();
const props = defineProps({
duration: {
type: Number,
default: 4,
},
});
const closeToast = () => {
show.value = false;
};
watch(() => page.props.flash, (flash) => {
if (flash.success || flash.error || flash.warning || flash.info) {
show.value = true;
message.value = flash.success || flash.error || flash.warning || flash.info;
type.value = flash.success
? 'success'
: flash.error
? 'danger'
: flash.warning
? 'warning'
: 'info';
setTimeout(() => {
show.value = false;
}, props.duration * 1000);
}
}, { immediate: true });
// Watch for global toast messages
watch(toastMessage, (val) => {
if (val) {
message.value = val.message;
type.value = val.type;
show.value = true;
setTimeout(() => {
show.value = false;
toastMessage.value = null;
}, props.duration * 1000);
}
});
const toastClasses = computed(() => {
console.log('Toast type is:', type.value);
switch (type.value) {
case 'success':
return 'text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200';
case 'danger':
return 'text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200';
case 'warning':
return 'text-orange-500 bg-orange-100 dark:bg-orange-700 dark:text-orange-200';
case 'info':
return 'text-blue-500 bg-blue-100 dark:bg-blue-800 dark:text-blue-200';
default:
return 'text-gray-800 bg-white dark:bg-gray-800 dark:text-gray-200';
}
});
</script>
<template>
<transition name="fade">
<div
v-if="show"
class="fixed top-5 right-5 z-50 w-full max-w-xs flex items-center p-4 rounded-lg shadow-sm"
:class="toastClasses"
role="alert"
>
<div class="inline-flex items-center justify-center shrink-0 w-8 h-8 rounded-lg">
<svg
v-if="type === 'success'"
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
</svg>
<svg
v-else-if="type === 'danger'"
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 11.793a1 1 0 1 1-1.414 1.414L10 11.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L8.586 10 6.293 7.707a1 1 0 0 1 1.414-1.414L10 8.586l2.293-2.293a1 1 0 0 1 1.414 1.414L11.414 10l2.293 2.293Z"/>
</svg>
<svg
v-else-if="type === 'warning'"
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM10 15a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-4a1 1 0 0 1-2 0V6a1 1 0 0 1 2 0v5Z"/>
</svg>
<svg
v-else
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
>
<path d="M10 2a8 8 0 100 16 8 8 0 000-16zm1 11H9v-2h2v2zm0-4H9V5h2v4z"/>
</svg>
</div>
<div class="ms-3 text-sm font-normal">
{{ message }}
</div>
<button
type="button"
@click="closeToast"
class="ms-auto -mx-1.5 -my-1.5 text-gray-400 hover:text-gray-900 rounded-lg focus:ring-2 focus:ring-gray-300 p-1.5 hover:bg-gray-100 inline-flex items-center justify-center h-8 w-8 dark:hover:text-white dark:hover:bg-gray-700"
>
<svg class="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1l6 6m0 0l6 6M7 7L1 13m6-6l6-6"/>
</svg>
</button>
</div>
</transition>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.4s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>