"use client"; import { AnimatePresence, motion, useReducedMotion } from "framer-motion"; import { LayoutRouterContext } from "next/dist/shared/lib/app-router-context.shared-runtime"; import { usePathname } from "next/navigation"; import { useContext, useState, type ReactNode } from "react"; /** * Pins the layout-router context captured when this instance mounted. Each * keyed page gets its own FrozenRouter, so the *outgoing* page keeps rendering * its old route data while it animates out. */ function FrozenRouter({ children }: { children: ReactNode }) { const context = useContext(LayoutRouterContext); const [frozen] = useState(context); if (!frozen) { return <>{children}; } return {children}; } /** * One unified page transition on every navigation. Lives in the (persistent) * site layout — NOT in a `template.tsx`, which Next re-creates on each * navigation and would reset AnimatePresence so nothing animates. The old page * animates out (rise + blur), then the new page animates in from below. */ export function PageTransition({ children }: { children: ReactNode }) { const reducedMotion = useReducedMotion(); const pathname = usePathname(); return ( {children} ); }