feat: add route-backed project case studies
Some checks failed
Test and deploy / Verify production build (push) Has been cancelled
Test and deploy / Deploy production (push) Has been cancelled

This commit is contained in:
2026-09-09 22:00:57 +03:30
parent b3cfcfe057
commit 24cd86ede7
25 changed files with 1892 additions and 65 deletions

View 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;
}