|
|
|
@ -11,18 +11,20 @@ import { |
|
|
|
FileCheck, |
|
|
|
FileCheck, |
|
|
|
Database, |
|
|
|
Database, |
|
|
|
Layers, |
|
|
|
Layers, |
|
|
|
|
|
|
|
Navigation, |
|
|
|
|
|
|
|
CheckCircle, |
|
|
|
|
|
|
|
Radio, |
|
|
|
} from "lucide-react"; |
|
|
|
} from "lucide-react"; |
|
|
|
|
|
|
|
|
|
|
|
const ease = [0.22, 1, 0.36, 1]; |
|
|
|
const ease = [0.22, 1, 0.36, 1]; |
|
|
|
const basePath = import.meta.env.BASE_URL; |
|
|
|
const basePath = import.meta.env.BASE_URL; |
|
|
|
|
|
|
|
|
|
|
|
const INTRO_CARDS = [ |
|
|
|
const INTRO_CARDS = [ |
|
|
|
{ label: "비행 계획", img: `${basePath}/images/utm_intro_icon1.png` }, |
|
|
|
{ label: "비행 계획", icon: Navigation }, |
|
|
|
{ label: "비행 승인", img: `${basePath}/images/utm_intro_icon2.png` }, |
|
|
|
{ label: "비행 승인", icon: CheckCircle }, |
|
|
|
{ label: "실시간 관제", img: `${basePath}/images/utm_intro_icon3.png` }, |
|
|
|
{ label: "실시간 관제", icon: Radio }, |
|
|
|
{ label: "데이터 관리", img: `${basePath}/images/utm_intro_icon4.png` }, |
|
|
|
{ label: "데이터 관리", icon: Database }, |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const UTM_WHAT_LEFT = [ |
|
|
|
const UTM_WHAT_LEFT = [ |
|
|
|
{ icon: MapPin, label: "실시간 위치 감시" }, |
|
|
|
{ icon: MapPin, label: "실시간 위치 감시" }, |
|
|
|
{ icon: ShieldAlert, label: "충돌 위험 사전 분석" }, |
|
|
|
{ icon: ShieldAlert, label: "충돌 위험 사전 분석" }, |
|
|
|
@ -61,7 +63,7 @@ const EVO_ITEMS = [ |
|
|
|
<> |
|
|
|
<> |
|
|
|
무인기 교통관리 시스템 도입. |
|
|
|
무인기 교통관리 시스템 도입. |
|
|
|
<br /> |
|
|
|
<br /> |
|
|
|
비행 경로 승인·충돌 방지· 공역 관리 체계화. |
|
|
|
비행 경로 승인·충돌 방지·공역 관리 체계화. |
|
|
|
</> |
|
|
|
</> |
|
|
|
), |
|
|
|
), |
|
|
|
tag: "공역 관리 시스템", |
|
|
|
tag: "공역 관리 시스템", |
|
|
|
@ -99,6 +101,49 @@ const EVO_ITEMS = [ |
|
|
|
active: true, |
|
|
|
active: true, |
|
|
|
}, |
|
|
|
}, |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const SECTORS = [ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: 0, |
|
|
|
|
|
|
|
num: "01", |
|
|
|
|
|
|
|
name: "UAM 기체 운용", |
|
|
|
|
|
|
|
color: "#E8193C", |
|
|
|
|
|
|
|
tags: [ |
|
|
|
|
|
|
|
"eVTOL 기체 직접 운용", |
|
|
|
|
|
|
|
"실 운용 데이터 기반 검증", |
|
|
|
|
|
|
|
"국내 유일 통합 사업자", |
|
|
|
|
|
|
|
"안전 관리 체계 구축", |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: 1, |
|
|
|
|
|
|
|
num: "02", |
|
|
|
|
|
|
|
name: "UTM 관제 기술", |
|
|
|
|
|
|
|
color: "#1A1F5E", |
|
|
|
|
|
|
|
tags: [ |
|
|
|
|
|
|
|
"실시간 공역 감시·관제", |
|
|
|
|
|
|
|
"충돌 위험 사전 분석", |
|
|
|
|
|
|
|
"비행 경로 승인 시스템", |
|
|
|
|
|
|
|
"지오펜싱·공역 설정", |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
id: 2, |
|
|
|
|
|
|
|
num: "03", |
|
|
|
|
|
|
|
name: "통합 항공 데이터 플랫폼", |
|
|
|
|
|
|
|
color: "#3D3D3D", |
|
|
|
|
|
|
|
tags: [ |
|
|
|
|
|
|
|
"비행 데이터 수집·분석", |
|
|
|
|
|
|
|
"UAM·드론 시스템 연동", |
|
|
|
|
|
|
|
"기상 정보 자동 연계", |
|
|
|
|
|
|
|
"통합 데이터 관리", |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ──────────────────────────────────────── |
|
|
|
|
|
|
|
EvoItem |
|
|
|
|
|
|
|
──────────────────────────────────────── */ |
|
|
|
function EvoItem({ item, index }) { |
|
|
|
function EvoItem({ item, index }) { |
|
|
|
const itemRef = useRef(null); |
|
|
|
const itemRef = useRef(null); |
|
|
|
const itemInView = useInView(itemRef, { once: true, margin: "-80px" }); |
|
|
|
const itemInView = useInView(itemRef, { once: true, margin: "-80px" }); |
|
|
|
@ -140,8 +185,7 @@ function EvoItem({ item, index }) { |
|
|
|
<div className="utm-evo__empty" /> |
|
|
|
<div className="utm-evo__empty" /> |
|
|
|
<div className="utm-evo__dot-wrap"> |
|
|
|
<div className="utm-evo__dot-wrap"> |
|
|
|
<div className="utm-evo__dot"> |
|
|
|
<div className="utm-evo__dot"> |
|
|
|
<span>{String(index + 1).padStart(2, "0")}</span>{" "} |
|
|
|
<span>{String(index + 1).padStart(2, "0")}</span> |
|
|
|
{/* 여기 span 추가 */} |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div className="utm-evo__card-wrap utm-evo__card-wrap--right"> |
|
|
|
<div className="utm-evo__card-wrap utm-evo__card-wrap--right"> |
|
|
|
@ -163,6 +207,10 @@ function EvoItem({ item, index }) { |
|
|
|
</motion.div> |
|
|
|
</motion.div> |
|
|
|
); |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ──────────────────────────────────────── |
|
|
|
|
|
|
|
IntroPage |
|
|
|
|
|
|
|
──────────────────────────────────────── */ |
|
|
|
function IntroPage() { |
|
|
|
function IntroPage() { |
|
|
|
const ref = useFadeIn(); |
|
|
|
const ref = useFadeIn(); |
|
|
|
const UTM_NAV = [ |
|
|
|
const UTM_NAV = [ |
|
|
|
@ -172,11 +220,17 @@ function IntroPage() { |
|
|
|
|
|
|
|
|
|
|
|
const introRef = useRef(null); |
|
|
|
const introRef = useRef(null); |
|
|
|
const introInView = useInView(introRef, { once: true, margin: "-60px" }); |
|
|
|
const introInView = useInView(introRef, { once: true, margin: "-60px" }); |
|
|
|
|
|
|
|
|
|
|
|
const whatRef = useRef(null); |
|
|
|
const whatRef = useRef(null); |
|
|
|
const whatInView = useInView(whatRef, { once: true, margin: "-200px" }); |
|
|
|
const whatInView = useInView(whatRef, { once: true, margin: "-100px" }); |
|
|
|
|
|
|
|
|
|
|
|
const evoRef = useRef(null); |
|
|
|
const evoRef = useRef(null); |
|
|
|
const evoInView = useInView(evoRef, { once: true, margin: "-100px" }); |
|
|
|
const evoInView = useInView(evoRef, { once: true, margin: "-100px" }); |
|
|
|
const evoTrackRef = useRef(null); |
|
|
|
const evoTrackRef = useRef(null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const capRef = useRef(null); |
|
|
|
|
|
|
|
const capInView = useInView(capRef, { once: true, margin: "-80px" }); |
|
|
|
|
|
|
|
|
|
|
|
const { scrollYProgress } = useScroll({ |
|
|
|
const { scrollYProgress } = useScroll({ |
|
|
|
target: evoTrackRef, |
|
|
|
target: evoTrackRef, |
|
|
|
offset: ["start center", "end center"], |
|
|
|
offset: ["start center", "end center"], |
|
|
|
@ -196,6 +250,7 @@ function IntroPage() { |
|
|
|
/> |
|
|
|
/> |
|
|
|
|
|
|
|
|
|
|
|
<div className="sub-content"> |
|
|
|
<div className="sub-content"> |
|
|
|
|
|
|
|
{/* ── 01 Overview ── */} |
|
|
|
<div className="inner-wrap"> |
|
|
|
<div className="inner-wrap"> |
|
|
|
<section className="utm-intro" ref={introRef}> |
|
|
|
<section className="utm-intro" ref={introRef}> |
|
|
|
<div className="utm-intro__top"> |
|
|
|
<div className="utm-intro__top"> |
|
|
|
@ -215,7 +270,8 @@ function IntroPage() { |
|
|
|
> |
|
|
|
> |
|
|
|
PAL Networks의 UTM/UATM은 |
|
|
|
PAL Networks의 UTM/UATM은 |
|
|
|
<br /> |
|
|
|
<br /> |
|
|
|
<em>도심 항공 관제의 새로운 기준</em>입니다. |
|
|
|
<em>도심 항공 관제의 {""}</em> |
|
|
|
|
|
|
|
<em>새로운 기준입니다.</em> |
|
|
|
</motion.h2> |
|
|
|
</motion.h2> |
|
|
|
<motion.p |
|
|
|
<motion.p |
|
|
|
className="utm-intro__desc" |
|
|
|
className="utm-intro__desc" |
|
|
|
@ -242,11 +298,27 @@ function IntroPage() { |
|
|
|
<span className="utm-intro__card-num"> |
|
|
|
<span className="utm-intro__card-num"> |
|
|
|
{String(i + 1).padStart(2, "0")} |
|
|
|
{String(i + 1).padStart(2, "0")} |
|
|
|
</span> |
|
|
|
</span> |
|
|
|
<img |
|
|
|
<span className="utm-intro__card-icon"> |
|
|
|
src={card.img} |
|
|
|
<svg width="0" height="0"> |
|
|
|
alt={card.label} |
|
|
|
<defs> |
|
|
|
className="utm-intro__card-img" |
|
|
|
<linearGradient |
|
|
|
/> |
|
|
|
id="icon-grad" |
|
|
|
|
|
|
|
x1="0%" |
|
|
|
|
|
|
|
y1="0%" |
|
|
|
|
|
|
|
x2="100%" |
|
|
|
|
|
|
|
y2="100%" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<stop offset="0%" stopColor="#C850C0" /> |
|
|
|
|
|
|
|
<stop offset="100%" stopColor="#4158D0" /> |
|
|
|
|
|
|
|
</linearGradient> |
|
|
|
|
|
|
|
</defs> |
|
|
|
|
|
|
|
</svg> |
|
|
|
|
|
|
|
<card.icon |
|
|
|
|
|
|
|
size={36} |
|
|
|
|
|
|
|
strokeWidth={1.5} |
|
|
|
|
|
|
|
stroke="url(#icon-grad)" |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
</span> |
|
|
|
<p className="utm-intro__card-label">{card.label}</p> |
|
|
|
<p className="utm-intro__card-label">{card.label}</p> |
|
|
|
</motion.li> |
|
|
|
</motion.li> |
|
|
|
))} |
|
|
|
))} |
|
|
|
@ -254,7 +326,7 @@ function IntroPage() { |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
{/* ── UTM 소개 섹션 ── */} |
|
|
|
{/* ── 02 What is UTM ── */} |
|
|
|
<section className="utm-what" ref={whatRef}> |
|
|
|
<section className="utm-what" ref={whatRef}> |
|
|
|
<div className="inner-wrap"> |
|
|
|
<div className="inner-wrap"> |
|
|
|
<motion.div |
|
|
|
<motion.div |
|
|
|
@ -286,7 +358,8 @@ function IntroPage() { |
|
|
|
transition={{ duration: 0.6, delay: 0.2, ease }} |
|
|
|
transition={{ duration: 0.6, delay: 0.2, ease }} |
|
|
|
> |
|
|
|
> |
|
|
|
UTM은 단순한 관제 시스템을 넘어, 도심 저고도 공역 전체를 |
|
|
|
UTM은 단순한 관제 시스템을 넘어, 도심 저고도 공역 전체를 |
|
|
|
디지털로 운영하는 통합 플랫폼입니다. <br /> |
|
|
|
디지털로 운영하는 통합 플랫폼입니다. |
|
|
|
|
|
|
|
<br /> |
|
|
|
실시간 감시부터 충돌 위험 분석, 기상 연계, 공역 관리까지 — |
|
|
|
실시간 감시부터 충돌 위험 분석, 기상 연계, 공역 관리까지 — |
|
|
|
비행의 모든 순간을 안전하게 연결합니다. |
|
|
|
비행의 모든 순간을 안전하게 연결합니다. |
|
|
|
</motion.p> |
|
|
|
</motion.p> |
|
|
|
@ -417,8 +490,8 @@ function IntroPage() { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* ── 03 Evolution ── */} |
|
|
|
<div className="inner-wrap"> |
|
|
|
<div className="inner-wrap"> |
|
|
|
{/* ── DRONE → UATM 진화 섹션 ── */} |
|
|
|
|
|
|
|
<section className="utm-evo" ref={evoRef}> |
|
|
|
<section className="utm-evo" ref={evoRef}> |
|
|
|
<motion.div |
|
|
|
<motion.div |
|
|
|
className="utm-evo__left" |
|
|
|
className="utm-evo__left" |
|
|
|
@ -460,6 +533,63 @@ function IntroPage() { |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</section> |
|
|
|
</section> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{/* ── 04 Capabilities ── */} |
|
|
|
|
|
|
|
<section className="utm-cap" ref={capRef}> |
|
|
|
|
|
|
|
<div className="inner-wrap"> |
|
|
|
|
|
|
|
<div className="utm-cap__top"> |
|
|
|
|
|
|
|
<motion.span |
|
|
|
|
|
|
|
className="fc-eyebrow" |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 16 }} |
|
|
|
|
|
|
|
animate={capInView ? { opacity: 1, y: 0 } : {}} |
|
|
|
|
|
|
|
transition={{ duration: 0.6, ease }} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
Capabilities |
|
|
|
|
|
|
|
</motion.span> |
|
|
|
|
|
|
|
<motion.h2 |
|
|
|
|
|
|
|
className="utm-cap__title" |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 20 }} |
|
|
|
|
|
|
|
animate={capInView ? { opacity: 1, y: 0 } : {}} |
|
|
|
|
|
|
|
transition={{ duration: 0.7, delay: 0.1, ease }} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
PAL Networks의 <br /> |
|
|
|
|
|
|
|
<em>세 가지 핵심 역량</em> |
|
|
|
|
|
|
|
</motion.h2> |
|
|
|
|
|
|
|
<motion.p |
|
|
|
|
|
|
|
className="utm-cap__desc" |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 16 }} |
|
|
|
|
|
|
|
animate={capInView ? { opacity: 1, y: 0 } : {}} |
|
|
|
|
|
|
|
transition={{ duration: 0.6, delay: 0.2, ease }} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
기체 운용부터 관제, 데이터까지 — 하나의 사업자가 모두 보유한 |
|
|
|
|
|
|
|
통합 역량입니다. |
|
|
|
|
|
|
|
</motion.p> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<ul className="utm-cap__cards"> |
|
|
|
|
|
|
|
{SECTORS.map((s, i) => ( |
|
|
|
|
|
|
|
<motion.li |
|
|
|
|
|
|
|
key={s.id} |
|
|
|
|
|
|
|
className="utm-cap__card" |
|
|
|
|
|
|
|
style={{ "--cap-color": s.color }} |
|
|
|
|
|
|
|
initial={{ opacity: 0, y: 48 }} |
|
|
|
|
|
|
|
animate={capInView ? { opacity: 1, y: 0 } : {}} |
|
|
|
|
|
|
|
transition={{ duration: 0.7, delay: 0.2 + i * 0.12, ease }} |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<span className="utm-cap__card-num">{s.num}</span> |
|
|
|
|
|
|
|
<div className="utm-cap__card-body"> |
|
|
|
|
|
|
|
<strong className="utm-cap__card-name">{s.name}</strong> |
|
|
|
|
|
|
|
<ul className="utm-cap__card-tags"> |
|
|
|
|
|
|
|
{s.tags.map((tag) => ( |
|
|
|
|
|
|
|
<li key={tag}>{tag}</li> |
|
|
|
|
|
|
|
))} |
|
|
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</motion.li> |
|
|
|
|
|
|
|
))} |
|
|
|
|
|
|
|
</ul> |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
</section> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</article> |
|
|
|
</article> |
|
|
|
); |
|
|
|
); |
|
|
|
|