gsearch / client /src /components /SourcePreviewModal.tsx
nanoppa's picture
Upload 100 files
10c8635 verified
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { ExternalLink } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
interface Source {
title: string;
url: string;
snippet: string;
}
interface SourcePreviewModalProps {
source: Source | null;
isOpen: boolean;
onClose: () => void;
}
export function SourcePreviewModal({ source, isOpen, onClose }: SourcePreviewModalProps) {
if (!source) return null;
return (
<AnimatePresence>
{isOpen && (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-3xl h-[80vh] flex flex-col">
<DialogHeader>
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.2 }}
>
<DialogTitle className="text-xl font-semibold mb-2">
{source.title}
</DialogTitle>
<a
href={source.url}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-muted-foreground hover:text-primary flex items-center gap-2"
>
<span className="truncate">{source.url}</span>
<ExternalLink className="h-4 w-4" />
</a>
</motion.div>
</DialogHeader>
<ScrollArea className="flex-1 mt-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3, delay: 0.1 }}
className="prose prose-slate dark:prose-invert max-w-none"
>
<div className="space-y-4">
<p className="text-base leading-relaxed">
{source.snippet}
</p>
{/* TODO: Add full content preview when available */}
</div>
</motion.div>
</ScrollArea>
</DialogContent>
</Dialog>
)}
</AnimatePresence>
);
}