Browse Source

플랫폼 인프라 주석

remotes/origin/main
김지은 3 weeks ago
parent
commit
3c780ec087
  1. 14
      src/components/Header.jsx
  2. 3
      src/css/common.css
  3. 235
      src/pages/solution/FlightControlPage.jsx

14
src/components/Header.jsx

@ -93,13 +93,13 @@ const menuData = [
{ label: "IBE (Internet Booking Engine)", to: "/solution/ibe", desc: "항공 예약·발권 엔진" },
],
},
{
title: "플랫폼 · 인프라",
items: [
{ label: "스마트 관광 예약 플랫폼", to: "/solution/smart-tour", desc: "관광 예약 통합 운영 플랫폼" },
{ label: "KT G-cloud 인천총판", to: "/solution/kt-gcloud", desc: "공공 클라우드 인프라 공급" },
],
},
// {
// title: " · ",
// items: [
// { label: " ", to: "/solution/smart-tour", desc: " " },
// { label: "KT G-cloud ", to: "/solution/kt-gcloud", desc: " " },
// ],
// },
],
featured: {
eyebrow: "Scalable Solutions",

3
src/css/common.css

@ -759,7 +759,7 @@ body{overflow-x:hidden;}
.fc-func-item__arrow {flex-shrink:0;color:var(--color-primary);display:flex;align-items:center;}
.fc-func-item__line {position:absolute;bottom:0;left:0;right:0;height:1px;background:var(--color-primary);transform-origin:left;will-change:transform;}
.fc-func-display {flex:0 0 340px;}
.fc-func-display {flex:0 0 500px;}
.fc-func-display__inner {position:relative;border-radius:.875rem;overflow:hidden;background:#0a0e2e;aspect-ratio:2/1;}
.fc-func-display__img {width:100%;height:100%;object-fit:cover;display:block;}
.fc-func-display__caption {position:absolute;bottom:0;left:0;right:0;padding:.85rem 1rem;background:linear-gradient(to top, rgba(10,14,46,.88) 0%, transparent 100%);display:flex;align-items:center;gap:.55rem;}
@ -865,6 +865,7 @@ body{overflow-x:hidden;}
.fc-highlight__desc { font-size: 0.82rem; }
.fc-highlight__float-icon { width: 48px; height: 48px; }
.fc-highlight__img-scene { transform: scale(0.75); transform-origin: top center; }
}
/*

235
src/pages/solution/FlightControlPage.jsx

@ -1,26 +1,14 @@
import { useRef, useState } from "react";
import { motion, useInView, AnimatePresence } from "framer-motion";
import {
Radio,
Puzzle,
Network,
Expand,
Shield,
ArrowUpRight,
Package,
Wind,
AlertTriangle,
Ship,
Plane,
} from "lucide-react";
import { Radio, Puzzle, Network, Expand, Shield, ArrowUpRight, Package, Wind, AlertTriangle, Ship, Plane } from "lucide-react";
import SubHero from "../../components/SubHero";
import useFadeIn from "../../hooks/useFadeIn";
const SOLUTION_NAV = [
{ label: "비행상황관리 시스템", to: "/solution/flight-control" },
{ label: "IBE", to: "/solution/ibe" },
{ label: "스마트 관광 예약 플랫폼", to: "/solution/smart-tour" },
{ label: "KT G-cloud 인천총판", to: "/solution/kt-gcloud" },
// { label: " ", to: "/solution/smart-tour" },
// { label: "KT G-cloud ", to: "/solution/kt-gcloud" },
];
const FEATURES = [
@ -100,12 +88,7 @@ const ease = [0.22, 1, 0.36, 1];
function RevealText({ children, delay = 0, className }) {
return (
<div style={{ overflow: "hidden" }}>
<motion.div
className={className}
initial={{ y: "105%", opacity: 0 }}
animate={{ y: "0%", opacity: 1 }}
transition={{ duration: 0.75, ease: [0.22, 1, 0.36, 1], delay }}
>
<motion.div className={className} initial={{ y: "105%", opacity: 0 }} animate={{ y: "0%", opacity: 1 }} transition={{ duration: 0.75, ease: [0.22, 1, 0.36, 1], delay }}>
{children}
</motion.div>
</div>
@ -115,10 +98,7 @@ function RevealText({ children, delay = 0, className }) {
function StaggerWords({ text, delay = 0, className }) {
const words = text.split(" ");
return (
<span
className={className}
style={{ display: "flex", flexWrap: "wrap", gap: "0 .3em" }}
>
<span className={className} style={{ display: "flex", flexWrap: "wrap", gap: "0 .3em" }}>
{words.map((word, i) => (
<span key={i} style={{ overflow: "hidden", display: "inline-block" }}>
<motion.span
@ -168,11 +148,7 @@ function FlightControlPage() {
return (
<article ref={ref}>
<SubHero
label="SOLUTION"
title={<em>Flight Management</em>}
navItems={SOLUTION_NAV}
/>
<SubHero label="SOLUTION" title={<em>Flight Management</em>} navItems={SOLUTION_NAV} />
<div className="sub-content">
<div className="inner-wrap">
@ -245,40 +221,19 @@ function FlightControlPage() {
{/* 개요 인트로 */}
<section className="fc-intro" ref={introRef}>
<div className="fc-intro__left">
<motion.span
className="fc-eyebrow"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<motion.span className="fc-eyebrow" initial={{ opacity: 0, y: 16 }} animate={introInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}>
Overview
</motion.span>
<motion.h2
className="fc-intro__title"
initial={{ opacity: 0, y: 24 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.7, ease, delay: 0.1 }}
>
<motion.h2 className="fc-intro__title" initial={{ opacity: 0, y: 24 }} animate={introInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.7, ease, delay: 0.1 }}>
모든 이동체 정보를
<br />
하나의 플랫폼에서
</motion.h2>
<motion.p
className="fc-intro__desc"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.2 }}
>
항공기, 무인기, 선박, 지상 이동체의 실시간 정보를 통합
모니터링하고 <br />
<motion.p className="fc-intro__desc" initial={{ opacity: 0, y: 16 }} animate={introInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease, delay: 0.2 }}>
항공기, 무인기, 선박, 지상 이동체의 실시간 정보를 통합 모니터링하고 <br />
상황을 인식하여 신속하고 안전한 운영 의사결정을 지원합니다.
</motion.p>
<motion.div
className="fc-intro__icons"
initial={{ opacity: 0, y: 16 }}
animate={introInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease, delay: 0.3 }}
>
<motion.div className="fc-intro__icons" initial={{ opacity: 0, y: 16 }} animate={introInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease, delay: 0.3 }}>
{[
{ img: "fc_aircraft.png", label: "항공기" },
{ img: "fc_drone.png", label: "무인기" },
@ -286,27 +241,15 @@ function FlightControlPage() {
{ img: "fc_car.png", label: "차량 등" },
].map((item, i) => (
<div key={i} className="fc-intro__icon-item">
<img
src={`${basePath}images/${item.img}`}
alt={item.label}
/>
<img src={`${basePath}images/${item.img}`} alt={item.label} />
<span>{item.label}</span>
</div>
))}
</motion.div>
</div>
<motion.div
className="fc-intro__right"
initial={{ opacity: 0, x: 40 }}
animate={introInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.9, ease, delay: 0.15 }}
>
<img
src={`${basePath}images/fc_computer.png`}
alt="비행상황관리 시스템"
className="fc-intro__monitor"
/>
<motion.div className="fc-intro__right" initial={{ opacity: 0, x: 40 }} animate={introInView ? { opacity: 1, x: 0 } : {}} transition={{ duration: 0.9, ease, delay: 0.15 }}>
<img src={`${basePath}images/fc_computer.png`} alt="비행상황관리 시스템" className="fc-intro__monitor" />
</motion.div>
</section>
@ -359,13 +302,7 @@ function FlightControlPage() {
icons: null,
},
].map((item, i) => (
<motion.div
key={i}
className="fc-highlight__item"
initial={{ opacity: 0, y: 40 }}
animate={highlightInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.7, ease, delay: i * 0.15 }}
>
<motion.div key={i} className="fc-highlight__item" initial={{ opacity: 0, y: 40 }} animate={highlightInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.7, ease, delay: i * 0.15 }}>
<div className="fc-highlight__text">
<span className="fc-eyebrow">{item.tag}</span>
<h3 className="fc-highlight__title">
@ -380,11 +317,7 @@ function FlightControlPage() {
</div>
<div className="fc-highlight__img-wrap">
<div className="fc-highlight__img-scene">
<img
src={`${basePath}images/${item.img}`}
alt={item.tag}
className="fc-highlight__tablet"
/>
<img src={`${basePath}images/${item.img}`} alt={item.tag} className="fc-highlight__tablet" />
{item.icons &&
item.icons.map((icon, j) => (
<motion.img
@ -394,11 +327,7 @@ function FlightControlPage() {
className="fc-highlight__float-icon"
style={{ left: icon.x, top: icon.y }}
initial={{ x: 0, y: 0 }}
animate={
highlightInView
? { x: icon.move.x[1], y: icon.move.y[1] }
: { x: 0, y: 0 }
}
animate={highlightInView ? { x: icon.move.x[1], y: icon.move.y[1] } : { x: 0, y: 0 }}
transition={{
duration: 2.5,
repeat: 0,
@ -410,30 +339,9 @@ function FlightControlPage() {
{i === 1 && (
<>
<motion.img
src={`${basePath}images/fc_left_tab.png`}
alt=""
className="fc-situation__left"
initial={{ opacity: 0, x: -30 }}
animate={highlightInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8, ease, delay: 0.3 }}
/>
<motion.img
src={`${basePath}images/fc_right_tab.png`}
alt=""
className="fc-situation__right"
initial={{ opacity: 0, x: 30 }}
animate={highlightInView ? { opacity: 1, x: 0 } : {}}
transition={{ duration: 0.8, ease, delay: 0.5 }}
/>
<motion.img
src={`${basePath}images/fc_bottom_tab.png`}
alt=""
className="fc-situation__bottom"
initial={{ opacity: 0, y: 30 }}
animate={highlightInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.8, ease, delay: 0.7 }}
/>
<motion.img src={`${basePath}images/fc_left_tab.png`} alt="" className="fc-situation__left" initial={{ opacity: 0, x: -30 }} animate={highlightInView ? { opacity: 1, x: 0 } : {}} transition={{ duration: 0.8, ease, delay: 0.3 }} />
<motion.img src={`${basePath}images/fc_right_tab.png`} alt="" className="fc-situation__right" initial={{ opacity: 0, x: 30 }} animate={highlightInView ? { opacity: 1, x: 0 } : {}} transition={{ duration: 0.8, ease, delay: 0.5 }} />
<motion.img src={`${basePath}images/fc_bottom_tab.png`} alt="" className="fc-situation__bottom" initial={{ opacity: 0, y: 30 }} animate={highlightInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.8, ease, delay: 0.7 }} />
</>
)}
</div>
@ -444,13 +352,7 @@ function FlightControlPage() {
{/* 2. 수치 지표 */}
<section className="fc-stats" ref={statsRef}>
{STATS.map(({ value, label }, i) => (
<motion.div
key={label}
className="fc-stat-item"
initial={{ opacity: 0, y: 24 }}
animate={statsInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.55, ease, delay: 0.08 * i }}
>
<motion.div key={label} className="fc-stat-item" initial={{ opacity: 0, y: 24 }} animate={statsInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.55, ease, delay: 0.08 * i }}>
<span className="fc-stat-item__value">{value}</span>
<span className="fc-stat-item__label">{label}</span>
</motion.div>
@ -459,24 +361,12 @@ function FlightControlPage() {
{/* 3. 적용 분야 */}
<section className="fc-domains" ref={domainsRef}>
<motion.span
className="fc-section-title"
initial={{ opacity: 0, y: 20 }}
animate={domainsInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<motion.span className="fc-section-title" initial={{ opacity: 0, y: 20 }} animate={domainsInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}>
적용 분야
</motion.span>
<div className="fc-domains__grid">
{DOMAINS.map(({ icon: Icon, label, desc }, i) => (
<motion.div
key={label}
className="fc-domain-card"
initial={{ opacity: 0, y: 24 }}
animate={domainsInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.55, ease, delay: 0.07 * i }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
>
<motion.div key={label} className="fc-domain-card" initial={{ opacity: 0, y: 24 }} animate={domainsInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.55, ease, delay: 0.07 * i }} whileHover={{ y: -4, transition: { duration: 0.2 } }}>
<div className="fc-domain-card__icon">
<Icon size={22} strokeWidth={1.5} />
</div>
@ -489,79 +379,31 @@ function FlightControlPage() {
{/* 4. 주요기능 */}
<section className="fc-functions" ref={funcRef}>
<motion.span
className="fc-section-title"
initial={{ opacity: 0, y: 20 }}
animate={funcInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<motion.span className="fc-section-title" initial={{ opacity: 0, y: 20 }} animate={funcInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}>
주요기능
</motion.span>
<div className="fc-functions__body">
<ul className="fc-func-list">
{FUNCTIONS.map(({ num, label }, i) => (
<motion.li
key={num}
className={`fc-func-item${activeIdx === i ? " is-active" : ""}`}
onMouseEnter={() => setActiveIdx(i)}
initial={{ opacity: 0, y: 16 }}
animate={funcInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, ease, delay: 0.05 * i }}
>
<motion.li key={num} className={`fc-func-item${activeIdx === i ? " is-active" : ""}`} onMouseEnter={() => setActiveIdx(i)} initial={{ opacity: 0, y: 16 }} animate={funcInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.5, ease, delay: 0.05 * i }}>
<span className="fc-func-item__num">{num}</span>
<span className="fc-func-item__label">{label}</span>
<motion.span
className="fc-func-item__arrow"
initial={{ opacity: 0, x: -6 }}
animate={
activeIdx === i
? { opacity: 1, x: 0 }
: { opacity: 0, x: -6 }
}
transition={{ duration: 0.2 }}
>
<motion.span className="fc-func-item__arrow" initial={{ opacity: 0, x: -6 }} animate={activeIdx === i ? { opacity: 1, x: 0 } : { opacity: 0, x: -6 }} transition={{ duration: 0.2 }}>
<ArrowUpRight size={16} strokeWidth={1.5} />
</motion.span>
<motion.div
className="fc-func-item__line"
animate={{ scaleX: activeIdx === i ? 1 : 0 }}
transition={{ duration: 0.35, ease }}
/>
<motion.div className="fc-func-item__line" animate={{ scaleX: activeIdx === i ? 1 : 0 }} transition={{ duration: 0.35, ease }} />
</motion.li>
))}
</ul>
<div className="fc-func-display">
<AnimatePresence mode="wait">
<motion.div
key={activeIdx}
className="fc-func-display__inner"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.35, ease: "easeInOut" }}
>
<img
src={FUNCTIONS[activeIdx].img}
alt={FUNCTIONS[activeIdx].label}
className="fc-func-display__img"
/>
<motion.div key={activeIdx} className="fc-func-display__inner" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.35, ease: "easeInOut" }}>
<img src={FUNCTIONS[activeIdx].img} alt={FUNCTIONS[activeIdx].label} className="fc-func-display__img" />
<div className="fc-func-display__caption">
<motion.span
key={`num-${activeIdx}`}
className="fc-func-display__num"
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25 }}
>
<motion.span key={`num-${activeIdx}`} className="fc-func-display__num" initial={{ opacity: 0, y: 6 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.25 }}>
{FUNCTIONS[activeIdx].num}
</motion.span>
<motion.span
key={`label-${activeIdx}`}
className="fc-func-display__label"
initial={{ opacity: 0, y: 6 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.25, delay: 0.05 }}
>
<motion.span key={`label-${activeIdx}`} className="fc-func-display__label" initial={{ opacity: 0, y: 6 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.25, delay: 0.05 }}>
{FUNCTIONS[activeIdx].label}
</motion.span>
</div>
@ -573,23 +415,12 @@ function FlightControlPage() {
{/* 5. 시스템 구성 흐름 */}
<section className="fc-flow" ref={flowRef}>
<motion.span
className="fc-section-title"
initial={{ opacity: 0, y: 20 }}
animate={flowInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<motion.span className="fc-section-title" initial={{ opacity: 0, y: 20 }} animate={flowInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}>
시스템 구성
</motion.span>
<div className="fc-flow__row">
{FLOW.map(({ step, label, desc }, i) => (
<motion.div
key={step}
className="fc-flow__item"
initial={{ opacity: 0, y: 20 }}
animate={flowInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.5, ease, delay: 0.08 * i }}
>
<motion.div key={step} className="fc-flow__item" initial={{ opacity: 0, y: 20 }} animate={flowInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.5, ease, delay: 0.08 * i }}>
<span className="fc-flow__step">{step}</span>
<span className="fc-flow__label">{label}</span>
<p className="fc-flow__desc">{desc}</p>

Loading…
Cancel
Save