124 lines
5.6 KiB
TypeScript
124 lines
5.6 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useState } from "react";
|
||
|
|
import Image from "next/image";
|
||
|
|
import ScrollReveal from "./ScrollReveal";
|
||
|
|
import { X } from "lucide-react";
|
||
|
|
|
||
|
|
const photos = [
|
||
|
|
{ src: "/images/photos/rack-build-ultrix.jpg", alt: "Ross Ultrix rack build", caption: "Ross Ultrix Router Build" },
|
||
|
|
{ src: "/images/photos/rack-build-wide.jpg", alt: "Full rack build wide view", caption: "Facility Rack Infrastructure" },
|
||
|
|
{ src: "/images/photos/monumental-buildout.jpg", alt: "Monumental Sports buildout", caption: "Monumental Sports Buildout" },
|
||
|
|
{ src: "/images/photos/led-wall-testing.jpg", alt: "LED wall testing", caption: "LED Wall Calibration" },
|
||
|
|
{ src: "/images/photos/thor-stage-setup.jpg", alt: "THOR stage setup", caption: "THOR Broadcast Stage" },
|
||
|
|
{ src: "/images/photos/rack-work.jpg", alt: "Rack wiring detail", caption: "Cable Infrastructure" },
|
||
|
|
{ src: "/images/photos/studio-construction.jpg", alt: "Studio under construction", caption: "Studio Construction" },
|
||
|
|
{ src: "/images/photos/red-camera-closeup.jpg", alt: "RED camera closeup", caption: "RED Camera System" },
|
||
|
|
];
|
||
|
|
|
||
|
|
export default function Gallery() {
|
||
|
|
const [lightbox, setLightbox] = useState<number | null>(null);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<section id="gallery" className="py-28 md:py-36 bg-surface-elevated noise-overlay">
|
||
|
|
<div className="relative z-10 max-w-6xl mx-auto px-6">
|
||
|
|
<ScrollReveal>
|
||
|
|
<div className="max-w-3xl mb-16">
|
||
|
|
<div className="w-10 h-px bg-accent mb-6 glow-accent-sm" />
|
||
|
|
<p className="font-mono text-[10px] tracking-[0.3em] uppercase text-accent mb-4">
|
||
|
|
Gallery
|
||
|
|
</p>
|
||
|
|
<h2 className="text-3xl md:text-4xl font-semibold text-white leading-tight mb-5">
|
||
|
|
Behind the <span className="text-gradient">builds.</span>
|
||
|
|
</h2>
|
||
|
|
<p className="text-white/55 leading-relaxed">
|
||
|
|
A look inside the integration process—from rack fabrication
|
||
|
|
and cable infrastructure to LED calibration and system commissioning.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
</ScrollReveal>
|
||
|
|
|
||
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 md:gap-4">
|
||
|
|
{photos.map((photo, i) => (
|
||
|
|
<ScrollReveal
|
||
|
|
key={photo.src}
|
||
|
|
delay={i * 50}
|
||
|
|
className={i === 0 || i === 5 ? "col-span-2 row-span-2" : ""}
|
||
|
|
>
|
||
|
|
<button
|
||
|
|
onClick={() => setLightbox(i)}
|
||
|
|
className="group relative block w-full h-full overflow-hidden rounded-lg cursor-pointer border border-border hover:border-border-hover transition-all duration-300"
|
||
|
|
>
|
||
|
|
<div className={`relative ${i === 0 || i === 5 ? "h-64 md:h-80" : "h-32 md:h-40"} w-full`}>
|
||
|
|
<Image
|
||
|
|
src={photo.src}
|
||
|
|
alt={photo.alt}
|
||
|
|
fill
|
||
|
|
className="object-cover group-hover:scale-105 transition-transform duration-500 ease-out"
|
||
|
|
sizes={i === 0 || i === 5 ? "50vw" : "25vw"}
|
||
|
|
/>
|
||
|
|
<div className="absolute inset-0 bg-black/20 group-hover:bg-black/50 transition-colors duration-300" />
|
||
|
|
<div className="absolute inset-0 flex items-end p-4 opacity-0 group-hover:opacity-100 transition-opacity duration-300">
|
||
|
|
<span className="text-xs font-medium text-white/90 bg-black/40 backdrop-blur-sm px-2 py-1 rounded">
|
||
|
|
{photo.caption}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</button>
|
||
|
|
</ScrollReveal>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
{/* Lightbox */}
|
||
|
|
{lightbox !== null && (
|
||
|
|
<div
|
||
|
|
className="fixed inset-0 z-[100] bg-black/95 backdrop-blur-md flex items-center justify-center p-6"
|
||
|
|
onClick={() => setLightbox(null)}
|
||
|
|
>
|
||
|
|
<button
|
||
|
|
onClick={() => setLightbox(null)}
|
||
|
|
className="absolute top-6 right-6 text-white/55 hover:text-white transition-colors"
|
||
|
|
aria-label="Close lightbox"
|
||
|
|
>
|
||
|
|
<X size={28} />
|
||
|
|
</button>
|
||
|
|
<div className="relative max-w-5xl w-full max-h-[85vh]" onClick={(e) => e.stopPropagation()}>
|
||
|
|
<Image
|
||
|
|
src={photos[lightbox].src}
|
||
|
|
alt={photos[lightbox].alt}
|
||
|
|
width={1200}
|
||
|
|
height={800}
|
||
|
|
className="object-contain w-full h-auto max-h-[80vh] rounded-lg"
|
||
|
|
/>
|
||
|
|
<p className="text-center text-sm text-white/60 mt-4">
|
||
|
|
{photos[lightbox].caption}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
{/* Nav arrows */}
|
||
|
|
{lightbox > 0 && (
|
||
|
|
<button
|
||
|
|
onClick={(e) => { e.stopPropagation(); setLightbox(lightbox - 1); }}
|
||
|
|
className="absolute left-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-white/5 hover:bg-white/15 border border-white/10 flex items-center justify-center text-white transition-all duration-200"
|
||
|
|
aria-label="Previous photo"
|
||
|
|
>
|
||
|
|
‹
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
{lightbox < photos.length - 1 && (
|
||
|
|
<button
|
||
|
|
onClick={(e) => { e.stopPropagation(); setLightbox(lightbox + 1); }}
|
||
|
|
className="absolute right-4 top-1/2 -translate-y-1/2 w-10 h-10 rounded-full bg-white/5 hover:bg-white/15 border border-white/10 flex items-center justify-center text-white transition-all duration-200"
|
||
|
|
aria-label="Next photo"
|
||
|
|
>
|
||
|
|
›
|
||
|
|
</button>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|