feat: add route-backed project case studies
This commit is contained in:
72
src/components/PortfolioRouteShell.tsx
Normal file
72
src/components/PortfolioRouteShell.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
'use client';
|
||||
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
|
||||
const PortfolioRouteContext = createContext<(() => void) | null>(null);
|
||||
|
||||
export function PortfolioRouteShell({
|
||||
children,
|
||||
homePath,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
homePath: string;
|
||||
}) {
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const previousPath = useRef(pathname);
|
||||
const canReturnWithBack = useRef(false);
|
||||
const returnScrollY = useRef<number | null>(null);
|
||||
const previousScrollRestoration = useRef<ScrollRestoration>('auto');
|
||||
|
||||
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(() => {
|
||||
if (canReturnWithBack.current) {
|
||||
router.back();
|
||||
return;
|
||||
}
|
||||
router.replace(homePath, { scroll: false });
|
||||
}, [homePath, router]);
|
||||
|
||||
return (
|
||||
<PortfolioRouteContext.Provider value={dismissCaseStudy}>
|
||||
{children}
|
||||
</PortfolioRouteContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useDismissCaseStudy() {
|
||||
const dismiss = useContext(PortfolioRouteContext);
|
||||
if (!dismiss) throw new Error('useDismissCaseStudy must be used within PortfolioRouteShell');
|
||||
return dismiss;
|
||||
}
|
||||
Reference in New Issue
Block a user