diff --git a/client/src/components/ui/toast.tsx b/client/src/components/ui/toast.tsx index a822477..d264dd4 100644 --- a/client/src/components/ui/toast.tsx +++ b/client/src/components/ui/toast.tsx @@ -1,127 +1,60 @@ -import * as React from "react" -import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" +// Basic toast component +import { useEffect, useState } from "react"; +import { X } from "lucide-react"; -import { cn } from "@/lib/utils" - -const ToastProvider = ToastPrimitives.Provider - -const ToastViewport = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -ToastViewport.displayName = ToastPrimitives.Viewport.displayName - -const toastVariants = cva( - "group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", - { - variants: { - variant: { - default: "border bg-background text-foreground", - destructive: - "destructive group border-destructive bg-destructive text-destructive-foreground", - }, - }, - defaultVariants: { - variant: "default", - }, - } -) - -const Toast = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, variant, ...props }, ref) => { - return ( - - ) -}) -Toast.displayName = ToastPrimitives.Root.displayName - -const ToastAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -ToastAction.displayName = ToastPrimitives.Action.displayName - -const ToastClose = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - -)) -ToastClose.displayName = ToastPrimitives.Close.displayName - -const ToastTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -ToastTitle.displayName = ToastPrimitives.Title.displayName - -const ToastDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -ToastDescription.displayName = ToastPrimitives.Description.displayName - -type ToastProps = React.ComponentPropsWithoutRef - -type ToastActionElement = React.ReactElement - -export { - type ToastProps, - type ToastActionElement, - ToastProvider, - ToastViewport, - Toast, - ToastTitle, - ToastDescription, - ToastClose, - ToastAction, +export interface ToastProps { + id: number; + title?: string; + description?: string; + variant?: "default" | "destructive"; + duration?: number; + onDismiss: (id: number) => void; } + +export function Toast({ + id, + title, + description, + variant = "default", + onDismiss, +}: ToastProps) { + const [isVisible, setIsVisible] = useState(true); + + useEffect(() => { + const timer = setTimeout(() => { + setIsVisible(false); + setTimeout(() => onDismiss(id), 300); // Allow time for fade out animation + }, 3000); + + return () => clearTimeout(timer); + }, [id, onDismiss]); + + const baseClasses = "fixed bottom-4 right-4 rounded-md shadow-lg p-4 transition-all duration-300 max-w-sm"; + const variantClasses = variant === "destructive" + ? "bg-red-500 text-white" + : "bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"; + const visibilityClasses = isVisible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-2"; + + return ( +
+
+
+ {title &&

{title}

} + {description &&

{description}

} +
+ +
+
+ ); +} + +// Types for prop references in other files +export type ToastActionElement = React.ReactElement; diff --git a/client/src/components/ui/toaster.tsx b/client/src/components/ui/toaster.tsx index 6c67edf..6d1101d 100644 --- a/client/src/components/ui/toaster.tsx +++ b/client/src/components/ui/toaster.tsx @@ -1,33 +1,27 @@ -import { useToast } from "@/hooks/use-toast" -import { - Toast, - ToastClose, - ToastDescription, - ToastProvider, - ToastTitle, - ToastViewport, -} from "@/components/ui/toast" +// Simple toast container +import { useToast } from "@/hooks/use-toast"; +import { Toast } from "./toast"; +import { createPortal } from "react-dom"; export function Toaster() { - const { toasts } = useToast() + const { toasts, dismiss } = useToast(); - return ( - - {toasts.map(function ({ id, title, description, action, ...props }) { - return ( - -
- {title && {title}} - {description && ( - {description} - )} -
- {action} - -
- ) - })} - -
- ) + if (!toasts.length) return null; + + // Create a portal to render toasts at the root level + return createPortal( +
+ {toasts.map((toast) => ( + + ))} +
, + document.body + ); } diff --git a/client/src/hooks/use-toast.ts b/client/src/hooks/use-toast.ts index b1a4f1b..8eff2c1 100644 --- a/client/src/hooks/use-toast.ts +++ b/client/src/hooks/use-toast.ts @@ -9,11 +9,13 @@ interface ToastOptions { variant?: ToastVariant; duration?: number; id?: number; + className?: string; } export function useToast() { const [toasts, setToasts] = useState([]); + // Create a function that matches the expected signature in BlogManagement const toast = (options: ToastOptions) => { const id = Date.now(); const newToast = {