feat: refactor Header with NAVIGATION_V2 and MegaDropdown integration

This commit is contained in:
张翔
2026-04-30 19:09:29 +08:00
parent 85fcb615d8
commit 6a098d115d
+17 -7
View File
@@ -7,7 +7,8 @@ import { usePathname, useSearchParams } from 'next/navigation';
import { Menu, X } from 'lucide-react'; import { Menu, X } from 'lucide-react';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { COMPANY_INFO, NAVIGATION, type NavigationItem } from '@/lib/constants'; import { COMPANY_INFO, NAVIGATION_V2, MEGA_DROPDOWN_DATA, type NavigationItemV2 } from '@/lib/constants';
import { MegaDropdown } from '@/components/layout/mega-dropdown';
import { useFocusTrap } from '@/hooks/use-focus-trap'; import { useFocusTrap } from '@/hooks/use-focus-trap';
declare global { declare global {
@@ -19,6 +20,7 @@ declare global {
function HeaderContent() { function HeaderContent() {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false); const [isScrolled, setIsScrolled] = useState(false);
const [openDropdown, setOpenDropdown] = useState<string | null>(null);
const pathname = usePathname(); const pathname = usePathname();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const focusTrapRef = useFocusTrap<HTMLDivElement>(isOpen); const focusTrapRef = useFocusTrap<HTMLDivElement>(isOpen);
@@ -91,7 +93,7 @@ function HeaderContent() {
} }
}, [isOpen]); }, [isOpen]);
const handleNavClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>, item: NavigationItem) => { const handleNavClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>, item: NavigationItemV2) => {
e.preventDefault(); e.preventDefault();
if (item.id === 'contact') { if (item.id === 'contact') {
@@ -133,7 +135,7 @@ function HeaderContent() {
setIsOpen(false); setIsOpen(false);
}, [pathname]); }, [pathname]);
const isActive = useCallback((item: NavigationItem) => { const isActive = useCallback((item: NavigationItemV2) => {
if (item.id === 'contact') { if (item.id === 'contact') {
return pathname === '/contact'; return pathname === '/contact';
} }
@@ -145,8 +147,6 @@ function HeaderContent() {
return false; return false;
}, [pathname, activeSection]); }, [pathname, activeSection]);
const navigationItems = NAVIGATION;
return ( return (
<> <>
<header <header
@@ -178,7 +178,16 @@ function HeaderContent() {
</StaticLink> </StaticLink>
<nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航" data-testid="desktop-navigation"> <nav className="hidden md:flex items-center gap-1" role="navigation" aria-label="主导航" data-testid="desktop-navigation">
{navigationItems.map((item) => ( {NAVIGATION_V2.map((item) => (
item.hasDropdown ? (
<MegaDropdown
key={item.id}
label={item.label}
items={MEGA_DROPDOWN_DATA[item.dropdownKey!]}
isOpen={openDropdown === item.id}
onToggle={() => setOpenDropdown(openDropdown === item.id ? null : item.id)}
/>
) : (
<StaticLink <StaticLink
key={item.id} key={item.id}
href={item.href} href={item.href}
@@ -205,6 +214,7 @@ function HeaderContent() {
`} `}
/> />
</StaticLink> </StaticLink>
)
))} ))}
</nav> </nav>
@@ -260,7 +270,7 @@ function HeaderContent() {
data-testid="mobile-navigation" data-testid="mobile-navigation"
> >
<nav className="container-wide py-6"> <nav className="container-wide py-6">
{navigationItems.map((item, index) => ( {NAVIGATION_V2.map((item, index) => (
<motion.div <motion.div
key={item.id} key={item.id}
initial={{ x: 20, opacity: 0 }} initial={{ x: 20, opacity: 0 }}