forked from Mirrors/elk
chore: add custom page scroll track
This commit is contained in:
parent
3e0b2a3e4b
commit
bb119d0f8d
4 changed files with 36 additions and 13 deletions
|
@ -4,11 +4,14 @@ import { DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||||
import type { Paginator, WsEvents, mastodon } from 'masto'
|
import type { Paginator, WsEvents, mastodon } from 'masto'
|
||||||
import type { GroupedAccountLike, NotificationSlot } from '~/types'
|
import type { GroupedAccountLike, NotificationSlot } from '~/types'
|
||||||
|
|
||||||
const { paginator, stream } = defineProps<{
|
const { path, paginator, stream } = defineProps<{
|
||||||
|
path: string
|
||||||
paginator: Paginator<mastodon.v1.Notification[], mastodon.v1.ListNotificationsParams>
|
paginator: Paginator<mastodon.v1.Notification[], mastodon.v1.ListNotificationsParams>
|
||||||
stream?: Promise<WsEvents>
|
stream?: Promise<WsEvents>
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
|
||||||
const virtualScroller = false // TODO: fix flickering issue with virtual scroll
|
const virtualScroller = false // TODO: fix flickering issue with virtual scroll
|
||||||
|
|
||||||
const groupCapacity = Number.MAX_VALUE // No limit
|
const groupCapacity = Number.MAX_VALUE // No limit
|
||||||
|
@ -113,6 +116,10 @@ function groupItems(items: mastodon.v1.Notification[]): NotificationSlot[] {
|
||||||
// Finalize remaining groups
|
// Finalize remaining groups
|
||||||
processGroup()
|
processGroup()
|
||||||
|
|
||||||
|
nextTick().then(() => {
|
||||||
|
nuxtApp.$trackScroll.restoreCustomPageScroll()
|
||||||
|
})
|
||||||
|
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +153,10 @@ function preprocess(items: NotificationSlot[]): NotificationSlot[] {
|
||||||
|
|
||||||
const { clearNotifications } = useNotifications()
|
const { clearNotifications } = useNotifications()
|
||||||
const { formatNumber } = useHumanReadableNumber()
|
const { formatNumber } = useHumanReadableNumber()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
nuxtApp.$trackScroll.registerCustomRoute(path)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -8,5 +8,5 @@ onActivated(clearNotifications)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NotificationPaginator v-bind="{ paginator, stream }" />
|
<NotificationPaginator v-bind="{ path: '/notification/mention', paginator, stream }" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -8,5 +8,5 @@ onActivated(clearNotifications)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NotificationPaginator v-bind="{ paginator, stream }" />
|
<NotificationPaginator v-bind="{ path: '/notification', paginator, stream }" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -4,6 +4,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
const track = ref(false)
|
const track = ref(false)
|
||||||
const { y } = useWindowScroll()
|
const { y } = useWindowScroll()
|
||||||
const storage = useLocalStorage<Record<string, number>>('elk-track-scroll', {})
|
const storage = useLocalStorage<Record<string, number>>('elk-track-scroll', {})
|
||||||
|
const customRoutes = new Set<string>()
|
||||||
|
|
||||||
router.beforeEach(async () => {
|
router.beforeEach(async () => {
|
||||||
track.value = false
|
track.value = false
|
||||||
|
@ -17,7 +18,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
window.scrollTo({ top: 0, left: 0, behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const restoreScroll = () => {
|
const restoreScrollCallback = (ignoreHook: boolean) => {
|
||||||
const path = route.fullPath
|
const path = route.fullPath
|
||||||
return nextTick().then(() => {
|
return nextTick().then(() => {
|
||||||
if (route.meta && route.meta?.noScrollTrack) {
|
if (route.meta && route.meta?.noScrollTrack) {
|
||||||
|
@ -33,6 +34,12 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!route.meta || !route.meta?.noScrollTrack) {
|
if (!route.meta || !route.meta?.noScrollTrack) {
|
||||||
|
const hook = ignoreHook ? undefined : customRoutes.has(route.fullPath)
|
||||||
|
if (hook) {
|
||||||
|
reject(new Error('hook detected'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const scrollPosition = storage.value[route.fullPath]
|
const scrollPosition = storage.value[route.fullPath]
|
||||||
if (scrollPosition)
|
if (scrollPosition)
|
||||||
window.scrollTo(0, scrollPosition)
|
window.scrollTo(0, scrollPosition)
|
||||||
|
@ -47,33 +54,38 @@ export default defineNuxtPlugin((nuxtApp) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
nuxtApp.hooks.hook('app:suspense:resolve', () => {
|
const restoreScroll = () => restoreScrollCallback(false)
|
||||||
if (isHydrated.value) {
|
|
||||||
restoreScroll().then(() => {
|
|
||||||
track.value = true
|
|
||||||
}).catch(noop)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
nuxtApp.hooks.hook('page:finish', () => {
|
const restoreScrollHook = () => {
|
||||||
if (isHydrated.value) {
|
if (isHydrated.value) {
|
||||||
restoreScroll().then(() => {
|
restoreScroll().then(() => {
|
||||||
track.value = true
|
track.value = true
|
||||||
}).catch(noop)
|
}).catch(noop)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const restoreCustomPageScroll = () => restoreScrollCallback(true)
|
||||||
|
|
||||||
|
nuxtApp.hooks.hook('app:suspense:resolve', restoreScrollHook)
|
||||||
|
nuxtApp.hooks.hook('page:finish', restoreScrollHook)
|
||||||
|
|
||||||
watch([track, y, () => route], ([trackEnabled, scrollPosition, r]) => {
|
watch([track, y, () => route], ([trackEnabled, scrollPosition, r]) => {
|
||||||
if (trackEnabled && (!r.meta || !r.meta?.noScrollTrack))
|
if (trackEnabled && (!r.meta || !r.meta?.noScrollTrack))
|
||||||
storage.value[r.fullPath] = Math.floor(scrollPosition)
|
storage.value[r.fullPath] = Math.floor(scrollPosition)
|
||||||
}, { immediate: true, flush: 'pre' })
|
}, { immediate: true, flush: 'pre' })
|
||||||
|
|
||||||
|
const registerCustomRoute = (path: string) => {
|
||||||
|
customRoutes.add(path)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
provide: {
|
provide: {
|
||||||
trackScroll: reactive({
|
trackScroll: reactive({
|
||||||
forceScroll,
|
forceScroll,
|
||||||
restoreScroll,
|
restoreScroll,
|
||||||
track,
|
track,
|
||||||
|
registerCustomRoute,
|
||||||
|
restoreCustomPageScroll,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue