Skip to content

Commit 7e926fe

Browse files
committed
refactor(landing-nav): simplify scroll-to-top to conventional pattern
1 parent 1f67317 commit 7e926fe

1 file changed

Lines changed: 1 addition & 52 deletions

File tree

apps/sim/app/(landing)/components/scroll-to-top.tsx

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,68 +3,17 @@
33
import { useEffect } from 'react'
44
import { usePathname } from 'next/navigation'
55

6-
/**
7-
* Timestamp of the most recent popstate. Module-scoped so it survives layout
8-
* remounts when navigating across sections (e.g., blog ↔ integrations ↔ models),
9-
* where the outgoing layout's component instances unmount before the incoming
10-
* layout's effect runs.
11-
*
12-
* Initialized to `-Infinity` so initial mounts don't mimic a recent popstate.
13-
* Consumed on first use (reset back to `-Infinity`) so a real link navigation
14-
* immediately after Back isn't swallowed. The timestamp window provides a
15-
* safety net for popstates that never trigger a pathname effect (e.g.,
16-
* hash-only back/forward), letting the signal self-expire.
17-
*/
18-
let lastPopstateAt = Number.NEGATIVE_INFINITY
19-
const POPSTATE_WINDOW_MS = 200
20-
21-
/**
22-
* Captured at module evaluation time. When this module is bundled into the
23-
* initial page payload (direct load / reload of a shelled route), readyState
24-
* is still `loading` or `interactive`, the browser will restore scroll on
25-
* reload, and we should skip the first reset. When the module is dynamically
26-
* imported during a client-side navigation (e.g., user clicked from `/` into
27-
* `/blog/x`), readyState is already `complete` and the first mount is a real
28-
* route change that should scroll to top.
29-
*/
30-
const wasInitialPageLoad = typeof document !== 'undefined' && document.readyState !== 'complete'
31-
32-
/**
33-
* Tracks whether any `ScrollToTop` instance has run its mount effect yet.
34-
* Module-scoped so cross-section navigation (which mounts a fresh instance)
35-
* doesn't re-trigger the initial-mount guard.
36-
*/
37-
let hasMounted = false
38-
39-
if (typeof window !== 'undefined') {
40-
window.addEventListener('popstate', () => {
41-
lastPopstateAt = performance.now()
42-
})
43-
}
44-
456
/**
467
* Resets window scroll to the top on App Router pathname changes.
478
*
489
* Next.js's default scroll handling only brings the new Page element into view,
4910
* which often resolves to "no scroll" inside shared layouts (see vercel/next.js#64435).
50-
*
51-
* Skipped on the very first mount of an initial page load (so browser scroll
52-
* restoration on reload wins), when the pathname change closely follows a
53-
* popstate (preserving browser back/forward restoration), and when a hash
54-
* anchor is targeted (letting the browser's native anchor scroll win).
11+
* Skipped when a hash anchor is targeted so the browser's native anchor scroll wins.
5512
*/
5613
export function ScrollToTop() {
5714
const pathname = usePathname()
5815

5916
useEffect(() => {
60-
if (!hasMounted) {
61-
hasMounted = true
62-
if (wasInitialPageLoad) return
63-
}
64-
if (performance.now() - lastPopstateAt < POPSTATE_WINDOW_MS) {
65-
lastPopstateAt = Number.NEGATIVE_INFINITY
66-
return
67-
}
6817
if (window.location.hash) return
6918
window.scrollTo(0, 0)
7019
}, [pathname])

0 commit comments

Comments
 (0)