新 lib/nav/ai-tools.ts (aiToolItems) + components/AiToolbar.tsx 服务端组件;AppShell 顶栏下渲染(仅项目页),用 --chrome CSS 变量统一 chrome 高度,6 个固定高度页改用 calc(100vh-var(--chrome,4rem)) 适配。TDD: ai-tools 测。前端门禁绿: lint/tsc/vitest/build。
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import Link from "next/link";
|
||
|
||
import { aiToolItems } from "@/lib/nav/ai-tools";
|
||
import type { ActiveNav } from "@/lib/nav/items";
|
||
|
||
interface AiToolbarProps {
|
||
projectId: string;
|
||
activeNav?: ActiveNav;
|
||
}
|
||
|
||
// T4-a · 项目内页常驻 AI 工具条(顶栏下,UX §3/§5)。
|
||
// 纯链接服务端组件:写本章=朱砂主动作,其余次级;激活项朱砂高亮。窄屏横向滚动。
|
||
export function AiToolbar({ projectId, activeNav }: AiToolbarProps) {
|
||
return (
|
||
<nav
|
||
aria-label="AI 工具条"
|
||
className="flex h-12 items-center gap-2 overflow-x-auto whitespace-nowrap border-b border-line bg-panel px-4 sm:px-6"
|
||
>
|
||
{aiToolItems(projectId).map((item) => {
|
||
const isActive = item.key === activeNav;
|
||
const className = toolClassName(item.primary === true, isActive);
|
||
return (
|
||
<Link
|
||
key={item.href}
|
||
href={item.href}
|
||
aria-current={isActive ? "page" : undefined}
|
||
className={className}
|
||
>
|
||
<span aria-hidden="true">{item.glyph}</span>
|
||
<span>{item.label}</span>
|
||
</Link>
|
||
);
|
||
})}
|
||
</nav>
|
||
);
|
||
}
|
||
|
||
function toolClassName(isPrimary: boolean, isActive: boolean): string {
|
||
const base =
|
||
"flex items-center gap-1.5 rounded border px-3 py-1.5 text-sm transition-colors";
|
||
if (isActive) {
|
||
return `${base} border-cinnabar text-cinnabar`;
|
||
}
|
||
if (isPrimary) {
|
||
return `${base} border-cinnabar bg-cinnabar text-panel hover:border-cinnabar`;
|
||
}
|
||
return `${base} border-line text-ink-soft hover:border-cinnabar hover:text-cinnabar`;
|
||
}
|