Something went wrong. Try again.
A Bsky-like frontend using the atprotocol natively.
Something went wrong. Try again.
3.0 kB · 88 lines
TSX
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889import { useState, useLayoutEffect, useCallback, useEffect, useRef, type ReactNode } from 'react';import { useLocation } from 'react-router-dom';import { NavigationMemoryContext } from './navigationMemoryContext';
export function NavigationMemoryProvider({ children }: { children: ReactNode }) { const location = useLocation(); const { pathname, search } = location;
const [mainContentPath, setMainContentPath] = useState(pathname); const [mainContentSearch, setMainContentSearch] = useState(search); const [scrollPositions, setScrollPositions] = useState<Record<string, number>>({}); const [pageStates, setPageStates] = useState<Record<string, any>>({});
const setScrollPosition = useCallback((path: string, pos: number) => { setScrollPositions((prev) => { if (prev[path] === pos) return prev; return { ...prev, [path]: pos }; }); }, []);
const clearScrollPosition = useCallback((path: string) => { setScrollPositions((prev) => { if (!(path in prev)) return prev; const next = { ...prev }; delete next[path]; return next; }); }, []);
const setPageState = useCallback((path: string, newStateOrUpdater: any) => { setPageStates((prev) => { const oldState = prev[path]; const newState = typeof newStateOrUpdater === 'function' ? newStateOrUpdater(oldState) : newStateOrUpdater; if (oldState === newState) return prev; return { ...prev, [path]: newState }; }); }, []);
const updateMainContent = useCallback((path: string, s: string) => { setMainContentPath(path); setMainContentSearch(s); }, []);
useLayoutEffect(() => { const isPostUrl = pathname.startsWith('/post/'); const isProfileUrl = pathname.match(/^\/profile\/[^/]+$/);
if (!isPostUrl && !isProfileUrl) { // eslint-disable-next-line react-hooks/set-state-in-effect updateMainContent(pathname, search); } }, [pathname, search, updateMainContent]);
const lastKnownScrollRef = useRef<Record<string, number>>({});
useEffect(() => { const handleScroll = () => { lastKnownScrollRef.current[pathname + search] = window.scrollY; setScrollPosition(pathname + search, window.scrollY); };
window.addEventListener('scroll', handleScroll, { passive: true }); return () => { window.removeEventListener('scroll', handleScroll); const currentScroll = window.scrollY; const lastKnown = lastKnownScrollRef.current[pathname + search]; if (lastKnown === undefined || Math.abs(currentScroll - lastKnown) < 5) { setScrollPosition(pathname + search, currentScroll); } }; }, [pathname, search, setScrollPosition]);
return ( <NavigationMemoryContext.Provider value={{ mainContentPath, mainContentSearch, scrollPositions, setScrollPosition, clearScrollPosition, pageStates, setPageState }}> {children} </NavigationMemoryContext.Provider> );}