83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
interface NotificationProps {
|
|
message: string;
|
|
type: 'success' | 'error' | 'info';
|
|
onClose: () => void;
|
|
}
|
|
|
|
export default function Notification({ message, type, onClose }: NotificationProps) {
|
|
const [isVisible, setIsVisible] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const timer = setTimeout(() => {
|
|
setIsVisible(false);
|
|
setTimeout(onClose, 300); // Wait for fade out animation
|
|
}, 3000);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, [onClose]);
|
|
|
|
const bgColor = type === 'success'
|
|
? 'bg-green-500/20 border-green-500/50'
|
|
: type === 'error'
|
|
? 'bg-red-500/20 border-red-500/50'
|
|
: 'bg-cyan-500/20 border-cyan-500/50';
|
|
|
|
const textColor = type === 'success'
|
|
? 'text-green-400'
|
|
: type === 'error'
|
|
? 'text-red-400'
|
|
: 'text-cyan-400';
|
|
|
|
const icon = type === 'success' ? (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
|
</svg>
|
|
) : type === 'error' ? (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
) : (
|
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className={`fixed top-4 right-4 z-50 transition-all duration-300 ${
|
|
isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-2'
|
|
}`}
|
|
>
|
|
<div className={`relative rounded-lg border-2 ${bgColor} bg-black/95 backdrop-blur-sm p-4 shadow-[0_0_20px_rgba(255,255,255,0.1)] neon-border-glow min-w-[300px] max-w-md`}>
|
|
<div className="absolute inset-0 rounded-lg bg-gradient-to-br from-white/5 to-transparent"></div>
|
|
<div className="relative flex items-start gap-3">
|
|
<div className={`flex-shrink-0 ${textColor}`}>
|
|
{icon}
|
|
</div>
|
|
<div className="flex-1">
|
|
<p className={`font-mono text-sm font-medium ${textColor}`}>
|
|
{message}
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={() => {
|
|
setIsVisible(false);
|
|
setTimeout(onClose, 300);
|
|
}}
|
|
className={`flex-shrink-0 ${textColor} opacity-60 hover:opacity-100 transition-opacity`}
|
|
>
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|