Untitled
unknown
plain_text
8 months ago
5.6 kB
6
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