95eb362bfc
QuantumLab template converted to Next.js 16 + React 19 + TypeScript: - 8 page routes (home, about, blog, contact, careers, team-members, coming-soon, 404) - Dynamic routes for blog posts, career positions, and team members - GSAP animations (marquee, counters, button hovers) - IntersectionObserver-based scroll reveal (blur-to-clear transitions) - Dark mode with next-themes - React Hook Form + Zod contact form - Framer Motion page transitions - Lottie animations via lottie-web Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
61 lines
2.0 KiB
TypeScript
61 lines
2.0 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useCallback } from "react"
|
|
|
|
interface VideoLightboxProps {
|
|
thumbnailSrc: string
|
|
videoUrl: string
|
|
className?: string
|
|
children?: React.ReactNode
|
|
}
|
|
|
|
export default function VideoLightbox({ thumbnailSrc, videoUrl, className, children }: VideoLightboxProps) {
|
|
const [open, setOpen] = useState(false)
|
|
|
|
const handleOpen = useCallback(() => setOpen(true), [])
|
|
const handleClose = useCallback(() => setOpen(false), [])
|
|
|
|
const embedUrl = videoUrl.includes("youtube.com/watch")
|
|
? videoUrl.replace("watch?v=", "embed/") + "?autoplay=1"
|
|
: videoUrl
|
|
|
|
return (
|
|
<>
|
|
<button type="button" className={className} onClick={handleOpen} style={{ cursor: "pointer", border: "none", background: "none", padding: 0 }}>
|
|
{children || <img src={thumbnailSrc} alt="Video thumbnail" style={{ width: "100%" }} />}
|
|
</button>
|
|
{open && (
|
|
<div
|
|
style={{
|
|
position: "fixed", inset: 0, zIndex: 9999,
|
|
background: "rgba(0,0,0,0.9)",
|
|
display: "flex", alignItems: "center", justifyContent: "center",
|
|
}}
|
|
onClick={handleClose}
|
|
>
|
|
<div style={{ position: "relative", width: "90vw", maxWidth: 1200, aspectRatio: "16/9" }} onClick={(e) => e.stopPropagation()}>
|
|
<iframe
|
|
src={embedUrl}
|
|
style={{ width: "100%", height: "100%", border: "none", borderRadius: 12 }}
|
|
allow="autoplay; fullscreen; picture-in-picture"
|
|
allowFullScreen
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={handleClose}
|
|
style={{
|
|
position: "absolute", top: -40, right: 0,
|
|
background: "none", border: "none", color: "#fff",
|
|
fontSize: 28, cursor: "pointer", lineHeight: 1,
|
|
}}
|
|
aria-label="Close"
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
)
|
|
}
|