Untitled

 avatar
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