Hero: centered layout, GSAP scroll, 1.5x video, remove CTA
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
330e75a6ea
commit
a72a3c61f9
|
|
@ -14,6 +14,7 @@
|
|||
"clsx": "^2.1.1",
|
||||
"dotted-map": "^3.1.0",
|
||||
"framer-motion": "^12.40.0",
|
||||
"gsap": "^3.15.0",
|
||||
"jalaali-js": "^1.2.8",
|
||||
"lucide-react": "^1.16.0",
|
||||
"react": "^19.2.6",
|
||||
|
|
@ -2201,6 +2202,12 @@
|
|||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/gsap": {
|
||||
"version": "3.15.0",
|
||||
"resolved": "https://registry.npmjs.org/gsap/-/gsap-3.15.0.tgz",
|
||||
"integrity": "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A==",
|
||||
"license": "Standard 'no charge' license: https://gsap.com/standard-license."
|
||||
},
|
||||
"node_modules/hermes-estree": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
"clsx": "^2.1.1",
|
||||
"dotted-map": "^3.1.0",
|
||||
"framer-motion": "^12.40.0",
|
||||
"gsap": "^3.15.0",
|
||||
"jalaali-js": "^1.2.8",
|
||||
"lucide-react": "^1.16.0",
|
||||
"react": "^19.2.6",
|
||||
|
|
|
|||
|
|
@ -1,131 +1,140 @@
|
|||
import { useState } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useLang } from '@/context/LangContext'
|
||||
import gsap from 'gsap'
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
|
||||
const T = {
|
||||
fa: {
|
||||
h1a: 'جایی که آینده', h1b: ' به تصمیم ', h1c: 'تبدیل میشود',
|
||||
sub: 'تحلیل روندها، فناوریها و سناریوهای آینده صنعت فولاد',
|
||||
cta1: 'گزارش ویژه ←', cta2: 'نبض صنعت',
|
||||
video: 'Short film · Future of Steel',
|
||||
tag: 'اندیشکده فولاد آینده',
|
||||
h1a: 'جایی که آینده',
|
||||
h1b: 'به تصمیم تبدیل میشود',
|
||||
sub: 'تحلیل روندها، فناوریها و سناریوهای آینده صنعت فولاد ایران و جهان',
|
||||
},
|
||||
en: {
|
||||
h1a: 'Where the Future', h1b: ' Becomes ', h1c: 'Decision',
|
||||
tag: 'Steel Policy Institute',
|
||||
h1a: 'Where the Future',
|
||||
h1b: 'Becomes Decision',
|
||||
sub: 'Analyzing trends, technologies and future scenarios of the global steel industry',
|
||||
cta1: 'Special Report →', cta2: 'Industry Pulse',
|
||||
video: 'Short film · Future of Steel',
|
||||
},
|
||||
}
|
||||
|
||||
export default function HeroSection() {
|
||||
const { lang } = useLang()
|
||||
const t = T[lang]
|
||||
const [repHov, setRepHov] = useState(false)
|
||||
const [pulseHov, setPulseHov] = useState(false)
|
||||
|
||||
const sectionRef = useRef<HTMLElement>(null)
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
const overlayRef = useRef<HTMLDivElement>(null)
|
||||
const textRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const el = textRef.current
|
||||
const video = videoRef.current
|
||||
const overlay = overlayRef.current
|
||||
if (!el || !video || !overlay) return
|
||||
|
||||
video.playbackRate = 1.5
|
||||
|
||||
// entrance
|
||||
const tl = gsap.timeline()
|
||||
tl.fromTo(el, { opacity: 0, y: 40 }, { opacity: 1, y: 0, duration: 1, ease: 'power3.out' })
|
||||
|
||||
// scroll parallax — scrub keeps it reversible
|
||||
ScrollTrigger.create({
|
||||
trigger: sectionRef.current,
|
||||
start: 'top top',
|
||||
end: 'bottom top',
|
||||
scrub: 1,
|
||||
onUpdate: (self) => {
|
||||
const p = self.progress
|
||||
gsap.set(video, { scale: 1 + p * 0.12 })
|
||||
gsap.set(overlay, { opacity: 0.15 + p * 0.55 })
|
||||
gsap.set(el, { y: p * -60, opacity: 1 - p * 1.6 })
|
||||
},
|
||||
})
|
||||
|
||||
return () => {
|
||||
tl.kill()
|
||||
ScrollTrigger.getAll().forEach(t => t.kill())
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<section
|
||||
ref={sectionRef}
|
||||
style={{
|
||||
position: 'relative',
|
||||
background: 'var(--ink)',
|
||||
borderBottom: '3px solid var(--red)',
|
||||
overflow: 'hidden',
|
||||
minHeight: '80vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
position: 'relative',
|
||||
background: 'var(--ink)',
|
||||
borderBottom:'3px solid var(--red)',
|
||||
overflow: 'hidden',
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{/* Background video */}
|
||||
<video
|
||||
ref={videoRef}
|
||||
aria-hidden="true"
|
||||
autoPlay
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 0 }}
|
||||
src="/hero-bg.mp4"
|
||||
autoPlay muted loop playsInline
|
||||
style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 0, transformOrigin: 'center center' }}
|
||||
src="/hero-bg.mp4#t=2"
|
||||
/>
|
||||
{/* Dark overlay */}
|
||||
<div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'linear-gradient(135deg, rgba(26,23,18,0.88) 0%, rgba(26,23,18,0.72) 100%)', zIndex: 1 }} />
|
||||
{/* Grid texture */}
|
||||
<div aria-hidden="true" style={{ position: 'absolute', inset: 0, backgroundImage: 'linear-gradient(to right, rgba(244,239,231,0.03) 1px, transparent 1px), linear-gradient(to bottom, rgba(244,239,231,0.03) 1px, transparent 1px)', backgroundSize: '80px 80px', pointerEvents: 'none', zIndex: 2 }} />
|
||||
{/* Red glow */}
|
||||
<div aria-hidden="true" style={{ position: 'absolute', inset: 0, backgroundImage: 'radial-gradient(ellipse 80% 60% at 60% 50%, rgba(180,20,20,0.12) 0%, transparent 70%)', zIndex: 1 }} />
|
||||
<div ref={overlayRef} aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'rgba(16,13,10,0.55)', zIndex: 1 }} />
|
||||
{/* Vignette */}
|
||||
<div aria-hidden="true" style={{ position: 'absolute', inset: 0, background: 'radial-gradient(ellipse 90% 80% at 50% 50%, transparent 40%, rgba(16,13,10,0.7) 100%)', zIndex: 2 }} />
|
||||
|
||||
{/* Centered content */}
|
||||
<div
|
||||
className="relative max-w-7xl mx-auto px-12 max-md:px-5"
|
||||
style={{ paddingTop: 80, paddingBottom: 88, position: 'relative', zIndex: 3 }}
|
||||
ref={textRef}
|
||||
style={{
|
||||
position: 'relative',
|
||||
zIndex: 3,
|
||||
textAlign: 'center',
|
||||
direction: lang === 'fa' ? 'rtl' : 'ltr',
|
||||
padding: '0 24px',
|
||||
maxWidth: 760,
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{/* Overline */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 8 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.4 }}
|
||||
style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 32 }}
|
||||
>
|
||||
<div style={{ width: 40, height: 2, background: 'var(--red)' }} />
|
||||
<span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase', color: 'rgba(244,239,231,0.5)' }}>
|
||||
FUTURE STEEL POLICY INSTITUTE
|
||||
{/* Tag */}
|
||||
<div style={{ display: 'inline-flex', alignItems: 'center', gap: 10, marginBottom: 28 }}>
|
||||
<div style={{ width: 28, height: 1.5, background: 'var(--red)' }} />
|
||||
<span style={{ fontSize: 11, fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase', color: 'rgba(244,239,231,0.5)' }}>
|
||||
{t.tag}
|
||||
</span>
|
||||
</motion.div>
|
||||
<div style={{ width: 28, height: 1.5, background: 'var(--red)' }} />
|
||||
</div>
|
||||
|
||||
{/* Headline */}
|
||||
<motion.h1
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.6, delay: 0.08 }}
|
||||
style={{ fontSize: 'clamp(36px, 5.5vw, 80px)', fontWeight: 900, lineHeight: 1.05, letterSpacing: '-2px', color: 'var(--paper)', marginBottom: 28, maxWidth: 820 }}
|
||||
>
|
||||
<h1 style={{
|
||||
fontSize: 'clamp(36px, 6vw, 88px)',
|
||||
fontWeight: 900,
|
||||
lineHeight: 1.08,
|
||||
letterSpacing: '-2px',
|
||||
color: 'var(--paper)',
|
||||
marginBottom: 24,
|
||||
}}>
|
||||
{t.h1a}
|
||||
<br />
|
||||
<span style={{ color: 'var(--red)' }}>{t.h1b}</span>
|
||||
{t.h1c}
|
||||
</motion.h1>
|
||||
</h1>
|
||||
|
||||
{/* Subtitle */}
|
||||
<motion.p
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.5, delay: 0.2 }}
|
||||
style={{ fontSize: 'clamp(15px, 1.3vw, 19px)', lineHeight: 1.75, fontWeight: 400, color: 'rgba(244,239,231,0.6)', maxWidth: 560, marginBottom: 48, borderRight: lang === 'fa' ? '2px solid var(--red)' : 'none', borderLeft: lang === 'en' ? '2px solid var(--red)' : 'none', paddingRight: lang === 'fa' ? 18 : 0, paddingLeft: lang === 'en' ? 18 : 0 }}
|
||||
>
|
||||
<p style={{
|
||||
fontSize: 'clamp(14px, 1.2vw, 18px)',
|
||||
lineHeight: 1.8,
|
||||
color: 'rgba(244,239,231,0.55)',
|
||||
maxWidth: 520,
|
||||
margin: '0 auto 36px',
|
||||
}}>
|
||||
{t.sub}
|
||||
</motion.p>
|
||||
</p>
|
||||
|
||||
{/* CTAs */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.4, delay: 0.32 }}
|
||||
style={{ display: 'flex', gap: 14, flexWrap: 'wrap' }}
|
||||
>
|
||||
<button
|
||||
onMouseEnter={() => setRepHov(true)}
|
||||
onMouseLeave={() => setRepHov(false)}
|
||||
style={{ background: repHov ? 'var(--red)' : 'var(--paper)', color: repHov ? 'var(--paper)' : 'var(--ink)', border: 'none', padding: '14px 32px', fontSize: 13, fontWeight: 700, fontFamily: 'Vazir, sans-serif', cursor: 'pointer', transition: 'background 160ms, color 160ms', whiteSpace: 'nowrap', letterSpacing: '0.3px' }}
|
||||
>
|
||||
{t.cta1}
|
||||
</button>
|
||||
<button
|
||||
onMouseEnter={() => setPulseHov(true)}
|
||||
onMouseLeave={() => setPulseHov(false)}
|
||||
style={{ background: 'transparent', color: 'rgba(244,239,231,0.8)', border: `1px solid ${pulseHov ? 'rgba(244,239,231,0.7)' : 'rgba(244,239,231,0.3)'}`, padding: '14px 32px', fontSize: 13, fontWeight: 600, fontFamily: 'Vazir, sans-serif', cursor: 'pointer', transition: 'border-color 160ms', whiteSpace: 'nowrap' }}
|
||||
>
|
||||
{t.cta2}
|
||||
</button>
|
||||
</motion.div>
|
||||
|
||||
{/* Video placeholder badge */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.4, delay: 0.5 }}
|
||||
className="max-md:hidden"
|
||||
style={{ position: 'absolute', bottom: 88, left: 48, display: 'flex', alignItems: 'center', gap: 10, color: 'rgba(244,239,231,0.35)', fontSize: 10, letterSpacing: '2px', textTransform: 'uppercase', direction: 'ltr' }}
|
||||
>
|
||||
<div style={{ width: 36, height: 36, border: '1px solid rgba(244,239,231,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14 }}>▶</div>
|
||||
Short film · Future of Steel
|
||||
</motion.div>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue