ImageGallery
imagegallery-1779379195705.tsx
'use client'
import { useState, useEffect } from 'react'
const IMAGES = [
{ id: 1, src: null, color: 'linear-gradient(135deg, #C9A84C, #6366f1)', caption: 'GlowButton Component', w: 1, h: 2 },
{ id: 2, src: null, color: 'linear-gradient(135deg, #6366f1, #22c55e)', caption: 'HoverTiltCard', w: 1, h: 1 },
{ id: 3, src: null, color: 'linear-gradient(135deg, #22c55e, #ef4444)', caption: 'CommandMenu', w: 1, h: 1 },
{ id: 4, src: null, color: 'linear-gradient(135deg, #ef4444, #f59e0b)', caption: 'DataTable', w: 2, h: 1 },
{ id: 5, src: null, color: 'linear-gradient(135deg, #f59e0b, #ec4899)', caption: 'ChatInterface', w: 1, h: 1 },
{ id: 6, src: null, color: 'linear-gradient(135deg, #ec4899, #C9A84C)', caption: 'RadialProgress', w: 1, h: 2 },
]
export default function ImageGallery() {
const [lightbox, setLightbox] = useState<number | null>(null)
useEffect(() => {
if (lightbox === null) return
const handler = (e: KeyboardEvent) => {
if (e.key === 'Escape') setLightbox(null)
if (e.key === 'ArrowRight') setLightbox(i => i !== null ? (i + 1) % IMAGES.length : null)
if (e.key === 'ArrowLeft') setLightbox(i => i !== null ? (i - 1 + IMAGES.length) % IMAGES.length : null)
}
document.addEventListener('keydown', handler)
return () => document.removeEventListener('keydown', handler)
}, [lightbox])
return (
<div style={{ padding: 24, background: '#0A0A0A' }}>
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gridAutoRows: '120px', gap: 8 }}>
{IMAGES.map((img, i) => (
<div key={img.id} onClick={() => setLightbox(i)}
style={{ gridColumn: `span ${img.w}`, gridRow: `span ${img.h}`, background: img.color, borderRadius: 12, cursor: 'pointer', position: 'relative', overflow: 'hidden', transition: 'transform 0.2s' }}
onMouseEnter={e => (e.currentTarget.style.transform = 'scale(0.97)')}
onMouseLeave={e => (e.currentTarget.style.transform = 'scale(1)')}>
<div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<span style={{ color: 'rgba(255,255,255,0.8)', fontSize: 24 }}>⬡</span>
</div>
<div style={{ position: 'absolute', bottom: 0, left: 0, right: 0, padding: '20px 12px 10px', background: 'linear-gradient(transparent, rgba(0,0,0,0.6))' }}>
<span style={{ color: '#fff', fontSize: 11, fontWeight: 600 }}>{img.caption}</span>
</div>
</div>
))}
</div>
{lightbox !== null && (
<div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.92)', backdropFilter: 'blur(12px)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999 }}
onClick={e => { if (e.target === e.currentTarget) setLightbox(null) }}>
<button onClick={() => setLightbox(i => i !== null ? (i - 1 + IMAGES.length) % IMAGES.length : null)} style={{ position: 'absolute', left: 24, background: 'rgba(255,255,255,0.1)', border: '1px solid rgba(255,255,255,0.2)', color: '#F5F5F0', borderRadius: '50%', width: 44, height: 44, cursor: 'pointer', fontSize: 18 }}>←</button>
<div style={{ width: 480, height: 320, background: IMAGES[lightbox].color, borderRadius: 16, display: 'flex', alignItems: 'center', justifyContent: 'center', animation: 'popIn 0.25s ease' }}>
<span style={{ color: 'rgba(255,255,255,0.8)', fontSize: 64 }}>⬡</span>
</div>
<button onClick={() => setLightbox(i => i !== null ? (i + 1) % IMAGES.length : null)} style={{ position: 'absolute', right: 24, background: 'rgba(255,255,255,0.1)', border: '1px solid rgba(255,255,255,0.2)', color: '#F5F5F0', borderRadius: '50%', width: 44, height: 44, cursor: 'pointer', fontSize: 18 }}>→</button>
<div style={{ position: 'absolute', bottom: 32, textAlign: 'center' }}>
<div style={{ color: '#F5F5F0', fontSize: 16, fontWeight: 600, marginBottom: 6 }}>{IMAGES[lightbox].caption}</div>
<div style={{ color: 'rgba(255,255,255,0.4)', fontSize: 12 }}>{lightbox + 1} / {IMAGES.length} · ESC to close</div>
</div>
<button onClick={() => setLightbox(null)} style={{ position: 'absolute', top: 20, right: 20, background: 'rgba(255,255,255,0.1)', border: '1px solid rgba(255,255,255,0.15)', color: '#F5F5F0', borderRadius: '50%', width: 36, height: 36, cursor: 'pointer', fontSize: 18, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>×</button>
</div>
)}
<style>{`@keyframes popIn { from { opacity:0; transform:scale(0.9) } to { opacity:1; transform:scale(1) } }`}</style>
</div>
)
}Component info
CategoryMedia
Frameworkreact
TierFREE
Views0
Copies0
About
Masonry image gallery with lightbox, keyboard navigation, zoom, and caption display