feat(wise-hearted-decor): initial luxury event decor website build with 5 pillars, portfolio, and booking funnel
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user