Files
writer-work-flow/apps/web/components/AiToolbar.tsx
2026-06-28 07:31:20 +02:00

94 lines
2.9 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.

import Link from "next/link";
import {
BookOpen,
ClipboardCheck,
ListTree,
PenLine,
Sparkles,
type LucideIcon,
} from "lucide-react";
import { AiToolbarMoreMenu } from "@/components/AiToolbarMoreMenu";
import {
aiToolItems,
primaryAiToolItems,
secondaryAiToolItems,
} from "@/lib/nav/ai-tools";
import type { ActiveNav } from "@/lib/nav/items";
import { buttonClass } from "@/lib/ui/variants";
interface AiToolbarProps {
projectId: string;
activeNav?: ActiveNav;
}
// T4-a · 项目内页常驻 AI 工具条顶栏下UX §3/§5
// 桌面展示完整工具条;窄屏只保留写本章/审稿,把低频入口收进更多菜单。
export function AiToolbar({ projectId, activeNav }: AiToolbarProps) {
const primaryItems = primaryAiToolItems(projectId);
const secondaryItems = secondaryAiToolItems(projectId);
return (
<nav
aria-label="AI 工具条"
className="flex h-12 items-center gap-2 border-b border-line bg-panel px-4 sm:px-6"
>
<div className="flex min-w-0 flex-1 items-center gap-2 overflow-hidden lg:hidden">
{primaryItems.map((item) => {
const isActive = item.key === activeNav;
const className = toolClassName(item.primary === true, isActive);
const Icon = toolIcon(item.key);
return (
<Link
key={item.href}
href={item.href}
aria-current={isActive ? "page" : undefined}
className={className}
>
<Icon className="h-4 w-4" aria-hidden="true" />
<span>{item.label}</span>
</Link>
);
})}
<AiToolbarMoreMenu items={secondaryItems} activeNav={activeNav} />
</div>
<div className="hidden items-center gap-2 overflow-x-auto whitespace-nowrap lg:flex">
{aiToolItems(projectId).map((item) => {
const isActive = item.key === activeNav;
const className = toolClassName(item.primary === true, isActive);
const Icon = toolIcon(item.key);
return (
<Link
key={item.href}
href={item.href}
aria-current={isActive ? "page" : undefined}
className={className}
>
<Icon className="h-4 w-4" aria-hidden="true" />
<span>{item.label}</span>
</Link>
);
})}
</div>
</nav>
);
}
function toolIcon(key: ActiveNav): LucideIcon {
if (key === "write") return PenLine;
if (key === "review") return ClipboardCheck;
if (key === "outline") return ListTree;
if (key === "codex") return BookOpen;
return Sparkles;
}
function toolClassName(isPrimary: boolean, isActive: boolean): string {
if (isActive) {
return buttonClass({ variant: "outline", size: "sm" });
}
if (isPrimary) {
return buttonClass({ variant: "primary", size: "sm" });
}
return buttonClass({ variant: "secondary", size: "sm" });
}