Untitled

 avatar
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