Browse Source

max-width 값 변경

remotes/origin/main
김지은 4 weeks ago
parent
commit
320e1b2c58
  1. BIN
      public/images/test111.png
  2. 2
      src/css/footer.css
  3. 6
      src/css/header.css
  4. 10
      src/css/main.css
  5. 173
      src/pages/solution/FlightControlPage.jsx

BIN
public/images/test111.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

2
src/css/footer.css

@ -1,5 +1,5 @@
.site-footer{background:#0a0a0a;color:rgba(255,255,255,.55);} .site-footer{background:#0a0a0a;color:rgba(255,255,255,.55);}
.footer-inner{max-width:1440px;margin:0 auto;padding:60px 40px 28px;} .footer-inner{max-width:1660px;margin:0 auto;padding:60px 40px 28px;}
.footer-top{display:grid;grid-template-columns:1.2fr 3.8fr;gap:40px;padding-bottom:36px;border-bottom:1px solid rgba(255,255,255,.08);}.footer-logo{display:inline-block;width:fit-content;} .footer-top{display:grid;grid-template-columns:1.2fr 3.8fr;gap:40px;padding-bottom:36px;border-bottom:1px solid rgba(255,255,255,.08);}.footer-logo{display:inline-block;width:fit-content;}
.footer-logo{min-width:200px} .footer-logo{min-width:200px}

6
src/css/header.css

@ -10,7 +10,7 @@ body.is-sub .pal-header.is-scrolled:not(.is-open)::before{opacity:0;}
body.is-sub .pal-header.is-scrolled:not(.is-open) .pal-header-inner{height:64px;background:rgba(255,255,255,.92);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border-radius:20px;border:1px solid rgba(17,17,17,.07);box-shadow:0 8px 32px rgba(15,23,42,.1);padding:0 28px;} body.is-sub .pal-header.is-scrolled:not(.is-open) .pal-header-inner{height:64px;background:rgba(255,255,255,.92);backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);border-radius:20px;border:1px solid rgba(17,17,17,.07);box-shadow:0 8px 32px rgba(15,23,42,.1);padding:0 28px;}
body.is-sub .pal-header.is-scrolled:not(.is-open) .pal-header-logo img{width:140px;} body.is-sub .pal-header.is-scrolled:not(.is-open) .pal-header-logo img{width:140px;}
.pal-header-inner{position:relative;display:flex;align-items:center;justify-content:space-between;max-width:1440px;height:96px;margin:0 auto;z-index:2;transition:height .4s cubic-bezier(.22,1,.36,1),background .4s cubic-bezier(.22,1,.36,1),border-radius .4s cubic-bezier(.22,1,.36,1),box-shadow .4s cubic-bezier(.22,1,.36,1),padding .4s cubic-bezier(.22,1,.36,1);} .pal-header-inner{position:relative;display:flex;align-items:center;justify-content:space-between;max-width:1660px;height:96px;margin:0 auto;z-index:2;transition:height .4s cubic-bezier(.22,1,.36,1),background .4s cubic-bezier(.22,1,.36,1),border-radius .4s cubic-bezier(.22,1,.36,1),box-shadow .4s cubic-bezier(.22,1,.36,1),padding .4s cubic-bezier(.22,1,.36,1);}
.pal-header-logo{flex:0 0 auto;margin:0;font-size:0;line-height:1;} .pal-header-logo{flex:0 0 auto;margin:0;font-size:0;line-height:1;}
.pal-header-logo a{display:inline-flex;align-items:center;font-size:28px;font-weight:800;line-height:1;color:#111;text-decoration:none;letter-spacing:-0.03em;} .pal-header-logo a{display:inline-flex;align-items:center;font-size:28px;font-weight:800;line-height:1;color:#111;text-decoration:none;letter-spacing:-0.03em;}
.pal-header-logo img{width:160px;display:block;transition:width .4s cubic-bezier(.22,1,.36,1);} .pal-header-logo img{width:160px;display:block;transition:width .4s cubic-bezier(.22,1,.36,1);}
@ -50,7 +50,7 @@ body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-ope
.pal-mega-panel.is-visible{pointer-events:auto;opacity:1;visibility:visible;} .pal-mega-panel.is-visible{pointer-events:auto;opacity:1;visibility:visible;}
.pal-mega-panel::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,.96);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-top:1px solid rgba(17,17,17,.06);box-shadow:0 24px 50px rgba(15,23,42,.08);} .pal-mega-panel::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,.96);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);border-top:1px solid rgba(17,17,17,.06);box-shadow:0 24px 50px rgba(15,23,42,.08);}
.pal-mega-panel-inner{position:relative;display:grid;grid-template-columns:360px 1fr;gap:40px;max-width:1440px;margin:0 auto;padding:24px 40px 28px;z-index:1;} .pal-mega-panel-inner{position:relative;display:grid;grid-template-columns:360px 1fr;gap:40px;max-width:1660px;margin:0 auto;padding:24px 40px 28px;z-index:1;}
.pal-mega-panel-intro{display:flex;flex-direction:column;justify-content:space-between;min-height:340px;padding:32px;border:1px solid rgba(17,17,17,.06);border-radius:32px;background:linear-gradient(180deg,var(--color-primary-soft-strong) 0%,rgba(26,31,94,.05) 100%);box-shadow:0 24px 50px rgba(15,23,42,.08);} .pal-mega-panel-intro{display:flex;flex-direction:column;justify-content:space-between;min-height:340px;padding:32px;border:1px solid rgba(17,17,17,.06);border-radius:32px;background:linear-gradient(180deg,var(--color-primary-soft-strong) 0%,rgba(26,31,94,.05) 100%);box-shadow:0 24px 50px rgba(15,23,42,.08);}
.pal-mega-panel-eyebrow{display:inline-block;margin-bottom:14px;font-size:13px;font-weight:700;line-height:1.2;color:var(--color-primary);letter-spacing:.08em;text-transform:uppercase;} .pal-mega-panel-eyebrow{display:inline-block;margin-bottom:14px;font-size:13px;font-weight:700;line-height:1.2;color:var(--color-primary);letter-spacing:.08em;text-transform:uppercase;}
@ -147,7 +147,7 @@ body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-ope
.pal-mobile-lang-btn:hover{color:#111;} .pal-mobile-lang-btn:hover{color:#111;}
.pal-mobile-lang-btn.is-active{background:#111;color:#fff;} .pal-mobile-lang-btn.is-active{background:#111;color:#fff;}
@media (max-width:1440px){ @media (max-width:1660px){
.pal-header-inner{padding:0 24px;} .pal-header-inner{padding:0 24px;}
.pal-mega-panel-inner{padding:24px 24px 24px;} .pal-mega-panel-inner{padding:24px 24px 24px;}
} }

10
src/css/main.css

@ -21,7 +21,7 @@ body{overflow-x:hidden;}
.main-page{width:100%;overflow:hidden;} .main-page{width:100%;overflow:hidden;}
.main-section{position:relative;height:100vh;} .main-section{position:relative;height:100vh;}
.main-bg-wrap{position:relative;width:100%;height:100vh;display:flex;align-items:flex-start;justify-content:center;overflow:hidden;} .main-bg-wrap{position:relative;width:100%;height:100vh;display:flex;align-items:flex-start;justify-content:center;overflow:hidden;}
.main-bg{position:relative;width:min(1440px,calc(100vw - 80px));height:750px;border-radius:24px;overflow:hidden;transform-origin:center center;will-change:transform,width,height,border-radius;background:#050b17;} .main-bg{position:relative;width:min(1660px,calc(100vw - 80px));height:750px;border-radius:24px;overflow:hidden;transform-origin:center center;will-change:transform,width,height,border-radius;background:#050b17;}
.main-bg-hero1{position:absolute;inset:0;background:url('/images/hero1.png') no-repeat 50% 50%/cover;transform:scale(1.04);} .main-bg-hero1{position:absolute;inset:0;background:url('/images/hero1.png') no-repeat 50% 50%/cover;transform:scale(1.04);}
@ -124,7 +124,7 @@ body{overflow-x:hidden;}
.main-utm-bg-glow--a{width:520px;height:520px;top:-160px;right:-120px;background:rgba(26,31,94,.13);} .main-utm-bg-glow--a{width:520px;height:520px;top:-160px;right:-120px;background:rgba(26,31,94,.13);}
.main-utm-bg-glow--b{width:460px;height:460px;left:-140px;bottom:-160px;background:rgba(112,180,255,.12);} .main-utm-bg-glow--b{width:460px;height:460px;left:-140px;bottom:-160px;background:rgba(112,180,255,.12);}
.main-utm-inner{position:relative;z-index:2;width:min(1440px,calc(100% - 120px));min-height:calc(100vh - 86px);margin:0 auto;padding-top:72px;padding-bottom:64px;} .main-utm-inner{position:relative;z-index:2;width:min(1660px,calc(100% - 120px));min-height:calc(100vh - 86px);margin:0 auto;padding-top:72px;padding-bottom:64px;}
.main-utm-head{position:relative;z-index:5;max-width:820px;margin-bottom:64px;} .main-utm-head{position:relative;z-index:5;max-width:820px;margin-bottom:64px;}
.main-utm-eyebrow{margin:0 0 14px;font-size:12px;font-weight:800;letter-spacing:.24em;color:#1a1f5e;} .main-utm-eyebrow{margin:0 0 14px;font-size:12px;font-weight:800;letter-spacing:.24em;color:#1a1f5e;}
@ -278,7 +278,7 @@ body{overflow-x:hidden;}
/* solution */ /* 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:100dvh;min-height:100dvh;overflow:hidden;padding:120px 8vw 110px;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-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:1440px;margin:0 auto;} .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-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-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:#1a1f5e;}
@ -307,7 +307,7 @@ body{overflow-x:hidden;}
/* News */ /* News */
.main-news-section{position:relative;min-height:100vh;padding:130px 8vw;background:#ffffff;overflow:hidden;} .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;} .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;}
.main-news-inner{position:relative;z-index:2;max-width:1440px;margin:0 auto;display:grid;grid-template-columns:.9fr 1.35fr;gap:80px;align-items:start;} .main-news-inner{position:relative;z-index:2;max-width:1660px;margin:0 auto;display:grid;grid-template-columns:.9fr 1.35fr;gap:80px;align-items:start;}
.main-news-head{position:sticky;top:140px;} .main-news-head{position:sticky;top:140px;}
.main-news-eyebrow{margin:0 0 16px;font-size:12px;font-weight:800;letter-spacing:.24em;color:#1a1f5e;} .main-news-eyebrow{margin:0 0 16px;font-size:12px;font-weight:800;letter-spacing:.24em;color:#1a1f5e;}
.main-news-title{margin:0;font-size:clamp(34px,4vw,58px);font-weight:800;line-height:1.08;letter-spacing:-.06em;color:#10142b;} .main-news-title{margin:0;font-size:clamp(34px,4vw,58px);font-weight:800;line-height:1.08;letter-spacing:-.06em;color:#10142b;}
@ -351,7 +351,7 @@ body{overflow-x:hidden;}
.contact-orb--3{width:45%;height:45%;background:radial-gradient(circle,#0c0e28 0%,transparent 70%);filter:blur(35px);animation:contact-drift3 22s ease-in-out infinite;} .contact-orb--3{width:45%;height:45%;background:radial-gradient(circle,#0c0e28 0%,transparent 70%);filter:blur(35px);animation:contact-drift3 22s ease-in-out infinite;}
.main-contact-inner{position:relative;z-index:2;width:100%;max-width:1440px;margin:0 auto;display:grid;grid-template-columns:.78fr 1.22fr;gap:64px;align-items:center;} .main-contact-inner{position:relative;z-index:2;width:100%;max-width:1660px;margin:0 auto;display:grid;grid-template-columns:.78fr 1.22fr;gap:64px;align-items:center;}
.main-contact-head{display:flex;flex-direction:column;justify-content:center;} .main-contact-head{display:flex;flex-direction:column;justify-content:center;}
.main-contact-eyebrow{margin:0 0 16px;font-size:12px;font-weight:800;letter-spacing:.24em;color:rgba(255,255,255,.72);} .main-contact-eyebrow{margin:0 0 16px;font-size:12px;font-weight:800;letter-spacing:.24em;color:rgba(255,255,255,.72);}
.main-contact-title{margin:0;font-size:clamp(42px,5vw,72px);font-weight:800;line-height:1.04;letter-spacing:-.07em;color:#fff;} .main-contact-title{margin:0;font-size:clamp(42px,5vw,72px);font-weight:800;line-height:1.04;letter-spacing:-.07em;color:#fff;}

173
src/pages/solution/FlightControlPage.jsx

@ -1,12 +1,12 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { motion, useInView, AnimatePresence } from "framer-motion"; import { motion, useInView, AnimatePresence, useMotionValue, useTransform, useSpring } from "framer-motion";
import { Radio, Puzzle, Network, Expand, Shield } from "lucide-react"; import { Radio, Puzzle, Network, Expand, Shield, ArrowUpRight } from "lucide-react";
import SubHero from "../../components/SubHero"; import SubHero from "../../components/SubHero";
import useFadeIn from "../../hooks/useFadeIn"; import useFadeIn from "../../hooks/useFadeIn";
const SOLUTION_NAV = [ const SOLUTION_NAV = [
{ label: "비행상황관리 시스템", to: "/solution/flight-control" }, { label: "비행상황관리 시스템", to: "/solution/flight-control" },
{ label: "IBE", to: "/solution/ibe" }, { label: "IBE (Internet Booking Engine)", to: "/solution/ibe" },
{ label: "스마트 관광 예약 플랫폼", to: "/solution/smart-tour" }, { label: "스마트 관광 예약 플랫폼", to: "/solution/smart-tour" },
{ label: "KT G-cloud 인천총판", to: "/solution/kt-gcloud" }, { label: "KT G-cloud 인천총판", to: "/solution/kt-gcloud" },
]; ];
@ -30,87 +30,138 @@ const FUNCTIONS = [
const ease = [0.22, 1, 0.36, 1]; 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 }}>
{children}
</motion.div>
</div>
);
}
function StaggerWords({ text, delay = 0, className }) {
const words = text.split(" ");
return (
<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 style={{ display: "inline-block" }} initial={{ y: "110%", opacity: 0 }} animate={{ y: "0%", opacity: 1 }} transition={{ duration: 0.65, ease: [0.22, 1, 0.36, 1], delay: delay + i * 0.055 }}>
{word}
</motion.span>
</span>
))}
</span>
);
}
function FlightControlPage() { function FlightControlPage() {
const ref = useFadeIn(); const ref = useFadeIn();
const [activeIdx, setActiveIdx] = useState(0);
const overviewRef = useRef(null); const overviewRef = useRef(null);
const funcRef = useRef(null); const funcRef = useRef(null);
const overviewInView = useInView(overviewRef, { once: true, margin: "-80px" }); const overviewInView = useInView(overviewRef, { once: true, margin: "-60px" });
const funcInView = useInView(funcRef, { once: true, margin: "-80px" }); const funcInView = useInView(funcRef, { once: true, margin: "-80px" });
/* 패럴랙스 */
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);
const springX = useSpring(mouseX, { stiffness: 60, damping: 20 });
const springY = useSpring(mouseY, { stiffness: 60, damping: 20 });
const bgX = useTransform(springX, [-1, 1], ["-2%", "2%"]);
const bgY = useTransform(springY, [-1, 1], ["-2%", "2%"]);
function handleMouseMove(e) {
const rect = e.currentTarget.getBoundingClientRect();
mouseX.set(((e.clientX - rect.left) / rect.width) * 2 - 1);
mouseY.set(((e.clientY - rect.top) / rect.height) * 2 - 1);
}
function handleMouseLeave() {
mouseX.set(0);
mouseY.set(0);
}
return ( return (
<article ref={ref}> <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="sub-content">
<div className="inner-wrap"> <div className="inner-wrap">
{/* {/* 1. 개요 */}
1. 개요 + 특징 배지 <section className="fc-overview" ref={overviewRef} onMouseMove={handleMouseMove} onMouseLeave={handleMouseLeave}>
*/} <motion.img src="./images/test111.png" alt="" className="fc-overview__bg" style={{ x: bgX, y: bgY, scale: 1.06 }} />
<section className="fc-overview" ref={overviewRef}> <div className="fc-overview__overlay" />
{/* 텍스트 + 배지 */}
<motion.div className="fc-overview__text" initial={{ opacity: 0, x: -36 }} animate={overviewInView ? { opacity: 1, x: 0 } : {}} transition={{ duration: 0.75, ease }}>
<span className="fc-eyebrow">비행상황 관리 시스템</span>
<p className="fc-overview__desc">항공기, 무인기, 선박 실시간 식별정보를 통하여 모니터링 상황관리를 있는 시스템</p>
<p className="fc-overview__desc fc-overview__desc--sub">각종 드론 상황관제, 환경측정, 미래산업인 드론/PAV/UAM을 활용한 사업들을 지원하기 위한 환경/물류/안티 드론 등의 상황관제 시스템을 연구하고 솔루션을 제공합니다.</p>
{/* 특징 배지 */}
<div className="fc-badges">
{FEATURES.map(({ icon: Icon, label }, i) => (
<motion.span key={label} className="fc-badge" initial={{ opacity: 0, y: 12 }} animate={overviewInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.45, ease, delay: 0.35 + i * 0.07 }}>
<Icon size={13} strokeWidth={2} />
{label}
</motion.span>
))}
</div>
</motion.div>
{/* 이미지 패널 */} <div className="fc-overview__content">
<motion.div className="fc-overview__panel" initial={{ opacity: 0, x: 48 }} animate={overviewInView ? { opacity: 1, x: 0 } : {}} transition={{ duration: 0.85, ease, delay: 0.1 }}> {/* eyebrow + 보더라인 */}
<div className="fc-overview__panel-inner"> <div className="fc-overview__eyebrow-wrap">
<img src="./images/solution01.png" alt="비행상황관리 시스템 화면" className="fc-overview__img" /> {overviewInView && <motion.div className="fc-overview__eyebrow-line" initial={{ scaleY: 0 }} animate={{ scaleY: 1 }} transition={{ duration: 0.5, ease, delay: 0.05 }} />}
{overviewInView && (
<RevealText delay={0.1} className="fc-eyebrow fc-eyebrow--light">
비행상황 관리 시스템
</RevealText>
)}
</div> </div>
</motion.div>
{/* 타이틀 */}
{overviewInView && (
<div className="fc-overview__title">
<StaggerWords text="항공기, 무인기, 선박 등 실시간 식별정보를 통하여 모니터링 및 상황관리를 할 수 있는 시스템" delay={0.15} className="fc-overview__title-inner" />
</div>
)}
{/* 서브 + 배지 */}
<motion.div className="fc-overview__bottom" initial={{ opacity: 0, filter: "blur(8px)", y: 12 }} animate={overviewInView ? { opacity: 1, filter: "blur(0px)", y: 0 } : {}} transition={{ duration: 0.85, ease, delay: 0.8 }}>
<p className="fc-overview__sub">각종 드론 상황관제, 환경측정, 미래산업인 드론/PAV/UAM을 활용한 사업들을 지원하기 위한 환경/물류/안티 드론 등의 상황관제 시스템을 연구하고 솔루션을 제공합니다.</p>
<div className="fc-badges">
{FEATURES.map(({ icon: Icon, label }, i) => (
<motion.span key={label} className="fc-badge fc-badge--light" initial={{ opacity: 0, y: 8 }} animate={overviewInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.4, ease, delay: 0.9 + i * 0.07 }}>
<Icon size={12} strokeWidth={2} />
{label}
</motion.span>
))}
</div>
</motion.div>
</div>
</section> </section>
{/* {/* 2. 주요기능 */}
2. 주요기능 카드
*/}
<section className="fc-functions" ref={funcRef}> <section className="fc-functions" ref={funcRef}>
<motion.span className="fc-eyebrow" initial={{ opacity: 0, y: 20 }} animate={funcInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}> <motion.span className="fc-eyebrow" initial={{ opacity: 0, y: 20 }} animate={funcInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.6, ease }}>
비행상황관리 시스템 주요기능 주요기능
</motion.span> </motion.span>
<div className="fc-functions__grid"> <div className="fc-functions__body">
{FUNCTIONS.map(({ num, img, label }, i) => ( <ul className="fc-func-list">
<motion.div key={num} className="fc-func-card" initial={{ opacity: 0, y: 28 }} animate={funcInView ? { opacity: 1, y: 0 } : {}} transition={{ duration: 0.55, ease, delay: 0.06 * i }} whileHover="hover"> {FUNCTIONS.map(({ num, label }, i) => (
<div className="fc-func-card__img-wrap"> <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.img <span className="fc-func-item__num">{num}</span>
src={img} <span className="fc-func-item__label">{label}</span>
alt={label} <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 }}>
className="fc-func-card__img" <ArrowUpRight size={16} strokeWidth={1.5} />
variants={{ </motion.span>
hover: { scale: 1.05, transition: { duration: 0.4, ease } }, <motion.div className="fc-func-item__line" animate={{ scaleX: activeIdx === i ? 1 : 0 }} transition={{ duration: 0.35, ease }} />
}} </motion.li>
/> ))}
</div> </ul>
<div className="fc-func-card__body">
<span className="fc-func-card__num">{num}</span> <div className="fc-func-display">
<span className="fc-func-card__label">{label}</span> <AnimatePresence mode="wait">
</div> <motion.div key={activeIdx} className="fc-func-display__inner" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.35, ease: "easeInOut" }}>
<motion.div <img src={FUNCTIONS[activeIdx].img} alt={FUNCTIONS[activeIdx].label} className="fc-func-display__img" />
className="fc-func-card__overlay" <div className="fc-func-display__caption">
variants={{ <motion.span key={`num-${activeIdx}`} className="fc-func-display__num" initial={{ opacity: 0, y: 6 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.25 }}>
hover: { opacity: 1, transition: { duration: 0.25 } }, {FUNCTIONS[activeIdx].num}
}} </motion.span>
initial={{ opacity: 0 }} <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}
<span className="fc-func-card__overlay-num">{num}</span> </motion.span>
<span className="fc-func-card__overlay-label">{label}</span> </div>
</motion.div> </motion.div>
</motion.div> </AnimatePresence>
))} </div>
</div> </div>
</section> </section>
</div> </div>

Loading…
Cancel
Save