From fa8fedcb3bd0fc19cf40bbc7a100bbac7bbc0e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?siyeon00=28=EC=9D=B4=EC=8B=9C=EC=97=B0=29?= Date: Wed, 10 Jun 2026 14:46:45 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=EC=86=94=EB=A3=A8=EC=85=98=20?= =?UTF-8?q?=EC=B9=B4=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/MainSolution.jsx | 282 ++++++++++++++++++++++----- src/css/main.css | 130 +++++++++--- 2 files changed, 345 insertions(+), 67 deletions(-) diff --git a/src/components/main/MainSolution.jsx b/src/components/main/MainSolution.jsx index a510a78..5adcd16 100644 --- a/src/components/main/MainSolution.jsx +++ b/src/components/main/MainSolution.jsx @@ -1,42 +1,234 @@ -import { useEffect, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { gsap } from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; +import { Link } from "react-router-dom"; gsap.registerPlugin(ScrollTrigger); +const BARS = [ + { label: "월", h: 45 }, + { label: "화", h: 60 }, + { label: "수", h: 50 }, + { label: "목", h: 75 }, + { label: "금", h: 65 }, + { label: "토", h: 85 }, + { label: "일", h: 100, active: true }, +]; + +function FlightMockup({ animate }) { + const cnt1Ref = useRef(null); + const cnt2Ref = useRef(null); + const cnt3Ref = useRef(null); + const row1Ref = useRef(null); + const row2Ref = useRef(null); + const barsRef = useRef([]); + + useEffect(() => { + if (!animate) return; + + function countUp(el, target, duration) { + let start = 0; + const step = target / (duration / 16); + const t = setInterval(() => { + start = Math.min(start + step, target); + el.textContent = Math.round(start); + if (start >= target) clearInterval(t); + }, 16); + return t; + } + + const timers = []; + + // 카운트업 + timers.push(countUp(cnt1Ref.current, 24, 800)); + timers.push(countUp(cnt2Ref.current, 138, 1000)); + timers.push(countUp(cnt3Ref.current, 7, 600)); + + // row 페이드인 + [row1Ref.current, row2Ref.current].forEach((r, i) => { + const t = setTimeout(() => { + r.style.opacity = "1"; + r.style.transform = "translateY(0)"; + }, i * 200); + timers.push(t); + }); + + // 차트 막대 + barsRef.current.forEach((b, i) => { + const t = setTimeout( + () => { + if (b) b.style.transform = "scaleY(1)"; + }, + 400 + i * 80, + ); + timers.push(t); + }); + + return () => timers.forEach(clearTimeout); + }, [animate]); + return ( +
+
+ + + + 실시간 운항 현황 + 운항 중 24 +
+
+
+
+ 0 +
+
운항 중
+
+
+
+ 0 +
+
완료
+
+
+
+ 0 +
+
대기
+
+
+
+
+
ICN → LAX
+
+ KE-201 · 08:30 출발 · 이코노미 +
+
+
+
11,000m
+
현재 고도
+
+
+
+
+
GMP → CJU
+
OZ-104 · 09:15 출발
+
+
+
6,500m
+
현재 고도
+
+
+
+
+ 일별 운항 편수 + 최근 7일 +
+
+ {BARS.map((b, i) => ( +
+
{ + barsRef.current[i] = el; + }} + /> +
+ {b.label} +
+
+ ))} +
+
+
+ ); +} + +function BookingMockup({ animate }) { + const priceRef = useRef(null); + + useEffect(() => { + if (!animate) return; + + let val = 0; + const target = 892000; + const step = target / 40; + + const t = setInterval(() => { + val = Math.min(val + step, target); + if (priceRef.current) + priceRef.current.textContent = "₩" + Math.round(val).toLocaleString(); + if (val >= target) clearInterval(t); + }, 20); + + return () => clearInterval(t); + }, [animate]); + + return ( +
+
+ + + + 결제 정보 확인 + + 3 / 3 단계 + +
+
+
+
ICN → LAX
+
+ KE-201 · 2025.08.14 · 성인 1명 +
+
+
+ ₩0 +
+
+
+
+
+
+
4521 •••• •••• 3847
+
+
KIM CHULSOO
+
08/27
+
+
+
+
+
+ 최종 결제금액 + ₩ 892,000 +
+
결제하기
+
+ ); +} function MainSolution() { const sectionRef = useRef(null); const headRef = useRef(null); const cardsRef = useRef([]); + const [animate, setAnimate] = useState(false); const solutions = [ { - icon: "/PALNetworks/images/airplane.png", label: "SOLUTION 01", title: "비행상황관리 시스템", desc: "운항 상태, 항로, 고도, 비행 이력을 실시간으로 확인하고 관리합니다.", + mockup: "flight", + link: "/solution/flight-control", }, { - icon: "/PALNetworks/images/cloud-network.png", label: "SOLUTION 02", - title: ( - <> - IBE - (Internet Booking Engine) - - ), + title: "IBE", desc: "항공 예약과 판매 흐름을 연결해 편리한 예약 환경을 제공합니다.", - }, - { - icon: "/PALNetworks/images/maps.png", - label: "SOLUTION 03", - title: "스마트 관광 예약 플랫폼", - desc: "관광 상품과 예약 데이터를 통합해 사용자 중심 서비스를 구성합니다.", - }, - { - icon: "/PALNetworks/images/cloud.png", - label: "SOLUTION 04", - title: "KT G-Cloud", - desc: "공공 클라우드 기반의 안정적인 인프라 운영 환경을 제공합니다.", + mockup: "booking", + link: "/solution/ibe", }, ]; @@ -52,6 +244,9 @@ function MainSolution() { start: "top 72%", end: "top 28%", scrub: 1, + once: true, + onEnter: () => setAnimate(true), + onLeaveBack: () => setAnimate(false), }, }) .to(headRef.current, { @@ -72,18 +267,6 @@ function MainSolution() { }, "-=0.35", ); - - gsap.to(".main-solution-bg-circle", { - y: 120, - scale: 1.08, - ease: "none", - scrollTrigger: { - trigger: sectionRef.current, - start: "top bottom", - end: "bottom top", - scrub: 1, - }, - }); }, sectionRef); return () => ctx.revert(); @@ -92,7 +275,6 @@ function MainSolution() { return (
-

PAL SOLUTION

@@ -110,23 +292,33 @@ function MainSolution() {
{solutions.map((item, index) => (
{ cardsRef.current[index] = el; }} > -
- {typeof item.icon === "string" && item.icon.includes(".png") ? ( - - ) : ( - item.icon - )} +
+ {item.label} +

+ {item.title} + {item.titleSub && ( + + {item.titleSub} + + )} +

+

{item.desc}

+ + 자세히 보기{" "} + +
-
- {item.label} -

{item.title}

-

{item.desc}

+
+ {item.mockup === "flight" && } + {item.mockup === "booking" && ( + + )}
))} diff --git a/src/css/main.css b/src/css/main.css index a83c124..afb7343 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -283,34 +283,120 @@ body{overflow-x:hidden;} @keyframes float-UTM{0%{transform:translateY(0px);}48%{transform:translateY(-1px);}100%{transform:translateY(0px);}} /* solution */ -.main-solution-section{position:relative;height:100dvh;min-height:100dvh;overflow:hidden;padding:120px 8vw 110px;background:linear-gradient(180deg,#ffffff 0%,#f7f9ff 52%,#ffffff 100%);} +.main-solution-section{position:relative;height:auto;min-height:100dvh;overflow:visible;padding:120px 8vw 160px;background:linear-gradient(180deg,#ffffff 0%,#f7f9ff 52%,#ffffff 100%);} .main-solution-section::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 8% 10%,rgba(26,31,94,.045),transparent 30%),radial-gradient(circle at 86% 76%,rgba(112,180,255,.08),transparent 34%);pointer-events:none;} .main-solution-inner{position:relative;z-index:2;max-width:1660px;margin:0 auto;} .main-solution-arrow{width:42px;height:42px;margin:0 auto 46px;display:flex;align-items:center;justify-content:center;font-size:34px;line-height:1;color:#1a1f5e;opacity:.82;} .main-solution-head{max-width:760px;margin-bottom:54px;will-change:transform,opacity;} -.main-solution-eyebrow{margin:0 0 16px;font-size:12px;font-weight:800;letter-spacing:.24em;color:#1a1f5e;} +.main-solution-eyebrow { margin: 0 0 16px; font-size: 12px; font-weight: 800; letter-spacing: .24em; color: #9333ea; opacity: 0.75; } .main-solution-title{margin:0;font-size:clamp(42px,5vw,76px);font-weight:800;line-height:1.02;letter-spacing:-.07em;color:#10142b;} .main-solution-desc{margin:24px 0 0;max-width:620px;font-size:17px;line-height:1.8;font-weight:500;color:rgba(16,20,43,.62);word-break:keep-all;} -.main-solution-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px;} - -.main-solution-card{position:relative;min-height:250px;padding:28px 26px;border-radius:28px;background:rgba(255,255,255,.72);border:1px solid rgba(255,255,255,.72);box-shadow:0 20px 60px rgba(26,31,94,.08),inset 0 1px 0 rgba(255,255,255,.9);backdrop-filter:blur(18px);transition:transform .42s cubic-bezier(.22,1,.36,1),box-shadow .42s cubic-bezier(.22,1,.36,1),border-color .3s ease,background .3s ease;will-change:transform;overflow:hidden;cursor:pointer;} -.main-solution-card:hover{transform:translateY(-14px);background:#1a1f5e;border-color:#1a1f5e;box-shadow:0 42px 100px rgba(26,31,94,.22),inset 0 1px 0 rgba(255,255,255,.08);} -.main-solution-card:hover .main-solution-card-body span{color:rgba(255,255,255,.55);} -.main-solution-card:hover .main-solution-card-body h3{color:#fff;} -.main-solution-card:hover .main-solution-card-body p{color:rgba(255,255,255,.6);} -.main-solution-card:hover .main-solution-card-icon{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.18);box-shadow:none;} -.main-solution-card:hover .main-solution-card-icon img{filter:brightness(0) invert(1);} - -.main-solution-card-icon{width:58px;height:58px;border-radius:18px;display:flex;align-items:center;justify-content:center;margin-bottom:34px;background:linear-gradient(180deg,rgba(255,255,255,.92),rgba(245,247,255,.82));border:1px solid rgba(95,110,255,.12);box-shadow:0 10px 24px rgba(26,31,94,.08),inset 0 1px 0 rgba(255,255,255,.95);transition:transform .38s cubic-bezier(.22,1,.36,1),border-color .3s ease,box-shadow .3s ease,background .3s ease;} -.main-solution-card-icon img{width:28px;height:28px;object-fit:contain;display:block;} -.main-solution-card-body{position:relative;z-index:2;} -.main-solution-card-body span{display:block;margin-bottom:14px;font-size:11px;font-weight:800;letter-spacing:.14em;color:#1a1f5e;} -.main-solution-card-body h3{margin:0 0 14px;font-size:24px;font-weight:800;line-height:1.2;letter-spacing:-.05em;color:#10142b;word-break:keep-all;} -.main-solution-card-body p{margin:0;font-size:15px;font-weight:500;line-height:1.7;color:rgba(16,20,43,.58);word-break:keep-all;} - -@media (max-width:1200px){.main-solution-section{height:auto;min-height:100dvh;padding:110px 6vw 100px;}.main-solution-head{max-width:680px;margin-bottom:44px;}.main-solution-title{font-size:clamp(40px,5.8vw,66px);}.main-solution-grid{grid-template-columns:repeat(2,1fr);gap:18px;}.main-solution-card{min-height:230px;}} -@media (max-width:768px){.main-solution-section{height:auto;min-height:auto;padding:86px 6vw 78px;overflow:hidden;}.main-solution-inner{max-width:100%;}.main-solution-head{max-width:100%;margin-bottom:34px;}.main-solution-eyebrow{margin-bottom:12px;font-size:11px;letter-spacing:.2em;}.main-solution-title{font-size:clamp(34px,10vw,48px);line-height:1.08;letter-spacing:-.06em;}.main-solution-desc{margin-top:18px;font-size:14px;line-height:1.75;}.main-solution-grid{grid-template-columns:1fr;gap:14px;}.main-solution-card{min-height:auto;padding:24px 22px;border-radius:24px;}.main-solution-card:hover{transform:translateY(-6px);}.main-solution-card-icon{width:52px;height:52px;margin-bottom:24px;border-radius:16px;}.main-solution-card-icon img{width:25px;height:25px;}.main-solution-card-body span{margin-bottom:10px;font-size:10px;letter-spacing:.13em;}.main-solution-card-body h3{font-size:21px;line-height:1.25;}.main-solution-card-body h3 small{font-size:12px;}.main-solution-card-body p{font-size:14px;line-height:1.7;}} -@media (max-width:480px){.main-solution-section{padding:72px 5vw 64px;}.main-solution-title{font-size:clamp(32px,11vw,42px);}.main-solution-desc{font-size:13.5px;}.main-solution-card{padding:22px 20px;border-radius:22px;}.main-solution-card-icon{width:48px;height:48px;margin-bottom:22px;}.main-solution-card-body h3{font-size:20px;}.main-solution-card-body p{font-size:13.5px;}} + +.main-solution-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; } +.main-solution-card { border-radius: 24px; background: #fff; border: 1px solid rgba(26,31,94,0.08); overflow: hidden; display: flex; flex-direction: column; box-shadow: 0 8px 40px rgba(26,31,94,0.07); } +.main-solution-card-top { padding: 28px 28px 20px; min-height: 180px; display: flex; flex-direction: column; } +.main-solution-card-link { display: inline-flex; align-items: center; gap: 6px; margin-top: auto; padding-top: 16px; font-size: 13px; font-weight: 700; color: #1a1f5e; text-decoration: none; transition: gap 0.2s ease; } +.main-solution-card-link:hover { gap: 10px; } +.main-solution-card-link__arrow { font-size: 14px; transition: transform 0.2s ease; } +.main-solution-card-link:hover .main-solution-card-link__arrow { transform: translateX(3px); } +.main-solution-card-label { display: block; font-size: 11px; font-weight: 700; letter-spacing: .18em; color: #6366F1; margin-bottom: 8px; } +.main-solution-card-title { font-size: 22px; font-weight: 800; color: #10142b; letter-spacing: -.04em; margin: 0 0 10px; line-height: 1.2; } +.main-solution-card-title-sub { display: block; font-size: 13px; font-weight: 500; color: rgba(16,20,43,.42); letter-spacing: 0; margin-top: 4px; } +.main-solution-card-desc { font-size: 14px; color: rgba(16,20,43,.55); line-height: 1.75; margin: 0; } +.main-solution-card-mockup { background: #f4f6fc; border-top: 1px solid rgba(26,31,94,0.07); flex: 1; overflow: hidden; position: relative; min-height: 380px; padding: 20px 20px 0; display: flex; align-items: flex-start; justify-content: center; } +.main-solution-card-mockup::after { content: ""; position: absolute; bottom: 0; left: 0; right: 0; height: 80px; background: linear-gradient(to bottom, transparent, #f4f6fc); pointer-events: none; } + +/* mock 공통 */ +.mock-win { background: #fff; border: 1px solid rgba(26,31,94,0.09); border-radius: 12px 12px 0 0; width: 100%; overflow: hidden; box-shadow: 0 4px 24px rgba(26,31,94,0.08); } + +.mock-win__bar { display: flex; align-items: center; gap: 5px; padding: 9px 14px; border-bottom: 1px solid rgba(26,31,94,0.07); } + +.mock-win__title { font-size: 11px; color: rgba(16,20,43,.4); margin-left: 8px; flex: 1; } + +.mock-win__badge { font-size: 10px; padding: 2px 8px; border-radius: 20px; background: rgba(139,92,246,0.07); color: #6d28d9; font-weight: 600; } + +.mock-win__badge--blue { background: rgba(99,102,241,0.07); color: #4338ca; } + +.mock-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; } +.mock-dot--red { background: #ef4444; } +.mock-dot--yellow { background: #eab308; } +.mock-dot--green { background: #22c55e; } + +/* stats */ +.mock-stat-chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; padding: 12px; } + +.mock-chip { background: #f4f6fc; border-radius: 8px; padding: 10px 12px; text-align: center; } + +.mock-chip__val { font-size: 18px; font-weight: 700; color: #10142b; } + +.mock-chip__label { font-size: 10px; color: rgba(16,20,43,.4); margin-top: 3px; } + +/* flight rows */ +.mock-flight-row { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-top: 1px solid rgba(26,31,94,0.06); } +.mock-flight-row--active { background: rgba(139,92,246,0.04); border-left: 3px solid rgba(139,92,246,0.5); } +.mock-flight-row__route { font-size: 14px; font-weight: 700; color: #10142b; margin-bottom: 3px; } +.mock-flight-row__info { font-size: 10px; color: rgba(16,20,43,.4); } +.mock-flight-row__right { text-align: right; } +.mock-flight-row__alt { font-size: 16px; font-weight: 700; color: #10142b; } +.mock-flight-row__altlabel { font-size: 10px; color: rgba(16,20,43,.38); margin-top: 2px; } +.mock-flight-row--anim { opacity: 0; transform: translateY(8px); transition: opacity 0.4s ease, transform 0.4s ease; } + +/* 차트 */ +.mock-chart { padding: 14px 16px 0; border-top: 1px solid rgba(26,31,94,0.06); } +.mock-chart__head { display: flex; justify-content: space-between; font-size: 10px; color: rgba(16,20,43,.4); margin-bottom: 10px; } +.mock-chart__bars { display: flex; align-items: flex-end; gap: 5px; height: 64px; } +.mock-chart__bar-wrap { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; height: 100%; justify-content: flex-end; } +.mock-chart__bar { width: 100%; border-radius: 3px 3px 0 0; background: #ede9fe; } +.mock-chart__bar--active { background: rgba(109,40,217,0.6); } +.mock-chart__bar-label { font-size: 9px; color: rgba(16,20,43,.35); } +.mock-chart__bar-label--active { color: rgba(109,40,217,0.7); font-weight: 600; } +.mock-chart__bar--anim { transform: scaleY(0); transform-origin: bottom; transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1); } + +/* booking */ +.mock-ticket { margin: 14px 16px; background: #f4f6fc; border-radius: 10px; padding: 12px 14px; display: flex; align-items: center; justify-content: space-between; } + +.mock-ticket__route { font-size: 14px; font-weight: 700; color: #10142b; } + +.mock-ticket__info { font-size: 10px; color: rgba(16,20,43,.4); margin-top: 3px; } + +.mock-ticket__price { font-size: 16px; font-weight: 700; color: #6d28d9; opacity: 0.85; } +.mock-card-wrap { margin: 0 16px 12px; perspective: 800px; } +.mock-card-inner { position: relative; height: 100px; transform-style: preserve-3d; transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1); } +.mock-card-inner.flipped { transform: rotateY(180deg); } +.mock-card-front, .mock-card-back { position: absolute; inset: 0; border-radius: 10px; backface-visibility: hidden; padding: 14px 16px; display: flex; flex-direction: column; } +.mock-card-front { background: linear-gradient(135deg, #312e81 0%, #1e1b4b 100%); justify-content: space-between; } +.mock-card-back { background: linear-gradient(135deg, #1e1b4b 0%, #312e81 100%); transform: rotateY(180deg); align-items: center; justify-content: center; gap: 6px; } +.mock-card-cvv-label { font-size: 10px; color: rgba(255,255,255,0.5); } +.mock-card-cvv { font-size: 20px; font-weight: 700; color: #fff; letter-spacing: .2em; } +.mock-card-area { margin: 0 16px 12px; } +.mock-card-label { font-size: 10px; color: rgba(16,20,43,.4); margin-bottom: 6px; } +.mock-card-visual { background: linear-gradient(135deg, #312e81 0%, #1e1b4b 100%); border-radius: 10px; padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; } +.mock-card-chip { width: 24px; height: 18px; background: #f0c040; border-radius: 3px; } +.mock-card-num { font-size: 13px; font-weight: 600; color: rgba(255,255,255,0.9); letter-spacing: .15em; } +.mock-card-bottom { display: flex; justify-content: space-between; } +.mock-card-name { font-size: 10px; color: rgba(255,255,255,0.6); } +.mock-card-exp { font-size: 10px; color: rgba(255,255,255,0.6); } +.mock-price-row { display: flex; justify-content: space-between; align-items: center; padding: 10px 16px; border-top: 1px solid rgba(26,31,94,0.07); } +.mock-price-label { font-size: 12px; font-weight: 600; color: #10142b; } +.mock-price-val { font-size: 15px; font-weight: 700; color: #6d28d9; opacity: 0.85; } +.mock-pay-btn { margin: 10px 16px 14px; background: linear-gradient(135deg, #1e1b4b 0%, #4c1d95 100%); border-radius: 8px; padding: 11px; text-align: center; font-size: 13px; font-weight: 700; color: #fff; } +.mock-flight-card--active { background: rgba(168,85,247,0.06); border-left: 3px solid #a855f7; } +.mock-flight-card__price { color: #7c3aed; } + + +/* 반응형 */ +@media (max-width: 768px) { + .main-solution-grid { grid-template-columns: 1fr; gap: 16px; } + .main-solution-card-top { padding: 22px 22px 16px; min-height: auto; } + .main-solution-card-title { font-size: 20px; } + .main-solution-card-mockup { min-height: 260px; } +} + +@media (max-width: 480px) { + .main-solution-card-top { padding: 18px 18px 14px; } + .main-solution-card-title { font-size: 18px; } + .main-solution-card-mockup { min-height: 220px; padding: 16px 16px 0; } +} /* News */ .main-news-section{position:relative;min-height:100vh;padding:130px 8vw;background:#ffffff;overflow:hidden;} .main-news-section::before{content:"";position:absolute;left:-18vw;bottom:-24vw;width:52vw;height:52vw;border-radius:50%;background:radial-gradient(circle,rgba(26,31,94,.08),transparent 70%);filter:blur(18px);pointer-events:none;}