| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- import React, {useState} from 'react';
- import menuItems from '@/data/menuItems';
- import {Link} from "react-router-dom";
- import {IMAGE_PREFIX} from "@/constants";
- const Header = () => {
- const [activeIndex, setActiveIndex] = useState<number | null>(null);
- const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
- const [mobileActiveIndex, setMobileActiveIndex] = useState<number | null>(null);
- const [isMenuHovered, setIsMenuHovered] = useState(false);
- const scrollToTop = () => {
- window.scrollTo({
- top: 0,
- behavior: 'smooth'
- });
- };
- return (
- <header className="fixed top-0 left-0 right-0 flex items-center h-16 sm:h-20 w-full bg-white shadow-md z-50">
- <article
- id="sidebar-dimmer"
- className={`fixed top-16 sm:top-20 left-0 w-full h-full transition-opacity duration-500 ease-in-out ${isMenuHovered ? 'bg-black/50 opacity-100 pointer-events-auto' : 'opacity-0 pointer-events-none'} hidden lg:block`}
- />
- <Link
- to="/"
- onClick={() => {
- setActiveIndex(null);
- setMobileMenuOpen(false);
- setMobileActiveIndex(null);
- scrollToTop();
- }}
- className="absolute left-4 sm:left-[40px] top-1/2 transform -translate-y-1/2 flex items-center gap-1 w-36"
- >
- <img className="w-12 h-8" src={`${IMAGE_PREFIX}/logo.png`} alt="logo"/>
- <div className="text-gray-600 text-2xl font-bold font-['Noto_Sans_KR']">반도산전</div>
- </Link>
- <nav
- className="hidden lg:flex justify-center items-center w-full h-full"
- onMouseEnter={() => setIsMenuHovered(true)}
- onMouseLeave={() => {
- setIsMenuHovered(false);
- setActiveIndex(null);
- }}
- >
- {menuItems.map((item, index) => (
- <div
- key={index}
- className="relative flex flex-col items-center px-[3vw] cursor-pointer"
- onMouseEnter={() => setActiveIndex(index)}
- >
- <div
- className={`relative group font-bold font-['Noto_Sans_KR'] cursor-pointer ${activeIndex === index ? 'text-blue-600' : 'text-gray-600'}`}>
- {item.label}
- <span
- className={`absolute left-0 bottom-[-2px] h-[1px] bg-blue-600 transition-all duration-300 ${activeIndex === index ? 'w-full' : 'w-0'}`}></span>
- </div>
- </div>
- ))}
- </nav>
- <button
- className="lg:hidden absolute right-4 top-1/2 transform -translate-y-1/2 flex flex-col justify-center items-center w-8 h-8 rounded-md hover:bg-gray-100 transition-colors duration-200"
- onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
- >
- <span className={`absolute block w-6 h-0.5 bg-gray-700 transition-all duration-300 ${mobileMenuOpen ? "rotate-45" : "-translate-y-2"}`}></span>
- <span className={`absolute block w-6 h-0.5 bg-gray-700 transition-all duration-300 ${mobileMenuOpen ? "opacity-0" : ""}`}></span>
- <span className={`absolute block w-6 h-0.5 bg-gray-700 transition-all duration-300 ${mobileMenuOpen ? "-rotate-45" : "translate-y-2"}`}></span>
- </button>
- {isMenuHovered && (
- <div
- id="menuBox"
- className="hidden lg:block absolute w-full h-[45vh] top-16 sm:top-20 bg-blue-900 overflow-hidden z-40"
- onMouseEnter={() => setIsMenuHovered(true)}
- onMouseLeave={() => {
- setIsMenuHovered(false);
- setActiveIndex(null);
- }}
- style={{
- animation: 'fadeIn 0.15s ease-in forwards'
- }}
- >
- <style>{`
- @keyframes fadeIn {
- from {
- opacity: 0;
- }
- to {
- opacity: 1;
- }
- }
- `}</style>
- <div className="max-w-7xl mx-auto flex justify-center items-start pt-8">
- {menuItems.map((item, index) => (
- <div key={index} className="flex flex-col items-center px-[3vw]">
- {item.children.length > 0 && (
- <div className="flex flex-col space-y-6 pt-4">
- {item.children.map((child, cIdx) => (
- <Link
- to={`${item.href}/${child.href}`}
- key={cIdx}
- className="relative inline-block text-md text-center font-medium font-['Noto_Sans_KR'] text-white whitespace-normal max-w-[100px] break-words hover:text-white/80 transition-all duration-200 group animate-in fade-in-0 slide-in-from-top-1"
- style={{ animationDelay: `${cIdx * 50}ms` }}
- onClick={() => {
- setActiveIndex(null);
- setIsMenuHovered(false);
- scrollToTop();
- }}
- >
- <span className="relative inline-block">
- {child.label}
- <span className="absolute left-0 bottom-[-2px] h-[1px] w-0 bg-white transition-all duration-300 group-hover:w-full"></span>
- </span>
- </Link>
- ))}
- </div>
- )}
- </div>
- ))}
- </div>
- </div>
- )}
- {mobileMenuOpen && (
- <div className="lg:hidden absolute top-16 sm:top-20 left-0 w-full bg-white shadow-xl border-t transform animate-in slide-in-from-top-2 duration-300">
- <nav className="flex flex-col">
- {menuItems.map((item, index) => (
- <div key={index} className="border-b border-gray-100">
- <div
- className="flex justify-between items-center px-5 py-3.5 text-gray-700 font-medium text-sm cursor-pointer hover:bg-blue-50 hover:text-blue-700 transition-all duration-200"
- onClick={() => setMobileActiveIndex(mobileActiveIndex === index ? null : index)}
- >
- <span>{item.label}</span>
- {item.children.length > 0 && (
- <svg
- className={`w-4 h-4 transition-transform duration-200 ${mobileActiveIndex === index ? 'rotate-180' : ''}`}
- fill="none"
- stroke="currentColor"
- viewBox="0 0 24 24"
- >
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
- </svg>
- )}
- </div>
- {mobileActiveIndex === index && item.children.length > 0 && (
- <div className="bg-gray-50 animate-in slide-in-from-top-1 duration-200">
- {item.children.map((child, cIdx) => (
- <Link
- to={`${item.href}/${child.href}`}
- key={cIdx}
- className="block px-8 py-2.5 text-sm text-gray-600 hover:text-blue-600 hover:bg-white transition-colors duration-200 border-l-2 border-transparent hover:border-blue-500"
- onClick={() => {
- setMobileActiveIndex(null);
- setMobileMenuOpen(false);
- scrollToTop();
- }}
- >
- {child.label}
- </Link>
- ))}
- </div>
- )}
- </div>
- ))}
- </nav>
- </div>
- )}
- </header>
- );
- };
- export default Header;
|