'use client'; import { useCallback, useEffect, useRef, useState, useTransition, type ReactNode, } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import type { PublicPortfolio } from '@/server/content'; import { PortfolioNavigationContext } from './PortfolioNavigation'; import { CaseStudyDrawer } from './CaseStudyDrawer'; import { CaseStudyLoading } from './CaseStudyLoading'; import { LoadingIndicator } from './LoadingIndicator'; export function PortfolioRouteShell({ children, homePath, background, portfolio, }: { children: ReactNode; homePath: string; background: ReactNode; portfolio: PublicPortfolio; }) { const pathname = usePathname(); const router = useRouter(); const [isPending, startTransition] = useTransition(); const [target, setTarget] = useState(null); const [kind, setKind] = useState<'project' | 'language' | 'dismiss'>('project'); const pending = isPending && target !== null; const languagePending = pending && kind === 'language'; const showDrawer = pathname !== homePath || (pending && kind === 'project'); const previousPath = useRef(pathname); const canReturnWithBack = useRef(false); const returnScrollY = useRef(null); const previousScrollRestoration = useRef('auto'); useEffect(() => { const onPageShow = (event: PageTransitionEvent) => { if (event.persisted) setTarget(null); }; window.addEventListener('pageshow', onPageShow); return () => window.removeEventListener('pageshow', onPageShow); }, []); useEffect(() => { if (pathname === homePath) { canReturnWithBack.current = false; if (previousPath.current !== homePath && returnScrollY.current !== null) { const scrollY = returnScrollY.current; requestAnimationFrame(() => window.scrollTo({ top: scrollY, behavior: 'instant' })); window.setTimeout(() => window.scrollTo({ top: scrollY, behavior: 'instant' }), 120); window.setTimeout(() => { window.scrollTo({ top: scrollY, behavior: 'instant' }); history.scrollRestoration = previousScrollRestoration.current; }, 600); returnScrollY.current = null; delete document.documentElement.dataset.caseStudyScrollY; } } else if (previousPath.current === homePath) { canReturnWithBack.current = true; const recordedScrollY = Number(document.documentElement.dataset.caseStudyScrollY); returnScrollY.current = Number.isFinite(recordedScrollY) ? recordedScrollY : window.scrollY; previousScrollRestoration.current = history.scrollRestoration; history.scrollRestoration = 'manual'; } previousPath.current = pathname; }, [homePath, pathname]); const dismissCaseStudy = useCallback(() => { setKind('dismiss'); setTarget(homePath); startTransition(() => { if (canReturnWithBack.current) router.back(); else router.replace(homePath, { scroll: false }); }); }, [homePath, router]); return ( { if (href === pathname && !pending) return; setTarget(href); setKind(options.kind ?? 'project'); startTransition(() => { if (options.replace) router.replace(href, { scroll: options.scroll }); else router.push(href, { scroll: options.scroll }); }); }, }}>
{background} {showDrawer ? {pending && kind === 'project' ? : children} : children}
{languagePending && }
); }