File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { getNavBlogPosts } from '@/lib/blog/registry'
22import { SITE_URL } from '@/lib/core/utils/urls'
33import Footer from '@/app/(landing)/components/footer/footer'
44import Navbar from '@/app/(landing)/components/navbar/navbar'
5+ import { ScrollToTop } from '@/app/(landing)/components/scroll-to-top'
56
67export default async function StudioLayout ( { children } : { children : React . ReactNode } ) {
78 const blogPosts = await getNavBlogPosts ( )
@@ -29,6 +30,7 @@ export default async function StudioLayout({ children }: { children: React.React
2930
3031 return (
3132 < div className = 'flex min-h-screen flex-col bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]' >
33+ < ScrollToTop />
3234 < script
3335 type = 'application/ld+json'
3436 dangerouslySetInnerHTML = { { __html : JSON . stringify ( orgJsonLd ) } }
Original file line number Diff line number Diff line change 1+ 'use client'
2+
3+ import { useEffect , useRef } from 'react'
4+ import { usePathname } from 'next/navigation'
5+
6+ /**
7+ * Resets window scroll to the top on App Router pathname changes.
8+ *
9+ * Next.js's default scroll handling only brings the new Page element into view,
10+ * which often resolves to "no scroll" inside shared layouts (see vercel/next.js#64435).
11+ * Popstate-driven navigations are skipped so browser back/forward scroll restoration
12+ * is preserved.
13+ */
14+ export function ScrollToTop ( ) {
15+ const pathname = usePathname ( )
16+ const isPopNavigationRef = useRef ( false )
17+
18+ useEffect ( ( ) => {
19+ const onPop = ( ) => {
20+ isPopNavigationRef . current = true
21+ }
22+ window . addEventListener ( 'popstate' , onPop )
23+ return ( ) => window . removeEventListener ( 'popstate' , onPop )
24+ } , [ ] )
25+
26+ useEffect ( ( ) => {
27+ if ( isPopNavigationRef . current ) {
28+ isPopNavigationRef . current = false
29+ return
30+ }
31+ window . scrollTo ( 0 , 0 )
32+ } , [ pathname ] )
33+
34+ return null
35+ }
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { getNavBlogPosts } from '@/lib/blog/registry'
22import { SITE_URL } from '@/lib/core/utils/urls'
33import Footer from '@/app/(landing)/components/footer/footer'
44import Navbar from '@/app/(landing)/components/navbar/navbar'
5+ import { ScrollToTop } from '@/app/(landing)/components/scroll-to-top'
56
67export default async function IntegrationsLayout ( { children } : { children : React . ReactNode } ) {
78 const blogPosts = await getNavBlogPosts ( )
@@ -29,6 +30,7 @@ export default async function IntegrationsLayout({ children }: { children: React
2930
3031 return (
3132 < div className = 'dark flex min-h-screen flex-col bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]' >
33+ < ScrollToTop />
3234 < script
3335 type = 'application/ld+json'
3436 dangerouslySetInnerHTML = { { __html : JSON . stringify ( orgJsonLd ) } }
Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ import { getNavBlogPosts } from '@/lib/blog/registry'
22import { SITE_URL } from '@/lib/core/utils/urls'
33import Footer from '@/app/(landing)/components/footer/footer'
44import Navbar from '@/app/(landing)/components/navbar/navbar'
5+ import { ScrollToTop } from '@/app/(landing)/components/scroll-to-top'
56
67export default async function ModelsLayout ( { children } : { children : React . ReactNode } ) {
78 const blogPosts = await getNavBlogPosts ( )
@@ -24,6 +25,7 @@ export default async function ModelsLayout({ children }: { children: React.React
2425
2526 return (
2627 < div className = 'dark flex min-h-screen flex-col bg-[var(--landing-bg)] font-[430] font-season text-[var(--landing-text)]' >
28+ < ScrollToTop />
2729 < script
2830 type = 'application/ld+json'
2931 dangerouslySetInnerHTML = { { __html : JSON . stringify ( orgJsonLd ) } }
You can’t perform that action at this time.
0 commit comments