mirror of
https://github.com/samanhappy/mcphub.git
synced 2026-01-01 04:08:52 -05:00
introduce market
This commit is contained in:
96
frontend/src/components/ui/Toast.tsx
Normal file
96
frontend/src/components/ui/Toast.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Check, X } from 'lucide-react';
|
||||
import { cn } from '@/utils/cn';
|
||||
|
||||
export type ToastType = 'success' | 'error' | 'info' | 'warning';
|
||||
|
||||
export interface ToastProps {
|
||||
message: string;
|
||||
type?: ToastType;
|
||||
duration?: number;
|
||||
onClose: () => void;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
const Toast: React.FC<ToastProps> = ({
|
||||
message,
|
||||
type = 'info',
|
||||
duration = 3000,
|
||||
onClose,
|
||||
visible
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
const timer = setTimeout(() => {
|
||||
onClose();
|
||||
}, duration);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [visible, duration, onClose]);
|
||||
|
||||
const icons = {
|
||||
success: <Check className="w-5 h-5 text-green-500" />,
|
||||
error: <X className="w-5 h-5 text-red-500" />,
|
||||
info: (
|
||||
<svg className="w-5 h-5 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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>
|
||||
),
|
||||
warning: (
|
||||
<svg className="w-5 h-5 text-yellow-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
)
|
||||
};
|
||||
|
||||
const bgColors = {
|
||||
success: 'bg-green-50 border-green-200',
|
||||
error: 'bg-red-50 border-red-200',
|
||||
info: 'bg-blue-50 border-blue-200',
|
||||
warning: 'bg-yellow-50 border-yellow-200'
|
||||
};
|
||||
|
||||
const textColors = {
|
||||
success: 'text-green-800',
|
||||
error: 'text-red-800',
|
||||
info: 'text-blue-800',
|
||||
warning: 'text-yellow-800'
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn(
|
||||
"fixed top-4 right-4 z-50 max-w-sm p-4 rounded-md shadow-lg border",
|
||||
bgColors[type],
|
||||
"transform transition-all duration-300 ease-in-out",
|
||||
visible ? "translate-x-0 opacity-100" : "translate-x-full opacity-0"
|
||||
)}>
|
||||
<div className="flex items-start">
|
||||
<div className="flex-shrink-0">
|
||||
{icons[type]}
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<p className={cn("text-sm font-medium", textColors[type])}>
|
||||
{message}
|
||||
</p>
|
||||
</div>
|
||||
<div className="ml-auto pl-3">
|
||||
<div className="-mx-1.5 -my-1.5">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={cn(
|
||||
"inline-flex rounded-md p-1.5",
|
||||
`hover:bg-${type}-100 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-${type}-500`
|
||||
)}
|
||||
>
|
||||
<span className="sr-only">Dismiss</span>
|
||||
<X className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Toast;
|
||||
Reference in New Issue
Block a user