feat: avoid reordering pagination border effects (#877)
parent
f8692ed480
commit
efe406df5b
|
@ -10,6 +10,7 @@ const {
|
||||||
keyProp = 'id',
|
keyProp = 'id',
|
||||||
virtualScroller = false,
|
virtualScroller = false,
|
||||||
eventType = 'update',
|
eventType = 'update',
|
||||||
|
buffer = 10,
|
||||||
preprocess,
|
preprocess,
|
||||||
} = defineProps<{
|
} = defineProps<{
|
||||||
paginator: Paginator<T[], O>
|
paginator: Paginator<T[], O>
|
||||||
|
@ -17,6 +18,10 @@ const {
|
||||||
virtualScroller?: boolean
|
virtualScroller?: boolean
|
||||||
stream?: Promise<WsEvents>
|
stream?: Promise<WsEvents>
|
||||||
eventType?: 'notification' | 'update'
|
eventType?: 'notification' | 'update'
|
||||||
|
// When preprocess is used, buffer is the number of items that will be hidden
|
||||||
|
// until the next pagination to avoid border effect between pages when reordering
|
||||||
|
// and grouping items
|
||||||
|
buffer?: number
|
||||||
preprocess?: (items: T[]) => any[]
|
preprocess?: (items: T[]) => any[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,13 @@ const showHistory = (edit: mastodon.v1.StatusEdit) => {
|
||||||
}
|
}
|
||||||
const timeAgoOptions = useTimeAgoOptions()
|
const timeAgoOptions = useTimeAgoOptions()
|
||||||
|
|
||||||
|
// TODO: rework, this is only reversing the first page of edits
|
||||||
const reverseHistory = (items: mastodon.v1.StatusEdit[]) =>
|
const reverseHistory = (items: mastodon.v1.StatusEdit[]) =>
|
||||||
[...items].reverse()
|
[...items].reverse()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CommonPaginator :paginator="paginator" key-prop="createdAt" :preprocess="reverseHistory">
|
<CommonPaginator :paginator="paginator" key-prop="createdAt" :preprocess="reverseHistory" :buffer="0">
|
||||||
<template #default="{ items, item, index }">
|
<template #default="{ items, item, index }">
|
||||||
<CommonDropdownItem
|
<CommonDropdownItem
|
||||||
px="0.5"
|
px="0.5"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const paginator = useMasto().v1.timelines.listHome()
|
const paginator = useMasto().v1.timelines.listHome({ limit: 30 })
|
||||||
const stream = useMasto().v1.stream.streamUser()
|
const stream = useMasto().v1.stream.streamUser()
|
||||||
onBeforeUnmount(() => stream?.then(s => s.disconnect()))
|
onBeforeUnmount(() => stream?.then(s => s.disconnect()))
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,12 +4,13 @@ import { DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||||
import type { Paginator, WsEvents, mastodon } from 'masto'
|
import type { Paginator, WsEvents, mastodon } from 'masto'
|
||||||
|
|
||||||
const { paginator, stream, account } = defineProps<{
|
const { paginator, stream, account, buffer = 10 } = defineProps<{
|
||||||
paginator: Paginator<mastodon.v1.Status[], mastodon.v1.ListAccountStatusesParams>
|
paginator: Paginator<mastodon.v1.Status[], mastodon.v1.ListAccountStatusesParams>
|
||||||
stream?: Promise<WsEvents>
|
stream?: Promise<WsEvents>
|
||||||
context?: mastodon.v2.FilterContext
|
context?: mastodon.v2.FilterContext
|
||||||
account?: mastodon.v1.Account
|
account?: mastodon.v1.Account
|
||||||
preprocess?: (items: mastodon.v1.Status[]) => mastodon.v1.Status[]
|
preprocess?: (items: mastodon.v1.Status[]) => mastodon.v1.Status[]
|
||||||
|
buffer?: number
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { formatNumber } = useHumanReadableNumber()
|
const { formatNumber } = useHumanReadableNumber()
|
||||||
|
@ -21,7 +22,7 @@ const showOriginSite = $computed(() =>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CommonPaginator v-bind="{ paginator, stream, preprocess }" :virtual-scroller="virtualScroller">
|
<CommonPaginator v-bind="{ paginator, stream, preprocess, buffer }" :virtual-scroller="virtualScroller">
|
||||||
<template #updater="{ number, update }">
|
<template #updater="{ number, update }">
|
||||||
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="update">
|
<button py-4 border="b base" flex="~ col" p-3 w-full text-primary font-bold @click="update">
|
||||||
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const paginator = useMasto().v1.timelines.listPublic()
|
const paginator = useMasto().v1.timelines.listPublic({ limit: 30 })
|
||||||
const stream = useMasto().v1.stream.streamPublicTimeline()
|
const stream = useMasto().v1.stream.streamPublicTimeline()
|
||||||
onBeforeUnmount(() => stream.then(s => s.disconnect()))
|
onBeforeUnmount(() => stream.then(s => s.disconnect()))
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const paginator = useMasto().v1.timelines.listPublic({ local: true })
|
const paginator = useMasto().v1.timelines.listPublic({ limit: 30, local: true })
|
||||||
const stream = useMasto().v1.stream.streamCommunityTimeline()
|
const stream = useMasto().v1.stream.streamCommunityTimeline()
|
||||||
onBeforeUnmount(() => stream.then(s => s.disconnect()))
|
onBeforeUnmount(() => stream.then(s => s.disconnect()))
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,6 +6,7 @@ export function usePaginator<T, P>(
|
||||||
stream?: Promise<WsEvents>,
|
stream?: Promise<WsEvents>,
|
||||||
eventType: 'notification' | 'update' = 'update',
|
eventType: 'notification' | 'update' = 'update',
|
||||||
preprocess: (items: T[]) => T[] = (items: T[]) => items,
|
preprocess: (items: T[]) => T[] = (items: T[]) => items,
|
||||||
|
buffer = 10,
|
||||||
) {
|
) {
|
||||||
const state = ref<PaginatorState>(isMastoInitialised.value ? 'idle' : 'loading')
|
const state = ref<PaginatorState>(isMastoInitialised.value ? 'idle' : 'loading')
|
||||||
const items = ref<T[]>([])
|
const items = ref<T[]>([])
|
||||||
|
@ -62,8 +63,10 @@ export function usePaginator<T, P>(
|
||||||
const result = await paginator.next()
|
const result = await paginator.next()
|
||||||
|
|
||||||
if (result.value?.length) {
|
if (result.value?.length) {
|
||||||
nextItems.value = preprocess(result.value) as any
|
const preprocessedItems = preprocess([...nextItems.value, ...result.value]) as any
|
||||||
items.value.push(...nextItems.value)
|
const itemsToShowCount = preprocessedItems.length - buffer
|
||||||
|
nextItems.value = preprocessedItems.slice(itemsToShowCount)
|
||||||
|
items.value.push(...preprocessedItems.slice(0, itemsToShowCount))
|
||||||
state.value = 'idle'
|
state.value = 'idle'
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -108,7 +111,6 @@ export function usePaginator<T, P>(
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
prevItems,
|
prevItems,
|
||||||
nextItems,
|
|
||||||
update,
|
update,
|
||||||
state,
|
state,
|
||||||
error,
|
error,
|
||||||
|
|
|
@ -8,7 +8,7 @@ const { t } = useI18n()
|
||||||
|
|
||||||
const account = await fetchAccountByHandle(handle)
|
const account = await fetchAccountByHandle(handle)
|
||||||
|
|
||||||
const paginator = useMasto().v1.accounts.listStatuses(account.id, { excludeReplies: true })
|
const paginator = useMasto().v1.accounts.listStatuses(account.id, { limit: 30, excludeReplies: true })
|
||||||
|
|
||||||
if (account) {
|
if (account) {
|
||||||
useHeadFixed({
|
useHeadFixed({
|
||||||
|
|
Loading…
Reference in New Issue