import { useEffect, useRef } from "react"; import gsap from "gsap"; import type { PresentPhoto } from "../../lib/photoWallMarquee"; type PhotoSpotlightProps = { photo: PresentPhoto | null; borderRadius: number | string; holdMs?: number; onComplete: () => void; }; /** * Full-screen spotlight for a newly added photo: fade/scale in → hold → out. * Optional `message` is shown as a quote (spotlight only — not on wall cards). */ export function PhotoSpotlight({ photo, borderRadius, holdMs = 2400, onComplete, }: PhotoSpotlightProps) { const rootRef = useRef(null); const cardRef = useRef(null); const frameRef = useRef(null); const nameRef = useRef(null); const messageRef = useRef(null); const onCompleteRef = useRef(onComplete); onCompleteRef.current = onComplete; const message = photo?.message?.trim() || ""; const effectiveHoldMs = message ? Math.max(holdMs, 3200) : holdMs; useEffect(() => { if (!photo || !rootRef.current || !cardRef.current || !frameRef.current) return; const ctx = gsap.context(() => { const tl = gsap.timeline({ onComplete: () => onCompleteRef.current(), }); gsap.set(rootRef.current, { autoAlpha: 0 }); gsap.set(cardRef.current, { scale: 0.82, autoAlpha: 0 }); gsap.set(frameRef.current, { boxShadow: "0 0 0 0 color-mix(in srgb, var(--theme-button-color) 0%, transparent)", }); if (nameRef.current) { gsap.set(nameRef.current, { autoAlpha: 0, y: 18 }); } if (messageRef.current) { gsap.set(messageRef.current, { autoAlpha: 0, y: 22 }); } tl.to(rootRef.current, { autoAlpha: 1, duration: 0.35, ease: "power2.out" }) .to( cardRef.current, { scale: 1, autoAlpha: 1, duration: 0.45, ease: "back.out(1.4)" }, "<0.05", ) .to( frameRef.current, { boxShadow: "0 0 48px 18px color-mix(in srgb, var(--theme-button-color) 22%, transparent), 0 0 90px 36px color-mix(in srgb, var(--theme-button-color) 12%, transparent), 0 16px 36px rgba(0,0,0,0.35)", duration: 0.55, ease: "power2.out", }, "<0.1", ); if (nameRef.current) { tl.to( nameRef.current, { autoAlpha: 1, y: 0, duration: 0.45, ease: "power3.out" }, "-=0.15", ); } if (messageRef.current) { tl.to( messageRef.current, { autoAlpha: 1, y: 0, duration: 0.5, ease: "power3.out" }, "-=0.2", ); } tl.to({}, { duration: effectiveHoldMs / 1000 }) .to(cardRef.current, { scale: 0.9, autoAlpha: 0, duration: 0.35, ease: "power2.in" }) .to(rootRef.current, { autoAlpha: 0, duration: 0.25, ease: "power2.in" }, "<"); }); return () => ctx.revert(); }, [photo, effectiveHoldMs]); if (!photo) return null; return (
{photo.displayName
{photo.displayName ? (

{photo.displayName}

) : null} {message ? (
“

{message}

”
) : null}
); }