smooth scroll header anchors

pull/4511/head
Divyansh Singh 8 months ago
parent 93abc90b61
commit 791f937623

@ -73,7 +73,7 @@ export function createRouter(
async function go( async function go(
href: string = inBrowser ? location.href : '/', href: string = inBrowser ? location.href : '/',
cause: Element | null = null smoothScroll = false
) { ) {
href = normalizeHref(href) href = normalizeHref(href)
const loc = inBrowser ? normalizeHref(location.href) : null const loc = inBrowser ? normalizeHref(location.href) : null
@ -97,7 +97,7 @@ export function createRouter(
}) })
) )
if (hash) scrollTo(hash, cause?.classList.contains('header-anchor')) if (hash) scrollTo(hash, smoothScroll)
else window.scrollTo(0, 0) else window.scrollTo(0, 0)
} }
@ -113,20 +113,19 @@ export function createRouter(
async function loadPage(href: string, scrollPosition = 0, isRetry = false) { async function loadPage(href: string, scrollPosition = 0, isRetry = false) {
if ((await router.onBeforePageLoad?.(href)) === false) return if ((await router.onBeforePageLoad?.(href)) === false) return
const targetLoc = new URL(href, fakeHost) const targetLoc = new URL(href, fakeHost)
const pendingPath = (latestPendingPath = targetLoc.pathname) const pendingPath = (latestPendingPath = targetLoc.pathname)
try { try {
let page = await loadPageModule(pendingPath) let page = await loadPageModule(pendingPath)
if (!page) { if (!page) throw new Error(`Page not found: ${pendingPath}`)
throw new Error(`Page not found: ${pendingPath}`)
}
if (latestPendingPath === pendingPath) { if (latestPendingPath === pendingPath) {
latestPendingPath = null latestPendingPath = null
const { default: comp, __pageData } = page const { default: comp, __pageData } = page
if (!comp) { if (!comp) throw new Error(`Invalid route component: ${comp}`)
throw new Error(`Invalid route component: ${comp}`)
}
await router.onAfterPageLoad?.(href) await router.onAfterPageLoad?.(href)
@ -141,9 +140,11 @@ export function createRouter(
let actualPathname = let actualPathname =
siteDataRef.value.base + siteDataRef.value.base +
__pageData.relativePath.replace(/(?:(^|\/)index)?\.md$/, '$1') __pageData.relativePath.replace(/(?:(^|\/)index)?\.md$/, '$1')
if (!siteDataRef.value.cleanUrls && !actualPathname.endsWith('/')) { if (!siteDataRef.value.cleanUrls && !actualPathname.endsWith('/')) {
actualPathname += '.html' actualPathname += '.html'
} }
if (actualPathname !== targetLoc.pathname) { if (actualPathname !== targetLoc.pathname) {
targetLoc.pathname = actualPathname targetLoc.pathname = actualPathname
href = actualPathname + targetLoc.search + targetLoc.hash href = actualPathname + targetLoc.search + targetLoc.hash
@ -191,9 +192,7 @@ export function createRouter(
} }
if (inBrowser) { if (inBrowser) {
if (history.state === null) { if (history.state === null) history.replaceState({}, '')
history.replaceState({}, '')
}
window.addEventListener( window.addEventListener(
'click', 'click',
(e) => { (e) => {
@ -206,8 +205,9 @@ export function createRouter(
e.shiftKey || e.shiftKey ||
e.altKey || e.altKey ||
e.metaKey e.metaKey
) ) {
return return
}
const link = e.target.closest<HTMLAnchorElement | SVGAElement>('a') const link = e.target.closest<HTMLAnchorElement | SVGAElement>('a')
if ( if (
@ -215,8 +215,9 @@ export function createRouter(
link.closest('.vp-raw') || link.closest('.vp-raw') ||
link.hasAttribute('download') || link.hasAttribute('download') ||
link.hasAttribute('target') link.hasAttribute('target')
) ) {
return return
}
const linkHref = const linkHref =
link.getAttribute('href') ?? link.getAttribute('href') ??
@ -228,7 +229,7 @@ export function createRouter(
// only intercept inbound html links // only intercept inbound html links
if (origin === currentLoc.origin && treatAsHtml(pathname)) { if (origin === currentLoc.origin && treatAsHtml(pathname)) {
e.preventDefault() e.preventDefault()
go(href) go(href, link.classList.contains('header-anchor'))
} }
}, },
{ capture: true } { capture: true }
@ -253,9 +254,7 @@ export function createRouter(
export function useRouter(): Router { export function useRouter(): Router {
const router = inject(RouterSymbol) const router = inject(RouterSymbol)
if (!router) { if (!router) throw new Error('useRouter() is called without provider.')
throw new Error('useRouter() is called without provider.')
}
return router return router
} }
@ -300,9 +299,7 @@ function handleHMR(route: Route): void {
if (import.meta.hot) { if (import.meta.hot) {
// hot reload pageData // hot reload pageData
import.meta.hot.on('vitepress:pageData', (payload: PageDataPayload) => { import.meta.hot.on('vitepress:pageData', (payload: PageDataPayload) => {
if (shouldHotReload(payload)) { if (shouldHotReload(payload)) route.data = payload.pageData
route.data = payload.pageData
}
}) })
} }
} }
@ -319,9 +316,10 @@ function normalizeHref(href: string): string {
const url = new URL(href, fakeHost) const url = new URL(href, fakeHost)
url.pathname = url.pathname.replace(/(^|\/)index(\.html)?$/, '$1') url.pathname = url.pathname.replace(/(^|\/)index(\.html)?$/, '$1')
// ensure correct deep link so page refresh lands on correct files. // ensure correct deep link so page refresh lands on correct files.
if (siteDataRef.value.cleanUrls) if (siteDataRef.value.cleanUrls) {
url.pathname = url.pathname.replace(/\.html$/, '') url.pathname = url.pathname.replace(/\.html$/, '')
else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) } else if (!url.pathname.endsWith('/') && !url.pathname.endsWith('.html')) {
url.pathname += '.html' url.pathname += '.html'
}
return url.pathname + url.search + url.hash return url.pathname + url.search + url.hash
} }

Loading…
Cancel
Save