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;