66 lines
2.7 KiB
TypeScript
66 lines
2.7 KiB
TypeScript
"use client";
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface TOCToggleProps {
|
|
onToggle: (visible: boolean) => void;
|
|
isVisible: boolean;
|
|
}
|
|
|
|
export default function TOCToggle({ onToggle, isVisible }: TOCToggleProps) {
|
|
return (
|
|
<button
|
|
onClick={() => onToggle(!isVisible)}
|
|
className={cn(
|
|
"fixed left-4 top-20 z-50 group transition-all duration-300 ease-out",
|
|
"bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700",
|
|
"rounded-xl shadow-xl backdrop-blur-sm bg-opacity-95 dark:bg-opacity-95",
|
|
"hover:shadow-2xl hover:scale-105 active:scale-95",
|
|
"focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 focus:ring-offset-2",
|
|
"hidden xl:flex items-center justify-center w-12 h-12",
|
|
{
|
|
"translate-x-0": isVisible,
|
|
"-translate-x-2": !isVisible
|
|
}
|
|
)}
|
|
title={isVisible ? "隐藏目录" : "显示目录"}
|
|
>
|
|
<div className="relative">
|
|
{/* 目录图标 */}
|
|
<svg
|
|
className={cn(
|
|
"w-5 h-5 text-gray-600 dark:text-gray-400 transition-all duration-300 ease-out group-hover:text-gray-900 dark:group-hover:text-gray-100",
|
|
isVisible ? "opacity-100 rotate-0" : "opacity-100 rotate-0"
|
|
)}
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
>
|
|
{isVisible ? (
|
|
/* X 图标 - 关闭 */
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
) : (
|
|
/* 菜单图标 - 打开 */
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M4 6h16M4 10h12M4 14h8"
|
|
/>
|
|
)}
|
|
</svg>
|
|
|
|
{/* 悬停提示点 */}
|
|
<div className={cn(
|
|
"absolute -top-1 -right-1 w-2 h-2 bg-blue-500 rounded-full transition-all duration-300 ease-out",
|
|
"opacity-0 scale-0 group-hover:opacity-100 group-hover:scale-100",
|
|
isVisible && "opacity-0"
|
|
)} />
|
|
</div>
|
|
</button>
|
|
);
|
|
} |