obsidian-visualiser/components/base/Toaster.vue

92 lines
3.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<ToastProvider>
<ToastRoot v-for="toast in model" :key="toast.id" :duration="toast.duration" class="ToastRoot bg-light-10 dark:bg-dark-10 border border-light-30 dark:border-dark-30 group" :open="toast.state ?? true" @update:open="(state: boolean) => tryClose(toast, state)" :data-type="toast.type ?? 'info'">
<div class="grid grid-cols-8 px-3 pt-2 pb-2">
<ToastTitle v-if="toast.title" class="font-semibold text-xl col-span-7 text-light-70 dark:text-dark-70" asChild><h4>{{ toast.title }}</h4></ToastTitle>
<ToastClose v-if="toast.closeable" aria-label="Close" class="text-xl -translate-y-2 translate-x-4 cursor-pointer"><span aria-hidden>×</span></ToastClose>
<ToastDescription v-if="toast.content" class="text-sm col-span-8 text-light-70 dark:text-dark-70" asChild><span>{{ toast.content }}</span></ToastDescription>
</div>
<TimerProgress v-if="toast.timer" shape="thin" :delay="toast.duration" class="mb-0 mt-0 w-full group-data-[type=error]:bg-light-red dark:group-data-[type=error]:bg-dark-red group-data-[type=error]:bg-opacity-50 dark:group-data-[type=error]:bg-opacity-50 group-data-[type=error]:*:bg-light-red dark:group-data-[type=error]:*:bg-dark-red
group-data-[type=success]:bg-light-green dark:group-data-[type=success]:bg-dark-green group-data-[type=success]:bg-opacity-50 dark:group-data-[type=success]:bg-opacity-50 group-data-[type=success]:*:bg-light-green dark:group-data-[type=success]:*:bg-dark-green" @finish="() => tryClose(toast, false)" />
</ToastRoot>
<ToastViewport class="fixed bottom-0 right-0 flex flex-col p-6 gap-2 max-w-[512px] z-50 outline-none min-w-72" />
</ToastProvider>
</template>
<script setup lang="ts">
const model = defineModel<ExtraToastConfig[]>();
function tryClose(config: ExtraToastConfig, state: boolean)
{
if(!state)
{
const m = model.value;
if(m)
{
const idx = m?.findIndex(e => e.id === config.id);
m[idx].state = false;
model.value = m;
}
setTimeout(() => model.value?.splice(model.value?.findIndex(e => e.id === config.id), 1), 500);
}
}
</script>
<style>
.ToastRoot[data-type='error'] {
@apply border-light-red;
@apply dark:border-dark-red;
@apply bg-light-red;
@apply dark:bg-dark-red;
@apply bg-opacity-15;
}
.ToastRoot[data-type='success'] {
@apply border-light-green;
@apply dark:border-dark-green;
@apply bg-light-green;
@apply dark:bg-dark-green;
@apply bg-opacity-15;
}
.ToastRoot[data-state='open'] {
animation: slideIn .15s cubic-bezier(0.16, 1, 0.3, 1);
}
.ToastRoot[data-state='closed'] {
animation: hide .1s ease-in;
}
.ToastRoot[data-swipe='move'] {
transform: translateX(var(--radix-toast-swipe-move-x));
}
.ToastRoot[data-swipe='cancel'] {
transform: translateX(0);
transition: transform .2s ease-out;
}
.ToastRoot[data-swipe='end'] {
animation: swipeRight .1s ease-out;
}
@keyframes hide {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes slideIn {
from {
transform: translateX(calc(100% + var(--viewport-padding)));
}
to {
transform: translateX(0);
}
}
@keyframes swipeRight {
from {
transform: translateX(var(--radix-toast-swipe-end-x));
}
to {
transform: translateX(100%);
}
}
</style>