File size: 2,229 Bytes
10c8635 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
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>
);
}
|