Browse Source

이미지 변경 및 main 작업

remotes/origin/main
김지은 2 months ago
parent
commit
b405881e83
  1. 47
      package-lock.json
  2. 1
      package.json
  3. BIN
      public/images/1111.png
  4. BIN
      public/images/hero1.png
  5. BIN
      public/images/hero2.png
  6. BIN
      public/images/hero3.png
  7. 48
      src/components/Header.jsx
  8. 54
      src/css/common.css
  9. 14
      src/css/header.css
  10. 149
      src/pages/MainPage.jsx

47
package-lock.json generated

@ -8,6 +8,7 @@
"name": "test", "name": "test",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"framer-motion": "^12.38.0",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4" "react-dom": "^19.2.4"
}, },
@ -1535,6 +1536,33 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/framer-motion": {
"version": "12.38.0",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.38.0.tgz",
"integrity": "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==",
"license": "MIT",
"dependencies": {
"motion-dom": "^12.38.0",
"motion-utils": "^12.36.0",
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0 || ^19.0.0",
"react-dom": "^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fsevents": { "node_modules/fsevents": {
"version": "2.3.3", "version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@ -2078,6 +2106,21 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/motion-dom": {
"version": "12.38.0",
"resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.38.0.tgz",
"integrity": "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==",
"license": "MIT",
"dependencies": {
"motion-utils": "^12.36.0"
}
},
"node_modules/motion-utils": {
"version": "12.36.0",
"resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.36.0.tgz",
"integrity": "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==",
"license": "MIT"
},
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -2438,9 +2481,7 @@
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"dev": true, "license": "0BSD"
"license": "0BSD",
"optional": true
}, },
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",

1
package.json

@ -10,6 +10,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"framer-motion": "^12.38.0",
"react": "^19.2.4", "react": "^19.2.4",
"react-dom": "^19.2.4" "react-dom": "^19.2.4"
}, },

BIN
public/images/1111.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

BIN
public/images/hero1.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 KiB

After

Width:  |  Height:  |  Size: 602 KiB

BIN
public/images/hero2.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
public/images/hero3.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 MiB

After

Width:  |  Height:  |  Size: 2.3 MiB

48
src/components/Header.jsx

@ -41,11 +41,7 @@ const menuData = [
{ {
title: "사업 분야", title: "사업 분야",
items: [ items: [
{ { label: "System Integration", to: "/business/system-integration", desc: "맞춤형 정보시스템 구축" },
label: "System Integration",
to: "/business/system-integration",
desc: "맞춤형 정보시스템 구축",
},
{ label: "플랫폼 구축", to: "/business/platform", desc: "서비스 플랫폼 기획·개발" }, { label: "플랫폼 구축", to: "/business/platform", desc: "서비스 플랫폼 기획·개발" },
{ label: "R&D", to: "/business/rnd", desc: "연구 개발 및 기술 고도화" }, { label: "R&D", to: "/business/rnd", desc: "연구 개발 및 기술 고도화" },
], ],
@ -55,11 +51,7 @@ const menuData = [
items: [ items: [
{ label: "항공/관제", to: "/business/aviation", desc: "항공·관제 특화 서비스" }, { label: "항공/관제", to: "/business/aviation", desc: "항공·관제 특화 서비스" },
{ label: "스마트 관광", to: "/business/tourism", desc: "관광·예약 플랫폼 구축" }, { label: "스마트 관광", to: "/business/tourism", desc: "관광·예약 플랫폼 구축" },
{ { label: "공공/기업 SI", to: "/business/public-enterprise", desc: "공공·기업 대상 구축 경험" },
label: "공공/기업 SI",
to: "/business/public-enterprise",
desc: "공공·기업 대상 구축 경험",
},
], ],
}, },
], ],
@ -80,11 +72,7 @@ const menuData = [
title: "주요 솔루션", title: "주요 솔루션",
items: [ items: [
{ label: "항공예약 플랫폼", to: "/solution/air-booking", desc: "예약·발권·운영 플랫폼" }, { label: "항공예약 플랫폼", to: "/solution/air-booking", desc: "예약·발권·운영 플랫폼" },
{ { label: "스마트 관광 플랫폼", to: "/solution/smart-tour", desc: "관광 서비스 통합 운영" },
label: "스마트 관광 플랫폼",
to: "/solution/smart-tour",
desc: "관광 서비스 통합 운영",
},
{ label: "상황관제 시스템", to: "/solution/control", desc: "실시간 상황 모니터링" }, { label: "상황관제 시스템", to: "/solution/control", desc: "실시간 상황 모니터링" },
], ],
}, },
@ -146,6 +134,7 @@ export default function PalRenewalHeader() {
const [activeMenu, setActiveMenu] = useState(null); const [activeMenu, setActiveMenu] = useState(null);
const [isHeaderHover, setIsHeaderHover] = useState(false); const [isHeaderHover, setIsHeaderHover] = useState(false);
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
const [isDarkHero, setIsDarkHero] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [mobileOpenKey, setMobileOpenKey] = useState(null); const [mobileOpenKey, setMobileOpenKey] = useState(null);
@ -156,18 +145,29 @@ export default function PalRenewalHeader() {
const activeData = menuData.find((item) => item.key === activeMenu); const activeData = menuData.find((item) => item.key === activeMenu);
const showPanel = Boolean(activeData && !activeData.simple && isHeaderHover); const showPanel = Boolean(activeData && !activeData.simple && isHeaderHover);
// const isActiveHeader = isScrolled || showPanel || isMobileMenuOpen;
useEffect(() => { useEffect(() => {
const onScroll = () => { const updateHeaderState = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0; const scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;
setIsScrolled(scrollTop > 2000); const darkHeroActive = document.body.classList.contains("is-dark-hero");
setIsDarkHero(darkHeroActive);
setIsScrolled(!darkHeroActive && scrollTop > 80);
}; };
onScroll(); updateHeaderState();
window.addEventListener("scroll", onScroll, { passive: true });
const observer = new MutationObserver(() => {
updateHeaderState();
});
observer.observe(document.body, { attributes: true, attributeFilter: ["class"] });
window.addEventListener("scroll", updateHeaderState, { passive: true });
return () => window.removeEventListener("scroll", onScroll); return () => {
observer.disconnect();
window.removeEventListener("scroll", updateHeaderState);
};
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -259,14 +259,16 @@ export default function PalRenewalHeader() {
} }
}; };
const isActiveHeader = isScrolled || showPanel || isMobileMenuOpen;
const logoSrc = isActiveHeader || !isDarkHero ? "./images/pal_logo.png" : "./images/pal_logo_wh.png";
return ( return (
<> <>
<header className={`pal-header ${isScrolled ? "is-scrolled" : ""} ${showPanel ? "is-open" : ""} ${isMobileMenuOpen ? "is-mobile-open" : ""}`} onMouseEnter={clearCloseTimer} onMouseLeave={scheduleClose}> <header className={`pal-header ${isScrolled ? "is-scrolled" : ""} ${showPanel ? "is-open" : ""} ${isMobileMenuOpen ? "is-mobile-open" : ""}`} onMouseEnter={clearCloseTimer} onMouseLeave={scheduleClose}>
<div className="pal-header-inner"> <div className="pal-header-inner">
<h1 className="pal-header-logo"> <h1 className="pal-header-logo">
<Link to="/Main" onClick={closeAllMenus}> <Link to="/Main" onClick={closeAllMenus}>
<img src="./images/pal_logo.png" alt="PAL Networks" /> <img src={logoSrc} alt="PAL Networks" />
{/* <img src={isActiveHeader ? "./images/pal_logo.png" : "./images/pal_logo_wh.png"} alt="PAL Networks" /> */}
</Link> </Link>
</h1> </h1>

54
src/css/common.css

@ -17,23 +17,49 @@ body{overflow-x:hidden;}
.main-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);} .main-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);}
.sub-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);} .sub-layout{min-height:calc(100vh - var(--header-height));padding-top:var(--header-height);}
/*main visual*/ /* main visual */
.main-section{height:200vh;} .main-page{width:100%;overflow:hidden;}
.main-bg{position:sticky;top:var(--header-height);display:flex;max-width:1440px;margin:0 auto;height:600px;border-radius:8px;overflow:hidden;background:url('/images/1111.png') no-repeat 100% 50%/cover;transform:scale(1);transform-origin:center center;} .main-section{position:relative;height:100vh;}
.main-bg-hero2{position:absolute;inset:0;background:url('/images/hero3.png') no-repeat 50% 50%/cover;opacity:0;} .main-bg-wrap{position:relative;width:100%;height:100vh;display:flex;align-items:flex-start;justify-content:center;overflow:hidden;}
.split-text-section{width:100%;} .main-bg{position:relative;width:min(1440px,calc(100vw - 80px));height:600px;border-radius:24px;overflow:hidden;transform-origin:center center;will-change:transform,width,height,border-radius;}
.main-text{position:relative;display:flex;flex:1;align-items:center;justify-content:center;padding:0 40px;}
.main-text .text{position:absolute;color:#fff;font-size:48px;line-height:1.2;width:100%;text-align:center;perspective:500px;font-weight:600;left:50%;top:50%;transform:translate(-50%,-50%);} .main-bg-hero1{position:absolute;inset:0;background:url('/images/hero1.png') no-repeat 50% 50%/cover;transform:scale(1.02);}
.main-bg-hero2{position:absolute;inset:0;background:url('/images/hero2.png') no-repeat 50% 50%/cover;opacity:0;}
.main-bg-hero3{position:absolute;inset:0;background:url('/images/hero3.png') no-repeat 50% 50%/cover;opacity:0;}
.main-bg::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 50% 78%,rgba(58,64,129,.24) 0%,rgba(58,64,129,.08) 18%,rgba(58,64,129,0) 45%);z-index:1;pointer-events:none;}
.main-bg::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(4,10,24,.1) 0%,rgba(4,10,24,.32) 52%,rgba(4,10,24,.58) 100%),linear-gradient(90deg,rgba(0,0,0,.2) 0%,rgba(0,0,0,.02) 40%,rgba(0,0,0,.14) 100%);z-index:1;pointer-events:none;}
.main-text{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:0 40px;z-index:2;}
.main-text .text{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:100%;max-width:1080px;color:#fff;text-align:center;font-size:56px;line-height:1.2;font-weight:700;letter-spacing:-.05em;will-change:transform,opacity,filter;text-shadow:0 10px 30px rgba(0,0,0,.22);}
.main-text .text-change{opacity:0;} .main-text .text-change{opacity:0;}
.main-text .text-fill .fill-line{display:inline-block;color:rgba(255,255,255,.28);background:linear-gradient(90deg,#fff 0%,#fff 50%,rgba(255,255,255,.28) 50%,rgba(255,255,255,.28) 100%);background-size:220% 100%;background-position:100% 0;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;}
.main-progress{position:absolute;left:50%;bottom:42px;transform:translateX(-50%);width:min(240px,calc(100% - 48px));height:2px;background:rgba(255,255,255,.22);z-index:3;overflow:hidden;border-radius:999px;}
.main-progress-bar{display:block;width:0%;height:100%;background:#fff;border-radius:999px;}
.main-scroll-indicator{position:absolute;left:50%;bottom:72px;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:10px;z-index:3;pointer-events:none;}
.main-scroll-line{display:block;width:1px;height:28px;background:linear-gradient(180deg,rgba(255,255,255,.15) 0%,rgba(255,255,255,.95) 100%);animation:scrollLine 1.8s ease-in-out infinite;}
.main-scroll-text{font-size:11px;line-height:1;letter-spacing:.28em;font-weight:600;color:rgba(255,255,255,.78);}
@media (max-width:1024px){ @keyframes scrollLine{
.main-bg{height:520px;} 0%{transform:translateY(0);opacity:.35;}
.main-text .text{font-size:38px;} 50%{transform:translateY(6px);opacity:1;}
100%{transform:translateY(0);opacity:.35;}
}
@media (max-width:1280px){
.main-bg{width:calc(100vw - 48px);height:540px;}
.main-text .text{font-size:44px;max-width:980px;}
} }
@media (max-width:768px){ @media (max-width:768px){
.main-section{height:170vh;} .main-bg{width:calc(100vw - 24px);height:72vh;border-radius:20px;}
.main-bg{top:80px;height:420px;}
.main-text{padding:0 20px;} .main-text{padding:0 20px;}
.main-text .text{font-size:28px;line-height:1.3;} .main-text .text{font-size:30px;line-height:1.28;letter-spacing:-.035em;max-width:100%;}
} .main-progress{bottom:28px;width:calc(100% - 32px);}
.main-scroll-indicator{bottom:56px;}
.main-scroll-line{height:22px;}
.main-scroll-text{font-size:10px;letter-spacing:.22em;}
}

14
src/css/header.css

@ -1,9 +1,8 @@
/*header.*/ /*header.*/
.pal-header{position:fixed;top:0;left:0;right:0;z-index:1000;background:transparent;transition:box-shadow .35s ease;} .pal-header{position:fixed;top:0;left:0;right:0;z-index:1000;background:transparent;transition:box-shadow .35s ease;}
.pal-header::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,.96);backdrop-filter:blur(16px);opacity:0;pointer-events:none;transition:opacity .35s ease;} .pal-header::before{content:"";position:absolute;left:0;top:0;width:100%;height:100%;background:rgba(255,255,255,.9);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);opacity:0;pointer-events:none;transition:opacity .35s ease;}
.pal-header.is-scrolled::before,.pal-header.is-open::before,.pal-header.is-mobile-open::before{opacity:1;} .pal-header.is-scrolled::before,.pal-header.is-open::before,.pal-header.is-mobile-open::before{opacity:1;}
.pal-header.is-scrolled,.pal-header.is-open,.pal-header.is-mobile-open{box-shadow:0 18px 40px rgba(15,23,42,.08);} .pal-header.is-scrolled,.pal-header.is-open,.pal-header.is-mobile-open{box-shadow:0 18px 40px rgba(15,23,42,.08);}
/* .pal-header.is-scrolled .pal-gnb-link,.pal-header.is-open .pal-gnb-link,.pal-header.is-mobile-open .pal-gnb-link{color:#111} */
.pal-header-inner{position:relative;display:flex;align-items:center;justify-content:space-between;max-width:1440px;height:96px;margin:0 auto;padding:0 40px;z-index:2;} .pal-header-inner{position:relative;display:flex;align-items:center;justify-content:space-between;max-width:1440px;height:96px;margin:0 auto;padding:0 40px;z-index:2;}
.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;}
@ -24,7 +23,7 @@
.pal-header-contact{display:inline-flex;align-items:center;justify-content:center;height:44px;padding:0 18px;border:1px solid rgba(17,17,17,.12);border-radius:999px;background:#fff;color:#111;font-size:14px;font-weight:700;line-height:1;text-decoration:none;transition:border-color .3s ease,background .3s ease,color .3s ease,transform .3s ease,box-shadow .3s ease;} .pal-header-contact{display:inline-flex;align-items:center;justify-content:center;height:44px;padding:0 18px;border:1px solid rgba(17,17,17,.12);border-radius:999px;background:#fff;color:#111;font-size:14px;font-weight:700;line-height:1;text-decoration:none;transition:border-color .3s ease,background .3s ease,color .3s ease,transform .3s ease,box-shadow .3s ease;}
.pal-header-contact:hover,.pal-header-contact:focus-visible{border-color:var(--color-primary);background:var(--color-primary);color:#fff;transform:translateY(-2px);box-shadow:0 12px 24px var(--color-primary-shadow);outline:none;} .pal-header-contact:hover,.pal-header-contact:focus-visible{border-color:var(--color-primary);background:var(--color-primary);color:#fff;transform:translateY(-2px);box-shadow:0 12px 24px var(--color-primary-shadow);outline:none;}
.pal-header-hamburger{display:none;position:relative;width:46px;height:46px;padding:0;border:1px solid rgba(17,17,17,.08);border-radius:14px;background:#fff;cursor:pointer;transition:border-color .3s ease,transform .3s ease,box-shadow .3s ease;} .pal-header-hamburger{display:none;position:relative;width:46px;height:46px;padding:0;border:1px solid rgba(17,17,17,.08);border-radius:14px;background:#fff;cursor:pointer;transition:border-color .3s ease,transform .3s ease,box-shadow .3s ease,background .3s ease;}
.pal-header-hamburger:hover,.pal-header-hamburger:focus-visible{border-color:var(--color-primary-border-strong);transform:translateY(-2px);box-shadow:0 12px 24px rgba(15,23,42,.08);outline:none;} .pal-header-hamburger:hover,.pal-header-hamburger:focus-visible{border-color:var(--color-primary-border-strong);transform:translateY(-2px);box-shadow:0 12px 24px rgba(15,23,42,.08);outline:none;}
.pal-header-hamburger span{position:absolute;left:50%;width:18px;height:2px;border-radius:999px;background:#111;transform:translateX(-50%);transition:top .28s ease,transform .28s ease,opacity .2s ease,background .28s ease;} .pal-header-hamburger span{position:absolute;left:50%;width:18px;height:2px;border-radius:999px;background:#111;transform:translateX(-50%);transition:top .28s ease,transform .28s ease,opacity .2s ease,background .28s ease;}
.pal-header-hamburger span:nth-child(1){top:15px;} .pal-header-hamburger span:nth-child(1){top:15px;}
@ -34,9 +33,16 @@
.pal-header-hamburger.is-active span:nth-child(2){opacity:0;} .pal-header-hamburger.is-active span:nth-child(2){opacity:0;}
.pal-header-hamburger.is-active span:nth-child(3){top:22px;transform:translateX(-50%) rotate(-45deg);background:var(--color-primary);} .pal-header-hamburger.is-active span:nth-child(3){top:22px;transform:translateX(-50%) rotate(-45deg);background:var(--color-primary);}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open)::before{opacity:0;}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open) .pal-gnb-link{color:#fff;}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open) .pal-gnb-link-text{text-shadow:0 2px 12px rgba(0,0,0,.28);}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open) .pal-header-contact{border:1px solid rgba(255,255,255,.22);background:rgba(255,255,255,.08);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);color:#fff;box-shadow:none;}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open) .pal-header-hamburger{border:1px solid rgba(255,255,255,.18);background:rgba(255,255,255,.08);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);}
body.is-dark-hero .pal-header:not(.is-scrolled):not(.is-open):not(.is-mobile-open) .pal-header-hamburger span{background:#fff;}
.pal-mega-panel{position:absolute;top:100%;left:0;width:100%;pointer-events:none;opacity:0;visibility:hidden;transition:opacity .18s ease;z-index:1;} .pal-mega-panel{position:absolute;top:100%;left:0;width:100%;pointer-events:none;opacity:0;visibility:hidden;transition:opacity .18s ease;z-index:1;}
.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,.98);backdrop-filter:blur(10px);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:1440px;margin:0 auto;padding:24px 40px 28px;z-index:1;}

149
src/pages/MainPage.jsx

@ -1,108 +1,109 @@
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
import { gsap } from "gsap"; import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger"; import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
gsap.registerPlugin(ScrollTrigger, SplitText); gsap.registerPlugin(ScrollTrigger);
function MainPage() { function MainPage() {
const sectionRef = useRef(null); const sectionRef = useRef(null);
const bgRef = useRef(null); const bgRef = useRef(null);
const hero2Ref = useRef(null); const hero2Ref = useRef(null);
const hero3Ref = useRef(null);
const text1Ref = useRef(null); const text1Ref = useRef(null);
const text2Ref = useRef(null); const text2Ref = useRef(null);
const splitRef = useRef(null); const text3Ref = useRef(null);
const progressBarRef = useRef(null);
useEffect(() => { useEffect(() => {
const setupText = () => { const ctx = gsap.context(() => {
if (splitRef.current) splitRef.current.revert(); gsap.set(hero2Ref.current, { opacity: 0, scale: 1.14, filter: "blur(10px)" });
gsap.set(hero3Ref.current, { opacity: 0, scale: 1.14, filter: "blur(10px)" });
gsap.set(text2Ref.current, { opacity: 0, y: 40, filter: "blur(8px)" });
gsap.set(text3Ref.current, { opacity: 0, y: 40, filter: "blur(8px)" });
gsap.set(progressBarRef.current, { width: "0%" });
gsap.set(".fill-line", { backgroundPosition: "100% 0%" });
splitRef.current = SplitText.create(text1Ref.current, { type: "chars" }); const tl = gsap.timeline({
scrollTrigger: {
gsap.from(splitRef.current.chars, { trigger: sectionRef.current,
x: 150, start: "top top",
opacity: 0, end: "+=2600",
duration: 0.7, scrub: 1.2,
ease: "power4", pin: true,
stagger: 0.04, anticipatePin: 1,
},
}); });
};
setupText(); tl.to(bgRef.current, { width: "100vw", height: "100vh", borderRadius: 0, ease: "none" }, 0)
.to(bgRef.current, { scale: 1.08, ease: "none" }, 0)
.to(progressBarRef.current, { width: "100%", ease: "none" }, 0)
.to(".fill-line", { backgroundPosition: "0% 0%", ease: "none", stagger: 0.12, duration: 1.2 }, 0.08)
.to(text1Ref.current, { opacity: 0, y: -40, filter: "blur(8px)", ease: "none" }, 1.35)
gsap.set(hero2Ref.current, { opacity: 0 }); .to(hero2Ref.current, { opacity: 1, scale: 1.03, filter: "blur(0px)", ease: "none" }, 1.15)
gsap.set(text2Ref.current, { opacity: 0, y: 30 }); .fromTo(text2Ref.current, { opacity: 0, y: 40, filter: "blur(8px)" }, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none" }, 1.22)
const tl = gsap.timeline({ .to(hero2Ref.current, { scale: 1.1, ease: "none" }, 1.72)
scrollTrigger: { .to(text2Ref.current, { opacity: 0, y: -40, filter: "blur(8px)", ease: "none" }, 2.02)
.to(hero3Ref.current, { opacity: 1, scale: 1.03, filter: "blur(0px)", ease: "none" }, 2.14)
.fromTo(text3Ref.current, { opacity: 0, y: 40, filter: "blur(8px)" }, { opacity: 1, y: 0, filter: "blur(0px)", ease: "none" }, 2.28)
.to(hero3Ref.current, { scale: 1.08, ease: "none" }, 2.82);
ScrollTrigger.create({
trigger: sectionRef.current, trigger: sectionRef.current,
start: "top top", start: "top top",
end: "+=100%", end: "+=2600",
scrub: 1, onEnter: () => document.body.classList.add("is-dark-hero"),
}, onEnterBack: () => document.body.classList.add("is-dark-hero"),
}); onLeave: () => document.body.classList.remove("is-dark-hero"),
onLeaveBack: () => document.body.classList.remove("is-dark-hero"),
tl.to( });
bgRef.current, }, sectionRef);
{
scale: 1.18,
borderRadius: 0,
ease: "none",
},
0,
)
.to(
text1Ref.current,
{
opacity: 0,
y: -30,
ease: "none",
},
0.2,
)
.to(
hero2Ref.current,
{
opacity: 1,
ease: "none",
},
0.35,
)
.to(
text2Ref.current,
{
opacity: 1,
y: 0,
ease: "none",
},
0.45,
);
window.addEventListener("resize", setupText);
return () => { return () => {
window.removeEventListener("resize", setupText); document.body.classList.remove("is-dark-hero");
tl.kill(); ctx.revert();
ScrollTrigger.getAll().forEach((trigger) => trigger.kill());
if (splitRef.current) splitRef.current.revert();
}; };
}, []); }, []);
return ( return (
<main className="main-page"> <main className="main-page">
<section className="main-section" ref={sectionRef}> <section className="main-section" ref={sectionRef}>
<div className="main-bg" ref={bgRef}> <div className="main-bg-wrap">
<div className="main-bg-hero2" ref={hero2Ref}></div> <div className="main-bg" ref={bgRef}>
<div className="main-bg-hero1"></div>
<div className="main-bg-hero2" ref={hero2Ref}></div>
<div className="main-bg-hero3" ref={hero3Ref}></div>
<div className="main-text">
<div className="text text-fill" ref={text1Ref}>
<span className="fill-line">Technology Partner for</span>
<br />
<span className="fill-line">Advanced Air Mobility</span>
</div>
<div className="text text-change" ref={text2Ref}>
항공 데이터와 통합 관제 기술로
<br />
안전한 하늘길을 설계합니다
</div>
<div className="text text-change" ref={text3Ref}>
공역관리와 드론 교통관리(UTM) 기반으로
<br />
실제 운영 가능한 항공 시스템을 구축합니다
</div>
</div>
<div className="main-text"> <div className="main-progress">
<div className="text" ref={text1Ref}> <span className="main-progress-bar" ref={progressBarRef}></span>
미래 항공 모빌리티를 구현하는 기술 파트너
</div> </div>
<div className="text text-change" ref={text2Ref}> <div className="main-scroll-indicator">
공역관리와 드론 교통관리(UTM) 기반으로 <span className="main-scroll-line"></span>
<br /> <span className="main-scroll-text">SCROLL</span>
실제 운영 가능한 항공 시스템을 구축합니다
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save