310 lines
12 KiB
TypeScript
310 lines
12 KiB
TypeScript
'use client';
|
||
|
||
import React, { useState } from 'react';
|
||
import Image from 'next/image';
|
||
|
||
interface GalleryItem {
|
||
id: number;
|
||
title: string;
|
||
category: string;
|
||
desc: string;
|
||
image: string;
|
||
tag: string;
|
||
}
|
||
|
||
const portfolioItems: GalleryItem[] = [
|
||
{
|
||
id: 1,
|
||
title: 'Titus & Alayna Tuscan Wedding Arch',
|
||
category: 'Weddings',
|
||
desc: 'Tuscan yellow centerpiece arch flanked by crisp white panels, organic lemon-white balloon clouds, and white floral arrangements.',
|
||
image: '/images/portfolio_titus_alayna_wedding.jpg',
|
||
tag: 'Weddings & Engagements',
|
||
},
|
||
{
|
||
id: 2,
|
||
title: 'Emelda Luxury Black, Gold & Crimson Birthday',
|
||
category: 'Birthdays',
|
||
desc: 'Black marble backdrop with gold script lettering, surrounded by a dramatic organic garland of chrome gold, crimson red, and onyx black balloons.',
|
||
image: '/images/portfolio_emelda_luxury_black_gold.jpg',
|
||
tag: 'Milestone Celebrations',
|
||
},
|
||
{
|
||
id: 3,
|
||
title: 'Berry Sweet Baby Shower Triple Arch',
|
||
category: 'Baby Showers',
|
||
desc: 'Triple custom arched panels with hand-illustrated strawberry & blueberry motifs, framed in organic strawberry red, navy blue, and pastel pink balloons.',
|
||
image: '/images/portfolio_berry_sweet_baby.jpg',
|
||
tag: 'Baby Showers',
|
||
},
|
||
{
|
||
id: 4,
|
||
title: 'Amina’s "Berry First Birthday" Backdrop',
|
||
category: 'Birthdays',
|
||
desc: 'Custom arched backdrop with 3D strawberry foil balloons and an organic balloon cascade in cherry red, blush pink, and white.',
|
||
image: '/images/portfolio_amina_berry_first_birthday.png',
|
||
tag: '1st Birthdays',
|
||
},
|
||
{
|
||
id: 5,
|
||
title: 'Sage Green, Blush & Chrome Gold Birthday Arch',
|
||
category: 'Birthdays',
|
||
desc: 'Elegant white arch with 3D gold "Happy Birthday" lettering, accented with faux eucalyptus greenery, silk roses, and chrome gold spheres.',
|
||
image: '/images/portfolio_sage_gold_birthday.jpg',
|
||
tag: 'Adult Birthdays',
|
||
},
|
||
{
|
||
id: 6,
|
||
title: 'Class of 2026 Tropical Brights Graduation',
|
||
category: 'Themed',
|
||
desc: 'Vibrant tropical color palette of hot pink, neon orange, bright turquoise, and lime green with monstera palm leaves on a lavender backdrop.',
|
||
image: '/images/portfolio_tropical_class_2026.jpg',
|
||
tag: 'Graduations',
|
||
},
|
||
{
|
||
id: 7,
|
||
title: 'Lavender Moon Arch & Giant Mosaic Letter "J"',
|
||
category: 'Specialty',
|
||
desc: 'Gold crescent moon hoop with deep navy and lilac balloons, paired with sheer lilac drape backdrops and a towering custom balloon mosaic "J".',
|
||
image: '/images/portfolio_lavender_moon_arch.jpg',
|
||
tag: 'Custom Mosaic Letters',
|
||
},
|
||
{
|
||
id: 8,
|
||
title: 'Patriotic Memorial Day Celebration Arch',
|
||
category: 'Themed',
|
||
desc: 'Grand red, white, royal blue, and chrome gold balloon arch featuring metallic 3D starburst foils for a high-impact holiday installation.',
|
||
image: '/images/portfolio_memorial_day_arch.jpg',
|
||
tag: 'Community Events',
|
||
},
|
||
{
|
||
id: 9,
|
||
title: '"Pop, Fizz, Fun!" Citrus Beverage Station',
|
||
category: 'Specialty',
|
||
desc: 'Vibrant orange and pearl white organic balloon wave framing an arched drink station with custom floral typography and rustic wooden beverage crates.',
|
||
image: '/images/portfolio_pop_fizz_orange.jpg',
|
||
tag: 'Drink & Treat Stations',
|
||
},
|
||
];
|
||
|
||
export default function PortfolioGallery() {
|
||
const [selectedCategory, setSelectedCategory] = useState('All');
|
||
const [activeModalImage, setActiveModalImage] = useState<GalleryItem | null>(null);
|
||
|
||
const categories = ['All', 'Weddings', 'Birthdays', 'Baby Showers', 'Themed', 'Specialty'];
|
||
|
||
const filteredItems = selectedCategory === 'All'
|
||
? portfolioItems
|
||
: portfolioItems.filter(item => item.category === selectedCategory);
|
||
|
||
return (
|
||
<section id="portfolio" style={{
|
||
padding: '100px 24px',
|
||
backgroundColor: '#080808',
|
||
position: 'relative',
|
||
borderBottom: '1px solid var(--border-gold)',
|
||
}}>
|
||
<div className="container">
|
||
|
||
{/* Heading */}
|
||
<div style={{ textAlign: 'center', marginBottom: '48px' }}>
|
||
<span style={{ fontSize: '0.85rem', fontWeight: 800, color: 'var(--color-pink-light)', letterSpacing: '0.15em', textTransform: 'uppercase', display: 'block', marginBottom: '10px' }}>
|
||
Real Client Installations
|
||
</span>
|
||
<h2 style={{ fontSize: 'clamp(2rem, 3.8vw, 2.8rem)', fontWeight: 800, marginBottom: '16px' }}>
|
||
Featured <span className="gold-gradient-text">Event Portfolio</span>
|
||
</h2>
|
||
<p style={{ fontSize: '1.1rem', color: '#94A3B8', maxWidth: '680px', margin: '0 auto', lineHeight: 1.7 }}>
|
||
Every event is a custom masterpiece. Browse through our real balloon garlands, custom backdrops, and bespoke styling.
|
||
</p>
|
||
</div>
|
||
|
||
{/* Filter Pills */}
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
gap: '12px',
|
||
flexWrap: 'wrap',
|
||
marginBottom: '50px',
|
||
}}>
|
||
{categories.map((cat) => (
|
||
<button
|
||
key={cat}
|
||
onClick={() => setSelectedCategory(cat)}
|
||
style={{
|
||
background: selectedCategory === cat ? 'var(--color-gold-gradient)' : 'rgba(255, 255, 255, 0.05)',
|
||
color: selectedCategory === cat ? '#080808' : '#CBD5E1',
|
||
border: selectedCategory === cat ? 'none' : '1px solid rgba(255, 255, 255, 0.12)',
|
||
padding: '10px 24px',
|
||
borderRadius: '50px',
|
||
fontSize: '0.9rem',
|
||
fontWeight: 700,
|
||
cursor: 'pointer',
|
||
transition: 'all 0.25s ease',
|
||
boxShadow: selectedCategory === cat ? '0 4px 15px rgba(212, 175, 55, 0.4)' : 'none',
|
||
}}
|
||
>
|
||
{cat === 'All' ? '✨ All Creations' : cat}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Gallery Grid */}
|
||
<div style={{
|
||
display: 'grid',
|
||
gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))',
|
||
gap: '28px',
|
||
}}>
|
||
{filteredItems.map((item) => (
|
||
<div
|
||
key={item.id}
|
||
onClick={() => setActiveModalImage(item)}
|
||
className="glass-panel"
|
||
style={{
|
||
borderRadius: '16px',
|
||
overflow: 'hidden',
|
||
cursor: 'pointer',
|
||
transition: 'transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease',
|
||
border: '1px solid rgba(212, 175, 55, 0.2)',
|
||
}}
|
||
onMouseEnter={(e) => {
|
||
e.currentTarget.style.transform = 'translateY(-6px)';
|
||
e.currentTarget.style.borderColor = 'var(--color-gold)';
|
||
e.currentTarget.style.boxShadow = '0 12px 30px rgba(212, 175, 55, 0.25)';
|
||
}}
|
||
onMouseLeave={(e) => {
|
||
e.currentTarget.style.transform = 'translateY(0)';
|
||
e.currentTarget.style.borderColor = 'rgba(212, 175, 55, 0.2)';
|
||
e.currentTarget.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.6)';
|
||
}}
|
||
>
|
||
{/* Image Container */}
|
||
<div style={{ position: 'relative', width: '100%', height: '360px', overflow: 'hidden', backgroundColor: '#141414' }}>
|
||
<Image
|
||
src={item.image}
|
||
alt={item.title}
|
||
fill
|
||
style={{ objectFit: 'cover', transition: 'transform 0.5s ease' }}
|
||
/>
|
||
<div style={{
|
||
position: 'absolute',
|
||
top: '16px',
|
||
right: '16px',
|
||
background: 'rgba(8, 8, 8, 0.85)',
|
||
backdropFilter: 'blur(8px)',
|
||
border: '1px solid var(--color-gold)',
|
||
color: 'var(--color-gold-light)',
|
||
fontSize: '0.75rem',
|
||
fontWeight: 800,
|
||
padding: '4px 12px',
|
||
borderRadius: '20px',
|
||
letterSpacing: '0.05em',
|
||
textTransform: 'uppercase',
|
||
}}>
|
||
{item.tag}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Caption */}
|
||
<div style={{ padding: '22px 24px' }}>
|
||
<h3 style={{ fontSize: '1.2rem', fontWeight: 700, color: '#FFFFFF', marginBottom: '8px' }}>
|
||
{item.title}
|
||
</h3>
|
||
<p style={{ fontSize: '0.9rem', lineHeight: 1.6, color: '#94A3B8', margin: 0 }}>
|
||
{item.desc}
|
||
</p>
|
||
<div style={{ marginTop: '16px', display: 'flex', alignItems: 'center', gap: '6px', color: 'var(--color-pink-light)', fontSize: '0.85rem', fontWeight: 700 }}>
|
||
<span>Click to view full photo</span> <span>↗</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
</div>
|
||
|
||
{/* Full-Screen Image Lightbox Modal */}
|
||
{activeModalImage && (
|
||
<div
|
||
onClick={() => setActiveModalImage(null)}
|
||
style={{
|
||
position: 'fixed',
|
||
top: 0,
|
||
left: 0,
|
||
width: '100%',
|
||
height: '100%',
|
||
backgroundColor: 'rgba(0, 0, 0, 0.92)',
|
||
backdropFilter: 'blur(12px)',
|
||
zIndex: 9999,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: '24px',
|
||
}}
|
||
>
|
||
<div
|
||
onClick={(e) => e.stopPropagation()}
|
||
style={{
|
||
position: 'relative',
|
||
maxWidth: '900px',
|
||
width: '100%',
|
||
maxHeight: '90vh',
|
||
background: '#0F0F0F',
|
||
border: '2px solid var(--color-gold)',
|
||
borderRadius: '16px',
|
||
overflow: 'hidden',
|
||
boxShadow: '0 0 40px rgba(212, 175, 55, 0.4)',
|
||
display: 'flex',
|
||
flexDirection: 'column',
|
||
}}
|
||
>
|
||
<button
|
||
onClick={() => setActiveModalImage(null)}
|
||
style={{
|
||
position: 'absolute',
|
||
top: '16px',
|
||
right: '16px',
|
||
zIndex: 10,
|
||
background: 'rgba(0,0,0,0.7)',
|
||
color: '#FFFFFF',
|
||
border: '1px solid var(--color-gold)',
|
||
borderRadius: '50%',
|
||
width: '40px',
|
||
height: '40px',
|
||
fontSize: '1.2rem',
|
||
cursor: 'pointer',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
}}
|
||
>
|
||
✕
|
||
</button>
|
||
|
||
<div style={{ position: 'relative', width: '100%', height: '65vh', backgroundColor: '#000000' }}>
|
||
<Image
|
||
src={activeModalImage.image}
|
||
alt={activeModalImage.title}
|
||
fill
|
||
style={{ objectFit: 'contain' }}
|
||
/>
|
||
</div>
|
||
|
||
<div style={{ padding: '20px 24px', background: '#141414', borderTop: '1px solid rgba(255,255,255,0.08)' }}>
|
||
<div style={{ display: 'inline-block', color: 'var(--color-pink-light)', fontSize: '0.8rem', fontWeight: 800, textTransform: 'uppercase', marginBottom: '4px' }}>
|
||
{activeModalImage.tag}
|
||
</div>
|
||
<h3 style={{ fontSize: '1.3rem', color: 'var(--color-gold-light)', fontWeight: 800, marginBottom: '6px' }}>
|
||
{activeModalImage.title}
|
||
</h3>
|
||
<p style={{ fontSize: '0.95rem', color: '#CBD5E1', margin: 0 }}>
|
||
{activeModalImage.desc}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</section>
|
||
);
|
||
}
|