You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.1 KiB
157 lines
4.1 KiB
import { useEffect, useRef } from "react"; |
|
import { gsap } from "gsap"; |
|
import { ScrollTrigger } from "gsap/ScrollTrigger"; |
|
|
|
gsap.registerPlugin(ScrollTrigger); |
|
|
|
function MainUam() { |
|
const sectionRef = useRef(null); |
|
const overlayRef = useRef(null); |
|
const titleRef = useRef(null); |
|
const vehicleRef = useRef(null); |
|
const panelsRef = useRef([]); |
|
|
|
const items = [ |
|
{ |
|
label: "UAM NETWORK", |
|
title: "Urban Air Mobility", |
|
desc: "도심 내 버티포트, 운항 경로, 항공 교통 데이터를 연결해 미래형 도심 항공 이동 환경을 구축합니다.", |
|
}, |
|
{ |
|
label: "VERTIPORT", |
|
title: "Vertiport Connection", |
|
desc: "도심 곳곳의 이착륙 거점을 연결해 사람과 도시의 이동 흐름을 확장합니다.", |
|
}, |
|
{ |
|
label: "AIR CORRIDOR", |
|
title: "Smart Air Corridor", |
|
desc: "복잡한 도심 상공에서도 안전한 항로를 구성하고 실시간 운항 흐름을 관리합니다.", |
|
}, |
|
]; |
|
|
|
useEffect(() => { |
|
const ctx = gsap.context(() => { |
|
gsap.set(overlayRef.current, { yPercent: 0 }); |
|
gsap.set(titleRef.current, { y: 80, opacity: 0 }); |
|
gsap.set(vehicleRef.current, { |
|
xPercent: -120, |
|
yPercent: 80, |
|
opacity: 0, |
|
}); |
|
gsap.set(panelsRef.current, { y: 40, opacity: 0 }); |
|
|
|
const tl = gsap.timeline({ |
|
scrollTrigger: { |
|
trigger: sectionRef.current, |
|
start: "top bottom", |
|
end: "+=1400", |
|
scrub: 1, |
|
}, |
|
}); |
|
|
|
tl.to(overlayRef.current, { |
|
yPercent: -100, |
|
duration: 1, |
|
ease: "none", |
|
}); |
|
|
|
tl.to( |
|
titleRef.current, |
|
{ |
|
y: 0, |
|
opacity: 1, |
|
duration: 0.8, |
|
ease: "none", |
|
}, |
|
"<0.25", |
|
); |
|
|
|
tl.to( |
|
vehicleRef.current, |
|
{ |
|
xPercent: 0, |
|
yPercent: 0, |
|
opacity: 1, |
|
duration: 1, |
|
ease: "none", |
|
}, |
|
"<0.2", |
|
); |
|
|
|
tl.to( |
|
panelsRef.current, |
|
{ |
|
y: 0, |
|
opacity: 1, |
|
stagger: 0.16, |
|
duration: 0.8, |
|
ease: "none", |
|
}, |
|
"<0.35", |
|
); |
|
}, sectionRef); |
|
|
|
return () => ctx.revert(); |
|
}, []); |
|
|
|
return ( |
|
<section className="main-uam-section" ref={sectionRef}> |
|
<div className="main-uam-screen-wipe" ref={overlayRef}> |
|
<span>FROM UTM</span> |
|
<strong>TO UAM</strong> |
|
</div> |
|
|
|
<div className="main-uam-bg-grid" /> |
|
<div className="main-uam-light main-uam-light--a" /> |
|
<div className="main-uam-light main-uam-light--b" /> |
|
|
|
<div className="main-uam-inner"> |
|
<div className="main-uam-visual"> |
|
<div className="main-uam-route main-uam-route--a" /> |
|
<div className="main-uam-route main-uam-route--b" /> |
|
<div className="main-uam-route main-uam-route--c" /> |
|
|
|
<div className="main-uam-node main-uam-node--a">V</div> |
|
<div className="main-uam-node main-uam-node--b">P</div> |
|
<div className="main-uam-node main-uam-node--c">C</div> |
|
|
|
<div className="main-uam-vehicle" ref={vehicleRef}> |
|
<span /> |
|
</div> |
|
</div> |
|
|
|
<div className="main-uam-content" ref={titleRef}> |
|
<p className="main-uam-eyebrow">UAM SYSTEM</p> |
|
<h2> |
|
도심항공교통 |
|
<br /> |
|
UAM |
|
</h2> |
|
<p> |
|
드론 관제에서 확장된 하늘길은 이제 도시의 이동 네트워크로 |
|
이어집니다. UAM은 버티포트, 항로, 운항 데이터를 하나의 흐름으로 |
|
연결합니다. |
|
</p> |
|
</div> |
|
|
|
<div className="main-uam-panels"> |
|
{items.map((item, index) => ( |
|
<article |
|
className="main-uam-panel" |
|
key={item.label} |
|
ref={(el) => { |
|
panelsRef.current[index] = el; |
|
}} |
|
> |
|
<span>{item.label}</span> |
|
<h3>{item.title}</h3> |
|
<p>{item.desc}</p> |
|
</article> |
|
))} |
|
</div> |
|
</div> |
|
</section> |
|
); |
|
} |
|
|
|
export default MainUam;
|
|
|