/* portfolio.jsx — Image-heavy grid + lightbox modal */ const { useState: _useState, useEffect: _useEffect, useMemo: _useMemo } = React; function PortfolioPage({ onNavigate, initialProject = null }) { const { t, lang } = useLang(); const { PORTFOLIO, FILTERS } = window.JMC_DATA; const [filter, setFilter] = _useState('all'); const [sort, setSort] = _useState('recent'); const [openId, setOpenId] = _useState(initialProject); _useEffect(() => { if (initialProject) setOpenId(initialProject); }, [initialProject]); const filtered = _useMemo(() => { let list = filter === 'all' ? PORTFOLIO : PORTFOLIO.filter(p => p.type === filter); list = [...list]; if (sort === 'recent') list.sort((a, b) => b.year - a.year); if (sort === 'capacity') list.sort((a, b) => { const num = s => parseFloat((s || '').replace(/[^\d.]/g, '')) || 0; return num(b.capacity) - num(a.capacity); }); if (sort === 'alpha') list.sort((a, b) => a.name.localeCompare(b.name)); return list; }, [filter, sort, PORTFOLIO]); const openProject = openId ? PORTFOLIO.find(p => p.id === openId) : null; return (
{/* Hero strip — full-bleed image */}
{t.portfolio.eyebrow}

{t.portfolio.title.map((l, i) => {l})}

{t.portfolio.sub}

{/* Filter + sort */}
{FILTERS.map(f => ( ))}
{t.portfolio.sort} {filtered.length} {t.portfolio.countOf} {PORTFOLIO.length}
{/* Grid */}
{filtered.length === 0 ? (
{t.portfolio.empty}
) : (
{filtered.map((p, i) => ( setOpenId(p.id)} /> ))}
)}
onNavigate('contact')} image="assets/portfolio/bess-03.png" /> {openProject && ( setOpenId(null)} onContact={() => { setOpenId(null); onNavigate('contact'); }} /> )}
); } /* ─────────────────────── Card ───────────────────── */ function PortfolioCard({ project, onOpen }) { const { lang } = useLang(); return (
{project.typeLabel[lang]} {project.year}

{project.name}

{project.summary[lang]}

{project.locationLabel[lang]}
{lang === 'es' ? 'Ver' : 'View'} →
); } /* ─────────────────────── Modal ───────────────────── */ function PortfolioModal({ project, onClose, onContact }) { const { t, lang } = useLang(); const [imgIdx, setImgIdx] = _useState(0); const images = project.images || [project.image]; _useEffect(() => { const onKey = e => { if (e.key === 'Escape') onClose(); if (e.key === 'ArrowRight') setImgIdx(i => (i + 1) % images.length); if (e.key === 'ArrowLeft') setImgIdx(i => (i - 1 + images.length) % images.length); }; document.addEventListener('keydown', onKey); document.body.style.overflow = 'hidden'; return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; }; }, [onClose, images.length]); return (
e.stopPropagation()}> {/* Hero image */}
{images.length > 1 && ( <> )}
{/* Thumb strip */} {images.length > 1 && (
{images.map((src, i) => { const vid = /\.(mp4|webm|mov)$/i.test(src); return ( ); })}
)}
{project.typeLabel[lang]} · {project.year}

{project.name}

{project.summary[lang]}

{[ [t.portfolio.modal.client, project.clientLabel[lang]], [t.portfolio.modal.location, project.locationLabel[lang]], [t.portfolio.modal.capacity, project.capacity], [t.portfolio.modal.delivered, project.year], ].map(([k, v], i) => (
{k}
{v}
))}

{t.portfolio.modal.deliverables}

{project.deliverables[lang].map(d => (
{d}
))}
{t.portfolio.modal.primary} {t.portfolio.modal.secondary}
); } window.PortfolioPage = PortfolioPage;