Skip to content

Commit ec25956

Browse files
authored
Merge pull request #43 from Janhavi078/feature-hero-animation
Added smooth hero section animation
2 parents e28f7b5 + 78b6da1 commit ec25956

File tree

1 file changed

+154
-57
lines changed

1 file changed

+154
-57
lines changed

src/components/Home/Hero.tsx

Lines changed: 154 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,172 @@
1-
import React from 'react';
1+
import React, { useState, useEffect, useRef } from 'react';
22
import { Play, Star, Users, Trophy } from 'lucide-react';
33

44
interface HeroProps {
55
onNavigate: (page: string) => void;
66
}
77

8+
// A new component for the animated background particles
9+
const Particles: React.FC = () => {
10+
const canvasRef = useRef<HTMLCanvasElement>(null);
11+
12+
useEffect(() => {
13+
const canvas = canvasRef.current;
14+
if (!canvas) return;
15+
16+
const ctx = canvas.getContext('2d');
17+
if (!ctx) return;
18+
19+
let particles: { x: number, y: number, radius: number, vx: number, vy: number }[] = [];
20+
21+
const resizeCanvas = () => {
22+
canvas.width = window.innerWidth;
23+
canvas.height = canvas.parentElement?.offsetHeight || window.innerHeight;
24+
25+
particles = [];
26+
const numParticles = Math.floor(canvas.width / 50);
27+
for (let i = 0; i < numParticles; i++) {
28+
particles.push({
29+
x: Math.random() * canvas.width,
30+
y: Math.random() * canvas.height,
31+
radius: Math.random() * 2 + 1,
32+
vx: Math.random() * 1 - 0.5,
33+
vy: Math.random() * 1 - 0.5
34+
});
35+
}
36+
};
37+
38+
resizeCanvas();
39+
window.addEventListener('resize', resizeCanvas);
40+
41+
const animate = () => {
42+
ctx.clearRect(0, 0, canvas.width, canvas.height);
43+
particles.forEach(p => {
44+
p.x += p.vx;
45+
p.y += p.vy;
46+
47+
if (p.x < 0 || p.x > canvas.width) p.vx = -p.vx;
48+
if (p.y < 0 || p.y > canvas.height) p.vy = -p.vy;
49+
50+
ctx.beginPath();
51+
ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2);
52+
ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
53+
ctx.fill();
54+
});
55+
requestAnimationFrame(animate);
56+
};
57+
58+
animate();
59+
60+
return () => window.removeEventListener('resize', resizeCanvas);
61+
}, []);
62+
63+
return <canvas ref={canvasRef} className="absolute inset-0 w-full h-full" />;
64+
};
65+
66+
867
export const Hero: React.FC<HeroProps> = ({ onNavigate }) => {
68+
const [isAnimated, setIsAnimated] = useState(false);
69+
70+
useEffect(() => {
71+
const timer = setTimeout(() => {
72+
setIsAnimated(true);
73+
}, 100);
74+
return () => clearTimeout(timer);
75+
}, []);
76+
977
return (
10-
<div className="relative bg-gradient-to-br from-purple-900 via-purple-800 to-blue-800 dark:from-gray-950 dark:via-gray-900 dark:to-gray-800 overflow-hidden transition-colors duration-300">
11-
{/* Background Pattern */}
12-
<div className="absolute inset-0 bg-gradient-to-br from-purple-600/20 to-blue-600/20 dark:from-gray-800/20 dark:to-gray-700/20"></div>
13-
<div className="absolute inset-0" style={{
14-
backgroundImage: `radial-gradient(circle at 1px 1px, rgba(255,255,255,0.1) 1px, transparent 0)`,
15-
backgroundSize: '20px 20px'
16-
}}></div>
17-
18-
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24">
19-
<div className="text-center">
20-
<h1 className="text-4xl md:text-6xl font-bold text-white mb-6 leading-tight">
21-
Can I Try This?
22-
</h1>
23-
<p className="text-xl md:text-2xl text-purple-100 dark:text-purple-200 mb-4 max-w-3xl mx-auto">
24-
Real Challenges, Real Skills
25-
</p>
26-
<p className="text-lg text-purple-200 dark:text-gray-400 mb-12 max-w-2xl mx-auto">
27-
A safe space to explore real-world challenges in design, development, writing, data, and more.
28-
Level up by actually doing. No grades. No judgment. Just feedback & growth.
29-
</p>
30-
31-
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-16">
32-
<button
33-
onClick={() => onNavigate('challenges')}
34-
className="inline-flex items-center px-8 py-4 bg-white text-purple-600 rounded-lg font-semibold text-lg hover:bg-gray-50 dark:bg-gray-700 dark:text-purple-400 dark:hover:bg-gray-600 transition-all duration-200 transform hover:scale-105 shadow-lg"
78+
<>
79+
<style>{`
80+
@keyframes subtle-pan {
81+
0% { background-position: 0% 50%; }
82+
50% { background-position: 100% 50%; }
83+
100% { background-position: 0% 50%; }
84+
}
85+
.animated-gradient {
86+
background-size: 200% 200%;
87+
animation: subtle-pan 15s ease infinite;
88+
}
89+
@keyframes aurora-sweep {
90+
0% { background-position: -200% 0; }
91+
100% { background-position: 200% 0; }
92+
}
93+
.aurora::before {
94+
content: '';
95+
position: absolute;
96+
top: 0; left: 0; right: 0; bottom: 0;
97+
background-image: radial-gradient(ellipse 80% 80% at 50% -20%, rgba(120, 80, 220, 0.4), transparent);
98+
animation: aurora-sweep 8s linear infinite;
99+
}
100+
`}</style>
101+
<div className="relative bg-gradient-to-br from-purple-900 via-indigo-900 to-blue-900 dark:from-gray-950 dark:via-gray-900 dark:to-black overflow-hidden transition-colors duration-300 animated-gradient aurora">
102+
<Particles />
103+
104+
<div className="absolute inset-0 bg-black/20"></div>
105+
106+
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 md:py-32">
107+
<div className="text-center">
108+
109+
<h1 className={`text-5xl md:text-7xl font-extrabold text-white mb-6 leading-tight transition-all duration-[1200ms] ease-out
110+
${isAnimated ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-6'}`}
111+
style={{ transitionDelay: '200ms', textShadow: '0 4px 20px rgba(0, 0, 0, 0.3)' }}
35112
>
36-
<Play className="h-5 w-5 mr-2" />
37-
Start Exploring
38-
</button>
39-
<button
40-
onClick={() => onNavigate('submit')}
41-
className="inline-flex items-center px-8 py-4 bg-transparent border-2 border-white text-white rounded-lg font-semibold text-lg hover:bg-white hover:text-purple-600 dark:hover:bg-gray-700 dark:hover:text-purple-400 transition-all duration-200"
113+
Can I Try This?
114+
</h1>
115+
116+
<p className={`text-xl md:text-2xl text-purple-200 dark:text-purple-300 mb-4 max-w-3xl mx-auto transition-all duration-[1200ms] ease-out
117+
${isAnimated ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-6'}`}
118+
style={{ transitionDelay: '400ms' }}
42119
>
43-
Submit Challenge
44-
</button>
45-
</div>
120+
Real Challenges, Real Skills
121+
</p>
122+
123+
<p className={`text-lg text-purple-300/80 dark:text-gray-400 mb-12 max-w-2xl mx-auto transition-all duration-[1200ms] ease-out
124+
${isAnimated ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-6'}`}
125+
style={{ transitionDelay: '600ms' }}
126+
>
127+
A safe space to explore real-world challenges in design, development, writing, data, and more.
128+
Level up by actually doing. No grades. No judgment. Just feedback & growth.
129+
</p>
46130

47-
{/* Stats */}
48-
<div className="grid grid-cols-1 sm:grid-cols-3 gap-8 max-w-2xl mx-auto">
49-
<div className="text-center">
50-
<div className="bg-white/10 dark:bg-gray-800/30 backdrop-blur-sm rounded-lg p-6 border border-white/20 dark:border-gray-700/20">
51-
<Trophy className="h-8 w-8 text-yellow-400 mx-auto mb-2" />
52-
<div className="text-2xl font-bold text-white dark:text-white">500+</div>
53-
<div className="text-purple-200 dark:text-gray-400">Challenges</div>
54-
</div>
55-
</div>
56-
<div className="text-center">
57-
<div className="bg-white/10 dark:bg-gray-800/30 backdrop-blur-sm rounded-lg p-6 border border-white/20 dark:border-gray-700/20">
58-
<Users className="h-8 w-8 text-green-400 mx-auto mb-2" />
59-
<div className="text-2xl font-bold text-white dark:text-white">12K+</div>
60-
<div className="text-purple-200 dark:text-gray-400">Learners</div>
61-
</div>
131+
<div className={`flex flex-col sm:flex-row gap-4 justify-center mb-16 transition-all duration-[1200ms] ease-out
132+
${isAnimated ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-6'}`}
133+
style={{ transitionDelay: '800ms' }}
134+
>
135+
<button
136+
onClick={() => onNavigate('challenges')}
137+
className="inline-flex items-center justify-center px-8 py-4 bg-white text-purple-700 rounded-lg font-semibold text-lg hover:bg-gray-100 dark:bg-purple-500 dark:text-white dark:hover:bg-purple-600 transition-all duration-300 transform hover:scale-105 shadow-2xl hover:shadow-purple-400/30"
138+
>
139+
<Play className="h-5 w-5 mr-2" />
140+
Start Exploring
141+
</button>
142+
<button
143+
onClick={() => onNavigate('submit')}
144+
className="inline-flex items-center justify-center px-8 py-4 bg-transparent border-2 border-purple-300 text-purple-200 rounded-lg font-semibold text-lg hover:bg-purple-300/10 hover:text-white dark:border-purple-400 dark:text-purple-300 dark:hover:bg-purple-400/20 dark:hover:text-white transition-all duration-300"
145+
>
146+
Submit Challenge
147+
</button>
62148
</div>
63-
<div className="text-center">
64-
<div className="bg-white/10 dark:bg-gray-800/30 backdrop-blur-sm rounded-lg p-6 border border-white/20 dark:border-gray-700/20">
65-
<Star className="h-8 w-8 text-blue-400 mx-auto mb-2" />
66-
<div className="text-2xl font-bold text-white dark:text-white">98%</div>
67-
<div className="text-purple-200 dark:text-gray-400">Success Rate</div>
68-
</div>
149+
150+
<div className={`grid grid-cols-1 sm:grid-cols-3 gap-8 max-w-3xl mx-auto transition-all duration-[1200ms] ease-out
151+
${isAnimated ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-6'}`}
152+
style={{ transitionDelay: '1000ms' }}
153+
>
154+
{[
155+
{ icon: Trophy, color: 'text-yellow-400', value: '500+', label: 'Challenges' },
156+
{ icon: Users, color: 'text-green-400', value: '12K+', label: 'Learners' },
157+
{ icon: Star, color: 'text-sky-400', value: '98%', label: 'Success Rate' },
158+
].map((stat, index) => (
159+
<div key={index} className="text-center bg-white/5 dark:bg-gray-800/20 backdrop-blur-md rounded-xl p-6 border border-white/10 dark:border-gray-700/30 transition-all duration-300 hover:bg-white/10 hover:border-white/20 transform hover:-translate-y-1">
160+
<stat.icon className={`h-8 w-8 ${stat.color} mx-auto mb-3`} />
161+
<div className="text-3xl font-bold text-white">{stat.value}</div>
162+
<div className="text-purple-200 dark:text-gray-400 mt-1">{stat.label}</div>
163+
</div>
164+
))}
69165
</div>
70166
</div>
71167
</div>
72168
</div>
73-
</div>
169+
</>
74170
);
75171
};
172+

0 commit comments

Comments
 (0)