Browse Source

feat : 인증 및 특허현황 추가

remotes/origin/main
이시연 2 weeks ago
parent
commit
273c71e013
  1. BIN
      public/images/cert/patents/대기질측정장치시스템.png
  2. BIN
      public/images/cert/patents/도심환경교통.png
  3. BIN
      public/images/cert/patents/특허증.png
  4. BIN
      public/images/cert/관광벤처인증.png
  5. BIN
      public/images/cert/관광사업자등록증.png
  6. BIN
      public/images/cert/국방벤처기업1.png
  7. BIN
      public/images/cert/국방벤처기업2.png
  8. BIN
      public/images/cert/기업부설연구소.png
  9. BIN
      public/images/cert/방송통신기자재_KC_인증.png
  10. BIN
      public/images/cert/벤처기업확인서.png
  11. BIN
      public/images/cert/이노비즈확인서_팔네트웍스.png
  12. BIN
      public/images/cert/정보통신공사업등록증.png
  13. BIN
      public/images/cert/항공선도기업.png
  14. 37
      src/Router.jsx
  15. 245
      src/components/Header.jsx
  16. 35
      src/css/common.css
  17. 1
      src/pages/company/AboutPage.jsx
  18. 208
      src/pages/company/CertPage.jsx
  19. 165
      src/pages/company/HistoryPage.jsx
  20. 1
      src/pages/company/LocationPage.jsx
  21. 1
      src/pages/company/PartnersPage.jsx

BIN
public/images/cert/patents/대기질측정장치시스템.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 MiB

BIN
public/images/cert/patents/도심환경교통.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

BIN
public/images/cert/patents/특허증.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 MiB

BIN
public/images/cert/관광벤처인증.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
public/images/cert/관광사업자등록증.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/images/cert/국방벤처기업1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

BIN
public/images/cert/국방벤처기업2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

BIN
public/images/cert/기업부설연구소.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

BIN
public/images/cert/방송통신기자재_KC_인증.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
public/images/cert/벤처기업확인서.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 940 KiB

BIN
public/images/cert/이노비즈확인서_팔네트웍스.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
public/images/cert/정보통신공사업등록증.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

BIN
public/images/cert/항공선도기업.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

37
src/Router.jsx

@ -8,6 +8,7 @@ import MainPage from "./pages/MainPage";
// Company // Company
import CompanyAboutPage from "./pages/company/AboutPage"; import CompanyAboutPage from "./pages/company/AboutPage";
import CompanyCertPage from "./pages/company/CertPage";
import CompanyHistoryPage from "./pages/company/HistoryPage"; import CompanyHistoryPage from "./pages/company/HistoryPage";
import CompanyPartnersPage from "./pages/company/PartnersPage"; import CompanyPartnersPage from "./pages/company/PartnersPage";
import CompanyLocationPage from "./pages/company/LocationPage"; import CompanyLocationPage from "./pages/company/LocationPage";
@ -45,8 +46,12 @@ function Router() {
{/* 서브 페이지 */} {/* 서브 페이지 */}
<Route element={<SubLayout />}> <Route element={<SubLayout />}>
{/* Company */} {/* Company */}
<Route path="/company" element={<Navigate to="/company/about" replace />} /> <Route
path="/company"
element={<Navigate to="/company/about" replace />}
/>
<Route path="/company/about" element={<CompanyAboutPage />} /> <Route path="/company/about" element={<CompanyAboutPage />} />
<Route path="/company/cert" element={<CompanyCertPage />} />
<Route path="/company/history" element={<CompanyHistoryPage />} /> <Route path="/company/history" element={<CompanyHistoryPage />} />
<Route path="/company/partners" element={<CompanyPartnersPage />} /> <Route path="/company/partners" element={<CompanyPartnersPage />} />
<Route path="/company/location" element={<CompanyLocationPage />} /> <Route path="/company/location" element={<CompanyLocationPage />} />
@ -57,20 +62,38 @@ function Router() {
<Route path="/utm/case" element={<UTMCasePage />} /> <Route path="/utm/case" element={<UTMCasePage />} />
{/* Business */} {/* Business */}
<Route path="/business" element={<Navigate to="/business/si" replace />} /> <Route
path="/business"
element={<Navigate to="/business/si" replace />}
/>
<Route path="/business/si" element={<BusinessSiPage />} /> <Route path="/business/si" element={<BusinessSiPage />} />
<Route path="/business/rnd" element={<BusinessRndPage />} /> <Route path="/business/rnd" element={<BusinessRndPage />} />
<Route path="/business/maintenance" element={<BusinessMaintenancePage />} /> <Route
path="/business/maintenance"
element={<BusinessMaintenancePage />}
/>
{/* Solution */} {/* Solution */}
<Route path="/solution" element={<Navigate to="/solution/flight-control" replace />} /> <Route
<Route path="/solution/flight-control" element={<SolutionFlightControlPage />} /> path="/solution"
element={<Navigate to="/solution/flight-control" replace />}
/>
<Route
path="/solution/flight-control"
element={<SolutionFlightControlPage />}
/>
<Route path="/solution/ibe" element={<SolutionIbePage />} /> <Route path="/solution/ibe" element={<SolutionIbePage />} />
<Route path="/solution/smart-tour" element={<SolutionSmartTourPage />} /> <Route
path="/solution/smart-tour"
element={<SolutionSmartTourPage />}
/>
<Route path="/solution/kt-gcloud" element={<SolutionKtGcloudPage />} /> <Route path="/solution/kt-gcloud" element={<SolutionKtGcloudPage />} />
{/* Contact Us */} {/* Contact Us */}
<Route path="/contact" element={<Navigate to="/contact/inquiry" replace />} /> <Route
path="/contact"
element={<Navigate to="/contact/inquiry" replace />}
/>
<Route path="/contact/inquiry" element={<ContactInquiryPage />} /> <Route path="/contact/inquiry" element={<ContactInquiryPage />} />
<Route path="/contact/recruit" element={<ContactRecruitPage />} /> <Route path="/contact/recruit" element={<ContactRecruitPage />} />
</Route> </Route>

245
src/components/Header.jsx

@ -12,15 +12,36 @@ const menuData = [
{ {
title: "회사 소개", title: "회사 소개",
items: [ items: [
{ label: "회사소개", to: "/company/about", desc: "기업 철학과 핵심 가치" }, {
{ label: "연혁", to: "/company/history", desc: "주요 실적과 성장 과정" }, label: "회사소개",
to: "/company/about",
desc: "기업 철학과 핵심 가치",
},
{
label: "인증 및 특허현황",
to: "/company/cert",
desc: "보유 인증 및 특허 현황 안내",
},
{
label: "연혁",
to: "/company/history",
desc: "주요 실적과 성장 과정",
},
], ],
}, },
{ {
title: "신뢰 정보", title: "신뢰 정보",
items: [ items: [
{ label: "고객 및 협력사", to: "/company/partners", desc: "주요 고객과 협력 네트워크" }, {
{ label: "찾아오시는 길", to: "/company/location", desc: "위치 및 연락처 안내" }, label: "고객 및 협력사",
to: "/company/partners",
desc: "주요 고객과 협력 네트워크",
},
{
label: "찾아오시는 길",
to: "/company/location",
desc: "위치 및 연락처 안내",
},
], ],
}, },
], ],
@ -41,8 +62,16 @@ const menuData = [
{ {
title: "기술 소개", title: "기술 소개",
items: [ items: [
{ label: "UTM/UATM 소개", to: "/utm/intro", desc: "도심 항공 모빌리티 핵심 기술" }, {
{ label: "도입사례", to: "/utm/case", desc: "주요 도입 및 운영 사례" }, label: "UTM/UATM 소개",
to: "/utm/intro",
desc: "도심 항공 모빌리티 핵심 기술",
},
{
label: "도입사례",
to: "/utm/case",
desc: "주요 도입 및 운영 사례",
},
], ],
}, },
], ],
@ -58,18 +87,33 @@ const menuData = [
label: "Business", label: "Business",
to: "/business", to: "/business",
panelTitle: "Business Area", panelTitle: "Business Area",
panelDesc: "구축부터 운영까지, PAL Networks의 종합 IT 서비스 역량을 소개합니다.", panelDesc:
"구축부터 운영까지, PAL Networks의 종합 IT 서비스 역량을 소개합니다.",
sections: [ sections: [
{ {
title: "구축 · 개발", title: "구축 · 개발",
items: [ items: [
{ label: "System Integration", to: "/business/si", desc: "맞춤형 정보시스템 구축" }, {
{ label: "R&D", to: "/business/rnd", desc: "연구 개발 및 기술 고도화" }, label: "System Integration",
to: "/business/si",
desc: "맞춤형 정보시스템 구축",
},
{
label: "R&D",
to: "/business/rnd",
desc: "연구 개발 및 기술 고도화",
},
], ],
}, },
{ {
title: "운영 · 지원", title: "운영 · 지원",
items: [{ label: "운영 · 유지보수", to: "/business/maintenance", desc: "안정적인 시스템 운영과 사후 관리" }], items: [
{
label: "운영 · 유지보수",
to: "/business/maintenance",
desc: "안정적인 시스템 운영과 사후 관리",
},
],
}, },
], ],
featured: { featured: {
@ -89,8 +133,16 @@ const menuData = [
{ {
title: "운영 솔루션", title: "운영 솔루션",
items: [ items: [
{ label: "비행상황관리 시스템", to: "/solution/flight-control", desc: "실시간 비행 상황 통합 관제" }, {
{ label: "IBE (Internet Booking Engine)", to: "/solution/ibe", desc: "항공 예약·발권 엔진" }, label: "비행상황관리 시스템",
to: "/solution/flight-control",
desc: "실시간 비행 상황 통합 관제",
},
{
label: "IBE (Internet Booking Engine)",
to: "/solution/ibe",
desc: "항공 예약·발권 엔진",
},
], ],
}, },
// { // {
@ -118,8 +170,16 @@ const menuData = [
{ {
title: "문의 및 채용", title: "문의 및 채용",
items: [ items: [
{ label: "문의하기", to: "/contact/inquiry", desc: "프로젝트 및 협업 문의" }, {
{ label: "채용정보", to: "/contact/recruit", desc: "함께할 동료를 찾습니다" }, label: "문의하기",
to: "/contact/inquiry",
desc: "프로젝트 및 협업 문의",
},
{
label: "채용정보",
to: "/contact/recruit",
desc: "함께할 동료를 찾습니다",
},
], ],
}, },
], ],
@ -149,7 +209,8 @@ export default function PalRenewalHeader() {
useEffect(() => { useEffect(() => {
const updateHeaderState = () => { const updateHeaderState = () => {
const scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0; const scrollTop =
window.pageYOffset || document.documentElement.scrollTop || 0;
const darkHeroActive = document.body.classList.contains("is-dark-hero"); const darkHeroActive = document.body.classList.contains("is-dark-hero");
setIsDarkHero(darkHeroActive); setIsDarkHero(darkHeroActive);
@ -162,7 +223,10 @@ export default function PalRenewalHeader() {
updateHeaderState(); updateHeaderState();
}); });
observer.observe(document.body, { attributes: true, attributeFilter: ["class"] }); observer.observe(document.body, {
attributes: true,
attributeFilter: ["class"],
});
window.addEventListener("scroll", updateHeaderState, { passive: true }); window.addEventListener("scroll", updateHeaderState, { passive: true });
return () => { return () => {
@ -261,11 +325,18 @@ export default function PalRenewalHeader() {
}; };
const isActiveHeader = isScrolled || showPanel || isMobileMenuOpen; const isActiveHeader = isScrolled || showPanel || isMobileMenuOpen;
const logoSrc = isActiveHeader || !isDarkHero ? "./images/pal_logo.png" : "./images/pal_logo_wh.png"; 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}>
@ -331,16 +402,37 @@ export default function PalRenewalHeader() {
</nav> </nav>
<div className="pal-header-util"> <div className="pal-header-util">
<div className="pal-header-lang" role="group" aria-label="언어 선택"> <div
<button type="button" className="pal-header-lang-btn is-active" aria-pressed="true"> className="pal-header-lang"
role="group"
aria-label="언어 선택"
>
<button
type="button"
className="pal-header-lang-btn is-active"
aria-pressed="true"
>
KOR KOR
</button> </button>
<button type="button" className="pal-header-lang-btn" aria-pressed="false"> <button
type="button"
className="pal-header-lang-btn"
aria-pressed="false"
>
ENG ENG
</button> </button>
</div> </div>
<button type="button" className={`pal-header-hamburger ${isMobileMenuOpen ? "is-active" : ""}`} aria-label={isMobileMenuOpen ? "모바일 메뉴 닫기" : "모바일 메뉴 열기"} aria-expanded={isMobileMenuOpen} aria-controls="pal-mobile-menu" onClick={toggleMobileMenu}> <button
type="button"
className={`pal-header-hamburger ${isMobileMenuOpen ? "is-active" : ""}`}
aria-label={
isMobileMenuOpen ? "모바일 메뉴 닫기" : "모바일 메뉴 열기"
}
aria-expanded={isMobileMenuOpen}
aria-controls="pal-mobile-menu"
onClick={toggleMobileMenu}
>
<span></span> <span></span>
<span></span> <span></span>
<span></span> <span></span>
@ -359,10 +451,16 @@ export default function PalRenewalHeader() {
{activeData && !activeData.simple && ( {activeData && !activeData.simple && (
<div className="pal-mega-panel-inner"> <div className="pal-mega-panel-inner">
<div className="pal-mega-panel-intro"> <div className="pal-mega-panel-intro">
<span className="pal-mega-panel-eyebrow">{activeData.panelTitle}</span> <span className="pal-mega-panel-eyebrow">
{activeData.panelTitle}
</span>
<h2>{activeData.featured.title}</h2> <h2>{activeData.featured.title}</h2>
<p>{activeData.featured.text}</p> <p>{activeData.featured.text}</p>
<Link to={activeData.featured.cta.to} className="pal-mega-panel-cta" onClick={closeAllMenus}> <Link
to={activeData.featured.cta.to}
className="pal-mega-panel-cta"
onClick={closeAllMenus}
>
{activeData.featured.cta.label} {activeData.featured.cta.label}
</Link> </Link>
</div> </div>
@ -380,9 +478,17 @@ export default function PalRenewalHeader() {
<ul> <ul>
{section.items.map((item) => ( {section.items.map((item) => (
<li key={item.label}> <li key={item.label}>
<Link to={item.to} className="pal-mega-item" onClick={closeAllMenus}> <Link
<span className="pal-mega-item-title">{item.label}</span> to={item.to}
<span className="pal-mega-item-desc">{item.desc}</span> className="pal-mega-item"
onClick={closeAllMenus}
>
<span className="pal-mega-item-title">
{item.label}
</span>
<span className="pal-mega-item-desc">
{item.desc}
</span>
</Link> </Link>
</li> </li>
))} ))}
@ -396,14 +502,32 @@ export default function PalRenewalHeader() {
</div> </div>
</header> </header>
<button type="button" className={`pal-header-dim ${showPanel ? "is-visible" : ""}`} aria-label="메뉴 닫기" onClick={closeDesktopMenu}></button> <button
type="button"
className={`pal-header-dim ${showPanel ? "is-visible" : ""}`}
aria-label="메뉴 닫기"
onClick={closeDesktopMenu}
></button>
<div className={`pal-mobile-dim ${isMobileMenuOpen ? "is-visible" : ""}`} onClick={closeAllMenus}></div> <div
className={`pal-mobile-dim ${isMobileMenuOpen ? "is-visible" : ""}`}
onClick={closeAllMenus}
></div>
<aside id="pal-mobile-menu" className={`pal-mobile-menu ${isMobileMenuOpen ? "is-open" : ""}`} aria-hidden={!isMobileMenuOpen}> <aside
id="pal-mobile-menu"
className={`pal-mobile-menu ${isMobileMenuOpen ? "is-open" : ""}`}
aria-hidden={!isMobileMenuOpen}
>
<div className="pal-mobile-menu-head"> <div className="pal-mobile-menu-head">
<strong>MENU</strong> <strong>MENU</strong>
<button type="button" className="pal-mobile-menu-close" aria-label="모바일 메뉴 닫기" onClick={closeAllMenus} ref={mobileFirstFocusableRef}> <button
type="button"
className="pal-mobile-menu-close"
aria-label="모바일 메뉴 닫기"
onClick={closeAllMenus}
ref={mobileFirstFocusableRef}
>
<span></span> <span></span>
<span></span> <span></span>
</button> </button>
@ -415,26 +539,45 @@ export default function PalRenewalHeader() {
const isOpen = mobileOpenKey === menu.key; const isOpen = mobileOpenKey === menu.key;
return ( return (
<li className={`pal-mobile-nav-item ${isOpen ? "is-open" : ""}`} key={menu.key}> <li
className={`pal-mobile-nav-item ${isOpen ? "is-open" : ""}`}
key={menu.key}
>
{menu.simple ? ( {menu.simple ? (
<Link to={menu.to} className="pal-mobile-nav-link" onClick={closeAllMenus}> <Link
to={menu.to}
className="pal-mobile-nav-link"
onClick={closeAllMenus}
>
<span>{menu.label}</span> <span>{menu.label}</span>
</Link> </Link>
) : ( ) : (
<> <>
<button type="button" className="pal-mobile-nav-toggle" onClick={() => handleMobileAccordion(menu.key)} aria-expanded={isOpen}> <button
type="button"
className="pal-mobile-nav-toggle"
onClick={() => handleMobileAccordion(menu.key)}
aria-expanded={isOpen}
>
<span>{menu.label}</span> <span>{menu.label}</span>
<i className="pal-mobile-nav-arrow"></i> <i className="pal-mobile-nav-arrow"></i>
</button> </button>
<div className="pal-mobile-submenu"> <div className="pal-mobile-submenu">
{menu.sections.map((section) => ( {menu.sections.map((section) => (
<div className="pal-mobile-submenu-group" key={section.title}> <div
className="pal-mobile-submenu-group"
key={section.title}
>
<h3>{section.title}</h3> <h3>{section.title}</h3>
<ul> <ul>
{section.items.map((item) => ( {section.items.map((item) => (
<li key={item.label}> <li key={item.label}>
<Link to={item.to} className="pal-mobile-submenu-link" onClick={closeAllMenus}> <Link
to={item.to}
className="pal-mobile-submenu-link"
onClick={closeAllMenus}
>
<strong>{item.label}</strong> <strong>{item.label}</strong>
<p>{item.desc}</p> <p>{item.desc}</p>
</Link> </Link>
@ -444,7 +587,11 @@ export default function PalRenewalHeader() {
</div> </div>
))} ))}
<Link to={menu.featured.cta.to} className="pal-mobile-featured-link" onClick={closeAllMenus}> <Link
to={menu.featured.cta.to}
className="pal-mobile-featured-link"
onClick={closeAllMenus}
>
<span>{menu.featured.eyebrow}</span> <span>{menu.featured.eyebrow}</span>
<strong>{menu.featured.cta.label}</strong> <strong>{menu.featured.cta.label}</strong>
</Link> </Link>
@ -458,18 +605,34 @@ export default function PalRenewalHeader() {
{/* 모바일 언어 토글 */} {/* 모바일 언어 토글 */}
<div className="pal-mobile-lang"> <div className="pal-mobile-lang">
<span className="pal-mobile-lang-label">Language</span> <span className="pal-mobile-lang-label">Language</span>
<div className="pal-mobile-lang-toggle" role="group" aria-label="언어 선택"> <div
<button type="button" className="pal-mobile-lang-btn is-active" aria-pressed="true"> className="pal-mobile-lang-toggle"
role="group"
aria-label="언어 선택"
>
<button
type="button"
className="pal-mobile-lang-btn is-active"
aria-pressed="true"
>
KOR KOR
</button> </button>
<button type="button" className="pal-mobile-lang-btn" aria-pressed="false"> <button
type="button"
className="pal-mobile-lang-btn"
aria-pressed="false"
>
ENG ENG
</button> </button>
</div> </div>
</div> </div>
<div className="pal-mobile-contact-box"> <div className="pal-mobile-contact-box">
<p>프로젝트 문의 협업 상담이 필요하시면 연락해 주세요.</p> <p>프로젝트 문의 협업 상담이 필요하시면 연락해 주세요.</p>
<Link to="/contact" className="pal-mobile-contact-link" onClick={closeAllMenus}> <Link
to="/contact"
className="pal-mobile-contact-link"
onClick={closeAllMenus}
>
Contact Us Contact Us
</Link> </Link>
</div> </div>

35
src/css/common.css

@ -110,6 +110,41 @@ body{overflow-x:hidden;}
.ab-eyebrow--light{color:rgba(255,255,255,.3);} .ab-eyebrow--light{color:rgba(255,255,255,.3);}
/* cert 인증 및 특허 */
.cert-section { padding-bottom: 80px; }
.cert-section__header { margin-bottom: 48px; }
.cert-section__title { font-size: 28px; font-weight: 700; color: #111; margin: 10px 0 12px; }
.cert-section__desc { font-size: 14px; color: #555; line-height: 1.8; }
.cert-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 24px; list-style: none; }
.cert-grid__item { display: flex; flex-direction: column; gap: 10px; }
.cert-grid__item--wide { grid-column: span 2; }
.cert-grid__card { background: #fff; border: 1px solid #EBEBEB; border-radius: 12px; padding: 4px 4px 4px; display: flex; flex-direction: column; align-items: center; box-shadow: 0 2px 8px rgba(0,0,0,0.06); overflow: hidden; }
.cert-grid__imgs { display: flex; flex-direction: column; gap: 4px; width: 100%; }
.cert-grid__item--wide .cert-grid__imgs { flex-direction: row; gap: 4px; }
.cert-grid__img-wrap { flex: 1; display: flex; justify-content: center; }
.cert-grid__img { width: 100%; height: auto; object-fit: cover; object-position: center; border-radius: 8px; display: block; }
.cert-grid__label { font-size: 14px; color: #555; text-align: center; line-height: 1.4; }
.patent-section { padding: 80px 0; }
.patent-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.patent-table thead tr { border-bottom: 2px solid #111; }
.patent-table th { padding: 14px 16px; text-align: left; font-weight: 600; color: #111; }
.patent-table th:last-child { text-align: center; width: 120px; }
.patent-table td { padding: 16px 16px; color: #444; border-bottom: 1px solid #EBEBEB; line-height: 1.6; }
.patent-table td:last-child { text-align: center; color: #888; white-space: nowrap; }
.patent-table tbody tr:last-child td { border-bottom: none; }
@media (max-width: 1024px) {
.cert-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 768px) {
.cert-grid { grid-template-columns: repeat(2, 1fr); }
.cert-grid__item--wide { grid-column: span 2; }
}
@media (max-width: 480px) {
.cert-grid { gap: 8px; }
}
/* ── Partners Page ── */ /* ── Partners Page ── */
.partners-wrap {margin-top:-5rem;padding: 0 0 6rem 0; } .partners-wrap {margin-top:-5rem;padding: 0 0 6rem 0; }
.partners-title-block { padding: 5rem 0 3.5rem; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.75rem; } .partners-title-block { padding: 5rem 0 3.5rem; text-align: center; display: flex; flex-direction: column; align-items: center; gap: 0.75rem; }

1
src/pages/company/AboutPage.jsx

@ -12,6 +12,7 @@ const heroRight = <FloatingKeywords />;
const COMPANY_NAV = [ const COMPANY_NAV = [
{ label: "회사소개", to: "/company/about" }, { label: "회사소개", to: "/company/about" },
{ label: "인증 및 특허현황", to: "/company/cert" },
{ label: "연혁", to: "/company/history" }, { label: "연혁", to: "/company/history" },
{ label: "고객 및 협력사", to: "/company/partners" }, { label: "고객 및 협력사", to: "/company/partners" },
{ label: "찾아오시는 길", to: "/company/location" }, { label: "찾아오시는 길", to: "/company/location" },

208
src/pages/company/CertPage.jsx

@ -0,0 +1,208 @@
import { useRef } from "react";
import SubHero from "../../components/SubHero";
import { motion, useInView } from "framer-motion";
const ease = [0.22, 1, 0.36, 1];
const COMPANY_NAV = [
{ label: "회사소개", to: "/company/about" },
{ label: "인증 및 특허현황", to: "/company/cert" },
{ label: "연혁", to: "/company/history" },
{ label: "고객 및 협력사", to: "/company/partners" },
{ label: "찾아오시는 길", to: "/company/location" },
];
const CERTS = [
{ imgs: ["관광벤처인증.png"], label: "관광벤처인증" },
{ imgs: ["관광사업자등록증.png"], label: "관광사업자등록증" },
{ imgs: ["국방벤처기업1.png"], label: "국방벤처기업" },
{ imgs: ["국방벤처기업2.png"], label: "국방벤처기업" },
{ imgs: ["기업부설연구소.png"], label: "기업부설연구소" },
{ imgs: ["방송통신기자재_KC_인증.png"], label: "방송통신기자재 KC 인증" },
{ imgs: ["벤처기업확인서.png"], label: "벤처기업확인서" },
{ imgs: ["이노비즈확인서_팔네트웍스.png"], label: "이노비즈확인서" },
{ imgs: ["정보통신공사업등록증.png"], label: "정보통신공사업등록증" },
{ imgs: ["항공선도기업.png"], label: "항공선도기업" },
];
const PATENTS = [
{ imgs: ["대기질측정장치시스템.png"], label: "대기질측정장치 시스템" },
{
imgs: ["도심환경교통.png"],
label: "도심환경교통의 비행체 성능 시뮬레이션 시스템",
},
{
imgs: ["특허증.png"],
label: "이기종 프로토콜 지원 무인 비행체 데이터 중계장치",
},
];
const PATENT_APPLICATIONS = [
{ title: "인터넷 기반의 항공권 예약 방법 및 시스템", date: "2022-02-17" },
{
title: "드론 식별장치 및 이를 이용한 비행 관제 시스템",
date: "2022-02-17",
},
{ title: "메타버스를 활용한 교육 방법 및 시스템", date: "2022-02-17" },
{
title: "메타버스를 활용한 모의비행 훈련 방법 및 시스템",
date: "2022-02-17",
},
{ title: "대기질 측정장치 및 시스템", date: "2023-02-27" },
{ title: "무인 비행체의 비행 관리 및 모니터링 장치", date: "2023-06-26" },
{
title: "식별자 분석을 통한 무인 비행체 비행 관리 및 모니터링 장치",
date: "2024-01-08",
},
];
function ImgGrid({ items, inView, folder = "cert" }) {
const basePath = import.meta.env.BASE_URL;
return (
<ul className="cert-grid">
{items.map((item, i) => (
<motion.li
key={item.label}
className={`cert-grid__item${item.imgs.length > 1 ? " cert-grid__item--wide" : ""}`}
initial={{ opacity: 0, y: 32 }}
animate={inView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, delay: i * 0.08, ease }}
>
<div className="cert-grid__card">
<div className="cert-grid__imgs">
{item.imgs.map((img, j) => (
<div key={j} className="cert-grid__img-wrap">
<img
src={`${basePath}images/${folder}/${img}`}
alt={item.label}
className="cert-grid__img"
/>
</div>
))}
</div>
</div>
<p className="cert-grid__label">{item.label}</p>
</motion.li>
))}
</ul>
);
}
export default function CertPage() {
const ref = useRef(null);
const certRef = useRef(null);
const certInView = useInView(certRef, { once: true, margin: "-80px" });
const patentRef = useRef(null);
const patentInView = useInView(patentRef, { once: true, margin: "-80px" });
const applicationRef = useRef(null);
const applicationInView = useInView(applicationRef, {
once: true,
margin: "-80px",
});
return (
<article ref={ref}>
<SubHero
label="Company"
title={
<>
<em>Certifications</em>
</>
}
navItems={COMPANY_NAV}
/>
<div className="sub-content">
<div className="inner-wrap">
<motion.div
className="ht-header"
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-80px" }}
transition={{ duration: 0.6, ease: [0.4, 0, 0.2, 1] }}
>
<p className="ht-header-title">
Certified <span>Expertise</span>,
<br />
Protected <b>Innovation</b>
</p>
<em className="ht-header-sub">
인증된 전문성과 특허로 보호된 혁신 기술
</em>
</motion.div>
{/* 인증 */}
<section className="cert-section" ref={certRef}>
<motion.div
className="cert-section__header"
initial={{ opacity: 0, y: 20 }}
animate={certInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<span className="about-section-label">Certification</span>
<h2 className="cert-section__title">인증 현황</h2>
<p className="cert-section__desc">
팔네트웍스가 보유한 주요 인증 목록입니다.
</p>
</motion.div>
<ImgGrid items={CERTS} inView={certInView} />
</section>
{/* 특허 */}
<section className="cert-section" ref={patentRef}>
<motion.div
className="cert-section__header"
initial={{ opacity: 0, y: 20 }}
animate={patentInView ? { opacity: 1, y: 0 } : {}}
transition={{ duration: 0.6, ease }}
>
<span className="about-section-label">Patent</span>
<h2 className="cert-section__title">특허 현황</h2>
<p className="cert-section__desc">
팔네트웍스가 보유한 주요 특허 목록입니다.
</p>
</motion.div>
<ImgGrid
items={PATENTS}
inView={patentInView}
folder="cert/patents"
/>
</section>
<section className="patent-section" ref={applicationRef}>
<motion.div
className="cert-section__header"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-80px" }}
transition={{ duration: 0.6, ease }}
>
<span className="about-section-label">Patent</span>
<h2 className="cert-section__title">출원 현황</h2>
</motion.div>
<table className="patent-table">
<thead>
<tr>
<th>발명의 명칭</th>
<th>출원일자</th>
</tr>
</thead>
<tbody>
{PATENT_APPLICATIONS.map((item, i) => (
<motion.tr
key={i}
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-40px" }}
transition={{ duration: 0.5, delay: i * 0.06, ease }}
>
<td>{item.title}</td>
<td>{item.date}</td>
</motion.tr>
))}
</tbody>
</table>
</section>
</div>
</div>
</article>
);
}

165
src/pages/company/HistoryPage.jsx

@ -4,6 +4,7 @@ import SubHero from "../../components/SubHero";
const COMPANY_NAV = [ const COMPANY_NAV = [
{ label: "회사소개", to: "/company/about" }, { label: "회사소개", to: "/company/about" },
{ label: "인증 및 특허현황", to: "/company/cert" },
{ label: "연혁", to: "/company/history" }, { label: "연혁", to: "/company/history" },
{ label: "고객 및 협력사", to: "/company/partners" }, { label: "고객 및 협력사", to: "/company/partners" },
{ label: "찾아오시는 길", to: "/company/location" }, { label: "찾아오시는 길", to: "/company/location" },
@ -15,45 +16,134 @@ const HISTORY = {
"2020's": [ "2020's": [
{ {
year: "2026", year: "2026",
items: ["KAC 드론교통관리 시스템 구축 (한국공항공사)", "공공용 UTM 시작품 정보공유체계 개발 (한국공항공사)", "DA42NG VR 시뮬레이터 구축 (청주대학교)", "국방벤처 혁신기술 지원사업 기업 선정 (인천국방벤처센터)", "인천 파브(PAV) 시제기 비행시험 지원사업 (인천테크노파크)", "인천광역시 지역혁신중심 대학지원체계(i-RISE) 산학공동 기술개발사업 (인하공업전문대학)\n- 저고도 드론 비행정보 기반 UTM 비정상상황 탐지·알림 시제품 개발", "인천지역 드론기업 바우처 지원사업 (인천테크노파크)", "감항인증 전문교육과정 위탁사업 (방위산업청)", "교육현안 해결형 에듀테크 프로젝트 선정 (한국교육학술정보원)\n- 경계선 지능 학생을 위한 맞춤형 AI 에듀테크 플랫폼 구축", "인천 파브(PAV) 시제기 개발 지원사업 (인천테크노파크)\n- K-인증기반 인천PAV 실증 및 핵심 부품 국산화"], items: [
"KAC 드론교통관리 시스템 구축 (한국공항공사)",
"공공용 UTM 시작품 정보공유체계 개발 (한국공항공사)",
"DA42NG VR 시뮬레이터 구축 (청주대학교)",
"국방벤처 혁신기술 지원사업 기업 선정 (인천국방벤처센터)",
"인천 파브(PAV) 시제기 비행시험 지원사업 (인천테크노파크)",
"인천광역시 지역혁신중심 대학지원체계(i-RISE) 산학공동 기술개발사업 (인하공업전문대학)\n- 저고도 드론 비행정보 기반 UTM 비정상상황 탐지·알림 시제품 개발",
"인천지역 드론기업 바우처 지원사업 (인천테크노파크)",
"감항인증 전문교육과정 위탁사업 (방위산업청)",
"교육현안 해결형 에듀테크 프로젝트 선정 (한국교육학술정보원)\n- 경계선 지능 학생을 위한 맞춤형 AI 에듀테크 플랫폼 구축",
"인천 파브(PAV) 시제기 개발 지원사업 (인천테크노파크)\n- K-인증기반 인천PAV 실증 및 핵심 부품 국산화",
],
}, },
{ {
year: "2025", year: "2025",
items: ["KAC 드론교통관리(UTM) 시스템 구축사업 (한국공항공사)", "항공우주 부트캠프사업단 홈페이지 구축 (청주대학교)", "DIAMOND DA40NG Simulator 구축 (청주대학교)", "UTM 시뮬레이터를 활용한 비행관제 시스템 전시 (부산 벡스코 드론쇼코리아)", "인천 파브(PAV) 기업대상 기업홍보 지원사업 선정 (인천테크노파크)", "파브(PAV) 부품기술개발 지원사업 (인천테크노파크)", "감항인증 전문교육과정 위탁사업 홈페이지 운영 (방위산업청)", "공공용 UTM 시작품 정보공유체계 개발 (한국공항공사)", "IBE 개발 및 안정화 (섬에어)", "기술혁신형 중소기업 이노비즈 취득"], items: [
"KAC 드론교통관리(UTM) 시스템 구축사업 (한국공항공사)",
"항공우주 부트캠프사업단 홈페이지 구축 (청주대학교)",
"DIAMOND DA40NG Simulator 구축 (청주대학교)",
"UTM 시뮬레이터를 활용한 비행관제 시스템 전시 (부산 벡스코 드론쇼코리아)",
"인천 파브(PAV) 기업대상 기업홍보 지원사업 선정 (인천테크노파크)",
"파브(PAV) 부품기술개발 지원사업 (인천테크노파크)",
"감항인증 전문교육과정 위탁사업 홈페이지 운영 (방위산업청)",
"공공용 UTM 시작품 정보공유체계 개발 (한국공항공사)",
"IBE 개발 및 안정화 (섬에어)",
"기술혁신형 중소기업 이노비즈 취득",
],
}, },
{ {
year: "2024", year: "2024",
items: ["강화도 화개정원 유지보수 (강화군)", "타이드스퀘어 PRIVIA 항공 개발 업무 (타이드스퀘어)", "항공교통데이터시스템 (아이비리더스)", "24년 군 감항인증 전문교육과정 홈페이지 유지보수 (방위사업청)", "HILS 기반 PAV 부품 성능시험 시스템 (인하공업전문대학)", "PAV 원격 모니터링 시스템 (인천테크노파크)", "드론 지형추적비행 매뉴얼 개발 용역 (소방청 국립소방연구소)", "UTM 팀코리아(UTK) 워킹그룹 참여 (국토교통부)", "KAC 드론교통관리(UTM) 시스템 구축사업 (한국공항공사)", "도심항공교통(UTM, AAM등) 관련 사업 분석 위탁용역 (인천테크노파크)"], items: [
"강화도 화개정원 유지보수 (강화군)",
"타이드스퀘어 PRIVIA 항공 개발 업무 (타이드스퀘어)",
"항공교통데이터시스템 (아이비리더스)",
"24년 군 감항인증 전문교육과정 홈페이지 유지보수 (방위사업청)",
"HILS 기반 PAV 부품 성능시험 시스템 (인하공업전문대학)",
"PAV 원격 모니터링 시스템 (인천테크노파크)",
"드론 지형추적비행 매뉴얼 개발 용역 (소방청 국립소방연구소)",
"UTM 팀코리아(UTK) 워킹그룹 참여 (국토교통부)",
"KAC 드론교통관리(UTM) 시스템 구축사업 (한국공항공사)",
"도심항공교통(UTM, AAM등) 관련 사업 분석 위탁용역 (인천테크노파크)",
],
}, },
{ {
year: "2023", year: "2023",
items: ["섬에어(주) 항공운항 예약시스템 구축", "남원시 드론 실증도시 구축사업 협약 체결 (국토교통부)", "팔네트웍스와 베셀 MOU 체결", "UTM 운항 공역 비행체 감시 기술개발 사전기획 (인천테크노파크)", "블록체인 기반 드론교통관리(UTM) 시스템 정보공유체계 개발 (한국공항공사)", "UTM 컨설팅 (SKT)", "항공모빌리티(PAV) 부품 기술개발 지원사업 (인천테크노파크)", "LAANC/드론/PAV/UTM 비행상황관리 시스템 전시 (서울 ADEX 2023)", "UTM 비행상황관리 시스템 전시 (2023 K-UTM CONFEX)", "PAV GNSS 시뮬레이터 1세트 등 3종 제작 구매 (인하공업전문대)"], items: [
"섬에어(주) 항공운항 예약시스템 구축",
"남원시 드론 실증도시 구축사업 협약 체결 (국토교통부)",
"팔네트웍스와 베셀 MOU 체결",
"UTM 운항 공역 비행체 감시 기술개발 사전기획 (인천테크노파크)",
"블록체인 기반 드론교통관리(UTM) 시스템 정보공유체계 개발 (한국공항공사)",
"UTM 컨설팅 (SKT)",
"항공모빌리티(PAV) 부품 기술개발 지원사업 (인천테크노파크)",
"LAANC/드론/PAV/UTM 비행상황관리 시스템 전시 (서울 ADEX 2023)",
"UTM 비행상황관리 시스템 전시 (2023 K-UTM CONFEX)",
"PAV GNSS 시뮬레이터 1세트 등 3종 제작 구매 (인하공업전문대)",
],
}, },
{ {
year: "2022", year: "2022",
items: ["현대자동차 QR 코드 출입시스템 운영 및 유지보수 (현대자동차)", "군감항인증전문교육과정위탁사업 (방위산업청)", "항공모빌리티(PAV) 부품 기술개발 (인천테크노파크)", "XR 메타버스 인천이음 프로젝트 활용확산 콘텐츠 개발 (인천테크노파크)", "드론교통관리(UTM) 시스템 설계", "남원시 항공산업(드론·UTM) 클러스터 조성 연구용역", "K-UTM CONFEX 전시회 참가 (무인비행장치 관제시스템)", "남원시 항공산업 업무협약"], items: [
"현대자동차 QR 코드 출입시스템 운영 및 유지보수 (현대자동차)",
"군감항인증전문교육과정위탁사업 (방위산업청)",
"항공모빌리티(PAV) 부품 기술개발 (인천테크노파크)",
"XR 메타버스 인천이음 프로젝트 활용확산 콘텐츠 개발 (인천테크노파크)",
"드론교통관리(UTM) 시스템 설계",
"남원시 항공산업(드론·UTM) 클러스터 조성 연구용역",
"K-UTM CONFEX 전시회 참가 (무인비행장치 관제시스템)",
"남원시 항공산업 업무협약",
],
}, },
{ {
year: "2021", year: "2021",
items: ["현대자동차 QR코드 출입시스템 운영 및 유지보수 (현대자동차)", "파브 기술 및 기업/산업 현황 분석 (인천테크노파크)", "KT 클라우드 인천총판 등록 (KT)", "드론 규제 샌드박스 사업 - 비행 관제시스템 구축 (항공안전기술원)", "KB 국민은행 소프트웨어 경진대회 메타버스 구축 (사피엔스 4.0)", "드론 실증 비즈니스 사업화(공공서비스 기술 고도화) 선정", "캐플릭스 OTA 항공서비스 구축 (제주패스)", "ADEX 2021 전시회 참가", "인천 PAV 컨소시엄 선정", "KMF(Korea Metaverse Festival) 전시회 참가"], items: [
"현대자동차 QR코드 출입시스템 운영 및 유지보수 (현대자동차)",
"파브 기술 및 기업/산업 현황 분석 (인천테크노파크)",
"KT 클라우드 인천총판 등록 (KT)",
"드론 규제 샌드박스 사업 - 비행 관제시스템 구축 (항공안전기술원)",
"KB 국민은행 소프트웨어 경진대회 메타버스 구축 (사피엔스 4.0)",
"드론 실증 비즈니스 사업화(공공서비스 기술 고도화) 선정",
"캐플릭스 OTA 항공서비스 구축 (제주패스)",
"ADEX 2021 전시회 참가",
"인천 PAV 컨소시엄 선정",
"KMF(Korea Metaverse Festival) 전시회 참가",
],
}, },
{ {
year: "2020", year: "2020",
items: ["하이에어 통합시스템 유지보수 (하이에어)", "VR·AR 융합콘텐츠 실증 및 개발지원 과제 선정 (인천테크노파크)", "QR코드 활용 방문자 방역관리 모바일웹 개발 (인천관광공사)", "QR 출입명부 및 자동도어제어 시스템 개발 (현대자동차)", "하이에어 웹투어 연동 (하이에어)", "IATA Online Agency Accreditation 인증"], items: [
"하이에어 통합시스템 유지보수 (하이에어)",
"VR·AR 융합콘텐츠 실증 및 개발지원 과제 선정 (인천테크노파크)",
"QR코드 활용 방문자 방역관리 모바일웹 개발 (인천관광공사)",
"QR 출입명부 및 자동도어제어 시스템 개발 (현대자동차)",
"하이에어 웹투어 연동 (하이에어)",
"IATA Online Agency Accreditation 인증",
],
}, },
], ],
"2010's": [ "2010's": [
{ {
year: "2019", year: "2019",
items: ["IBS(PSS, 승무원 스케쥴, MRO) MOU 체결", "하이에어 IBS PSS 개발 및 납품", "하이에어 안전보안시스템(E-SMS) 개발", "하이에어 Weight & Balance System 개발"], items: [
"IBS(PSS, 승무원 스케쥴, MRO) MOU 체결",
"하이에어 IBS PSS 개발 및 납품",
"하이에어 안전보안시스템(E-SMS) 개발",
"하이에어 Weight & Balance System 개발",
],
}, },
{ {
year: "2018", year: "2018",
items: ["항공사 홈페이지 예약시스템 구축 (에어필립)", "드론을 활용한 항공등화시설 정밀점검 (항공안전기술원)", "PAL&TOUR 국외여행업 등록", "벤처기업 인증", "시험용 UTM 시스템 DB 구축 용역 개발 (KT)", "인천광역시 인천 항공 유망기업 지정"], items: [
"항공사 홈페이지 예약시스템 구축 (에어필립)",
"드론을 활용한 항공등화시설 정밀점검 (항공안전기술원)",
"PAL&TOUR 국외여행업 등록",
"벤처기업 인증",
"시험용 UTM 시스템 DB 구축 용역 개발 (KT)",
"인천광역시 인천 항공 유망기업 지정",
],
}, },
{ {
year: "2017", year: "2017",
items: ["경량항공기 내비게이션 및 비행상황관리시스템 개발 (국토교통부)", "A CDM 설계 및 RMS 개선용역 (한국공항공사)", "IBTP MOU 체결", "항공사 정비시스템 구축 (에어필립)", "본사 로봇타워 이전"], items: [
"경량항공기 내비게이션 및 비행상황관리시스템 개발 (국토교통부)",
"A CDM 설계 및 RMS 개선용역 (한국공항공사)",
"IBTP MOU 체결",
"항공사 정비시스템 구축 (에어필립)",
"본사 로봇타워 이전",
],
}, },
{ {
year: "2016", year: "2016",
@ -61,11 +151,23 @@ const HISTORY = {
}, },
{ {
year: "2015", year: "2015",
items: ["주민자치센터 홈페이지 운영시스템 (인천시)", "기업부설연구소 인정", "아우리포탈 ActiveX 제거사업 (인천공항공사)", "㈜팔네트웍스 법인 전환", "중소기업청 창업성장과제 채택 (완료: 성공판정)"], items: [
"주민자치센터 홈페이지 운영시스템 (인천시)",
"기업부설연구소 인정",
"아우리포탈 ActiveX 제거사업 (인천공항공사)",
"㈜팔네트웍스 법인 전환",
"중소기업청 창업성장과제 채택 (완료: 성공판정)",
],
}, },
{ {
year: "2014", year: "2014",
items: ["개인기업 '팔네트웍스' 개업", "항공인력양성사업 정보화시스템 보완 용역 (항공협회)", "미얀마국제항공 웹사이트 구축 (크리스탈에비에이션)", "직접생산등록", "세계 책의 수도 홈페이지 구축용역 (인천시)"], items: [
"개인기업 '팔네트웍스' 개업",
"항공인력양성사업 정보화시스템 보완 용역 (항공협회)",
"미얀마국제항공 웹사이트 구축 (크리스탈에비에이션)",
"직접생산등록",
"세계 책의 수도 홈페이지 구축용역 (인천시)",
],
}, },
], ],
}; };
@ -77,7 +179,10 @@ function YearGroup({ group }) {
useEffect(() => { useEffect(() => {
const el = ref.current; const el = ref.current;
if (!el) return; if (!el) return;
const observer = new IntersectionObserver(([entry]) => setActive(entry.isIntersecting), { rootMargin: "-30% 0px -60% 0px" }); const observer = new IntersectionObserver(
([entry]) => setActive(entry.isIntersecting),
{ rootMargin: "-30% 0px -60% 0px" },
);
observer.observe(el); observer.observe(el);
return () => observer.disconnect(); return () => observer.disconnect();
}, []); }, []);
@ -85,12 +190,23 @@ function YearGroup({ group }) {
return ( return (
<div ref={ref} className="ht-group"> <div ref={ref} className="ht-group">
<div className={`ht-dot${active ? " is-active" : ""}`} /> <div className={`ht-dot${active ? " is-active" : ""}`} />
<motion.h3 className="ht-year" animate={{ color: active ? "var(--color-primary)" : "#ccc" }} transition={{ duration: 0.4 }}> <motion.h3
className="ht-year"
animate={{ color: active ? "var(--color-primary)" : "#ccc" }}
transition={{ duration: 0.4 }}
>
{group.year} {group.year}
</motion.h3> </motion.h3>
<ul className="ht-list"> <ul className="ht-list">
{group.items.map((text, i) => ( {group.items.map((text, i) => (
<motion.li key={i} className="ht-item" initial={{ opacity: 0, y: 8 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true, margin: "-40px" }} transition={{ delay: i * 0.04, duration: 0.3 }}> <motion.li
key={i}
className="ht-item"
initial={{ opacity: 0, y: 8 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-40px" }}
transition={{ delay: i * 0.04, duration: 0.3 }}
>
<span className="ht-bullet" /> <span className="ht-bullet" />
<span className="ht-text">{text}</span> <span className="ht-text">{text}</span>
</motion.li> </motion.li>
@ -121,7 +237,10 @@ function TimelinePanel({ tab }) {
{/* 중앙 라인 — 1px 얇은 선 */} {/* 중앙 라인 — 1px 얇은 선 */}
<div className="ht-line-col"> <div className="ht-line-col">
<div className="ht-line-bg" /> <div className="ht-line-bg" />
<motion.div className="ht-line-fill" style={{ scaleY: lineScaleY, transformOrigin: "top" }} /> <motion.div
className="ht-line-fill"
style={{ scaleY: lineScaleY, transformOrigin: "top" }}
/>
</div> </div>
{/* 오른쪽 콘텐츠 */} {/* 오른쪽 콘텐츠 */}
@ -152,7 +271,13 @@ export default function HistoryPage() {
<div className="sub-content"> <div className="sub-content">
<div className="inner-wrap"> <div className="inner-wrap">
{/* 상단 타이틀 */} {/* 상단 타이틀 */}
<motion.div className="ht-header" initial={{ opacity: 0, y: 32 }} whileInView={{ opacity: 1, y: 0 }} viewport={{ once: true, margin: "-80px" }} transition={{ duration: 0.6, ease: [0.4, 0, 0.2, 1] }}> <motion.div
className="ht-header"
initial={{ opacity: 0, y: 32 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-80px" }}
transition={{ duration: 0.6, ease: [0.4, 0, 0.2, 1] }}
>
<p className="ht-header-title"> <p className="ht-header-title">
Leading the Future Leading the Future
<br /> <br />
@ -171,7 +296,11 @@ export default function HistoryPage() {
<div className="ht-card"> <div className="ht-card">
<div className="ht-tabs"> <div className="ht-tabs">
{TABS.map((tab) => ( {TABS.map((tab) => (
<button key={tab} className={`ht-tab${activeTab === tab ? " is-active" : ""}`} onClick={() => setActiveTab(tab)}> <button
key={tab}
className={`ht-tab${activeTab === tab ? " is-active" : ""}`}
onClick={() => setActiveTab(tab)}
>
{tab} {tab}
</button> </button>
))} ))}

1
src/pages/company/LocationPage.jsx

@ -6,6 +6,7 @@ import { Link } from "react-router-dom";
const COMPANY_NAV = [ const COMPANY_NAV = [
{ label: "회사소개", to: "/company/about" }, { label: "회사소개", to: "/company/about" },
{ label: "인증 및 특허현황", to: "/company/cert" },
{ label: "연혁", to: "/company/history" }, { label: "연혁", to: "/company/history" },
{ label: "고객 및 협력사", to: "/company/partners" }, { label: "고객 및 협력사", to: "/company/partners" },
{ label: "찾아오시는 길", to: "/company/location" }, { label: "찾아오시는 길", to: "/company/location" },

1
src/pages/company/PartnersPage.jsx

@ -11,6 +11,7 @@ gsap.registerPlugin(ScrollTrigger);
const COMPANY_NAV = [ const COMPANY_NAV = [
{ label: "회사소개", to: "/company/about" }, { label: "회사소개", to: "/company/about" },
{ label: "인증 및 특허현황", to: "/company/cert" },
{ label: "연혁", to: "/company/history" }, { label: "연혁", to: "/company/history" },
{ label: "고객 및 협력사", to: "/company/partners" }, { label: "고객 및 협력사", to: "/company/partners" },
{ label: "찾아오시는 길", to: "/company/location" }, { label: "찾아오시는 길", to: "/company/location" },

Loading…
Cancel
Save