Files

224 lines
8.1 KiB
TypeScript

import React, { useRef } from 'react'
import { motion, useScroll, useTransform } from 'framer-motion'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls, Sphere, MeshDistortMaterial, Environment, Float } from '@react-three/drei'
import { TypeAnimation } from 'react-type-animation'
import Tilt from 'react-parallax-tilt'
import { useInView } from 'react-intersection-observer'
interface Hero3DProps {
title: string
subtitle: string
description: string
primaryColor: string
secondaryColor: string
features?: string[]
}
function AnimatedSphere({ color }: { color: string }) {
const meshRef = useRef<any>(null)
useFrame((state) => {
if (meshRef.current) {
meshRef.current.rotation.x = state.clock.getElapsedTime() * 0.2
meshRef.current.rotation.y = state.clock.getElapsedTime() * 0.3
}
})
return (
<Float speed={2} rotationIntensity={1} floatIntensity={1}>
<Sphere ref={meshRef} args={[1, 100, 100]} scale={2.5}>
<MeshDistortMaterial
color={color}
attach="material"
distort={0.3}
speed={2}
roughness={0}
metalness={0.8}
/>
</Sphere>
</Float>
)
}
export function Hero3D({ title, subtitle, description, primaryColor, secondaryColor, features = [] }: Hero3DProps) {
const { ref, inView } = useInView({
threshold: 0.1,
triggerOnce: true
})
const containerRef = useRef<HTMLDivElement>(null)
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ["start start", "end start"]
})
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0])
return (
<section ref={containerRef} className="relative min-h-screen overflow-hidden">
{/* Animated gradient background */}
<div
className="absolute inset-0 opacity-30"
style={{
background: `linear-gradient(135deg, ${primaryColor} 0%, ${secondaryColor} 50%, ${primaryColor} 100%)`,
backgroundSize: '400% 400%',
animation: 'gradient 15s ease infinite'
}}
/>
{/* Particle effect background */}
<div className="absolute inset-0">
{[...Array(50)].map((_, i) => (
<motion.div
key={i}
className="absolute w-1 h-1 bg-white rounded-full"
initial={{
x: Math.random() * window.innerWidth,
y: Math.random() * window.innerHeight,
opacity: Math.random()
}}
animate={{
y: [null, Math.random() * -100 - 50],
opacity: [null, 0, Math.random()]
}}
transition={{
duration: Math.random() * 10 + 10,
repeat: Infinity,
ease: "linear"
}}
/>
))}
</div>
<motion.div style={{ y, opacity }} className="relative z-10">
<div className="container mx-auto px-4 pt-32 pb-20">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Left content */}
<motion.div
ref={ref}
initial={{ opacity: 0, x: -50 }}
animate={inView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8, delay: 0.2 }}
>
<motion.div
initial={{ scale: 0 }}
animate={inView ? { scale: 1 } : {}}
transition={{ type: "spring", stiffness: 100, delay: 0.1 }}
className="inline-block"
>
<span className="px-4 py-2 rounded-full text-sm font-semibold text-white bg-gradient-to-r from-purple-600 to-pink-600 mb-6 inline-block">
✨ Next Generation Platform
</span>
</motion.div>
<h1 className="text-5xl lg:text-7xl font-bold mb-6">
<TypeAnimation
sequence={[
title,
2000,
`${title} 🚀`,
2000,
]}
wrapper="span"
speed={50}
className="bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent"
repeat={Infinity}
/>
</h1>
<p className="text-xl lg:text-2xl text-gray-600 dark:text-gray-300 mb-8">
{subtitle}
</p>
<p className="text-gray-500 dark:text-gray-400 mb-8">
{description}
</p>
{/* Animated feature list */}
<div className="space-y-3 mb-8">
{features.map((feature, index) => (
<motion.div
key={feature}
initial={{ opacity: 0, x: -20 }}
animate={inView ? { opacity: 1, x: 0 } : {}}
transition={{ delay: 0.5 + index * 0.1 }}
className="flex items-center gap-3"
>
<motion.div
whileHover={{ scale: 1.2, rotate: 360 }}
className="w-6 h-6 rounded-full bg-gradient-to-r from-green-400 to-emerald-400 flex items-center justify-center"
>
<span className="text-white text-xs">✓</span>
</motion.div>
<span className="text-gray-700 dark:text-gray-300">{feature}</span>
</motion.div>
))}
</div>
{/* CTA Buttons */}
<div className="flex flex-wrap gap-4">
<Tilt tiltMaxAngleX={5} tiltMaxAngleY={5}>
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="px-8 py-4 bg-gradient-to-r from-blue-600 to-purple-600 text-white rounded-xl font-semibold shadow-2xl hover:shadow-purple-500/25"
>
Get Started Free
</motion.button>
</Tilt>
<Tilt tiltMaxAngleX={5} tiltMaxAngleY={5}>
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
className="px-8 py-4 bg-white dark:bg-gray-800 text-gray-900 dark:text-white rounded-xl font-semibold shadow-xl border border-gray-200 dark:border-gray-700"
>
Watch Demo
</motion.button>
</Tilt>
</div>
</motion.div>
{/* Right 3D content */}
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={inView ? { opacity: 1, scale: 1 } : {}}
transition={{ duration: 1, delay: 0.3 }}
className="h-[500px] lg:h-[600px]"
>
<Canvas camera={{ position: [0, 0, 5] }}>
<ambientLight intensity={0.5} />
<directionalLight position={[10, 10, 5]} intensity={1} />
<AnimatedSphere color={primaryColor} />
<Environment preset="city" />
<OrbitControls enableZoom={false} autoRotate />
</Canvas>
</motion.div>
</div>
</div>
</motion.div>
{/* Scroll indicator */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1, repeat: Infinity, duration: 2 }}
className="absolute bottom-8 left-1/2 -translate-x-1/2"
>
<div className="flex flex-col items-center gap-2">
<span className="text-sm text-gray-500">Scroll to explore</span>
<motion.div
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 1.5 }}
>
<svg className="w-6 h-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 14l-7 7m0 0l-7-7m7 7V3" />
</svg>
</motion.div>
</div>
</motion.div>
</section>
)
}