import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; import { TOCItem } from '@/libs/document'; import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; import { findParentPath } from '@/utils/toc'; import { getContentMd5 } from '@/utils/misc'; import { eventDispatcher } from '@/utils/event'; const createExpanderIcon = (isExpanded: boolean) => { return ( ); }; const TOCItemView: React.FC<{ bookKey: string; item: TOCItem; depth: number; expandedItems: string[]; }> = ({ bookKey, item, depth, expandedItems }) => { const [isExpanded, setIsExpanded] = useState(expandedItems.includes(item.href || '')); const { getView, getProgress } = useReaderStore(); const progress = getProgress(bookKey); const handleToggleExpand = (event: React.MouseEvent) => { event.preventDefault(); event.stopPropagation(); setIsExpanded((prev) => !prev); }; const handleClickItem = (event: React.MouseEvent) => { event.preventDefault(); eventDispatcher.dispatch('navigate', { bookKey, href: item.href }); if (item.href) { getView(bookKey)?.goTo(item.href); } }; const isActive = progress ? progress.sectionHref === item.href : false; useEffect(() => { setIsExpanded(expandedItems.includes(item.href || '')); }, [expandedItems, item.href]); return (
  • {item.subitems && ( {createExpanderIcon(isExpanded)} )} {item.label} {item.subitems && isExpanded && (
      {item.subitems.map((subitem, index) => ( ))}
    )}
  • ); }; const TOCView: React.FC<{ bookKey: string; toc: TOCItem[]; }> = ({ bookKey, toc }) => { const { getProgress } = useReaderStore(); const { sideBarBookKey } = useSidebarStore(); const progress = getProgress(bookKey); const [expandedItems, setExpandedItems] = useState([]); const viewRef = useRef(null); const expandParents = (toc: TOCItem[], href: string) => { const parentPath = findParentPath(toc, href).map((item) => item.href); setExpandedItems(parentPath.filter(Boolean) as string[]); }; useEffect(() => { if (!progress) return; const { sectionHref: currentHref } = progress; const hrefMd5 = currentHref ? getContentMd5(currentHref) : ''; const currentItem = viewRef.current?.querySelector(`[data-href="${hrefMd5}"]`); if (currentItem) { const rect = currentItem.getBoundingClientRect(); const isVisible = rect.top >= 0 && rect.bottom <= window.innerHeight; if (!isVisible) { (currentItem as HTMLElement).scrollIntoView({ behavior: 'instant', block: 'center' }); } (currentItem as HTMLElement).setAttribute('aria-current', 'page'); } if (currentHref) { expandParents(toc, currentHref); } }, [toc, progress, sideBarBookKey]); return (
      {toc && toc.map((item, index) => ( ))}
    ); }; export default TOCView;