initial: bootstrap from BukidBountyApp base
This commit is contained in:
150
resources/js/Components/SystemBroadcast.vue
Normal file
150
resources/js/Components/SystemBroadcast.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import axios from 'axios';
|
||||
|
||||
const message = ref(null);
|
||||
const visible = ref(true);
|
||||
|
||||
const fetchMessage = async () => {
|
||||
try {
|
||||
const response = await axios.get('/api/public/global-message');
|
||||
if (response.data.success && response.data.data) {
|
||||
message.value = response.data.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching global message:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const dismiss = () => {
|
||||
visible.value = false;
|
||||
// Optional: Store in localStorage to keep it dismissed for the session
|
||||
sessionStorage.setItem('dismissed_global_message', JSON.stringify(message.value));
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const dismissed = sessionStorage.getItem('dismissed_global_message');
|
||||
fetchMessage().then(() => {
|
||||
if (dismissed && message.value && JSON.stringify(message.value) === dismissed) {
|
||||
visible.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh every 30 seconds
|
||||
setInterval(fetchMessage, 30000);
|
||||
});
|
||||
|
||||
const getIcon = (type) => {
|
||||
switch (type) {
|
||||
case 'success': return 'check-circle';
|
||||
case 'warning': return 'exclamation-triangle';
|
||||
case 'danger': return 'exclamation-circle';
|
||||
default: return 'info-circle';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<transition name="fade">
|
||||
<div v-if="message && visible" :class="['system-broadcast', `broadcast-${message.type || 'info'}`]">
|
||||
<div class="broadcast-container">
|
||||
<div class="broadcast-content">
|
||||
<i :class="['fas', `fa-${getIcon(message.type)}`, 'broadcast-icon']"></i>
|
||||
<span class="broadcast-text">{{ message.text }}</span>
|
||||
</div>
|
||||
<button class="broadcast-close" @click="dismiss">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.system-broadcast {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
position: relative;
|
||||
z-index: 10001;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
animation: slideDown 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from { transform: translateY(-100%); }
|
||||
to { transform: translateY(0); }
|
||||
}
|
||||
|
||||
.broadcast-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.broadcast-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.broadcast-icon {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.broadcast-text {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.broadcast-close {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: inherit;
|
||||
font-size: 1.1rem;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
padding: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.broadcast-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Types */
|
||||
.broadcast-info {
|
||||
background: linear-gradient(90deg, #0284c7, #0ea5e9);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.broadcast-success {
|
||||
background: linear-gradient(90deg, #059669, #10b981);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.broadcast-warning {
|
||||
background: linear-gradient(90deg, #d97706, #f59e0b);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.broadcast-danger {
|
||||
background: linear-gradient(90deg, #dc2626, #ef4444);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.5s, transform 0.5s;
|
||||
}
|
||||
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user