'use client';
import { useEffect, useRef, useState } from 'react';
import { XIcon } from 'lucide-react';
import { AnimatePresence, motion } from 'motion/react';
import { type GeneratedImage, useGeneratedImages } from '@/hooks/useGeneratedImages';
import { cn } from '@/lib/shadcn/utils';
const MotionPanel = motion.create('div');
interface ImageCardProps {
image: GeneratedImage;
onDismiss: () => void;
}
function ImageCard({ image, onDismiss }: ImageCardProps) {
const src = image.imageUrl;
return (
{/* eslint-disable-next-line @next/next/no-img-element */}
{image.prompt && (
)}
);
}
interface GeneratedImagePanelProps {
chatOpen?: boolean;
}
/**
* Listens for images generated by the agent and shows the most recent one.
* When chat is open, repositions to the top-right corner to avoid covering the transcript.
*
* HACK HERE: swap for a gallery view, a fullscreen modal, download button, etc.
*/
export function GeneratedImagePanel({ chatOpen = false }: GeneratedImagePanelProps) {
const images = useGeneratedImages();
const [dismissed, setDismissed] = useState>(new Set());
const prevLengthRef = useRef(0);
// Auto-scroll to latest image
useEffect(() => {
if (images.length > prevLengthRef.current) {
prevLengthRef.current = images.length;
}
}, [images]);
const visible = images.filter((img) => !dismissed.has(img.id));
const latest = visible.at(-1);
const dismiss = (id: string) => {
setDismissed((prev) => new Set([...prev, id]));
};
return (
{latest && (
dismiss(latest.id)} />
)}
);
}