"use client"; import { ChevronLeft, ChevronRight } from "lucide-react"; import { AnimatePresence, motion } from "motion/react"; import { useCallback, useEffect, useRef, useState } from "react"; import { ExpandedGifOverlay, useExpandedGif } from "@/components/ui/expanded-gif-overlay"; const carouselItems = [ { title: "Connect & Sync", description: "Connect data sources like Notion, Drive and Gmail. Automatically sync to keep them updated.", src: "/homepage/hero_tutorial/ConnectorFlowGif.mp4", }, { title: "Upload Documents", description: "Upload documents directly, from images to massive PDFs.", src: "/homepage/hero_tutorial/DocUploadGif.mp4", }, { title: "Video Generation", description: "Create short videos with AI-generated visuals and narration from your sources.", src: "/homepage/hero_tutorial/video_gen_surf.mp4", }, { title: "Search & Citation", description: "Ask questions and get cited responses from your knowledge base.", src: "/homepage/hero_tutorial/BSNCGif.mp4", }, { title: "Targeted Document Q&A", description: "Mention specific documents in chat for targeted answers.", src: "/homepage/hero_tutorial/BQnaGif_compressed.mp4", }, { title: "Produce Reports Instantly", description: "Generate reports from your sources in many formats.", src: "/homepage/hero_tutorial/ReportGenGif_compressed.mp4", }, { title: "Create Podcasts", description: "Turn anything into a podcast in under 20 seconds.", src: "/homepage/hero_tutorial/PodcastGenGif.mp4", }, { title: "Image Generation", description: "Generate high-quality images easily from your conversations.", src: "/homepage/hero_tutorial/ImageGenGif.mp4", }, { title: "Collaborative AI Chat", description: "Collaborate on AI-powered conversations in realtime with your team.", src: "/homepage/hero_realtime/RealTimeChatGif.mp4", }, { title: "Realtime Comments", description: "Add comments and tag teammates on any message.", src: "/homepage/hero_realtime/RealTimeCommentsFlow.mp4", }, ]; function HeroCarouselCard({ title, description, src, onExpandedChange, }: { title: string; description: string; src: string; onExpandedChange?: (expanded: boolean) => void; }) { const { expanded, open, close } = useExpandedGif(); const videoRef = useRef(null); const [hasLoaded, setHasLoaded] = useState(false); useEffect(() => { onExpandedChange?.(expanded); }, [expanded, onExpandedChange]); useEffect(() => { const video = videoRef.current; if (video) { setHasLoaded(false); video.currentTime = 0; video.play().catch(() => {}); } }, [src]); const handleCanPlay = useCallback(() => { setHasLoaded(true); }, []); return ( <>
{" "}

{title}

{description}

{expanded && } ); } function usePrefetchVideos() { const videosRef = useRef([]); useEffect(() => { let cancelled = false; async function prefetch() { for (const item of carouselItems) { if (cancelled) break; await new Promise((resolve) => { const video = document.createElement("video"); video.preload = "auto"; video.src = item.src; video.oncanplaythrough = () => resolve(); video.onerror = () => resolve(); setTimeout(resolve, 10000); videosRef.current.push(video); }); } } prefetch(); return () => { cancelled = true; videosRef.current = []; }; }, []); } const AUTOPLAY_MS = 6000; function HeroCarousel() { const [activeIndex, setActiveIndex] = useState(0); const [isGifExpanded, setIsGifExpanded] = useState(false); const [isHovered, setIsHovered] = useState(false); const [isTabVisible, setIsTabVisible] = useState(true); const directionRef = useRef<"forward" | "backward">("forward"); usePrefetchVideos(); const shouldAutoPlay = !isGifExpanded && !isHovered && isTabVisible; useEffect(() => { if (!shouldAutoPlay) return; const id = setTimeout(() => { directionRef.current = "forward"; setActiveIndex((prev) => (prev >= carouselItems.length - 1 ? 0 : prev + 1)); }, AUTOPLAY_MS); return () => clearTimeout(id); }, [activeIndex, shouldAutoPlay]); useEffect(() => { const handler = () => setIsTabVisible(!document.hidden); document.addEventListener("visibilitychange", handler); return () => document.removeEventListener("visibilitychange", handler); }, []); const goTo = useCallback( (newIndex: number) => { directionRef.current = newIndex >= activeIndex ? "forward" : "backward"; setActiveIndex(newIndex); }, [activeIndex] ); const goToPrev = useCallback(() => { goTo(activeIndex <= 0 ? carouselItems.length - 1 : activeIndex - 1); }, [activeIndex, goTo]); const goToNext = useCallback(() => { goTo(activeIndex >= carouselItems.length - 1 ? 0 : activeIndex + 1); }, [activeIndex, goTo]); const item = carouselItems[activeIndex]; const isForward = directionRef.current === "forward"; return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} >
{carouselItems.map((_, i) => ( ))}
); } export { HeroCarousel, HeroCarouselCard };