import {
CheckCircle2,
Info,
LoaderCircle,
TriangleAlert,
XCircle,
} from 'lucide-react'
import { motion } from 'motion/react'
import { createPortal } from 'react-dom'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { NOTIFICATION_EXIT_DURATION_MS } from '@/constants'
import { useNotificationStore } from '@/lib/notify'
import { cn } from '@/lib/utils'
const TONE_CLASS_BY_TYPE = {
error: {
alert:
'border-[#E37284]/38 bg-[linear-gradient(180deg,rgba(46,11,18,0.96),rgba(23,7,11,0.98))] shadow-[0_calc(var(--design-unit)*18)_calc(var(--design-unit)*44)_rgba(118,18,40,0.34)]',
glow: 'from-[#FF7D93]/20 via-[#FF7D93]/8 to-transparent',
icon: ,
iconShell:
'border-[rgba(255,154,168,0.26)] bg-[linear-gradient(180deg,rgba(124,34,46,0.42),rgba(76,19,29,0.3))] shadow-[inset_0_1px_0_rgba(255,224,228,0.16)]',
line: 'bg-[#FF7D93]',
title: 'text-[#FFF5F7]',
},
info: {
alert:
'border-[rgba(114,226,243,0.34)] bg-[linear-gradient(180deg,rgba(5,30,43,0.96),rgba(4,17,26,0.98))] shadow-[0_calc(var(--design-unit)*18)_calc(var(--design-unit)*44)_rgba(9,78,108,0.34)]',
glow: 'from-[#6FEAFF]/20 via-[#6FEAFF]/8 to-transparent',
icon: ,
iconShell:
'border-[rgba(121,228,238,0.24)] bg-[linear-gradient(180deg,rgba(17,85,98,0.38),rgba(10,53,63,0.28))] shadow-[inset_0_1px_0_rgba(227,252,255,0.14)]',
line: 'bg-[#73ECFF]',
title: 'text-[#F2FEFF]',
},
loading: {
alert:
'border-[rgba(114,226,243,0.34)] bg-[linear-gradient(180deg,rgba(5,30,43,0.96),rgba(4,17,26,0.98))] shadow-[0_calc(var(--design-unit)*18)_calc(var(--design-unit)*44)_rgba(9,78,108,0.34)]',
glow: 'from-[#6FEAFF]/20 via-[#6FEAFF]/8 to-transparent',
icon: (
),
iconShell:
'border-[rgba(121,228,238,0.24)] bg-[linear-gradient(180deg,rgba(17,85,98,0.38),rgba(10,53,63,0.28))] shadow-[inset_0_1px_0_rgba(227,252,255,0.14)]',
line: 'bg-[#73ECFF]',
title: 'text-[#F2FEFF]',
},
success: {
alert:
'border-[rgba(121,229,171,0.34)] bg-[linear-gradient(180deg,rgba(8,36,29,0.96),rgba(5,18,14,0.98))] shadow-[0_calc(var(--design-unit)*18)_calc(var(--design-unit)*44)_rgba(12,89,53,0.34)]',
glow: 'from-[#73F0B0]/18 via-[#73F0B0]/7 to-transparent',
icon: ,
iconShell:
'border-[rgba(127,236,177,0.24)] bg-[linear-gradient(180deg,rgba(24,98,66,0.38),rgba(15,60,40,0.28))] shadow-[inset_0_1px_0_rgba(232,255,242,0.14)]',
line: 'bg-[#73F0B0]',
title: 'text-[#F4FFF8]',
},
warning: {
alert:
'border-[rgba(239,197,103,0.36)] bg-[linear-gradient(180deg,rgba(48,31,10,0.96),rgba(25,17,7,0.98))] shadow-[0_calc(var(--design-unit)*18)_calc(var(--design-unit)*44)_rgba(109,72,12,0.34)]',
glow: 'from-[#FFD66E]/20 via-[#FFD66E]/8 to-transparent',
icon: ,
iconShell:
'border-[rgba(255,214,110,0.24)] bg-[linear-gradient(180deg,rgba(110,77,26,0.38),rgba(66,46,15,0.28))] shadow-[inset_0_1px_0_rgba(255,247,223,0.14)]',
line: 'bg-[#FFD66E]',
title: 'text-[#FFFAEF]',
},
} as const
export function AppNotificationAlert() {
const activeDialog = useNotificationStore((state) => state.activeDialog)
const closingDialogId = useNotificationStore((state) => state.closingDialogId)
if (!activeDialog || typeof document === 'undefined') {
return null
}
const tone = TONE_CLASS_BY_TYPE[activeDialog.type]
const isClosing = closingDialogId === activeDialog.id
const isMobileViewport =
typeof window !== 'undefined' ? window.innerWidth <= 768 : false
const motionState = isClosing ? 'closing' : 'visible'
const motionVariants = {
closing: {
filter: 'blur(1px)',
opacity: 0,
scale: 0.985,
y: -8,
transition: {
duration: NOTIFICATION_EXIT_DURATION_MS / 1000,
ease: [0.22, 1, 0.36, 1],
},
},
hidden: {
filter: 'blur(3px)',
opacity: 0,
scale: 0.94,
y: -18,
},
visible: {
filter: 'blur(0px)',
opacity: 1,
scale: 1,
y: 0,
transition: {
type: 'spring',
damping: 26,
mass: 0.72,
stiffness: 360,
},
},
} as const
return createPortal(
{tone.icon}
{activeDialog.message}
{activeDialog.description ? (
{activeDialog.description}
) : null}
,
document.body,
)
}