297 lines
11 KiB
TypeScript
297 lines
11 KiB
TypeScript
import { useState, useEffect, useRef } from "react";
|
|
import { useLocation } from "wouter";
|
|
import { Button } from "@/components/ui/button";
|
|
import { ArrowRight, DollarSign, IndianRupee } from "lucide-react";
|
|
import heroVideo from "@assets/generated_videos/abstract_finance_visualization_video.mp4";
|
|
import StrategySelectorModal from "./StrategySelectorModal";
|
|
|
|
type HeroSectionProps = {
|
|
onExploreStrategies: () => void;
|
|
};
|
|
|
|
export default function HeroSection({ onExploreStrategies }: HeroSectionProps) {
|
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
|
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
const [scrollY, setScrollY] = useState(0);
|
|
const [, navigate] = useLocation();
|
|
|
|
useEffect(() => {
|
|
setIsLoaded(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const handleScroll = () => {
|
|
setScrollY(window.scrollY);
|
|
};
|
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
return () => window.removeEventListener("scroll", handleScroll);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const handleMouseMove = (e: MouseEvent) => {
|
|
if (!containerRef.current) return;
|
|
const rect = containerRef.current.getBoundingClientRect();
|
|
const x = (e.clientX - rect.left - rect.width / 2) / rect.width;
|
|
const y = (e.clientY - rect.top - rect.height / 2) / rect.height;
|
|
setMousePosition({ x: x * 30, y: y * 30 });
|
|
};
|
|
|
|
const container = containerRef.current;
|
|
container?.addEventListener("mousemove", handleMouseMove);
|
|
return () => container?.removeEventListener("mousemove", handleMouseMove);
|
|
}, []);
|
|
|
|
const parallaxY = scrollY * 0.5;
|
|
const videoScale = 1 + scrollY * 0.0003;
|
|
const videoOpacity = Math.max(0.4 - scrollY * 0.0005, 0.15);
|
|
|
|
return (
|
|
<section
|
|
ref={containerRef}
|
|
className="relative min-h-screen flex items-center justify-center overflow-hidden"
|
|
data-testid="section-hero"
|
|
style={{ perspective: "1000px" }}
|
|
>
|
|
<div
|
|
className="absolute inset-0 z-0"
|
|
style={{
|
|
transform: `translateY(${parallaxY}px) scale(${videoScale})`,
|
|
transformOrigin: "center center",
|
|
}}
|
|
>
|
|
<video
|
|
autoPlay
|
|
loop
|
|
muted
|
|
playsInline
|
|
className={`absolute inset-0 w-full h-full object-cover transition-opacity duration-1000 ${
|
|
isLoaded ? "opacity-100" : "opacity-0"
|
|
}`}
|
|
style={{
|
|
opacity: videoOpacity,
|
|
filter: "blur(1px) saturate(0.8)",
|
|
}}
|
|
>
|
|
<source src={heroVideo} type="video/mp4" />
|
|
</video>
|
|
<div className="absolute inset-0 bg-gradient-to-b from-background/70 via-background/50 to-background" />
|
|
</div>
|
|
|
|
<div
|
|
className="absolute inset-0 transition-transform duration-300 ease-out z-10"
|
|
style={{
|
|
transform: `translate3d(${mousePosition.x * 0.3}px, ${mousePosition.y * 0.3}px, 0) rotateX(${mousePosition.y * 0.02}deg) rotateY(${-mousePosition.x * 0.02}deg)`,
|
|
transformStyle: "preserve-3d",
|
|
}}
|
|
>
|
|
<div
|
|
className={`absolute top-1/4 left-1/4 w-96 h-96 bg-primary/20 rounded-full blur-3xl transition-all duration-1000 ${
|
|
isLoaded ? "opacity-100 scale-100" : "opacity-0 scale-50"
|
|
}`}
|
|
style={{
|
|
transform: `translateZ(50px)`,
|
|
}}
|
|
/>
|
|
<div
|
|
className={`absolute bottom-1/3 right-1/4 w-80 h-80 bg-chart-2/20 rounded-full blur-3xl transition-all duration-1000 delay-200 ${
|
|
isLoaded ? "opacity-100 scale-100" : "opacity-0 scale-50"
|
|
}`}
|
|
style={{
|
|
transform: `translateZ(30px)`,
|
|
}}
|
|
/>
|
|
<div
|
|
className={`absolute top-1/2 right-1/3 w-64 h-64 bg-chart-3/15 rounded-full blur-3xl transition-all duration-1000 delay-500 ${
|
|
isLoaded ? "opacity-100 scale-100" : "opacity-0 scale-50"
|
|
}`}
|
|
style={{
|
|
transform: `translateZ(70px)`,
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div className="absolute inset-0 overflow-hidden z-10">
|
|
{[...Array(25)].map((_, i) => (
|
|
<div
|
|
key={i}
|
|
className={`absolute rounded-full transition-all duration-700 ${
|
|
isLoaded ? "opacity-60" : "opacity-0"
|
|
}`}
|
|
style={{
|
|
width: `${3 + (i % 4) * 2}px`,
|
|
height: `${3 + (i % 4) * 2}px`,
|
|
left: `${5 + (i * 3.8)}%`,
|
|
top: `${15 + Math.sin(i * 0.7) * 35}%`,
|
|
background: i % 3 === 0
|
|
? "hsl(var(--primary))"
|
|
: i % 3 === 1
|
|
? "hsl(var(--chart-2))"
|
|
: "hsl(var(--chart-3))",
|
|
transform: `translate3d(${mousePosition.x * (0.5 + i * 0.08)}px, ${mousePosition.y * (0.5 + i * 0.08)}px, ${i * 5}px)`,
|
|
transitionDelay: `${i * 30}ms`,
|
|
animation: `float-3d ${4 + (i % 4)}s ease-in-out infinite`,
|
|
animationDelay: `${i * 0.15}s`,
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div
|
|
className="absolute inset-0 z-10 pointer-events-none"
|
|
style={{
|
|
transform: `translate3d(${mousePosition.x * 0.1}px, ${mousePosition.y * 0.1}px, 0)`,
|
|
}}
|
|
>
|
|
<div
|
|
className={`absolute top-20 left-[15%] w-20 h-20 transition-all duration-1000 ${
|
|
isLoaded ? "opacity-100 rotate-12" : "opacity-0 rotate-0"
|
|
}`}
|
|
style={{
|
|
transform: `rotate(${12 + mousePosition.x * 0.3}deg) translateZ(100px)`,
|
|
animation: "float-rotate 8s ease-in-out infinite",
|
|
}}
|
|
aria-hidden="true"
|
|
>
|
|
<DollarSign className="w-full h-full text-primary/25 drop-shadow-sm" strokeWidth={1.25} />
|
|
</div>
|
|
<div
|
|
className={`absolute bottom-32 right-[20%] w-16 h-16 transition-all duration-1000 delay-300 ${
|
|
isLoaded ? "opacity-100" : "opacity-0"
|
|
}`}
|
|
style={{
|
|
transform: `translateZ(80px)`,
|
|
animation: "pulse-float 6s ease-in-out infinite",
|
|
}}
|
|
aria-hidden="true"
|
|
>
|
|
<IndianRupee className="w-full h-full text-chart-2/25 drop-shadow-sm" strokeWidth={1.25} />
|
|
</div>
|
|
<div
|
|
className={`absolute top-1/3 right-[10%] w-12 h-12 transition-all duration-1000 delay-500 ${
|
|
isLoaded ? "opacity-100 rotate-45" : "opacity-0 rotate-0"
|
|
}`}
|
|
style={{
|
|
transform: `rotate(${45 + mousePosition.y * 0.5}deg) translateZ(60px)`,
|
|
animation: "float-rotate-reverse 10s ease-in-out infinite",
|
|
}}
|
|
aria-hidden="true"
|
|
>
|
|
<DollarSign className="w-full h-full text-chart-3/25 drop-shadow-sm" strokeWidth={1.25} />
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
className="relative z-20 max-w-4xl mx-auto px-6 text-center"
|
|
style={{
|
|
transform: `translate3d(${mousePosition.x * 0.15}px, ${mousePosition.y * 0.15}px, 100px)`,
|
|
transformStyle: "preserve-3d",
|
|
}}
|
|
>
|
|
<div
|
|
className={`transition-all duration-1000 delay-300 ${
|
|
isLoaded ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
|
}`}
|
|
>
|
|
<h1
|
|
className="text-5xl md:text-7xl font-bold tracking-tight mb-6 leading-tight"
|
|
data-testid="text-hero-headline"
|
|
style={{ transform: "translateZ(20px)" }}
|
|
>
|
|
<span className="inline-block animate-fade-in-up" style={{ animationDelay: "0.4s" }}>
|
|
Invest with
|
|
</span>
|
|
<br />
|
|
<span
|
|
className="text-primary inline-block animate-fade-in-up bg-clip-text"
|
|
style={{
|
|
animationDelay: "0.6s",
|
|
textShadow: "0 0 60px hsl(var(--primary) / 0.3)",
|
|
}}
|
|
>
|
|
Clarity
|
|
</span>
|
|
</h1>
|
|
</div>
|
|
|
|
<p
|
|
className={`text-xl md:text-2xl text-muted-foreground max-w-2xl mx-auto mb-12 leading-relaxed transition-all duration-1000 delay-700 ${
|
|
isLoaded ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
|
}`}
|
|
data-testid="text-hero-subheadline"
|
|
style={{ transform: "translateZ(10px)" }}
|
|
>
|
|
Simple, disciplined strategies for long-term wealth building.
|
|
No noise. Just steady growth. test for the auto deployment by quantfortune team
|
|
</p>
|
|
|
|
<div
|
|
className={`flex flex-col sm:flex-row items-center justify-center gap-4 transition-all duration-1000 delay-1000 ${
|
|
isLoaded ? "opacity-100 translate-y-0" : "opacity-0 translate-y-8"
|
|
}`}
|
|
style={{ transform: "translateZ(30px)" }}
|
|
>
|
|
<Button
|
|
size="lg"
|
|
className="rounded-xl px-8 py-6 text-lg group relative overflow-hidden shadow-lg shadow-primary/20"
|
|
data-testid="button-explore-strategies"
|
|
onClick={onExploreStrategies}
|
|
>
|
|
<span className="relative z-10 flex items-center">
|
|
Explore Strategies test for thhe auto deployment by quantfortune team
|
|
<ArrowRight className="ml-2 h-5 w-5 transition-transform group-hover:translate-x-1" />
|
|
</span>
|
|
<div className="absolute inset-0 bg-gradient-to-r from-primary to-chart-1 opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
|
|
</Button>
|
|
<Button
|
|
variant="ghost"
|
|
size="lg"
|
|
className="rounded-xl px-8 py-6 text-lg text-muted-foreground backdrop-blur-sm"
|
|
data-testid="button-learn-more"
|
|
onClick={() => navigate("/learn-more")}
|
|
>
|
|
Learn More
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
className={`absolute bottom-8 left-1/2 -translate-x-1/2 z-20 transition-all duration-1000 delay-1500 ${
|
|
isLoaded ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4"
|
|
}`}
|
|
>
|
|
<div className="w-6 h-10 border-2 border-muted-foreground/30 rounded-full flex justify-center pt-2 backdrop-blur-sm">
|
|
<div className="w-1.5 h-3 bg-muted-foreground/50 rounded-full animate-bounce" />
|
|
</div>
|
|
</div>
|
|
|
|
<style>{`
|
|
@keyframes float-3d {
|
|
0%, 100% { transform: translateY(0px) translateZ(0px); }
|
|
50% { transform: translateY(-15px) translateZ(10px); }
|
|
}
|
|
@keyframes fade-in-up {
|
|
from { opacity: 0; transform: translateY(20px) translateZ(0); }
|
|
to { opacity: 1; transform: translateY(0) translateZ(20px); }
|
|
}
|
|
@keyframes float-rotate {
|
|
0%, 100% { transform: rotate(12deg) translateY(0) translateZ(100px); }
|
|
50% { transform: rotate(18deg) translateY(-20px) translateZ(120px); }
|
|
}
|
|
@keyframes float-rotate-reverse {
|
|
0%, 100% { transform: rotate(45deg) translateY(0) translateZ(60px); }
|
|
50% { transform: rotate(35deg) translateY(-15px) translateZ(80px); }
|
|
}
|
|
@keyframes pulse-float {
|
|
0%, 100% { transform: scale(1) translateY(0) translateZ(80px); opacity: 0.6; }
|
|
50% { transform: scale(1.1) translateY(-10px) translateZ(100px); opacity: 0.8; }
|
|
}
|
|
.animate-fade-in-up {
|
|
animation: fade-in-up 0.8s ease-out forwards;
|
|
opacity: 0;
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
}
|