Improve snackbar style and duration

This commit is contained in:
josedario87
2025-06-11 04:25:40 -06:00
parent 74b9c0ad7e
commit aa480e8faa
3 changed files with 29 additions and 36 deletions

View File

@@ -1,12 +1,13 @@
<template> <template>
<div class="snackbar-wrapper pointer-events-none"> <div class="snackbar-wrapper pointer-events-none">
<transition-group name="snackbar" tag="div" class="snackbar-container"> <transition-group name="snackbar" tag="div" class="flex flex-col gap-2">
<div <div
v-for="snack in snackbar.snacks" v-for="snack in snackbar.snacks"
:key="snack.id" :key="snack.id"
:class="['snackbar', snack.type]" :class="['snackbar-item', typeClass(snack.type)]"
> >
{{ snack.text }} <span class="flex-1">{{ snack.text }}</span>
<button class="ml-3 text-white/70 hover:text-white" @click="snackbar.remove(snack.id)">&times;</button>
</div> </div>
</transition-group> </transition-group>
</div> </div>
@@ -15,10 +16,22 @@
<script setup> <script setup>
import { useSnackbarStore } from '@/stores/useSnackbar' import { useSnackbarStore } from '@/stores/useSnackbar'
const typeClass = (t) => {
switch (t) {
case 'success':
return 'bg-green-600/90'
case 'error':
return 'bg-red-600/90'
default:
return 'bg-gray-800/90'
}
}
const snackbar = useSnackbarStore() const snackbar = useSnackbarStore()
</script> </script>
<style scoped> <style scoped>
.snackbar-wrapper { .snackbar-wrapper {
position: fixed; position: fixed;
bottom: 1rem; bottom: 1rem;
@@ -26,42 +39,16 @@ const snackbar = useSnackbarStore()
z-index: 1000; z-index: 1000;
} }
.snackbar-container { .snackbar-item {
display: flex; @apply pointer-events-auto text-white px-4 py-3 rounded-md shadow-lg flex items-start;
flex-direction: column;
gap: 0.5rem;
} }
.snackbar {
pointer-events: auto;
background-color: #333;
color: white;
padding: 0.75rem 1rem;
border-radius: 0.375rem;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
}
.snackbar.info {
background-color: #323232;
}
.snackbar.success {
background-color: #22c55e;
color: #fff;
}
.snackbar.error {
background-color: #ef4444;
color: #fff;
}
.snackbar-enter-active, .snackbar-enter-active,
.snackbar-leave-active { .snackbar-leave-active {
transition: opacity 0.3s, transform 0.3s; transition: opacity 0.35s, transform 0.35s;
} }
.snackbar-enter-from, .snackbar-enter-from,
.snackbar-leave-to { .snackbar-leave-to {
opacity: 0; opacity: 0;
transform: translateY(20px); transform: translateY(16px);
} }
</style> </style>

View File

@@ -59,7 +59,9 @@ export const useRealtimeStore = defineStore('realtime', {
const snackbar = useSnackbarStore(); const snackbar = useSnackbarStore();
const idPart = payload.new?.id || payload.old?.id; const idPart = payload.new?.id || payload.old?.id;
const message = `${payload.operation} ${payload.table}${idPart ? ' #' + idPart : ''}`; const message = `${payload.operation} ${payload.table}${idPart ? ' #' + idPart : ''}`;
snackbar.push({ text: message }); const type = payload.operation === 'DELETE' ? 'error' :
payload.operation === 'INSERT' ? 'success' : 'info';
snackbar.push({ text: message, type });
// mark badge for module and operation // mark badge for module and operation
if (this.badges[payload.table]) { if (this.badges[payload.table]) {

View File

@@ -2,12 +2,16 @@ import { defineStore } from 'pinia'
export const useSnackbarStore = defineStore('snackbar', { export const useSnackbarStore = defineStore('snackbar', {
state: () => ({ state: () => ({
snacks: [] snacks: [],
maxSnacks: 5
}), }),
actions: { actions: {
push({ text, type = 'info', duration = 4000 }) { push({ text, type = 'info', duration = 6000 }) {
const id = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).slice(2) const id = crypto.randomUUID ? crypto.randomUUID() : Date.now().toString(36) + Math.random().toString(36).slice(2)
const snack = { id, text, type } const snack = { id, text, type }
if (this.snacks.length >= this.maxSnacks) {
this.snacks.shift()
}
this.snacks.push(snack) this.snacks.push(snack)
if (duration > 0) { if (duration > 0) {
setTimeout(() => this.remove(id), duration) setTimeout(() => this.remove(id), duration)