feat: initial
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type ToastKind = "success" | "error" | "info";
|
||||
interface Toast {
|
||||
id: number;
|
||||
kind: ToastKind;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface ToastApi {
|
||||
push: (message: string, kind?: ToastKind) => void;
|
||||
success: (message: string) => void;
|
||||
error: (message: string) => void;
|
||||
}
|
||||
|
||||
const ToastContext = createContext<ToastApi | null>(null);
|
||||
|
||||
export function ToastProvider({ children }: { children: React.ReactNode }) {
|
||||
const [toasts, setToasts] = useState<Toast[]>([]);
|
||||
const idRef = useRef(0);
|
||||
|
||||
const push = useCallback((message: string, kind: ToastKind = "info") => {
|
||||
const id = ++idRef.current;
|
||||
setToasts((prev) => [...prev, { id, kind, message }]);
|
||||
setTimeout(() => {
|
||||
setToasts((prev) => prev.filter((t) => t.id !== id));
|
||||
}, 4000);
|
||||
}, []);
|
||||
|
||||
const api: ToastApi = {
|
||||
push,
|
||||
success: (m) => push(m, "success"),
|
||||
error: (m) => push(m, "error"),
|
||||
};
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={api}>
|
||||
{children}
|
||||
<div className="fixed bottom-4 left-4 z-[100] flex flex-col gap-2">
|
||||
{toasts.map((t) => (
|
||||
<div
|
||||
key={t.id}
|
||||
className={cn(
|
||||
"min-w-64 rounded-xl px-4 py-3 text-sm text-white shadow-lg",
|
||||
t.kind === "success" && "bg-success",
|
||||
t.kind === "error" && "bg-danger",
|
||||
t.kind === "info" && "bg-foreground",
|
||||
)}
|
||||
>
|
||||
{t.message}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useToast(): ToastApi {
|
||||
const ctx = useContext(ToastContext);
|
||||
if (!ctx) throw new Error("useToast must be used within <ToastProvider>");
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user