Untitled
unknown
plain_text
14 days ago
5.6 kB
4
Indexable
// components/hero-designs/CarouselHero.tsx import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { ChevronDown, ChevronLeft, ChevronRight } from "lucide-react"; import { ClientConfig } from "@/lib/client-config"; import { getR2ImageUrl } from "@/lib/r2"; interface CarouselHeroProps { config: ClientConfig; } export function CarouselHero({ config }: CarouselHeroProps) { const heroConfig = config.welcomeHero || {}; const images = heroConfig.images || [config.highlightImage]; // Get processed image URLs const imageUrls = images.map(img => img.startsWith('http') ? img : getR2ImageUrl(config.id, img.split('/').pop() || '') ); const [currentIndex, setCurrentIndex] = useState(0); const overlayOpacity = heroConfig.overlayOpacity ?? 0.4; const textColor = heroConfig.textColor === 'dark' ? 'text-gray-800' : 'text-white'; // Auto advance carousel useEffect(() => { if (imageUrls.length <= 1) return; const interval = setInterval(() => { setCurrentIndex((prevIndex) => (prevIndex + 1) % imageUrls.length); }, 5000); return () => clearInterval(interval); }, [imageUrls.length]); const nextSlide = () => { setCurrentIndex((prevIndex) => (prevIndex + 1) % imageUrls.length); }; const prevSlide = () => { setCurrentIndex((prevIndex) => prevIndex === 0 ? imageUrls.length - 1 : prevIndex - 1 ); }; return ( <div className="relative h-screen w-full overflow-hidden"> {/* Carousel Images */} <AnimatePresence mode="wait"> <motion.div key={currentIndex} className="absolute inset-0" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 1 }} > <img src={imageUrls[currentIndex]} alt={`Slide ${currentIndex + 1}`} className="h-full w-full object-cover" /> <div className="absolute inset-0 bg-black" style={{ opacity: overlayOpacity }} /> </motion.div> </AnimatePresence> {/* Navigation Arrows (only if multiple images) */} {imageUrls.length > 1 && ( <> <button className="absolute left-4 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition-all hover:bg-black/50" onClick={prevSlide} > <ChevronLeft className="h-6 w-6" /> </button> <button className="absolute right-4 top-1/2 z-10 -translate-y-1/2 rounded-full bg-black/30 p-2 text-white backdrop-blur-sm transition-all hover:bg-black/50" onClick={nextSlide} > <ChevronRight className="h-6 w-6" /> </button> </> )} {/* Content */} <div className="relative z-10 flex h-full flex-col items-center justify-center px-4 text-center"> {heroConfig.showLogo && heroConfig.logoUrl && ( <motion.img src={heroConfig.logoUrl} alt="Logo" className="mb-8 h-16 w-auto" initial={{ opacity: 0, y: -20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 0.2 }} /> )} <motion.h1 className={`${textColor} mb-4 max-w-4xl text-4xl font-bold sm:text-5xl md:text-6xl lg:text-7xl`} initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.8, delay: 0.4 }} > {config.title} </motion.h1> {heroConfig.subtitle && ( <motion.p className={`${textColor} max-w-xl text-lg sm:text-xl`} initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.8, delay: 0.6 }} > {heroConfig.subtitle} </motion.p> )} <motion.div className={`${textColor} mt-6 text-lg sm:text-xl`} initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.8, delay: 0.8 }} > {config.date} </motion.div> {/* Indicators */} {imageUrls.length > 1 && ( <div className="absolute bottom-16 left-0 right-0 flex justify-center gap-2"> {imageUrls.map((_, index) => ( <button key={index} className={`h-2 w-2 rounded-full ${ index === currentIndex ? 'bg-white' : 'bg-white/50' }`} onClick={() => setCurrentIndex(index)} /> ))} </div> )} </div> {/* Scroll Indicator */} {(heroConfig.scrollIndicator ?? true) && ( <motion.div className="absolute bottom-8 left-0 right-0 flex justify-center" initial={{ opacity: 0, y: -20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 1, repeat: Infinity, repeatType: "reverse", repeatDelay: 0.5 }} > <ChevronDown className={`${textColor} h-8 w-8`} /> </motion.div> )} </div> ); }
Editor is loading...
Leave a Comment