Files
writer-work-flow/apps/web/components/NavDrawer.tsx
Yaojia Wang 47d5558e4a feat(web): NavDrawer 补 aria-controls + ForeshadowCard 语义化 dl/dt/dd(a11y)
NavDrawer 汉堡按钮补 aria-controls 指向抽屉面板(Drawer 新增可选 id prop,默认 nav-drawer);ForeshadowCard 的 <dl> 裸 <div> 行改真 <dt>/<dd> 结构,可视文案不变,importance 用 sr-only 标签。行为不变。
2026-07-08 13:27:32 +02:00

75 lines
2.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useRef, useState } from "react";
import { Menu, Search } from "lucide-react";
import { Button } from "@/components/ui/Button";
import { openCommandPalette } from "@/components/command/CommandPalette";
import type { ActiveNav } from "@/lib/nav/items";
import { focusRing } from "@/lib/ui/variants";
import { Drawer } from "./Drawer";
import { NavItems } from "./NavItems";
interface NavDrawerProps {
projectId?: string;
activeNav?: ActiveNav;
}
// 抽屉面板 id供汉堡按钮 aria-controls 关联(无障碍)。
const DRAWER_ID = "nav-drawer";
// 移动端导航:汉堡按钮 + 左侧抽屉(仅 <lg桌面用 LeftNav 静态侧栏。UX §5.1。
export function NavDrawer({ projectId, activeNav }: NavDrawerProps) {
const [open, setOpen] = useState(false);
const triggerRef = useRef<HTMLButtonElement>(null);
const openSearch = (): void => {
setOpen(false);
openCommandPalette();
};
return (
<>
<Button
ref={triggerRef}
onClick={() => setOpen(true)}
aria-label="打开导航"
aria-expanded={open}
aria-controls={DRAWER_ID}
variant="ghost"
size="icon"
className="-ml-2 lg:hidden"
>
<Menu className="h-5 w-5" aria-hidden="true" />
</Button>
<Drawer
open={open}
onClose={() => setOpen(false)}
side="left"
label="主导航"
id={DRAWER_ID}
triggerRef={triggerRef}
>
<div className="px-2 pb-2">
<button
type="button"
onClick={openSearch}
className={`flex w-full items-center gap-2 rounded border border-line bg-bg px-3 py-2 text-sm text-ink-soft transition-colors hover:text-cinnabar ${focusRing}`}
>
<Search className="h-4 w-4 shrink-0" aria-hidden="true" />
<kbd className="ml-auto rounded border border-line bg-panel px-1 font-mono text-2xs">
K
</kbd>
</button>
</div>
<NavItems
projectId={projectId}
activeNav={activeNav}
onNavigate={() => setOpen(false)}
/>
</Drawer>
</>
);
}