import { useState, useMemo } from 'react'; import { Drawer, Input, List, Typography, Empty, Tag } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; import type { Chapter } from '../types'; const { Link } = Typography; interface GroupedChapters { outlineId: string | null; outlineTitle: string; chapters: Chapter[]; } interface FloatingIndexPanelProps { visible: boolean; onClose: () => void; groupedChapters: GroupedChapters[]; onChapterSelect: (chapterId: string) => void; } export default function FloatingIndexPanel({ visible, onClose, groupedChapters, onChapterSelect, }: FloatingIndexPanelProps) { const [searchTerm, setSearchTerm] = useState(''); const filteredGroups = useMemo(() => { if (!searchTerm) { return groupedChapters; } return groupedChapters .map(group => { const filteredChapters = group.chapters.filter(chapter => chapter.title.toLowerCase().includes(searchTerm.toLowerCase()) ); return { ...group, chapters: filteredChapters }; }) .filter(group => group.chapters.length > 0); }, [searchTerm, groupedChapters]); const handleChapterClick = (chapterId: string) => { onChapterSelect(chapterId); onClose(); }; return (
} value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} allowClear />
{filteredGroups.length > 0 ? ( (
{group.outlineTitle}
( handleChapterClick(chapter.id)}> {`第${chapter.chapter_number}章: ${chapter.title}`} )} split={false} />
)} style={{ height: 'calc(100vh - 120px)', overflowY: 'auto' }} /> ) : ( )}
); }