fix: introduce virtua virtual scroller library (#3567)
This commit is contained in:
parent
df5ed65560
commit
e413a8cd96
7 changed files with 69 additions and 72 deletions
|
|
@ -1,8 +1,6 @@
|
|||
<script setup lang="ts" generic="T, O, U = T">
|
||||
import type { mastodon } from 'masto'
|
||||
// @ts-expect-error missing types
|
||||
import { DynamicScroller } from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
import { WindowVirtualizer } from 'virtua/vue'
|
||||
|
||||
const {
|
||||
paginator,
|
||||
|
|
@ -27,7 +25,6 @@ defineSlots<{
|
|||
items: U[]
|
||||
item: U
|
||||
index: number
|
||||
active?: boolean
|
||||
older: U
|
||||
newer: U // newer is undefined when index === 0
|
||||
}) => void
|
||||
|
|
@ -83,23 +80,16 @@ defineExpose({ createEntry, removeEntry, updateEntry })
|
|||
<slot v-if="prevItems.length" name="updater" v-bind="{ number: prevItems.length, update }" />
|
||||
<slot name="items" :items="items as U[]">
|
||||
<template v-if="virtualScroller">
|
||||
<DynamicScroller
|
||||
v-slot="{ item, active, index }"
|
||||
:items="items"
|
||||
:min-item-size="200"
|
||||
:key-field="keyProp"
|
||||
page-mode
|
||||
>
|
||||
<WindowVirtualizer v-slot="{ item, index }" :data="items">
|
||||
<slot
|
||||
v-bind="{ key: item[keyProp] }"
|
||||
v-bind="{ key: (item as any)[keyProp] }"
|
||||
:item="item"
|
||||
:active="active"
|
||||
:older="items[index + 1] as U"
|
||||
:newer="items[index - 1] as U"
|
||||
:index="index"
|
||||
:items="items as U[]"
|
||||
/>
|
||||
</DynamicScroller>
|
||||
</WindowVirtualizer>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { GroupedAccountLike, NotificationSlot } from '#shared/types'
|
||||
import type { mastodon } from 'masto'
|
||||
// @ts-expect-error missing types
|
||||
import { DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||
|
||||
defineProps<{
|
||||
paginator: mastodon.Paginator<mastodon.v1.Notification[], mastodon.rest.v1.ListNotificationsParams>
|
||||
|
|
@ -186,26 +184,24 @@ const { formatNumber } = useHumanReadableNumber()
|
|||
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||
</button>
|
||||
</template>
|
||||
<template #default="{ item, active }">
|
||||
<template #default="{ item }">
|
||||
<template v-if="virtualScroller">
|
||||
<DynamicScrollerItem :item="item" :active="active" tag="div">
|
||||
<NotificationGroupedFollow
|
||||
v-if="item.type === 'grouped-follow'"
|
||||
:items="item"
|
||||
border="b base"
|
||||
/>
|
||||
<NotificationGroupedLikes
|
||||
v-else-if="item.type === 'grouped-reblogs-and-favourites'"
|
||||
:group="item"
|
||||
border="b base"
|
||||
/>
|
||||
<NotificationCard
|
||||
v-else
|
||||
:notification="item"
|
||||
hover:bg-active
|
||||
border="b base"
|
||||
/>
|
||||
</DynamicScrollerItem>
|
||||
<NotificationGroupedFollow
|
||||
v-if="item.type === 'grouped-follow'"
|
||||
:items="item"
|
||||
border="b base"
|
||||
/>
|
||||
<NotificationGroupedLikes
|
||||
v-else-if="item.type === 'grouped-reblogs-and-favourites'"
|
||||
:group="item"
|
||||
border="b base"
|
||||
/>
|
||||
<NotificationCard
|
||||
v-else
|
||||
:notification="item"
|
||||
hover:bg-active
|
||||
border="b base"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NotificationGroupedFollow
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import type { mastodon } from 'masto'
|
||||
// @ts-expect-error missing types
|
||||
import { DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
|
||||
const { account, buffer = 10, endMessage = true, followedTags = [] } = defineProps<{
|
||||
paginator: mastodon.Paginator<mastodon.v1.Status[], mastodon.rest.v1.ListAccountStatusesParams>
|
||||
|
|
@ -36,17 +33,15 @@ function getFollowedTag(status: mastodon.v1.Status): string | null {
|
|||
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||
</button>
|
||||
</template>
|
||||
<template #default="{ item, older, newer, active }">
|
||||
<template #default="{ item, older, newer }">
|
||||
<template v-if="virtualScroller">
|
||||
<DynamicScrollerItem :item="item" :active="active" tag="article">
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" :account="account" />
|
||||
</DynamicScrollerItem>
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" :account="account" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<StatusCard :followed-tag="getFollowedTag(item)" :status="item" :context="context" :older="older" :newer="newer" :account="account" />
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="context === 'account' " #done="{ items }">
|
||||
<template v-if="context === 'account'" #done="{ items }">
|
||||
<div
|
||||
v-if="showOriginSite || items.length === 0"
|
||||
p5 text-secondary text-center flex flex-col items-center gap1
|
||||
|
|
|
|||
|
|
@ -2,10 +2,6 @@
|
|||
import type { CommonPaginator } from '#components'
|
||||
import type { mastodon } from 'masto'
|
||||
import type { ComponentExposed } from 'vue-component-type-helpers'
|
||||
// @ts-expect-error missing types
|
||||
import { DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
|
||||
const { account, buffer = 10, endMessage = true } = defineProps<{
|
||||
paginator: mastodon.Paginator<mastodon.v1.ScheduledStatus[], mastodon.DefaultPaginationParams>
|
||||
|
|
@ -38,11 +34,10 @@ const showOriginSite = computed(() =>
|
|||
{{ $t('timeline.show_new_items', number, { named: { v: formatNumber(number) } }) }}
|
||||
</button>
|
||||
</template>
|
||||
<template #default="{ item, active }">
|
||||
<template #default="{ item }">
|
||||
<component
|
||||
:is="virtualScroller ? DynamicScrollerItem : 'article'"
|
||||
:item="item"
|
||||
:active="active"
|
||||
:is="virtualScroller ? 'div' : 'article'"
|
||||
:key="item.id"
|
||||
>
|
||||
<StatusScheduledCard
|
||||
:item="item"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { ComponentPublicInstance } from 'vue'
|
||||
// @ts-expect-error missing types
|
||||
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
|
||||
import { WindowVirtualizer } from 'virtua/vue'
|
||||
|
||||
definePageMeta({
|
||||
name: 'status',
|
||||
|
|
@ -95,26 +94,20 @@ onReactivated(() => {
|
|||
/>
|
||||
|
||||
<template v-if="!pendingContext">
|
||||
<DynamicScroller
|
||||
v-slot="{ item, index, active }"
|
||||
:items="context?.descendants || []"
|
||||
:min-item-size="200"
|
||||
:buffer="800"
|
||||
key-field="id"
|
||||
page-mode
|
||||
<WindowVirtualizer
|
||||
v-slot="{ item, index }"
|
||||
:data="context?.descendants || []"
|
||||
>
|
||||
<DynamicScrollerItem :item="item" :active="active">
|
||||
<StatusCard
|
||||
:key="item.id"
|
||||
:status="item"
|
||||
context="account"
|
||||
:older="context?.descendants[index + 1]"
|
||||
:newer="index > 0 ? context?.descendants[index - 1] : status"
|
||||
:has-newer="index === 0"
|
||||
:main="status"
|
||||
/>
|
||||
</DynamicScrollerItem>
|
||||
</DynamicScroller>
|
||||
<StatusCard
|
||||
:key="item.id"
|
||||
:status="item"
|
||||
context="account"
|
||||
:older="context?.descendants[index + 1]"
|
||||
:newer="index > 0 ? context?.descendants[index - 1] : status"
|
||||
:has-newer="index === 0"
|
||||
:main="status"
|
||||
/>
|
||||
</WindowVirtualizer>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@
|
|||
"ultrahtml": "^1.5.3",
|
||||
"unimport": "^5.6.0",
|
||||
"unstorage": "^1.17.1",
|
||||
"virtua": "^0.48.6",
|
||||
"vite": "^7.1.7",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vue": "^3.5.4",
|
||||
|
|
|
|||
|
|
@ -266,6 +266,9 @@ importers:
|
|||
unstorage:
|
||||
specifier: ^1.17.4
|
||||
version: 1.17.4(@upstash/redis@1.35.4)(@vercel/kv@3.0.0)(db0@0.3.2(better-sqlite3@12.4.1))(idb-keyval@6.2.2)(ioredis@5.8.0)
|
||||
virtua:
|
||||
specifier: ^0.48.6
|
||||
version: 0.48.8(vue@3.5.22(typescript@5.9.2))
|
||||
vite:
|
||||
specifier: ^7.1.7
|
||||
version: 7.1.11(@types/node@25.4.0)(jiti@2.6.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.20.6)(yaml@2.8.2)
|
||||
|
|
@ -10190,6 +10193,26 @@ packages:
|
|||
vfile@6.0.3:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
virtua@0.48.8:
|
||||
resolution: {integrity: sha512-jpsxOw5V4B6hg44JePRLo9DL0TV7N1lBEVtPjKpAJebXyhI2s9lfiXJESaLapNtr3vtiSk/pWHiLf7B2a6UcgQ==}
|
||||
peerDependencies:
|
||||
react: '>=16.14.0'
|
||||
react-dom: '>=16.14.0'
|
||||
solid-js: '>=1.0'
|
||||
svelte: '>=5.0'
|
||||
vue: ^3.5.4
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
react-dom:
|
||||
optional: true
|
||||
solid-js:
|
||||
optional: true
|
||||
svelte:
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
|
||||
vite-dev-rpc@1.1.0:
|
||||
resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==}
|
||||
peerDependencies:
|
||||
|
|
@ -22917,6 +22940,10 @@ snapshots:
|
|||
'@types/unist': 3.0.3
|
||||
vfile-message: 4.0.3
|
||||
|
||||
virtua@0.48.8(vue@3.5.22(typescript@5.9.2)):
|
||||
optionalDependencies:
|
||||
vue: 3.5.22(typescript@5.9.2)
|
||||
|
||||
vite-dev-rpc@1.1.0(vite@7.1.11(@types/node@25.4.0)(jiti@2.6.0)(lightningcss@1.30.2)(terser@5.46.0)(tsx@4.20.6)(yaml@2.8.2)):
|
||||
dependencies:
|
||||
birpc: 2.6.1
|
||||
|
|
|
|||
Loading…
Reference in a new issue