Import source: src/components/Hero/Hero

Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
arsam
2026-09-18 23:07:59 +03:30
parent aee93c6fdb
commit 06cf3aa383
+159
View File
@@ -0,0 +1,159 @@
import { useEffect, useRef } from 'react'
import { motion } from 'framer-motion'
import { gsap } from 'gsap'
import AudioVisualizer3D from './AudioVisualizer3D'
import HeroParticles from './HeroParticles'
const fadeUp = (delay = 0) => ({
initial: { opacity: 0, y: 32 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.85, ease: [0.22, 1, 0.36, 1], delay },
})
export default function Hero({ isPlaying, onTogglePlay }) {
const headingRef = useRef()
useEffect(() => {
const ctx = gsap.context(() => {
gsap.from('.hero-line', {
y: 80,
opacity: 0,
duration: 1,
stagger: 0.14,
ease: 'power4.out',
delay: 0.2,
})
})
return () => ctx.revert()
}, [])
return (
<section className="relative min-h-screen flex items-center justify-center overflow-hidden"
style={{ background: 'var(--dark-base)' }}>
{/* Particle bg */}
<div className="absolute inset-0 pointer-events-none">
<HeroParticles />
</div>
{/* Ambient blobs */}
<div className="absolute pointer-events-none"
style={{ top: '20%', left: '50%', transform: 'translate(-50%,-50%)',
width: 700, height: 700,
background: 'radial-gradient(ellipse, rgba(201,168,76,0.055) 0%, transparent 68%)',
borderRadius: '50%' }} />
<div className="absolute pointer-events-none"
style={{ bottom: '10%', right: '8%', width: 380, height: 380,
background: 'radial-gradient(ellipse, rgba(232,197,71,0.04) 0%, transparent 70%)',
borderRadius: '50%' }} />
<div className="absolute pointer-events-none"
style={{ top: '30%', left: '5%', width: 300, height: 300,
background: 'radial-gradient(ellipse, rgba(201,168,76,0.03) 0%, transparent 70%)',
borderRadius: '50%' }} />
{/* 3D Visualizer */}
<div className="absolute inset-0 pointer-events-none">
<AudioVisualizer3D isPlaying={isPlaying} />
</div>
{/* Main content */}
<div className="relative z-10 text-center px-6 max-w-5xl mx-auto pt-24">
{/* Badge */}
<motion.div {...fadeUp(0.1)} className="inline-flex items-center gap-2.5 mb-10 px-5 py-2 rounded-full glass-gold">
<span className="w-1.5 h-1.5 rounded-full bg-gold animate-pulse-gold" />
<span className="text-xs tracking-[0.22em] gold-text uppercase font-medium">Now Streaming</span>
<span className="text-muted text-xs">·</span>
<span className="text-xs text-secondary">40M tracks</span>
</motion.div>
{/* Headline */}
<div ref={headingRef} className="overflow-hidden mb-6">
<div className="hero-line font-display font-extrabold text-white leading-none"
style={{ fontSize: 'clamp(3.5rem, 11vw, 9rem)', letterSpacing: '-0.03em' }}>
Feel The
</div>
<div className="hero-line font-display font-extrabold leading-none gold-gradient-text"
style={{ fontSize: 'clamp(3.5rem, 11vw, 9rem)', letterSpacing: '-0.03em' }}>
Music
</div>
<div className="hero-line font-display font-medium text-secondary tracking-wide"
style={{ fontSize: 'clamp(1.4rem, 4vw, 3.5rem)', letterSpacing: '0.04em', marginTop: '0.15em' }}>
In Three Dimensions
</div>
</div>
{/* Subtitle */}
<motion.p {...fadeUp(0.55)}
className="text-secondary text-base md:text-lg mb-12 max-w-lg mx-auto leading-relaxed">
Where sound becomes sculpture. Every frequency, every beat — visualized in real time across a living 3D canvas.
</motion.p>
{/* CTAs */}
<motion.div {...fadeUp(0.7)} className="flex items-center justify-center gap-4 flex-wrap mb-16">
<motion.button
whileHover={{ scale: 1.05, boxShadow: '0 0 40px rgba(201,168,76,0.4)' }}
whileTap={{ scale: 0.96 }}
onClick={onTogglePlay}
className="flex items-center gap-3 px-8 py-4 rounded-full font-semibold text-sm tracking-wide transition-all duration-200 shadow-card"
style={{ background: 'linear-gradient(135deg, #c9a84c, #e8c547)', color: '#070709' }}
>
{isPlaying
? <><PauseIcon /> Pause</>
: <><PlayIcon /> Start Listening</>
}
</motion.button>
<motion.button
whileHover={{ scale: 1.04, borderColor: 'rgba(201,168,76,0.4)', color: 'var(--gold)' }}
whileTap={{ scale: 0.96 }}
className="flex items-center gap-2 px-8 py-4 rounded-full font-semibold text-sm tracking-wide text-secondary transition-all duration-200 glass"
>
Explore Collection
<svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</motion.button>
</motion.div>
{/* Stats row */}
<motion.div {...fadeUp(0.85)}
className="flex items-center justify-center gap-0 divide-x divide-dark-border">
{[['40M+', 'Tracks'], ['2.1M', 'Artists'], ['180+', 'Countries'], ['99.9%', 'Uptime']].map(([num, label]) => (
<div key={label} className="px-6 md:px-10 text-center first:pl-0 last:pr-0">
<p className="font-display font-bold text-xl md:text-2xl gold-text">{num}</p>
<p className="text-xs text-muted tracking-widest uppercase mt-0.5">{label}</p>
</div>
))}
</motion.div>
</div>
{/* Scroll cue */}
<motion.div
animate={{ y: [0, 9, 0] }}
transition={{ repeat: Infinity, duration: 2.6, ease: 'easeInOut' }}
className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-1.5"
>
<span className="text-xs tracking-widest text-muted uppercase">Scroll</span>
<svg className="w-4 h-4 text-muted" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M19 9l-7 7-7-7" />
</svg>
</motion.div>
</section>
)
}
function PlayIcon() {
return (
<svg className="w-4 h-4 ml-0.5" fill="currentColor" viewBox="0 0 24 24">
<path d="M8 5v14l11-7z" />
</svg>
)
}
function PauseIcon() {
return (
<svg className="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
</svg>
)
}