Untitled
unknown
plain_text
2 months ago
5.1 kB
1
Indexable
"use client" import { useState } from "react" import Image from "next/image" import { motion } 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 }[] } export function Gallery({ images }: GalleryProps) { const [selectedImage, setSelectedImage] = useState<number | null>(null) const handleDownload = async (imageSrc: string) => { try { 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); } catch (error) { console.error('Download failed:', error); } }; return ( <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4"> {images.map((image, index) => ( <motion.div key={index} initial={{ opacity: 0, scale: 0.9 }} animate={{ opacity: 1, scale: 1 }} transition={{ delay: index * 0.1 }} className="group relative aspect-square overflow-hidden rounded-lg bg-muted/30" > <Image src={image.src} alt={image.alt} fill className="object-cover transition-transform duration-500 will-change-transform group-hover:scale-105" sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw" priority={index < 4} /> <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" > <Dialog> <DialogTrigger asChild> <Button variant="secondary" size="icon" className="h-9 w-9" onClick={() => setSelectedImage(index)} > <Expand className="h-4 w-4" /> </Button> </DialogTrigger> <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={() => handleDownload(images[selectedImage ?? index].src)} > <Download className="mr-2 h-4 w-4" /> Bild herunterladen </Button> </div> <TabsContent value="preview" className="relative"> <div style={{ position: 'relative', width: '100%', height: '70vh', maxHeight: '800px' }} > <img src={images[selectedImage ?? index].src} alt={images[selectedImage ?? index].alt} style={{ width: '100%', height: '100%', objectFit: 'contain' }} /> </div> </TabsContent> <TabsContent value="comments"> <PhotoComments photoId={`photo-${selectedImage ?? index}`} /> </TabsContent> </Tabs> </DialogContent> </Dialog> <Button variant="secondary" size="icon" className="h-9 w-9" onClick={() => handleDownload(image.src)} > <Download className="h-4 w-4" /> </Button> </motion.div> </motion.div> ))} </div> ) }
Editor is loading...
Leave a Comment