SPB Git

spb/autoscholar

Public
1.5 KB · 44 lines tsx
1"use client";2import { createContext, type ReactNode, useCallback, useContext, useState } from "react";34type Toast = { id: number; kind: "info" | "error" | "success"; text: string };5const Ctx = createContext<{ push: (kind: Toast["kind"], text: string) => void }>({ push: () => {} });67export function ToastProvider({ children }: { children: ReactNode }) {8  const [items, setItems] = useState<Toast[]>([]);9  const push = useCallback((kind: Toast["kind"], text: string) => {10    const id = Date.now() + Math.random();11    setItems((x) => [...x, { id, kind, text }]);12    setTimeout(() => setItems((x) => x.filter((t) => t.id !== id)), 6000);13  }, []);14  return (15    <Ctx.Provider value={{ push }}>16      {children}17      <div18        aria-live="polite"19        aria-atomic="false"20        className="pointer-events-none fixed inset-x-0 bottom-4 z-50 flex flex-col items-center gap-2 px-4"21      >22        {items.map((t) => (23          <div24            key={t.id}25            role={t.kind === "error" ? "alert" : "status"}26            className="surface pointer-events-auto max-w-lg px-4 py-2 text-sm shadow-lg"27            style={{28              borderColor:29                t.kind === "error"30                  ? "var(--color-danger-500)"31                  : t.kind === "success"32                    ? "var(--color-ok-500)"33                    : "var(--line-strong)",34            }}35          >36            {t.text}37          </div>38        ))}39      </div>40    </Ctx.Provider>41  );42}43export const useToast = () => useContext(Ctx);44
Files · 87b4e55c3b9fbcc2cd191a1e469b33de0a24ccc8
Menu

Theme