Files
KVideo/components/ScrollPositionManager.tsx
T

90 lines
3.2 KiB
TypeScript

'use client';
import { useEffect, useCallback } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import { settingsStore } from '@/lib/store/settings-store';
/**
* ScrollPositionManager - Maintains scroll position across navigation and refreshes
* Uses sessionStorage to persist scroll state per URL
*/
export function ScrollPositionManager() {
const pathname = usePathname();
const searchParams = useSearchParams();
// Create a unique key for the current page including search params
const getPageKey = useCallback(() => {
const params = searchParams.toString();
return `scroll-pos:${pathname}${params ? '?' + params : ''}`;
}, [pathname, searchParams]);
// Restoration logic
useEffect(() => {
const settings = settingsStore.getSettings();
if (!settings.rememberScrollPosition) return;
const key = getPageKey();
const savedPos = sessionStorage.getItem(key);
if (savedPos) {
const position = parseInt(savedPos, 10);
if (!isNaN(position) && position > 0) {
// We use multiple attempts to restore scroll because content might be loading dynamically
// (e.g., search results, movie grids)
// Keep trying until we actually scroll there or a timeout occurs
let attempts = 0;
const maxAttempts = 10;
const tryScroll = () => {
const currentScroll = window.scrollY;
window.scrollTo(0, position);
attempts++;
// Verify if we actually reached the target position (with some wiggle room)
const reached = Math.abs(window.scrollY - position) < 10;
if (!reached && attempts < maxAttempts) {
// If we didn't reach it, it's likely because the page height hasn't caught up yet
setTimeout(tryScroll, 200);
}
};
const timerId = setTimeout(tryScroll, 100);
return () => clearTimeout(timerId);
}
}
}, [getPageKey, pathname, searchParams]); // Run on navigation
// Saving logic
useEffect(() => {
let timeoutId: NodeJS.Timeout;
const handleScroll = () => {
const settings = settingsStore.getSettings();
if (!settings.rememberScrollPosition) return;
// Debounce saving to avoid excessive writes to sessionStorage
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const key = getPageKey();
// Only save if we have scrolled
if (window.scrollY > 0) {
sessionStorage.setItem(key, window.scrollY.toString());
} else {
sessionStorage.removeItem(key);
}
}, 500);
};
window.addEventListener('scroll', handleScroll, { passive: true });
return () => {
window.removeEventListener('scroll', handleScroll);
clearTimeout(timeoutId);
};
}, [getPageKey]);
return null;
}