feat: 优化header组件语义化
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname, useRouter } from "next/navigation";
|
import { usePathname, useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerContent,
|
DrawerContent,
|
||||||
@@ -29,81 +29,100 @@ export default function Header() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>, path: string) => {
|
const handleClick = (e: React.MouseEvent<HTMLAnchorElement>, path: string) => {
|
||||||
e.preventDefault();
|
|
||||||
if (path === '/console') {
|
if (path === '/console') {
|
||||||
|
e.preventDefault();
|
||||||
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
|
const token = typeof window !== 'undefined' ? localStorage.getItem('token') : null;
|
||||||
router.push(token ? '/console' : '/console/login');
|
router.push(token ? '/console' : '/console/login');
|
||||||
|
setShowMenu(false);
|
||||||
} else {
|
} else {
|
||||||
router.push(path);
|
setShowMenu(false);
|
||||||
}
|
}
|
||||||
setShowMenu(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const menuButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showMenu && menuButtonRef.current) {
|
||||||
|
menuButtonRef.current.focus();
|
||||||
|
}
|
||||||
|
}, [showMenu]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-50 backdrop-blur-sm bg-white/40 shadow">
|
<>
|
||||||
<div className="flex items-center justify-between px-10 md:h-18 md:px-20 h-14 duration-300">
|
<header className="sticky top-0 z-50 backdrop-blur-sm bg-white/40 shadow" role="banner" aria-label="网站顶部导航栏">
|
||||||
<Link
|
<div className="flex items-center justify-between px-10 md:h-18 md:px-20 h-14 duration-300" aria-label="主菜单">
|
||||||
href="/"
|
<Link
|
||||||
className={cn(
|
href="/"
|
||||||
"cursor-pointer font-medium text-zinc-500 hover:text-zinc-800 border-b-4 border-transparent duration-200",
|
className={cn(
|
||||||
pathname === "/" && "text-zinc-800"
|
"cursor-pointer font-medium text-zinc-500 hover:text-zinc-800 border-b-4 border-transparent duration-200",
|
||||||
)}
|
pathname === "/" && "text-zinc-800"
|
||||||
>
|
)}
|
||||||
{pathname === "/"
|
aria-current={pathname === "/" ? "page" : undefined}
|
||||||
? <div className="text-2xl"> 🍭</div>
|
>
|
||||||
: <div className="md:text-lg">特恩(TONE)</div>}
|
<span className="sr-only">特恩(TONE)</span>
|
||||||
</Link>
|
{pathname === "/"
|
||||||
|
? <span className="text-2xl" aria-hidden="true" >🍭</span>
|
||||||
|
: <span className="md:text-lg" aria-hidden="true">特恩(TONE)</span>}
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
<nav className={cn(
|
||||||
|
"items-center gap-12 hidden sm:flex",
|
||||||
|
)}>
|
||||||
|
{menuItems.slice(1).map((item) => (
|
||||||
|
<Link
|
||||||
|
key={item.name}
|
||||||
|
href={item.path}
|
||||||
|
className={cn(
|
||||||
|
"cursor-pointer md:text-lg font-medium text-zinc-500 hover:text-zinc-800 border-b-4 border-transparent duration-200",
|
||||||
|
pathname.startsWith(item.path) && "text-zinc-800 border-b-pink-500"
|
||||||
|
)}
|
||||||
|
onClick={e => handleClick(e, item.path)}
|
||||||
|
aria-current={pathname === item.path ? "page" : undefined}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
|
||||||
<Drawer direction="right" open={showMenu} onOpenChange={(state) => !state && setShowMenu(false)}>
|
<button
|
||||||
<DrawerTrigger>
|
ref={menuButtonRef}
|
||||||
<div className="sm:hidden cursor-pointer text-zinc-600" onClick={() => setShowMenu(true)}>
|
className="sm:hidden text-zinc-600"
|
||||||
菜单
|
onClick={() => setShowMenu(true)}
|
||||||
</div>
|
aria-label="打开主菜单"
|
||||||
</DrawerTrigger>
|
>菜单</button>
|
||||||
<DrawerContent>
|
|
||||||
<DrawerHeader>
|
|
||||||
<DrawerTitle className="flex justify-between">
|
|
||||||
<span>菜单</span>
|
|
||||||
<X className="cursor-pointer" onClick={() => setShowMenu(false)} />
|
|
||||||
</DrawerTitle>
|
|
||||||
<DrawerDescription>请选择需要前往的页面</DrawerDescription>
|
|
||||||
</DrawerHeader>
|
|
||||||
<div className="w-full flex flex-col px-4 gap-2">
|
|
||||||
{menuItems.slice(1).map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.name}
|
|
||||||
href={item.path}
|
|
||||||
onClick={e => handleClick(e, item.path)}
|
|
||||||
>
|
|
||||||
<Button className="w-full" size='lg'
|
|
||||||
variant={pathname.startsWith(item.path) ? 'default' : 'outline'}
|
|
||||||
>{item.name}</Button>
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</DrawerContent>
|
|
||||||
</Drawer>
|
|
||||||
|
|
||||||
<div className={cn(
|
|
||||||
"sm:flex items-center gap-12 hidden",
|
|
||||||
)}>
|
|
||||||
{menuItems.slice(1).map((item) => (
|
|
||||||
<Link
|
|
||||||
key={item.name}
|
|
||||||
href={item.path}
|
|
||||||
className={cn(
|
|
||||||
"cursor-pointer md:text-lg font-medium text-zinc-500 hover:text-zinc-800 border-b-4 border-transparent duration-200",
|
|
||||||
pathname.startsWith(item.path) && "text-zinc-800 border-b-pink-500"
|
|
||||||
)}
|
|
||||||
onClick={e => handleClick(e, item.path)}
|
|
||||||
>
|
|
||||||
{item.name}
|
|
||||||
</Link>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</header >
|
||||||
</header >
|
|
||||||
|
<Drawer direction="right" open={showMenu} onOpenChange={setShowMenu}>
|
||||||
|
<DrawerContent>
|
||||||
|
<DrawerHeader>
|
||||||
|
<DrawerTitle className="flex justify-between">
|
||||||
|
<span>菜单</span>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowMenu(false)}
|
||||||
|
aria-label="关闭菜单"
|
||||||
|
>
|
||||||
|
<X className="size-5" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
</DrawerTitle>
|
||||||
|
<DrawerDescription>请选择需要前往的页面</DrawerDescription>
|
||||||
|
</DrawerHeader>
|
||||||
|
<nav className="w-full flex flex-col px-4 gap-2" aria-label="移动设备主菜单">
|
||||||
|
{menuItems.slice(1).map((item) => (
|
||||||
|
<Link
|
||||||
|
key={item.name}
|
||||||
|
href={item.path}
|
||||||
|
onClick={e => handleClick(e, item.path)}
|
||||||
|
aria-current={pathname === item.path ? "page" : undefined}
|
||||||
|
>
|
||||||
|
<Button className="w-full" size='lg'
|
||||||
|
variant={pathname.startsWith(item.path) ? 'default' : 'outline'}
|
||||||
|
>{item.name}</Button>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user