login
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
'use client'
|
||||
import { CloseCircle, InfoCircle, TickCircle } from 'iconsax-react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface Toast {
|
||||
id: string;
|
||||
message: string;
|
||||
type?: 'success' | 'error' | 'info';
|
||||
}
|
||||
|
||||
let addToast: (toast: Toast) => void;
|
||||
|
||||
const ToastContainer: React.FC = () => {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
|
||||
// ثبت toast جدید
|
||||
const showToast = (toast: Toast) => {
|
||||
setToasts((prev) => [...prev, toast]);
|
||||
|
||||
// حذف خودکار بعد از ۳ ثانیه
|
||||
setTimeout(() => {
|
||||
setToasts((prev) => prev.filter((t) => t.id !== toast.id));
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
// تخصیص تابع نمایش toast به متغیر سراسری
|
||||
useEffect(() => {
|
||||
addToast = showToast;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="fixed top-4 text-sm right-0 left-0 mx-auto w-fit z-50 flex flex-col gap-2">
|
||||
{toasts.map((toast) => (
|
||||
<div
|
||||
key={toast.id}
|
||||
className={`px-4 flex items-center gap-2 backdrop-blur-2xl h-16 min-w-[300px] rounded-2xl shadow-md transition-transform ${toast.type === 'success'
|
||||
? 'bg-white/70 text-black'
|
||||
: toast.type === 'error'
|
||||
? 'bg-white/70 text-black'
|
||||
: 'bg-white/70 text-black'
|
||||
}`}
|
||||
>
|
||||
{
|
||||
toast.type === 'success' ? <TickCircle className='size-5' color='green' /> :
|
||||
toast.type === 'error' ? <CloseCircle className='size-5' color='red' /> :
|
||||
<InfoCircle className='size-5' color='blue' />
|
||||
}
|
||||
{toast.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const toast = (message: string, type: 'success' | 'error' | 'info' = 'info') => {
|
||||
addToast({ id: Date.now().toString(), message, type });
|
||||
};
|
||||
|
||||
export default ToastContainer;
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as React from "react"
|
||||
import { Slot } from "@radix-ui/react-slot"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
import { ClipLoader } from "react-spinners"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
@@ -40,10 +41,14 @@ function Button({
|
||||
variant,
|
||||
size,
|
||||
asChild = false,
|
||||
isLoading = false,
|
||||
disabled,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<"button"> &
|
||||
VariantProps<typeof buttonVariants> & {
|
||||
asChild?: boolean
|
||||
isLoading?: boolean
|
||||
}) {
|
||||
const Comp = asChild ? Slot : "button"
|
||||
|
||||
@@ -51,8 +56,18 @@ function Button({
|
||||
<Comp
|
||||
data-slot="button"
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
disabled={disabled || isLoading}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{isLoading ? (
|
||||
<>
|
||||
<ClipLoader size={16} color="currentColor" />
|
||||
<span>در حال بارگذاری...</span>
|
||||
</>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Comp>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user