49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
"use client";
|
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export interface TocEntry {
|
|
id: string;
|
|
title: string;
|
|
level: number;
|
|
numbering: string;
|
|
}
|
|
|
|
interface DocumentTocProps {
|
|
entries: TocEntry[];
|
|
visible: boolean;
|
|
onJump: (id: string) => void;
|
|
}
|
|
|
|
export function DocumentToc({ entries, visible, onJump }: DocumentTocProps) {
|
|
if (!visible || entries.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div className="pointer-events-none absolute right-0 top-0 z-10 hidden lg:block">
|
|
<div className="pointer-events-auto mt-2 w-48 max-h-[65vh] overflow-y-auto rounded-2xl border border-[#e4e4e7] bg-white/90 p-3 text-xs text-gray-600 shadow-lg backdrop-blur">
|
|
<div className="mb-2 text-[11px] font-semibold text-gray-400">标题目录</div>
|
|
<ul className="space-y-1">
|
|
{entries.map((entry) => (
|
|
<li key={entry.id}>
|
|
<button
|
|
type="button"
|
|
className={cn(
|
|
"w-full rounded-md px-2 py-1 text-left text-[11px] text-gray-500 transition-colors hover:bg-[#eef2ff] hover:text-[#2563eb]",
|
|
entry.level > 1 && "pl-4",
|
|
entry.level > 2 && "pl-6",
|
|
)}
|
|
onClick={() => onJump(entry.id)}
|
|
>
|
|
<span className="mr-2 font-mono text-[10px] text-gray-400">{entry.numbering}</span>
|
|
{entry.title || "未命名"}
|
|
</button>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|