Untitled
unknown
plain_text
2 months ago
5.5 kB
2
Indexable
"use client" import { useState, useRef, useEffect } from "react" import Image from "next/image" import { motion, useInView } from "framer-motion" import { Download, Expand } from "lucide-react" import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from "@/components/ui/dialog" import { PhotoComments } from "@/components/photo-comments" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" interface GalleryProps { images: { src: string alt: string width: number height: number }[] } function GalleryImage({ image, index, onDownload, onSelect }: any) { const ref = useRef(null) const isInView = useInView(ref, { once: true, margin: "100px" }) const aspectRatio = image.width / image.height const isPortrait = aspectRatio < 0.8 const isLandscape = aspectRatio > 1.2 return ( <motion.div ref={ref} initial={{ opacity: 0, y: 20 }} animate={isInView ? { opacity: 1, y: 0 } : { opacity: 0, y: 20 }} transition={{ duration: 0.5 }} className="relative mb-4 break-inside-avoid" > <div className={`relative overflow-hidden rounded-lg bg-muted/30 ${ isPortrait ? 'h-[500px]' : isLandscape ? 'h-[300px]' : 'h-[400px]' }`}> <img src={image.src} alt={image.alt} className="h-full w-full object-cover" loading="lazy" /> <motion.div initial={false} animate={{ opacity: 0 }} whileHover={{ opacity: 1 }} transition={{ duration: 0.2 }} className="absolute inset-0 flex items-center justify-center gap-2 bg-black/60" > <DialogTrigger asChild> <Button variant="secondary" size="icon" className="h-9 w-9" onClick={() => onSelect(index)} > <Expand className="h-4 w-4" /> </Button> </DialogTrigger> <Button variant="secondary" size="icon" className="h-9 w-9" onClick={() => onDownload(image.src)} > <Download className="h-4 w-4" /> </Button> </motion.div> </div> </motion.div> ) } export function Gallery({ images: unsortedImages }: GalleryProps) { const [selectedImage, setSelectedImage] = useState<number | null>(null) const [isDownloading, setIsDownloading] = useState(false) // Sort images by filename const images = [...unsortedImages].sort((a, b) => { const fileNameA = a.src.split('/').pop() || '' const fileNameB = b.src.split('/').pop() || '' return fileNameA.localeCompare(fileNameB) }) const handleDownload = async (imageSrc: string) => { try { setIsDownloading(true) const response = await fetch(imageSrc) const blob = await response.blob() const url = window.URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = imageSrc.split('/').pop() || 'image' document.body.appendChild(link) link.click() document.body.removeChild(link) window.URL.revokeObjectURL(url) } finally { setIsDownloading(false) } } return ( <Dialog> <div className="columns-1 sm:columns-2 md:columns-3 lg:columns-4 gap-4"> {images.map((image, index) => ( <GalleryImage key={index} image={image} index={index} onDownload={handleDownload} onSelect={setSelectedImage} /> ))} </div> <DialogContent className="max-w-7xl"> <DialogHeader> <DialogTitle>Bildvorschau</DialogTitle> <DialogDescription>Ansehen und herunterladen des Bildes in voller Auflösung</DialogDescription> </DialogHeader> <Tabs defaultValue="preview"> <div className="flex items-center justify-between mb-4"> <TabsList> <TabsTrigger value="preview">Vorschau</TabsTrigger> <TabsTrigger value="comments">Kommentare</TabsTrigger> </TabsList> <Button onClick={() => selectedImage !== null && handleDownload(images[selectedImage].src)} disabled={isDownloading} > <Download className="mr-2 h-4 w-4" /> Bild herunterladen </Button> </div> <TabsContent value="preview"> <div className="flex items-center justify-center overflow-hidden rounded-lg bg-background"> {selectedImage !== null && ( <img src={images[selectedImage].src} alt={images[selectedImage].alt} className="max-h-[80vh] w-auto" style={{ maxWidth: '100%', objectFit: 'contain' }} /> )} </div> </TabsContent> <TabsContent value="comments"> {selectedImage !== null && ( <PhotoComments photoId={`photo-${selectedImage}`} /> )} </TabsContent> </Tabs> </DialogContent> </Dialog> ) }
Editor is loading...
Leave a Comment