diff --git a/components/common/CommonPaginator.vue b/components/common/CommonPaginator.vue index 9d26aaba..2cd07162 100644 --- a/components/common/CommonPaginator.vue +++ b/components/common/CommonPaginator.vue @@ -10,6 +10,7 @@ const { keyProp = 'id', virtualScroller = false, eventType = 'update', + buffer = 10, preprocess, } = defineProps<{ paginator: Paginator<T[], O> @@ -17,6 +18,10 @@ const { virtualScroller?: boolean stream?: Promise<WsEvents> 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[] }>() diff --git a/components/status/edit/StatusEditHistory.vue b/components/status/edit/StatusEditHistory.vue index c5d29343..2d6f2f80 100644 --- a/components/status/edit/StatusEditHistory.vue +++ b/components/status/edit/StatusEditHistory.vue @@ -13,12 +13,13 @@ const showHistory = (edit: mastodon.v1.StatusEdit) => { } const timeAgoOptions = useTimeAgoOptions() +// TODO: rework, this is only reversing the first page of edits const reverseHistory = (items: mastodon.v1.StatusEdit[]) => [...items].reverse() </script> <template> - <CommonPaginator :paginator="paginator" key-prop="createdAt" :preprocess="reverseHistory"> + <CommonPaginator :paginator="paginator" key-prop="createdAt" :preprocess="reverseHistory" :buffer="0"> <template #default="{ items, item, index }"> <CommonDropdownItem px="0.5" diff --git a/components/timeline/TimelineHome.vue b/components/timeline/TimelineHome.vue index 4404ea7c..6450cc8f 100644 --- a/components/timeline/TimelineHome.vue +++ b/components/timeline/TimelineHome.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -const paginator = useMasto().v1.timelines.listHome() +const paginator = useMasto().v1.timelines.listHome({ limit: 30 }) const stream = useMasto().v1.stream.streamUser() onBeforeUnmount(() => stream?.then(s => s.disconnect())) </script> diff --git a/components/timeline/TimelinePaginator.vue b/components/timeline/TimelinePaginator.vue index 49d7cc84..ea013bee 100644 --- a/components/timeline/TimelinePaginator.vue +++ b/components/timeline/TimelinePaginator.vue @@ -4,12 +4,13 @@ import { DynamicScrollerItem } from 'vue-virtual-scroller' import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' 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> stream?: Promise<WsEvents> context?: mastodon.v2.FilterContext account?: mastodon.v1.Account preprocess?: (items: mastodon.v1.Status[]) => mastodon.v1.Status[] + buffer?: number }>() const { formatNumber } = useHumanReadableNumber() @@ -21,7 +22,7 @@ const showOriginSite = $computed(() => </script> <template> - <CommonPaginator v-bind="{ paginator, stream, preprocess }" :virtual-scroller="virtualScroller"> + <CommonPaginator v-bind="{ paginator, stream, preprocess, buffer }" :virtual-scroller="virtualScroller"> <template #updater="{ number, 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) } }) }} diff --git a/components/timeline/TimelinePublic.vue b/components/timeline/TimelinePublic.vue index 06122783..3cf34d32 100644 --- a/components/timeline/TimelinePublic.vue +++ b/components/timeline/TimelinePublic.vue @@ -1,5 +1,5 @@ <script setup lang="ts"> -const paginator = useMasto().v1.timelines.listPublic() +const paginator = useMasto().v1.timelines.listPublic({ limit: 30 }) const stream = useMasto().v1.stream.streamPublicTimeline() onBeforeUnmount(() => stream.then(s => s.disconnect())) </script> diff --git a/components/timeline/TimelinePublicLocal.vue b/components/timeline/TimelinePublicLocal.vue index 4db8e093..546d5a24 100644 --- a/components/timeline/TimelinePublicLocal.vue +++ b/components/timeline/TimelinePublicLocal.vue @@ -1,5 +1,5 @@ <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() onBeforeUnmount(() => stream.then(s => s.disconnect())) </script> diff --git a/composables/paginator.ts b/composables/paginator.ts index 9689dcb8..08716b10 100644 --- a/composables/paginator.ts +++ b/composables/paginator.ts @@ -7,6 +7,7 @@ export function usePaginator<T, P>( stream?: Promise<WsEvents>, eventType: 'notification' | 'update' = 'update', preprocess: (items: T[]) => T[] = (items: T[]) => items, + buffer = 10, ) { const state = ref<PaginatorState>(isMastoInitialised.value ? 'idle' : 'loading') const items = ref<T[]>([]) @@ -66,8 +67,10 @@ export function usePaginator<T, P>( const result = await paginator.next() if (result.value?.length) { - nextItems.value = preprocess(result.value) as any - items.value.push(...nextItems.value) + const preprocessedItems = preprocess([...nextItems.value, ...result.value]) as any + const itemsToShowCount = preprocessedItems.length - buffer + nextItems.value = preprocessedItems.slice(itemsToShowCount) + items.value.push(...preprocessedItems.slice(0, itemsToShowCount)) state.value = 'idle' } else { @@ -136,7 +139,6 @@ export function usePaginator<T, P>( return { items, prevItems, - nextItems, update, state, error, diff --git a/pages/[[server]]/@[account]/index/index.vue b/pages/[[server]]/@[account]/index/index.vue index 7eba1a71..ec484285 100644 --- a/pages/[[server]]/@[account]/index/index.vue +++ b/pages/[[server]]/@[account]/index/index.vue @@ -8,7 +8,7 @@ const { t } = useI18n() 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) { useHeadFixed({