You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

162 lines
5.7 KiB

"use client";
import React, { useState, useEffect } from "react";
import type { NavItem } from "../types";
import { LangSwitch } from "./LangSwitch";
export interface MainNavProps {
items: NavItem[];
basePath?: string; // e.g. /zh-CN
locale?: string; // zh-CN | en
}
export function MainNav({ items, basePath = "", locale = "zh-CN" }: MainNavProps) {
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
const [currentPath, setCurrentPath] = useState("");
useEffect(() => {
const updatePath = () => {
setCurrentPath(window.location.pathname);
};
updatePath();
// 监听浏览器前进/后退
window.addEventListener("popstate", updatePath);
// 监听点击事件(处理 Next.js 客户端导航)
const handleClick = (e: MouseEvent) => {
const target = e.target as HTMLElement;
const link = target.closest("a");
if (link && link.href) {
setTimeout(() => {
updatePath();
}, 100);
}
};
document.addEventListener("click", handleClick);
return () => {
window.removeEventListener("popstate", updatePath);
document.removeEventListener("click", handleClick);
};
}, []);
const isActive = (href: string) => {
if (!currentPath) return false;
if (href.startsWith("#")) return false;
const fullPath = `${basePath}${href}`;
// 首页匹配
if (href === "/" || href === "") {
return currentPath === basePath || currentPath === `${basePath}/`;
}
// 精确匹配或作为路径前缀匹配
return currentPath === fullPath || currentPath.startsWith(`${fullPath}/`);
};
return (
<header className="w-full bg-huilong-bg fixed top-0 left-0 right-0 z-50 border-b border-[rgba(255,255,255,0.02)]">
<div className="max-w-[1200px] mx-auto px-4 md:px-6 py-3 md:py-5 flex items-center justify-between">
<a href={basePath || "/"} className="flex items-center gap-2 md:gap-3 no-underline flex-shrink-0">
<div className="bg-gradient-to-b from-huilong-gold to-[#a8823d] px-2 md:px-[10px] py-1 md:py-[6px] rounded text-xs md:text-sm font-bold text-huilong-bg">
{locale === "en" ? "HL" : "汇龙"}
</div>
<div className="font-semibold tracking-wide text-white text-sm md:text-base hidden sm:block">Huilong Xingda</div>
</a>
{/* PC端导航菜单 */}
<nav className="hidden md:flex items-center gap-3 lg:gap-4">
{items.map((item) => {
const isCta = item.href === "/contact";
const isAnchor = item.href.startsWith("#");
const href = isAnchor ? item.href : `${basePath}${item.href}`;
const active = isActive(item.href);
return (
<a
key={item.label}
href={href}
className={`no-underline transition-colors text-sm lg:text-base ${
isCta
? `px-3 py-2 rounded-md border ${
active
? "border-huilong-gold bg-huilong-gold/10 text-huilong-gold"
: "border-[rgba(196,161,75,0.12)] text-huilong-gold"
}`
: active
? "mr-2 lg:mr-3.5 text-white font-medium"
: "mr-2 lg:mr-3.5 text-huilong-muted hover:text-white"
}`}
>
{item.label}
</a>
);
})}
</nav>
<div className="flex items-center gap-3">
<LangSwitch basePath={basePath} locale={locale} />
{/* 移动端菜单按钮 */}
<button
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
className="md:hidden p-2 text-huilong-muted hover:text-white focus:outline-none"
aria-label="Toggle menu"
>
<svg
className="w-6 h-6"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
stroke="currentColor"
>
{mobileMenuOpen ? (
<path d="M6 18L18 6M6 6l12 12" />
) : (
<path d="M4 6h16M4 12h16M4 18h16" />
)}
</svg>
</button>
</div>
</div>
{/* 移动端导航菜单 */}
{mobileMenuOpen && (
<div className="md:hidden bg-huilong-bg border-t border-[rgba(255,255,255,0.02)] max-h-[calc(100vh-80px)] overflow-y-auto">
<nav className="max-w-[1200px] mx-auto px-4 md:px-6 py-4 space-y-2">
{items.map((item) => {
const isCta = item.href === "/contact";
const isAnchor = item.href.startsWith("#");
const href = isAnchor ? item.href : `${basePath}${item.href}`;
const active = isActive(item.href);
return (
<a
key={item.label}
href={href}
className={`block py-2 px-2 rounded ${
isCta
? `border ${
active
? "border-huilong-gold bg-huilong-gold/10 text-huilong-gold"
: "border-[rgba(196,161,75,0.12)] text-huilong-gold"
}`
: active
? "text-white font-medium bg-[rgba(196,161,75,0.05)]"
: "text-huilong-muted hover:text-white"
}`}
onClick={() => setMobileMenuOpen(false)}
>
{item.label}
</a>
);
})}
</nav>
</div>
)}
</header>
);
}