feat(ux): T4-a 全局 AI 工具条 — 项目页顶部常驻写本章/审稿/大纲/设定库/工具箱

新 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。
This commit is contained in:
Yaojia Wang
2026-06-20 18:19:46 +02:00
parent 6e5d0e88f6
commit 8779530806
10 changed files with 122 additions and 8 deletions

View File

@@ -0,0 +1,48 @@
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`;
}