webapps/packages/layers/ux/app/plugins/scroll-behavior.ts
Dominik Milacher 0dc24c4db7
Some checks failed
Build and deploy updated apps / Build & deploy (push) Failing after 50s
Extend ux layer and overhaul panoramablick-saalbach.at
2025-11-21 21:17:52 +01:00

57 lines
1.5 KiB
TypeScript

import { isNavigationFailure } from 'vue-router'
async function waitFor<T>(
obtain: () => T | Promise<T>,
tries = 30,
delay = 100
): Promise<T | undefined> {
for (let i = 0; i < tries; i++) {
const result = await obtain()
if (result !== undefined) {
return result
}
await new Promise((resolve) => setTimeout(resolve, delay))
}
return undefined
}
export default defineNuxtPlugin((app) => {
app.hook('app:mounted', () => {
const router = useRouter()
router.options.scrollBehavior = (to, from, savedPosition) => {
if (to.query.freeze) {
return false
}
if (to.hash && to.path === from.path) {
return false
}
return { top: 0 }
}
router.afterEach(async (to, from, failure) => {
if (isNavigationFailure(failure)) {
console.warn(`Failed navigation: ${JSON.stringify(failure)}`)
} else if (to.hash) {
const [header, element, atTop] = await Promise.all([
waitFor(() => document.querySelector('#scaffold-header') ?? undefined),
waitFor(() => document.querySelector(to.hash) ?? undefined),
waitFor(() => (to.path === from.path || window.scrollY < 10 ? true : undefined)),
])
if (element && atTop) {
const offset = header ? header.offsetHeight : 0
const position = element.getBoundingClientRect().top
window.scrollTo({ top: position - offset + window.scrollY })
}
}
})
})
})