Files
hosting-files/src/components/Gallery.tsx
T
orohiandCursor 8bb436ea4f first commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 14:59:02 +03:00

99 lines
3.7 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import Image from "next/image";
import { Images, Eye, Calendar } from "lucide-react";
interface Photo {
id: string;
filename: string;
originalName: string;
url: string;
views: number;
createdAt: string;
}
interface GalleryProps {
initialPhotos: Photo[];
}
export function Gallery({ initialPhotos }: GalleryProps) {
const [photos, setPhotos] = useState(initialPhotos);
useEffect(() => {
const handler = (e: Event) => {
const customEvent = e as CustomEvent<Photo>;
setPhotos((prev) => [customEvent.detail, ...prev].slice(0, 12));
};
window.addEventListener("photo-uploaded", handler);
return () => window.removeEventListener("photo-uploaded", handler);
}, []);
return (
<section id="gallery" className="px-6 py-16">
<div className="mx-auto max-w-7xl">
<div className="mb-10 text-center">
<div className="mb-3 inline-flex items-center gap-2 text-indigo-400">
<Images className="h-5 w-5" />
<span className="text-sm font-medium uppercase tracking-wider">
Галерея
</span>
</div>
<h2 className="text-3xl font-bold md:text-4xl">
Недавние загрузки
</h2>
<p className="mt-3 text-muted">
Последние фотографии, загруженные на сервис
</p>
</div>
{photos.length === 0 ? (
<div className="glass mx-auto max-w-md rounded-2xl p-12 text-center">
<Images className="mx-auto h-12 w-12 text-muted/50" />
<p className="mt-4 text-muted">
Пока нет загруженных фото. Будьте первым!
</p>
</div>
) : (
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
{photos.map((photo, index) => (
<a
key={photo.id}
href={photo.url}
target="_blank"
rel="noopener noreferrer"
className="group relative aspect-square overflow-hidden rounded-2xl bg-surface transition-all duration-300 hover:scale-[1.02] hover:shadow-xl hover:shadow-indigo-500/10"
style={{ animationDelay: `${index * 50}ms` }}
>
<Image
src={photo.url}
alt={photo.originalName}
fill
className="object-cover transition-transform duration-500 group-hover:scale-110"
sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/70 via-transparent to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100" />
<div className="absolute right-0 bottom-0 left-0 translate-y-full p-4 transition-transform duration-300 group-hover:translate-y-0">
<p className="truncate text-sm font-medium text-white">
{photo.originalName}
</p>
<div className="mt-1 flex items-center gap-3 text-xs text-white/70">
<span className="flex items-center gap-1">
<Eye className="h-3 w-3" />
{photo.views}
</span>
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{new Date(photo.createdAt).toLocaleDateString("ru-RU")}
</span>
</div>
</div>
</a>
))}
</div>
)}
</div>
</section>
);
}