111 lines
4.3 KiB
Vue
111 lines
4.3 KiB
Vue
<script setup>
|
|
import { ref } from 'vue'
|
|
import DashboardLayout from '../layouts/DashboardLayout.vue'
|
|
|
|
const dismissed = ref(new Set())
|
|
|
|
const alerts = [
|
|
{ id: 1, type: 'success', icon: 'check_circle', title: 'Success', message: 'This is a success notification — something went well.' },
|
|
{ id: 2, type: 'info', icon: 'info', title: 'Info', message: 'This is an info notification — just letting you know.' },
|
|
{ id: 3, type: 'warning', icon: 'warning', title: 'Warning', message: 'This is a warning notification — you should take action.' },
|
|
{ id: 4, type: 'danger', icon: 'error', title: 'Error', message: 'This is an error notification — something went wrong.' },
|
|
]
|
|
|
|
const typeStyle = {
|
|
success: 'bg-success text-white',
|
|
info: 'bg-info text-white',
|
|
warning: 'bg-warning text-white',
|
|
danger: 'bg-danger text-white',
|
|
}
|
|
|
|
const notifications = [
|
|
{ id: 10, avatar: 'PC', color: 'primary', name: 'Patrick Collins', time: '13 minutes ago', text: 'New message in Design System channel' },
|
|
{ id: 11, avatar: 'MR', color: 'info', name: 'Mikaela Ramos', time: '2 hours ago', text: 'Updated the icon grid component' },
|
|
{ id: 12, avatar: 'TP', color: 'success', name: 'Tom Perez', time: 'Yesterday', text: 'Released v0.2.0 with table improvements' },
|
|
{ id: 13, avatar: 'LC', color: 'warning', name: 'Lacina Cosmo', time: '2 days ago', text: 'Flagged a responsiveness issue on mobile' },
|
|
{ id: 14, avatar: 'AM', color: 'danger', name: 'Ally Maria', time: 'Last week', text: 'Added font preload entries to index.html' },
|
|
]
|
|
|
|
function dismiss(id) {
|
|
dismissed.value.add(id)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<DashboardLayout>
|
|
<div class="grid gap-6 lg:grid-cols-2">
|
|
|
|
<!-- Dismissible alerts -->
|
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
|
<h6 class="mb-1 text-sm font-bold text-dark">Alert States</h6>
|
|
<p class="mb-6 text-xs text-secondary">Dismissible alerts for each semantic color</p>
|
|
<div class="space-y-3">
|
|
<transition-group name="alert">
|
|
<div
|
|
v-for="alert in alerts"
|
|
v-show="!dismissed.has(alert.id)"
|
|
:key="alert.id"
|
|
class="flex items-start gap-3 rounded-lg p-4 text-sm font-medium"
|
|
:class="typeStyle[alert.type]"
|
|
>
|
|
<span class="material-icons text-lg leading-none shrink-0">{{ alert.icon }}</span>
|
|
<p class="flex-1">
|
|
<span class="font-bold">{{ alert.title }} — </span>{{ alert.message }}
|
|
</p>
|
|
<button
|
|
class="shrink-0 opacity-70 hover:opacity-100 transition-opacity"
|
|
@click="dismiss(alert.id)"
|
|
>
|
|
<span class="material-icons text-lg leading-none">close</span>
|
|
</button>
|
|
</div>
|
|
</transition-group>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Notification feed -->
|
|
<div class="rounded-2xl bg-white p-6 shadow-soft-md">
|
|
<div class="mb-6 flex items-center justify-between">
|
|
<h6 class="text-sm font-bold text-dark">Recent Notifications</h6>
|
|
<span class="rounded-full bg-primary/10 px-2.5 py-1 text-xs font-medium text-primary">
|
|
{{ notifications.length }} new
|
|
</span>
|
|
</div>
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="n in notifications"
|
|
:key="n.id"
|
|
class="flex items-start gap-3"
|
|
>
|
|
<div
|
|
class="flex h-9 w-9 shrink-0 items-center justify-center rounded-xl text-xs font-bold text-white shadow-soft-sm"
|
|
:class="`bg-gradient-${n.color} shadow-${n.color}`"
|
|
>
|
|
{{ n.avatar }}
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<p class="text-sm font-medium text-dark truncate">{{ n.name }}</p>
|
|
<p class="text-xs text-secondary mt-0.5">{{ n.text }}</p>
|
|
</div>
|
|
<span class="shrink-0 text-xs text-secondary">{{ n.time }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</DashboardLayout>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.alert-leave-active {
|
|
transition: all 0.3s ease;
|
|
}
|
|
.alert-leave-to {
|
|
opacity: 0;
|
|
transform: translateX(1rem);
|
|
max-height: 0;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
</style>
|