Untitled
unknown
plain_text
17 days ago
5.6 kB
4
Indexable
// gallery.tsx "use client" import { useState } from "react" import { Download, MessageCircle, ChevronLeft, ChevronRight, X } from "lucide-react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog" interface Section { title: string description?: string images: { src: string alt: string width: number height: number thumbnailSrc?: string }[] } interface GalleryProps { sections: Section[] } function ImageDialog({ sections, currentSectionIndex, currentImageIndex, onNavigate, onClose, handleDownload, isDownloading, }) { const section = sections[currentSectionIndex] const image = section.images[currentImageIndex] const hasPrevious = currentImageIndex > 0 const hasNext = currentImageIndex < section.images.length - 1 return ( <div className="flex flex-col h-full"> <button onClick={onClose} className="absolute right-2 top-2 p-1 bg-gray-800 rounded-full text-white" > <X className="h-4 w-4" /> </button> <div className="relative h-full flex items-center justify-center"> {hasPrevious && ( <button onClick={() => onNavigate("prev")} className="absolute left-2 p-2 bg-gray-800 rounded-full text-white" > <ChevronLeft /> </button> )} <img src={image.src} alt={image.alt} className="max-h-full max-w-full object-contain" loading="lazy" /> {hasNext && ( <button onClick={() => onNavigate("next")} className="absolute right-2 p-2 bg-gray-800 rounded-full text-white" > <ChevronRight /> </button> )} </div> <Button onClick={() => handleDownload(image.src)} disabled={isDownloading} className="mt-4" > <Download className="mr-2 h-4 w-4" /> Download </Button> </div> ) } export function Gallery({ sections }: GalleryProps) { const [currentSectionIndex, setCurrentSectionIndex] = useState(0) const [currentImageIndex, setCurrentImageIndex] = useState(0) const [isDialogOpen, setIsDialogOpen] = useState(false) const [isDownloading, setIsDownloading] = useState(false) const handleDownload = async (src: string) => { setIsDownloading(true) try { const response = await fetch(src) const blob = await response.blob() const url = window.URL.createObjectURL(blob) const link = document.createElement("a") link.href = url link.download = src.split("/").pop() || "image.jpg" link.click() window.URL.revokeObjectURL(url) } catch (error) { console.error("Download failed:", error) } finally { setIsDownloading(false) } } const handleNavigate = (direction: "prev" | "next") => { if (direction === "prev" && currentImageIndex > 0) { setCurrentImageIndex(currentImageIndex - 1) } else if ( direction === "next" && currentImageIndex < sections[currentSectionIndex].images.length - 1 ) { setCurrentImageIndex(currentImageIndex + 1) } } return ( <div className="space-y-12"> <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}> <DialogContent className="max-w-4xl h-[90vh] p-6"> <DialogHeader> <DialogTitle>Image Preview</DialogTitle> <DialogDescription>View and download the full-resolution image</DialogDescription> </DialogHeader> <ImageDialog sections={sections} currentSectionIndex={currentSectionIndex} currentImageIndex={currentImageIndex} handleDownload={handleDownload} isDownloading={isDownloading} onNavigate={handleNavigate} onClose={() => setIsDialogOpen(false)} /> </DialogContent> </Dialog> {sections.map((section, sectionIndex) => ( <div key={sectionIndex} className="space-y-4"> <h2 className="text-2xl font-bold">{section.title}</h2> {section.description && <p className="text-gray-500">{section.description}</p>} <div className="grid grid-cols-3 gap-0"> {section.images.map((image, imageIndex) => { const aspectRatio = image.width / image.height const rowSpan = Math.ceil((image.height / image.width) * 3) // Dynamic row span return ( <div key={imageIndex} className="relative overflow-hidden" style={{ gridRow: `span ${rowSpan}`, aspectRatio: aspectRatio, }} > <img src={image.thumbnailSrc || image.src} alt={image.alt} className="w-full h-full object-cover" loading="lazy" onClick={() => { setCurrentSectionIndex(sectionIndex) setCurrentImageIndex(imageIndex) setIsDialogOpen(true) }} /> </div> ) })} </div> </div> ))} </div> ) }
Editor is loading...
Leave a Comment