Files
wise-hearted-decor/src/components/PortfolioGallery.tsx
T

310 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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: 'Aminas "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>
);
}