summaryrefslogtreecommitdiff
path: root/components/layout/Header.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout/Header.tsx')
-rw-r--r--components/layout/Header.tsx215
1 files changed, 113 insertions, 102 deletions
diff --git a/components/layout/Header.tsx b/components/layout/Header.tsx
index 1b6c45bb..498668eb 100644
--- a/components/layout/Header.tsx
+++ b/components/layout/Header.tsx
@@ -26,19 +26,20 @@ import { SearchIcon, BellIcon, Menu } from "lucide-react";
import { useParams, usePathname } from "next/navigation";
import { cn } from "@/lib/utils";
import Image from "next/image";
-import { mainNav, additionalNav, MenuSection, mainNavVendor, additionalNavVendor } from "@/config/menuConfig"; // 메뉴 구성 임포트
+import { mainNav, additionalNav, MenuSection, MenuItem, mainNavVendor, additionalNavVendor } from "@/config/menuConfig"; // 메뉴 구성 임포트
import { MobileMenu } from "./MobileMenu";
import { CommandMenu } from "./command-menu";
import { useSession, signOut } from "next-auth/react";
-
+import GroupedMenuRenderer from "./GroupedMenuRender";
export function Header() {
const params = useParams();
- const lng = params.lng as string;
+ const lng = params?.lng as string;
const pathname = usePathname();
const { data: session } = useSession();
- const userName = session?.user?.name || ""; // 없을 수도 있으니 안전하게 처리
+ const userName = session?.user?.name || "";
+ const domain = session?.user?.domain || "";
const initials = userName
.split(" ")
.map((word) => word[0]?.toUpperCase())
@@ -51,7 +52,7 @@ export function Header() {
setIsMobileMenuOpen(!isMobileMenuOpen);
};
- const isPartnerRoute = pathname.includes("/partners");
+ const isPartnerRoute = pathname?.includes("/partners");
const main = isPartnerRoute ? mainNavVendor : mainNav;
const additional = isPartnerRoute ? additionalNavVendor : additionalNav;
@@ -60,10 +61,10 @@ export function Header() {
return (
<>
- <header className="border-grid sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
+ <header className="border-grid sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container-wrapper">
<div className="container flex h-14 items-center">
-
+ {/* 햄버거 메뉴 버튼 (모바일) */}
<Button
onClick={toggleMobileMenu}
variant="ghost"
@@ -86,105 +87,115 @@ export function Header() {
<span className="sr-only">Toggle Menu</span>
</Button>
-
- <div className="mr-4 hidden md:flex">
-
- {/* 로고 영역 */}
- <div className="mr-4 flex items-center gap-2 lg:mr-6">
- <Link href={`/${lng}/evcp`} className="flex items-center gap-2">
- <Image
- className="dark:invert"
- src="/images/vercel.svg"
- alt="EVCP Logo"
- width={20}
- height={20}
- />
- <span className="hidden font-bold lg:inline-block">eVCP</span>
- </Link>
- </div>
- {/* 데스크탑 네비게이션 메뉴 */}
- <NavigationMenu className="flex items-center gap-4 text-sm xl:gap-6">
- <NavigationMenuList>
- {main.map((section: MenuSection) => (
- <NavigationMenuItem key={section.title}>
- <NavigationMenuTrigger>{section.title}</NavigationMenuTrigger>
- <NavigationMenuContent>
- <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
- {section.items.map((item) => (
- <ListItem
- key={item.title}
- title={item.title}
- href={`/${lng}${item.href}`}
- >
- {item.description}
- </ListItem>
- ))}
- </ul>
- </NavigationMenuContent>
- </NavigationMenuItem>
- ))}
-
-
- {/* 추가 네비게이션 항목 */}
- {additional.map((item) => (
- <NavigationMenuItem key={item.title}>
- <Link href={`/${lng}${item.href}`} legacyBehavior passHref>
- <NavigationMenuLink className={navigationMenuTriggerStyle()}>
- {item.title}
- </NavigationMenuLink>
- </Link>
- </NavigationMenuItem>
- ))}
- </NavigationMenuList>
+ {/* 로고 영역 - 항상 표시 */}
+ <div className="mr-4 flex-shrink-0 flex items-center gap-2 lg:mr-6">
+ <Link href={`/${lng}/evcp`} className="flex items-center gap-2">
+ <Image
+ className="dark:invert"
+ src="/images/vercel.svg"
+ alt="EVCP Logo"
+ width={20}
+ height={20}
+ />
+ <span className="hidden font-bold lg:inline-block">eVCP</span>
+ </Link>
+ </div>
+
+ {/* 네비게이션 메뉴 - 내부 스크롤 적용, 드롭다운은 제약 없이 표시 */}
+ <div className="hidden md:block flex-1 min-w-0">
+ {/* NavigationMenu는 z-index를 높게 설정하여 드롭다운이 제대로 표시되도록 함 */}
+ <NavigationMenu className="relative z-50">
+ {/* 스크롤 가능한 메뉴 리스트 컨테이너 */}
+ <div className="w-full overflow-x-auto pb-1">
+ <NavigationMenuList className="flex-nowrap w-max">
+ {main.map((section: MenuSection) => (
+ <NavigationMenuItem key={section.title}>
+ <NavigationMenuTrigger className="px-2 xl:px-3 text-sm whitespace-nowrap">
+ {section.title}
+ </NavigationMenuTrigger>
+
+ {/* 그룹핑이 필요한 메뉴의 경우 GroupedMenuRenderer 사용 */}
+ {section.useGrouping ? (
+ <NavigationMenuContent>
+ <GroupedMenuRenderer items={section.items} lng={lng} />
+ </NavigationMenuContent>
+ ) : (
+ <NavigationMenuContent>
+ <ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
+ {section.items.map((item) => (
+ <ListItem
+ key={item.title}
+ title={item.title}
+ href={`/${lng}${item.href}`}
+ >
+ {item.description}
+ </ListItem>
+ ))}
+ </ul>
+ </NavigationMenuContent>
+ )}
+ </NavigationMenuItem>
+ ))}
+
+ {/* 추가 네비게이션 항목 */}
+ {additional.map((item) => (
+ <NavigationMenuItem key={item.title}>
+ <Link href={`/${lng}${item.href}`} legacyBehavior passHref>
+ <NavigationMenuLink
+ className={cn(
+ navigationMenuTriggerStyle(),
+ "px-2 xl:px-3 text-sm whitespace-nowrap"
+ )}
+ >
+ {item.title}
+ </NavigationMenuLink>
+ </Link>
+ </NavigationMenuItem>
+ ))}
+ </NavigationMenuList>
+ </div>
</NavigationMenu>
-
-
</div>
-
- {/* 우측 영역 */}
- <div className="flex flex-1 items-center justify-between gap-2 md:justify-end">
-
- <CommandMenu />
-
-
- <div className="flex items-center space-x-4">
- {/* 알림 버튼 */}
- <Button variant="ghost" className="relative p-2" aria-label="Notifications">
- <BellIcon className="h-5 w-5" />
- {/* 알림 뱃지 예시 */}
- <span className="absolute -top-1 -right-1 inline-flex h-2 w-2 rounded-full bg-red-500"></span>
- </Button>
-
- {/* 사용자 메뉴 (DropdownMenu) */}
- <DropdownMenu>
- <DropdownMenuTrigger asChild>
- <Avatar className="cursor-pointer">
- <AvatarImage src={`/profiles/${session?.user?.image}`||"/user-avatar.jpg"} alt="User Avatar" />
- <AvatarFallback>
- {initials || "?"}
- </AvatarFallback>
- </Avatar>
- </DropdownMenuTrigger>
- <DropdownMenuContent className="w-48" align="end">
- <DropdownMenuLabel>My Account</DropdownMenuLabel>
- <DropdownMenuSeparator />
- {/* <DropdownMenuItem asChild>
- <Link href={`${basePath}/profile`}>Profile</Link>
- </DropdownMenuItem> */}
- <DropdownMenuItem asChild>
- <Link href={`${basePath}/settings`}>Settings</Link>
- </DropdownMenuItem>
- <DropdownMenuSeparator />
- <DropdownMenuItem onSelect={() => signOut({ callbackUrl: `/${lng}/login` })}>
- Logout
- </DropdownMenuItem>
- </DropdownMenuContent>
- </DropdownMenu>
-
- {/* 모바일 햄버거 메뉴 버튼 */}
-
+ {/* 우측 영역 - 고정 너비와 우선순위로 항상 표시되도록 함 */}
+ <div className="ml-auto flex flex-shrink-0 items-center space-x-2">
+ {/* 데스크탑에서는 CommandMenu, 모바일에서는 검색 아이콘만 */}
+ <div className="hidden md:block md:w-auto">
+ <CommandMenu />
</div>
+ <Button variant="ghost" size="icon" className="md:hidden" aria-label="Search">
+ <SearchIcon className="h-5 w-5" />
+ </Button>
+
+ {/* 알림 버튼 */}
+ <Button variant="ghost" size="icon" className="relative" aria-label="Notifications">
+ <BellIcon className="h-5 w-5" />
+ {/* 알림 뱃지 예시 */}
+ <span className="absolute -top-1 -right-1 inline-flex h-2 w-2 rounded-full bg-red-500"></span>
+ </Button>
+
+ {/* 사용자 메뉴 (DropdownMenu) */}
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Avatar className="cursor-pointer h-8 w-8">
+ <AvatarImage src={`/profiles/${session?.user?.image}`||"/user-avatar.jpg"} alt="User Avatar" />
+ <AvatarFallback>
+ {initials || "?"}
+ </AvatarFallback>
+ </Avatar>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent className="w-48" align="end">
+ <DropdownMenuLabel>My Account</DropdownMenuLabel>
+ <DropdownMenuSeparator />
+ <DropdownMenuItem asChild>
+ <Link href={`${basePath}/settings`}>Settings</Link>
+ </DropdownMenuItem>
+ <DropdownMenuSeparator />
+ <DropdownMenuItem onSelect={() => signOut({ callbackUrl: `/${lng}/${domain}` })}>
+ Logout
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
</div>
</div>
</div>