feat: toast undo button and hover/focus pause
This commit is contained in:
@@ -1,17 +1,30 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useToastStore } from '../stores/toast'
|
import { useToastStore } from '../stores/toast'
|
||||||
import { Check, AlertCircle, Info } from 'lucide-vue-next'
|
import { Check, AlertCircle, Info, X, Undo2 } from 'lucide-vue-next'
|
||||||
|
|
||||||
const toastStore = useToastStore()
|
const toastStore = useToastStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed top-4 left-1/2 -translate-x-1/2 z-[100] flex flex-col gap-2 pointer-events-none" style="margin-left: 24px;">
|
<div
|
||||||
|
role="region"
|
||||||
|
aria-label="Notifications"
|
||||||
|
aria-live="polite"
|
||||||
|
aria-atomic="false"
|
||||||
|
class="fixed top-4 left-1/2 -translate-x-1/2 z-[100] flex flex-col gap-2 pointer-events-none"
|
||||||
|
style="margin-left: 24px;"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
v-for="toast in toastStore.toasts"
|
v-for="toast in toastStore.toasts"
|
||||||
:key="toast.id"
|
:key="toast.id"
|
||||||
@click="toastStore.removeToast(toast.id)"
|
:role="toast.type === 'error' ? 'alert' : 'status'"
|
||||||
class="w-80 flex items-center gap-3 px-4 py-3 bg-bg-surface border border-border-subtle rounded-lg shadow-lg cursor-pointer pointer-events-auto border-l-[3px]"
|
tabindex="0"
|
||||||
|
@keydown.escape="toastStore.removeToast(toast.id)"
|
||||||
|
@mouseenter="toastStore.pauseToast(toast.id)"
|
||||||
|
@mouseleave="toastStore.resumeToast(toast.id)"
|
||||||
|
@focusin="toastStore.pauseToast(toast.id)"
|
||||||
|
@focusout="toastStore.resumeToast(toast.id)"
|
||||||
|
class="w-80 flex items-center gap-3 px-4 py-3 bg-bg-surface border border-border-subtle rounded-lg shadow-lg pointer-events-auto border-l-[3px]"
|
||||||
:class="[
|
:class="[
|
||||||
toast.exiting ? 'animate-toast-exit' : 'animate-toast-enter',
|
toast.exiting ? 'animate-toast-exit' : 'animate-toast-enter',
|
||||||
toast.type === 'success' ? 'border-l-status-running' : '',
|
toast.type === 'success' ? 'border-l-status-running' : '',
|
||||||
@@ -19,10 +32,26 @@ const toastStore = useToastStore()
|
|||||||
toast.type === 'info' ? 'border-l-accent' : ''
|
toast.type === 'info' ? 'border-l-accent' : ''
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<Check v-if="toast.type === 'success'" class="w-4 h-4 text-status-running shrink-0" :stroke-width="2" />
|
<Check v-if="toast.type === 'success'" class="w-4 h-4 text-status-running shrink-0" aria-hidden="true" :stroke-width="2" />
|
||||||
<AlertCircle v-if="toast.type === 'error'" class="w-4 h-4 text-status-error shrink-0" :stroke-width="2" />
|
<AlertCircle v-if="toast.type === 'error'" class="w-4 h-4 text-status-error shrink-0" aria-hidden="true" :stroke-width="2" />
|
||||||
<Info v-if="toast.type === 'info'" class="w-4 h-4 text-accent shrink-0" :stroke-width="2" />
|
<Info v-if="toast.type === 'info'" class="w-4 h-4 text-accent shrink-0" aria-hidden="true" :stroke-width="2" />
|
||||||
<span class="text-sm text-text-primary">{{ toast.message }}</span>
|
<span class="sr-only">{{ toast.type === 'success' ? 'Success:' : toast.type === 'error' ? 'Error:' : 'Info:' }}</span>
|
||||||
|
<span class="text-sm text-text-primary flex-1">{{ toast.message }}</span>
|
||||||
|
<button
|
||||||
|
v-if="toast.onUndo"
|
||||||
|
aria-label="Undo"
|
||||||
|
@click.stop="toastStore.undoToast(toast.id)"
|
||||||
|
class="shrink-0 p-1 text-accent hover:text-accent/80 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent rounded"
|
||||||
|
>
|
||||||
|
<Undo2 class="w-3.5 h-3.5" aria-hidden="true" :stroke-width="2" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-label="Dismiss"
|
||||||
|
@click.stop="toastStore.removeToast(toast.id)"
|
||||||
|
class="shrink-0 p-1 text-text-tertiary hover:text-text-primary transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent rounded"
|
||||||
|
>
|
||||||
|
<X class="w-3.5 h-3.5" aria-hidden="true" :stroke-width="2" />
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user