website-01/components/front/ManualTreeNav.tsx

96 lines
2.8 KiB
TypeScript
Raw Normal View History

2026-06-22 14:43:46 +08:00
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { Folder, FileText } from 'lucide-react';
import { cn } from '@/lib/utils';
import type { ManualTreeNode } from '@/lib/types';
interface TreeNavProps {
nodes: ManualTreeNode[];
}
/** 递归渲染节点(含子孙) */
function TreeItem({ node, depth = 0 }: { node: ManualTreeNode; depth?: number }) {
const pathname = usePathname();
const href = `/manual/${node.id}`;
const active = pathname === href;
// ===== 顶层目录 → 分区标题(带分隔线 + 缩进引导线) =====
if (depth === 0 && node.type === 0) {
return (
<div className="border-t border-gray-100 pt-3 first:border-t-0 first:pt-0">
<div className="flex items-center gap-1.5 px-2 py-1 text-[11px] font-bold uppercase tracking-wider text-slate-400">
<Folder className="h-3.5 w-3.5 shrink-0 text-amber-500" />
{node.title}
</div>
{node.children.length > 0 && (
<div className="mt-1 ml-3 space-y-0.5 border-l border-gray-100 pl-2">
{node.children.map((c) => (
<TreeItem key={c.id} node={c} depth={depth + 1} />
))}
</div>
)}
</div>
);
}
// ===== 嵌套目录 → 子标题(带缩进引导线) =====
if (node.type === 0) {
return (
<div className="pt-2">
<div className="flex items-center gap-1.5 px-2 py-1 text-sm font-semibold text-slate-700">
<Folder className="h-3.5 w-3.5 shrink-0 text-amber-400" />
{node.title}
</div>
{node.children.length > 0 && (
<div className="mt-0.5 ml-3 space-y-0.5 border-l border-gray-100 pl-2">
{node.children.map((c) => (
<TreeItem key={c.id} node={c} depth={depth + 1} />
))}
</div>
)}
</div>
);
}
// ===== 文档 → 可点击链接 =====
return (
<Link
href={href}
className={cn(
'flex items-center gap-1.5 rounded-md px-2 py-1.5 text-sm transition-colors',
active
? 'bg-brand-50 font-medium text-brand-700'
: 'text-slate-600 hover:bg-slate-100 hover:text-slate-900',
)}
>
<FileText
className={cn(
'h-3.5 w-3.5 shrink-0',
active ? 'text-brand-600' : 'text-slate-400',
)}
/>
<span className="truncate">{node.title}</span>
</Link>
);
}
/** 使用手册左侧树形导航(始终展开) */
export function ManualTreeNav({ nodes }: TreeNavProps) {
if (nodes.length === 0) {
return (
<div className="px-3 py-6 text-center text-xs text-slate-400">
</div>
);
}
return (
<nav className="space-y-1">
{nodes.map((n) => (
<TreeItem key={n.id} node={n} />
))}
</nav>
);
}