115 lines
3.7 KiB
TypeScript
115 lines
3.7 KiB
TypeScript
"use client";
|
|
import { FC, useState } from "react";
|
|
import { FaImages } from "react-icons/fa";
|
|
import LightGallery from "lightgallery/react";
|
|
|
|
// import styles
|
|
import "lightgallery/css/lightgallery.css";
|
|
import "lightgallery/css/lg-zoom.css";
|
|
import "lightgallery/css/lg-thumbnail.css";
|
|
import { Button } from "@/components/atoms/Button";
|
|
|
|
type ImageData = {
|
|
aspect_ratio: number;
|
|
file_path: string;
|
|
height: number;
|
|
width: number;
|
|
};
|
|
|
|
type Props = {
|
|
heading?: string;
|
|
images: ImageData[] | Record<string, ImageData[]>;
|
|
limit?: number;
|
|
};
|
|
|
|
export const Gallery: FC<Props> = ({
|
|
images,
|
|
heading,
|
|
limit: initialLimit = 14,
|
|
}) => {
|
|
const categories = Array.isArray(images) ? [] : Object.keys(images);
|
|
const [limit, setLimit] = useState(initialLimit);
|
|
const [selectedCategory, setSelectedCategory] = useState<string | null>(
|
|
categories[0] || null
|
|
);
|
|
|
|
const currentImages: ImageData[] =
|
|
selectedCategory && typeof images === "object"
|
|
? (images[selectedCategory as keyof typeof images] as ImageData[])
|
|
: (images as ImageData[]);
|
|
|
|
const getImageUrl = (path: string, size: string = "w500") => {
|
|
return `https://image.tmdb.org/t/p/${size}${path}`;
|
|
};
|
|
|
|
return (
|
|
<section className="py-16">
|
|
<div className="px-6 lg:px-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
{heading && (
|
|
<div className="flex items-center gap-3 mb-8">
|
|
<div className="p-2 rounded-lg bg-gradient-to-r from-purple-500 to-pink-500">
|
|
<FaImages className="text-white" size={20} />
|
|
</div>
|
|
<h2 className="text-3xl font-bold bg-gradient-to-r from-purple-400 to-pink-400 bg-clip-text text-transparent">
|
|
{heading}
|
|
</h2>
|
|
</div>
|
|
)}
|
|
|
|
{/* Category tabs */}
|
|
{categories.length > 0 && (
|
|
<div className="flex gap-4 mb-8">
|
|
{Object.entries(images).map(([category, categoryImages]) => {
|
|
if (!categoryImages.length) return null;
|
|
|
|
return (
|
|
<button
|
|
key={category}
|
|
onClick={() =>
|
|
setSelectedCategory(category as keyof typeof images)
|
|
}
|
|
className={`px-6 py-3 rounded-xl font-medium transition-all duration-300 ${
|
|
selectedCategory === category
|
|
? "bg-gradient-to-r from-purple-600 to-pink-600 text-white shadow-lg"
|
|
: "bg-white/10 text-gray-300 hover:bg-white/20 hover:text-white"
|
|
}`}
|
|
>
|
|
{category} ({categoryImages.length})
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
|
|
{/* Image grid */}
|
|
<div className={`grid gap-4 grid-auto-cols-160 [&>div]:contents`}>
|
|
<LightGallery>
|
|
{currentImages.slice(0, limit).map((image, index) => (
|
|
<a
|
|
key={index}
|
|
href={getImageUrl(image.file_path)}
|
|
className="group relative overflow-hidden rounded-xl cursor-pointer bg-slate-800"
|
|
>
|
|
<img src={getImageUrl(image.file_path, "w185")} />
|
|
</a>
|
|
))}
|
|
</LightGallery>
|
|
</div>
|
|
{limit < currentImages.length && (
|
|
<div className="flex justify-center mt-6">
|
|
<Button
|
|
theme="teal"
|
|
size="small"
|
|
onClick={() => setLimit(currentImages.length)}
|
|
>
|
|
Pokaż wszystkie ({currentImages.length - limit})
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|