feat(ui): compact toast notifications and skeleton editor selection
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div class="toast-container fixed top-4 right-4 z-50 space-y-2 pointer-events-none">
|
||||
<div
|
||||
class="toast-container pointer-events-none fixed bottom-4 right-4 z-50 flex flex-col gap-2 items-end"
|
||||
>
|
||||
<TransitionGroup name="toast">
|
||||
<div
|
||||
v-for="toast in toasts"
|
||||
@@ -7,11 +9,11 @@
|
||||
class="toast-item"
|
||||
:class="[
|
||||
'transform transition-all duration-300 ease-in-out',
|
||||
toast.visible ? 'translate-x-0 opacity-100 pointer-events-auto' : 'translate-x-full opacity-0 pointer-events-none'
|
||||
toast.visible ? 'translate-y-0 opacity-100 pointer-events-auto' : 'translate-y-4 opacity-0 pointer-events-none'
|
||||
]"
|
||||
>
|
||||
<div
|
||||
class="alert shadow-lg max-w-sm"
|
||||
class="alert toast-card shadow-md px-3 py-2 text-sm"
|
||||
:class="getToastClasses(toast.type)"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
@@ -19,37 +21,37 @@
|
||||
<div class="flex-shrink-0">
|
||||
<IconLucideCheck
|
||||
v-if="toast.type === 'success'"
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IconLucideX
|
||||
v-else-if="toast.type === 'error'"
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IconLucideAlertTriangle
|
||||
v-else-if="toast.type === 'warning'"
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<IconLucideInfo
|
||||
v-else
|
||||
class="w-5 h-5"
|
||||
class="w-4 h-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Message -->
|
||||
<div class="flex-1">
|
||||
<span class="text-sm font-medium">{{ toast.message }}</span>
|
||||
<span class="font-medium">{{ toast.message }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Close button -->
|
||||
<button
|
||||
class="btn btn-ghost btn-xs"
|
||||
class="btn btn-ghost btn-2xs"
|
||||
@click="removeToast(toast.id)"
|
||||
>
|
||||
<IconLucideX class="w-4 h-4" aria-hidden="true" />
|
||||
<IconLucideX class="w-3 h-3" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,13 +72,13 @@ const { toasts, removeToast } = useToast()
|
||||
const getToastClasses = (type) => {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
return 'alert-success'
|
||||
return 'alert-success text-success-content'
|
||||
case 'error':
|
||||
return 'alert-error'
|
||||
return 'alert-error text-error-content'
|
||||
case 'warning':
|
||||
return 'alert-warning'
|
||||
return 'alert-warning text-warning-content'
|
||||
case 'info':
|
||||
return 'alert-info'
|
||||
return 'alert-info text-info-content'
|
||||
default:
|
||||
return 'alert-info'
|
||||
}
|
||||
@@ -91,15 +93,21 @@ const getToastClasses = (type) => {
|
||||
|
||||
.toast-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transform: translateY(16px);
|
||||
}
|
||||
|
||||
.toast-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transform: translateY(16px);
|
||||
}
|
||||
|
||||
.toast-move {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.toast-card {
|
||||
max-width: 20rem;
|
||||
pointer-events: auto;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const toasts = ref([])
|
||||
const MAX_TOASTS = 3
|
||||
let nextId = 1
|
||||
|
||||
export function useToast () {
|
||||
const showToast = (message, type = 'info', duration = 5000) => {
|
||||
const showToast = (message, type = 'info', duration = 3500) => {
|
||||
const id = nextId++
|
||||
const toast = {
|
||||
id,
|
||||
@@ -13,6 +14,10 @@ export function useToast () {
|
||||
visible: true
|
||||
}
|
||||
|
||||
if (toasts.value.length >= MAX_TOASTS) {
|
||||
toasts.value.shift()
|
||||
}
|
||||
|
||||
toasts.value.push(toast)
|
||||
|
||||
// Auto-remove after duration
|
||||
@@ -27,7 +32,7 @@ export function useToast () {
|
||||
return showToast(message, 'success', duration)
|
||||
}
|
||||
|
||||
const showError = (message, duration = 7000) => {
|
||||
const showError = (message, duration = 5000) => {
|
||||
return showToast(message, 'error', duration)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user