72 lines
2.4 KiB
TypeScript
72 lines
2.4 KiB
TypeScript
import React from 'react'
|
||
import type { TOCItem } from '@/lib/utils'
|
||
import { useWallpaper } from '@/stores'
|
||
|
||
export interface TOCProps {
|
||
isOpen: boolean
|
||
onClose: () => void
|
||
tocItems: TOCItem[]
|
||
width: number
|
||
onResizeStart: (e: React.MouseEvent) => void
|
||
onTOCItemClick: (id: string) => void
|
||
}
|
||
|
||
const renderTOCItem = (item: TOCItem, onTOCItemClick: (id: string) => void) => {
|
||
const indent = (item.level - 1) * 16
|
||
|
||
return (
|
||
<div key={item.id} className="mb-1">
|
||
<div
|
||
className="text-gray-600 dark:text-gray-200 hover:text-gray-900 dark:hover:text-white cursor-pointer px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
||
style={{ marginLeft: `${indent}px` }}
|
||
onClick={() => onTOCItemClick(item.id)}
|
||
>
|
||
{item.text}
|
||
</div>
|
||
{item.children.length > 0 && (
|
||
<div className="mt-1">
|
||
{item.children.map(child => renderTOCItem(child, onTOCItemClick))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export const TOC: React.FC<TOCProps> = ({ isOpen, onClose, tocItems, width, onResizeStart, onTOCItemClick }) => {
|
||
const { opacity } = useWallpaper()
|
||
|
||
return (
|
||
<div
|
||
className={`absolute left-0 top-0 bottom-0 border-r border-gray-200 dark:border-gray-700/60 flex flex-col z-30 transition-transform duration-300 ease-in-out transform backdrop-blur-sm ${isOpen ? 'translate-x-0' : '-translate-x-full'}`}
|
||
style={{
|
||
width,
|
||
backgroundColor: `rgba(var(--app-toc-bg-rgb), ${opacity})`,
|
||
}}
|
||
>
|
||
<div className="h-12 flex items-center px-4 border-b border-gray-200 dark:border-gray-700/60 font-semibold text-gray-700 dark:text-gray-200 flex justify-between">
|
||
<span className="text-base">目录</span>
|
||
<button
|
||
onClick={onClose}
|
||
className="w-8 h-8 hover:bg-gray-100 dark:hover:bg-gray-700 rounded flex items-center justify-center text-2xl"
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
<div className="flex-1 overflow-y-auto p-4 no-scrollbar">
|
||
{tocItems.length > 0 ? (
|
||
<div>
|
||
{tocItems.map(item => renderTOCItem(item, onTOCItemClick))}
|
||
</div>
|
||
) : (
|
||
<div className="text-gray-600 dark:text-gray-200"></div>
|
||
)}
|
||
</div>
|
||
|
||
<div
|
||
className="absolute right-0 top-0 bottom-0 w-1 cursor-col-resize z-10"
|
||
onMouseDown={onResizeStart}
|
||
/>
|
||
</div>
|
||
)
|
||
}
|