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.
319 lines
9.7 KiB
319 lines
9.7 KiB
import { useEffect, useRef } from "react"; |
|
import { Link } from "react-router-dom"; |
|
import { gsap } from "gsap"; |
|
import { ScrollTrigger } from "gsap/ScrollTrigger"; |
|
import SubHero from "../../components/SubHero"; |
|
import FloatingKeywords from "../../components/FloatingKeywords"; |
|
|
|
gsap.registerPlugin(ScrollTrigger); |
|
|
|
const heroRight = <FloatingKeywords />; |
|
|
|
const COMPANY_NAV = [ |
|
{ label: "회사소개", to: "/company/about" }, |
|
{ label: "연혁", to: "/company/history" }, |
|
{ label: "고객 및 협력사", to: "/company/partners" }, |
|
{ label: "찾아오시는 길", to: "/company/location" }, |
|
]; |
|
|
|
const STATS = [ |
|
{ num: 2010, suffix: "", label: "설립연도", note: "FOUNDED" }, |
|
{ num: 50, suffix: "+", label: "완료 프로젝트", note: "PROJECTS" }, |
|
{ num: 15, suffix: "+", label: "주요 고객사", note: "CLIENTS" }, |
|
{ num: 10, suffix: "+", label: "R&D 전문인력", note: "EXPERTS" }, |
|
]; |
|
|
|
const VALUES = [ |
|
{ |
|
idx: "01", |
|
title: "기술 혁신", |
|
en: "Innovation", |
|
desc: "항공 데이터와 UTM 기술의 경계를 지속적으로 확장하며 미래 모빌리티 시대를 선도합니다.", |
|
}, |
|
{ |
|
idx: "02", |
|
title: "신뢰와 책임", |
|
en: "Trust", |
|
desc: "공공·항공 분야의 핵심 인프라를 다루는 만큼 모든 서비스에 안전과 신뢰를 최우선으로 합니다.", |
|
}, |
|
{ |
|
idx: "03", |
|
title: "파트너십", |
|
en: "Partnership", |
|
desc: "고객사와 장기 파트너로서 구축부터 운영·유지보수까지 전 과정을 함께합니다.", |
|
}, |
|
{ |
|
idx: "04", |
|
title: "전문성", |
|
en: "Expertise", |
|
desc: "항공 IT 분야 10년 이상의 전문 인력이 SI, R&D, 솔루션 개발을 일관되게 수행합니다.", |
|
}, |
|
]; |
|
|
|
const AWARDS = [ |
|
{ |
|
year: "2022", |
|
title: "인천 항공산업 선도기업 유망기업 선정", |
|
org: "인천시 · 인천테크노파크", |
|
}, |
|
{ |
|
year: "2021", |
|
title: "소프트웨어 품질인증 GS 인증 획득", |
|
org: "한국정보통신기술협회(TTA)", |
|
}, |
|
{ year: "2021", title: "기업부설연구소 인정", org: "한국산업기술진흥협회" }, |
|
{ year: "2020", title: "조달청 우수제품 지정", org: "비행상황관제 시스템" }, |
|
]; |
|
|
|
function animateCount(el, target, suffix, duration = 1600) { |
|
const from = target > 100 ? target - 4 : 0; |
|
let start = null; |
|
const step = (ts) => { |
|
if (!start) start = ts; |
|
const p = Math.min((ts - start) / duration, 1); |
|
const ease = 1 - Math.pow(1 - p, 4); |
|
el.textContent = Math.floor(from + (target - from) * ease) + suffix; |
|
if (p < 1) requestAnimationFrame(step); |
|
}; |
|
requestAnimationFrame(step); |
|
} |
|
|
|
export default function AboutPage() { |
|
const statRefs = useRef([]); |
|
|
|
useEffect(() => { |
|
const ctx = gsap.context(() => { |
|
/* stats 카운터 */ |
|
ScrollTrigger.create({ |
|
trigger: ".ab-stats", |
|
start: "top 75%", |
|
toggleActions: "play none none reset", |
|
onEnter: () => { |
|
statRefs.current.forEach((el, i) => { |
|
if (!el) return; |
|
setTimeout( |
|
() => animateCount(el, STATS[i].num, STATS[i].suffix), |
|
i * 100, |
|
); |
|
}); |
|
}, |
|
}); |
|
|
|
/* stats 스태거 */ |
|
gsap.fromTo( |
|
".ab-si", |
|
{ opacity: 0, y: 40 }, |
|
{ |
|
opacity: 1, |
|
y: 0, |
|
stagger: 0.12, |
|
duration: 0.8, |
|
ease: "power3.out", |
|
scrollTrigger: { trigger: ".ab-stats", start: "top 78%" }, |
|
}, |
|
); |
|
|
|
/* 소개 */ |
|
gsap.fromTo( |
|
".ab-intro-text > *", |
|
{ opacity: 0, y: 32 }, |
|
{ |
|
opacity: 1, |
|
y: 0, |
|
stagger: 0.1, |
|
duration: 0.9, |
|
ease: "power3.out", |
|
scrollTrigger: { trigger: ".ab-intro", start: "top 70%" }, |
|
}, |
|
); |
|
|
|
/* 가치 */ |
|
gsap.fromTo( |
|
".ab-val-row", |
|
{ opacity: 0, x: -32 }, |
|
{ |
|
opacity: 1, |
|
x: 0, |
|
stagger: 0.1, |
|
duration: 0.8, |
|
ease: "power3.out", |
|
scrollTrigger: { trigger: ".ab-vals", start: "top 72%" }, |
|
}, |
|
); |
|
|
|
/* 수상 */ |
|
gsap.fromTo( |
|
".ab-awd-item", |
|
{ opacity: 0, y: 24 }, |
|
{ |
|
opacity: 1, |
|
y: 0, |
|
stagger: 0.09, |
|
duration: 0.7, |
|
ease: "power2.out", |
|
scrollTrigger: { trigger: ".ab-awds", start: "top 75%" }, |
|
}, |
|
); |
|
|
|
/* CTA */ |
|
gsap.fromTo( |
|
".ab-cta-inner > *", |
|
{ opacity: 0, y: 32 }, |
|
{ |
|
opacity: 1, |
|
y: 0, |
|
stagger: 0.12, |
|
duration: 0.9, |
|
ease: "power2.out", |
|
scrollTrigger: { trigger: ".ab-cta", start: "top 75%" }, |
|
}, |
|
); |
|
}); |
|
return () => ctx.revert(); |
|
}, []); |
|
|
|
return ( |
|
<article> |
|
{/* ① 히어로 */} |
|
<SubHero |
|
title={ |
|
<> |
|
<span style={{ color: "#111" }}>가치를 실천하는</span> |
|
<br /> |
|
<em>항공 IT 전문기업</em> |
|
</> |
|
} |
|
desc="팔네트웍스는 항공 데이터와 통합 관제 기술을 기반으로 안전한 하늘길을 만들어갑니다." |
|
navItems={COMPANY_NAV} |
|
rightSlot={heroRight} |
|
/> |
|
|
|
{/* ② 소개 — 흰 배경, 히어로와 자연스럽게 연결 */} |
|
<section className="ab-intro"> |
|
<div className="ab-intro-inner"> |
|
<div className="ab-intro-left"> |
|
<span className="ab-eyebrow">Our Philosophy</span> |
|
<h2 className="ab-intro-title"> |
|
항공산업의 |
|
<br /> |
|
기술혁신을 |
|
<br /> |
|
<em>선도합니다.</em> |
|
</h2> |
|
</div> |
|
<div className="ab-intro-text"> |
|
<div className="ab-intro-badge"> |
|
<span>2010년 설립 이후</span> |
|
<strong>항공 IT 한 길</strong> |
|
</div> |
|
<p> |
|
팔네트웍스는 2010년 설립 이후 항공 예약 플랫폼, 비행상황관제 |
|
시스템, UTM 솔루션까지 항공 IT 분야의 핵심 기술을 꾸준히 |
|
개발해왔습니다. |
|
</p> |
|
<p> |
|
인천광역시 로봇랜드에서 UAM/UATM 미래 기술을 선행 연구하며 안전한 |
|
하늘길을 만들어가고 있습니다. |
|
</p> |
|
</div> |
|
</div> |
|
</section> |
|
|
|
{/* ③ Stats — 연한 네이비 배경 */} |
|
<section className="ab-stats"> |
|
<div className="ab-stats-inner"> |
|
<span className="ab-eyebrow ab-eyebrow--light"> |
|
PAL Networks in Numbers |
|
</span> |
|
<div className="ab-stats-grid"> |
|
{STATS.map((s, i) => ( |
|
<div className="ab-si" key={s.note}> |
|
<span className="ab-si-bg"> |
|
{s.num} |
|
{s.suffix} |
|
</span> |
|
<span className="ab-si-note">{s.note}</span> |
|
<strong |
|
className="ab-si-num" |
|
ref={(el) => (statRefs.current[i] = el)} |
|
> |
|
{s.num} |
|
{s.suffix} |
|
</strong> |
|
<span className="ab-si-lbl">{s.label}</span> |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
</section> |
|
|
|
{/* ④ 핵심가치 — 흰 배경 */} |
|
<section className="ab-vals"> |
|
<div className="ab-vals-inner"> |
|
<div className="ab-vals-head"> |
|
<span className="ab-eyebrow">Core Values</span> |
|
<h2 className="ab-vals-title">우리가 지키는 가치</h2> |
|
</div> |
|
<div className="ab-vals-list"> |
|
{VALUES.map((v) => ( |
|
<div className="ab-val-row" key={v.idx}> |
|
<div className="ab-val-left"> |
|
<span className="ab-val-idx">{v.idx}</span> |
|
<span className="ab-val-en">{v.en}</span> |
|
</div> |
|
<h3 className="ab-val-name">{v.title}</h3> |
|
<p className="ab-val-desc">{v.desc}</p> |
|
<span className="ab-val-arr">→</span> |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
</section> |
|
|
|
{/* ⑤ 수상/인증 — 연한 배경 */} |
|
<section className="ab-awds"> |
|
<div className="ab-awds-inner"> |
|
<div className="ab-awds-head"> |
|
<span className="ab-eyebrow">Certifications & Awards</span> |
|
<h2 className="ab-awds-title">인증 및 수상</h2> |
|
</div> |
|
<ul className="ab-awds-list"> |
|
{AWARDS.map((a, i) => ( |
|
<li className="ab-awd-item" key={i}> |
|
<span className="ab-awd-yr">{a.year}</span> |
|
<div className="ab-awd-line" /> |
|
<div className="ab-awd-body"> |
|
<strong className="ab-awd-name">{a.title}</strong> |
|
<span className="ab-awd-org">{a.org}</span> |
|
</div> |
|
</li> |
|
))} |
|
</ul> |
|
</div> |
|
</section> |
|
|
|
{/* ⑥ CTA — 네이비 배경 */} |
|
<section className="ab-cta"> |
|
<div className="ab-cta-inner"> |
|
<span className="ab-cta-chip">Contact Us</span> |
|
<h2 className="ab-cta-title"> |
|
팔네트웍스와 |
|
<br /> |
|
함께하세요 |
|
</h2> |
|
<p className="ab-cta-desc"> |
|
파트너십 문의, 채용, 사업 협력 등 무엇이든 편하게 연락주세요. |
|
</p> |
|
<div className="ab-cta-btns"> |
|
<Link to="/contact/inquiry" className="ab-cta-btn ab-cta-btn--fill"> |
|
문의하기 |
|
</Link> |
|
<Link to="/contact/recruit" className="ab-cta-btn ab-cta-btn--line"> |
|
채용 안내 |
|
</Link> |
|
</div> |
|
</div> |
|
</section> |
|
</article> |
|
); |
|
}
|
|
|