File size: 2,496 Bytes
212c959
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import * as Toast from '@radix-ui/react-toast'
import { AnimatePresence, motion } from 'framer-motion'
import { CheckCircle2, CircleAlert, Info, X } from 'lucide-react'
import { useAppStore } from '../../store/useAppStore'

const icons = {
  success: CheckCircle2,
  danger: CircleAlert,
  info: Info,
}

export default function Toaster() {
  const toasts = useAppStore((state) => state.toasts)
  const removeToast = useAppStore((state) => state.removeToast)

  return (
    <Toast.Provider swipeDirection="right">
      <AnimatePresence>
        {toasts.map((toast) => {
          const Icon = icons[toast.variant] || Info
          return (
            <Toast.Root
              key={toast.id}
              open
              asChild
              onOpenChange={(open) => {
                if (!open) removeToast(toast.id)
              }}
            >
              <motion.div
                initial={{ opacity: 0, y: 16, scale: 0.96 }}
                animate={{ opacity: 1, y: 0, scale: 1 }}
                exit={{ opacity: 0, y: 16, scale: 0.96 }}
                className="rounded-[24px] border border-border/70 bg-card/96 p-4 shadow-panel backdrop-blur-2xl"
              >
                <div className="flex items-start gap-3">
                  <div className="mt-0.5 rounded-2xl bg-secondary p-2 text-accent">
                    <Icon className="h-4 w-4" />
                  </div>
                  <div className="flex-1">
                    <Toast.Title className="text-sm font-semibold text-foreground">
                      {toast.title}
                    </Toast.Title>
                    {toast.description ? (
                      <Toast.Description className="mt-1 text-sm text-muted-foreground">
                        {toast.description}
                      </Toast.Description>
                    ) : null}
                  </div>
                  <button
                    type="button"
                    onClick={() => removeToast(toast.id)}
                    className="rounded-full p-1 text-muted-foreground transition hover:bg-secondary hover:text-foreground"
                  >
                    <X className="h-4 w-4" />
                  </button>
                </div>
              </motion.div>
            </Toast.Root>
          )
        })}
      </AnimatePresence>
      <Toast.Viewport className="fixed bottom-4 right-4 z-[70] flex w-[min(24rem,calc(100vw-2rem))] flex-col gap-3 outline-none" />
    </Toast.Provider>
  )
}