mirror of
https://github.com/readest/readest.git
synced 2026-04-28 11:30:48 +00:00
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (rust) (push) Waiting to run
PR checks / rust_lint (push) Waiting to run
PR checks / build_web_app (push) Waiting to run
PR checks / build_tauri_app (push) Waiting to run
Deploy to vercel on merge / build_and_deploy (push) Waiting to run
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import { useEffect, useMemo, useRef } from 'react';
|
|
import { BookProgress } from '@/types/book';
|
|
import { isCfiInLocation } from '@/utils/cfi';
|
|
|
|
const useScrollToItem = (
|
|
cfi: string,
|
|
progress: BookProgress | null,
|
|
isNearest: boolean = false,
|
|
) => {
|
|
const viewRef = useRef<HTMLLIElement | null>(null);
|
|
|
|
const isCurrent = useMemo(() => isCfiInLocation(cfi, progress?.location), [cfi, progress]);
|
|
const shouldScroll = isCurrent || isNearest;
|
|
|
|
useEffect(() => {
|
|
if (!viewRef.current || !shouldScroll) return;
|
|
|
|
const element = viewRef.current;
|
|
const rect = element.getBoundingClientRect();
|
|
|
|
// Find the actual scrollable container (OverlayScrollbars viewport)
|
|
const scrollContainer = element.closest('[data-overlayscrollbars-viewport]');
|
|
const containerRect = scrollContainer?.getBoundingClientRect();
|
|
|
|
const isVisible = containerRect
|
|
? rect.top >= containerRect.top && rect.bottom <= containerRect.bottom
|
|
: rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
|
|
if (!isVisible) {
|
|
const isEink = document.documentElement.getAttribute('data-eink') === 'true';
|
|
|
|
const containerCenter = containerRect
|
|
? (containerRect.top + containerRect.bottom) / 2
|
|
: window.innerHeight / 2;
|
|
const distance = Math.abs(rect.top - containerCenter);
|
|
const SMOOTH_THRESHOLD = 1000;
|
|
const behavior = isEink || distance > SMOOTH_THRESHOLD ? 'auto' : 'smooth';
|
|
|
|
element.scrollIntoView({ behavior, block: 'center' });
|
|
}
|
|
|
|
if (isCurrent) {
|
|
element.setAttribute('aria-current', 'page');
|
|
}
|
|
}, [shouldScroll, isCurrent]);
|
|
|
|
return { isCurrent, viewRef };
|
|
};
|
|
|
|
export default useScrollToItem;
|