353 lines
12 KiB
TypeScript
353 lines
12 KiB
TypeScript
"use client";
|
|
|
|
import { useBackgroundImage } from "@/hooks/usePreferences";
|
|
import Link from "next/link";
|
|
import { useState, useEffect } from "react";
|
|
|
|
interface Particle {
|
|
width: number;
|
|
height: number;
|
|
left: number;
|
|
top: number;
|
|
duration: number;
|
|
delay: number;
|
|
shadow: number;
|
|
fadeIn: number;
|
|
fadeOut: number;
|
|
visibleDuration: number;
|
|
moveY1: number;
|
|
moveX1: number;
|
|
moveY2: number;
|
|
moveX2: number;
|
|
moveY3: number;
|
|
moveX3: number;
|
|
moveY4: number;
|
|
moveX4: number;
|
|
moveY5: number;
|
|
moveX5: number;
|
|
moveY6: number;
|
|
moveX6: number;
|
|
}
|
|
|
|
interface Orb {
|
|
width: number;
|
|
height: number;
|
|
left: number;
|
|
top: number;
|
|
duration: number;
|
|
delay: number;
|
|
}
|
|
|
|
export default function HeroSection() {
|
|
const backgroundImage = useBackgroundImage("home", "/got-2.jpg");
|
|
const [particles, setParticles] = useState<Particle[]>([]);
|
|
const [orbs, setOrbs] = useState<Orb[]>([]);
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
// Generate particles - more visible and dynamic
|
|
setParticles(
|
|
Array.from({ length: 30 }, () => {
|
|
const fadeIn = Math.random() * 5 + 2; // 2-7% of animation - faster fade in
|
|
const visibleDuration = Math.random() * 30 + 20; // 20-50% of animation
|
|
const fadeOut = Math.random() * 5 + 2; // 2-7% of animation - faster fade out
|
|
return {
|
|
width: Math.random() * 6 + 3,
|
|
height: Math.random() * 6 + 3,
|
|
left: Math.random() * 100,
|
|
top: Math.random() * 100,
|
|
duration: 10 + Math.random() * 15,
|
|
delay: Math.random() * 8,
|
|
shadow: Math.random() * 15 + 8,
|
|
fadeIn: fadeIn,
|
|
fadeOut: fadeOut,
|
|
visibleDuration: visibleDuration,
|
|
moveY1: 20 + Math.random() * 20,
|
|
moveX1: Math.random() * 10 - 5,
|
|
moveY2: 40 + Math.random() * 20,
|
|
moveX2: Math.random() * 15 - 7,
|
|
moveY3: 60 + Math.random() * 20,
|
|
moveX3: Math.random() * 10 - 5,
|
|
moveY4: 80 + Math.random() * 20,
|
|
moveX4: Math.random() * 10 - 5,
|
|
moveY5: 100 + Math.random() * 20,
|
|
moveX5: Math.random() * 10 - 5,
|
|
moveY6: 120 + Math.random() * 20,
|
|
moveX6: Math.random() * 10 - 5,
|
|
};
|
|
})
|
|
);
|
|
// Generate orbs
|
|
setOrbs(
|
|
Array.from({ length: 4 }, () => ({
|
|
width: 100 + Math.random() * 200,
|
|
height: 100 + Math.random() * 200,
|
|
left: Math.random() * 80,
|
|
top: Math.random() * 80,
|
|
duration: 20 + Math.random() * 15,
|
|
delay: Math.random() * 10,
|
|
}))
|
|
);
|
|
}, []);
|
|
|
|
return (
|
|
<section className="relative w-full min-h-screen flex flex-col items-center justify-center overflow-hidden pt-24">
|
|
{/* Background Image */}
|
|
<div
|
|
className="absolute inset-0 bg-cover bg-center bg-no-repeat"
|
|
style={{
|
|
backgroundImage: `url('${backgroundImage}')`,
|
|
}}
|
|
>
|
|
{/* Dark overlay for readability */}
|
|
<div className="absolute inset-0 bg-gradient-to-b from-black/70 via-black/60 to-black/80 z-[1]"></div>
|
|
|
|
{/* Animated particles */}
|
|
{mounted && (
|
|
<div className="absolute inset-0 overflow-hidden z-[2]">
|
|
{particles.map((particle, i) => (
|
|
<div
|
|
key={i}
|
|
className="absolute rounded-full"
|
|
style={{
|
|
width: `${particle.width}px`,
|
|
height: `${particle.height}px`,
|
|
left: `${particle.left}%`,
|
|
top: `${particle.top}%`,
|
|
background: `radial-gradient(circle, rgba(218, 165, 32, 0.9) 0%, rgba(218, 165, 32, 0.4) 50%, transparent 100%)`,
|
|
animation: `float-particle-${i} ${particle.duration}s infinite ease-in-out`,
|
|
animationDelay: `${particle.delay}s`,
|
|
boxShadow: `0 0 ${
|
|
particle.shadow
|
|
}px rgba(218, 165, 32, 0.8), 0 0 ${
|
|
particle.shadow * 2
|
|
}px rgba(218, 165, 32, 0.4)`,
|
|
filter: "blur(0.5px)",
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Animated light rays */}
|
|
<div className="absolute inset-0 overflow-hidden opacity-30">
|
|
{[...Array(3)].map((_, i) => {
|
|
const rotation = -15 + i * 15;
|
|
return (
|
|
<div
|
|
key={i}
|
|
className="absolute w-1 bg-gradient-to-b from-transparent via-pixel-gold/20 to-transparent"
|
|
style={{
|
|
height: "100%",
|
|
left: `${20 + i * 30}%`,
|
|
transform: `rotate(${rotation}deg)`,
|
|
animation: `light-ray-${i} ${
|
|
8 + i * 2
|
|
}s infinite ease-in-out`,
|
|
animationDelay: `${i * 2}s`,
|
|
transformOrigin: "top center",
|
|
}}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
|
|
{/* Glowing orbs */}
|
|
{mounted && (
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
{orbs.map((orb, i) => (
|
|
<div
|
|
key={i}
|
|
className="absolute rounded-full blur-xl"
|
|
style={{
|
|
width: `${orb.width}px`,
|
|
height: `${orb.height}px`,
|
|
left: `${orb.left}%`,
|
|
top: `${orb.top}%`,
|
|
background: `radial-gradient(circle, rgba(218, 165, 32, 0.2) 0%, transparent 70%)`,
|
|
animation: `orb-float ${orb.duration}s infinite ease-in-out`,
|
|
animationDelay: `${orb.delay}s`,
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
{/* Shimmer effect */}
|
|
<div className="absolute inset-0 overflow-hidden">
|
|
<div
|
|
className="absolute inset-0 bg-gradient-to-r from-transparent via-pixel-gold/10 to-transparent"
|
|
style={{
|
|
transform: "skewX(-20deg)",
|
|
animation: "shimmer 8s infinite",
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Hero Content */}
|
|
<div className="relative z-10 w-full max-w-5xl xl:max-w-6xl mx-auto px-8 py-16 text-center flex flex-col items-center">
|
|
{/* Game Title */}
|
|
<div className="w-full flex justify-center mb-4">
|
|
<h1 className="text-6xl md:text-8xl lg:text-9xl xl:text-9xl font-gaming font-black tracking-tight">
|
|
<span
|
|
className="bg-gradient-to-r from-pixel-gold via-orange-400 to-pixel-gold bg-clip-text text-transparent"
|
|
style={{
|
|
textShadow: "0 0 30px rgba(218, 165, 32, 0.5)",
|
|
}}
|
|
>
|
|
GAME.OF.TECH
|
|
</span>
|
|
</h1>
|
|
</div>
|
|
|
|
{/* Subtitle */}
|
|
<div className="text-pixel-gold text-xl md:text-2xl font-gaming-subtitle font-semibold flex items-center justify-center gap-2 mb-8 tracking-wider">
|
|
<span>✦</span>
|
|
<span>Peaksys</span>
|
|
<span>✦</span>
|
|
</div>
|
|
|
|
{/* Description */}
|
|
<p className="text-white text-base md:text-lg max-w-3xl mx-auto mb-12 leading-relaxed px-4">
|
|
Dans un monde numérique de technologie de pointe, où les systèmes d'IA
|
|
évoluent et où d'anciens codes attendent d'être découverts. Partez
|
|
pour un voyage épique pour forger des alliances, conquérir des défis
|
|
et raconter votre histoire d'innovation au sein d'une communauté de
|
|
gaming tech florissante.
|
|
</p>
|
|
|
|
{/* Call-to-Action Buttons */}
|
|
<div className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-16">
|
|
<Link href="/events">
|
|
<button className="px-8 py-3 border border-pixel-gold/50 bg-black/60 text-white uppercase text-sm tracking-widest rounded hover:bg-pixel-gold/10 hover:border-pixel-gold transition">
|
|
<span>See events</span>
|
|
</button>
|
|
</Link>
|
|
<Link href="/leaderboard">
|
|
<button className="px-8 py-3 border border-pixel-gold/50 bg-black/60 text-white uppercase text-sm tracking-widest rounded hover:bg-pixel-gold/10 hover:border-pixel-gold transition flex items-center gap-2">
|
|
<span>⏵</span>
|
|
<span>See leaderboard</span>
|
|
</button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
|
|
<style jsx>{`
|
|
@keyframes float {
|
|
0%,
|
|
100% {
|
|
transform: translateY(0px);
|
|
}
|
|
50% {
|
|
transform: translateY(-20px);
|
|
}
|
|
}
|
|
|
|
${particles
|
|
.map((particle, i) => {
|
|
const fadeInPercent = particle.fadeIn;
|
|
const visibleStart = fadeInPercent;
|
|
const visibleEnd = visibleStart + particle.visibleDuration;
|
|
const fadeOutStart = visibleEnd;
|
|
const fadeOutEnd = Math.min(100, fadeOutStart + particle.fadeOut);
|
|
|
|
return `
|
|
@keyframes float-particle-${i} {
|
|
0% {
|
|
transform: translateY(0px) translateX(0px) scale(0.8);
|
|
opacity: 0;
|
|
}
|
|
${fadeInPercent}% {
|
|
transform: translateY(-${particle.moveY1}px) translateX(${particle.moveX1}px) scale(1);
|
|
opacity: 0.9;
|
|
}
|
|
${visibleStart}% {
|
|
transform: translateY(-${particle.moveY2}px) translateX(${particle.moveX2}px) scale(1.1);
|
|
opacity: 1;
|
|
}
|
|
${visibleEnd}% {
|
|
transform: translateY(-${particle.moveY3}px) translateX(${particle.moveX3}px) scale(1.05);
|
|
opacity: 1;
|
|
}
|
|
${fadeOutStart}% {
|
|
transform: translateY(-${particle.moveY4}px) translateX(${particle.moveX4}px) scale(0.9);
|
|
opacity: 0.7;
|
|
}
|
|
${fadeOutEnd}% {
|
|
transform: translateY(-${particle.moveY5}px) translateX(${particle.moveX5}px) scale(0.5);
|
|
opacity: 0;
|
|
}
|
|
100% {
|
|
transform: translateY(-${particle.moveY6}px) translateX(${particle.moveX6}px) scale(0.3);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
`;
|
|
})
|
|
.join("")}
|
|
|
|
@keyframes light-ray-0 {
|
|
0%,
|
|
100% {
|
|
opacity: 0.2;
|
|
transform: rotate(-15deg) scaleY(0.8);
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
transform: rotate(-15deg) scaleY(1.2);
|
|
}
|
|
}
|
|
@keyframes light-ray-1 {
|
|
0%,
|
|
100% {
|
|
opacity: 0.2;
|
|
transform: rotate(0deg) scaleY(0.8);
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
transform: rotate(0deg) scaleY(1.2);
|
|
}
|
|
}
|
|
@keyframes light-ray-2 {
|
|
0%,
|
|
100% {
|
|
opacity: 0.2;
|
|
transform: rotate(15deg) scaleY(0.8);
|
|
}
|
|
50% {
|
|
opacity: 0.5;
|
|
transform: rotate(15deg) scaleY(1.2);
|
|
}
|
|
}
|
|
|
|
@keyframes orb-float {
|
|
0%,
|
|
100% {
|
|
transform: translate(0, 0) scale(1);
|
|
opacity: 0.2;
|
|
}
|
|
33% {
|
|
transform: translate(30px, -30px) scale(1.1);
|
|
opacity: 0.3;
|
|
}
|
|
66% {
|
|
transform: translate(-20px, 20px) scale(0.9);
|
|
opacity: 0.25;
|
|
}
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
0% {
|
|
transform: translateX(-100%) skewX(-20deg);
|
|
}
|
|
100% {
|
|
transform: translateX(200%) skewX(-20deg);
|
|
}
|
|
}
|
|
`}</style>
|
|
</section>
|
|
);
|
|
}
|