pref: Use virtual scroll load models
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
minimizeIcon="pi pi-arrow-down-left-and-arrow-up-right-to-center"
|
||||
:pt:mask:class="['group', { open }]"
|
||||
pt:root:class="max-h-full group-[:not(.open)]:!hidden"
|
||||
pt:content:class="px-0"
|
||||
pt:content:class="px-0 flex-1"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex flex-1 items-center justify-between pr-2">
|
||||
@@ -37,6 +37,7 @@
|
||||
['--card-width']: `${cardWidth}px`,
|
||||
['--gutter']: `${gutter}px`,
|
||||
}"
|
||||
v-resize="onContainerResize"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
@@ -72,34 +73,42 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ResponseScrollArea class="h-full">
|
||||
<div
|
||||
:class="[
|
||||
'-mt-8 grid grid-cols-1 justify-center gap-8 px-8',
|
||||
'@lg/content:grid-cols-[repeat(auto-fit,var(--card-width))]',
|
||||
'@lg/content:gap-[var(--gutter)]',
|
||||
'@lg/content:-mt-[var(--gutter)]',
|
||||
'@lg/content:px-4',
|
||||
]"
|
||||
>
|
||||
<div class="col-span-full"></div>
|
||||
<div v-for="model in list" v-show="model.visible" :key="model.id">
|
||||
<ResponseScroll
|
||||
:items="list"
|
||||
:itemSize="cardWidth / aspect + gutter"
|
||||
:row-key="(item) => item.map(genModelKey).join(',')"
|
||||
class="h-full flex-1"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div
|
||||
:class="[
|
||||
'grid grid-cols-1 justify-center gap-8 px-8',
|
||||
'@lg/content:grid-cols-[repeat(auto-fit,var(--card-width))]',
|
||||
'@lg/content:gap-[var(--gutter)]',
|
||||
'@lg/content:px-4',
|
||||
]"
|
||||
>
|
||||
<DialogModelCard
|
||||
:key="`${model.type}:${model.pathIndex}:${model.fullname}`"
|
||||
v-for="model in item"
|
||||
:key="genModelKey(model)"
|
||||
:model="model"
|
||||
></DialogModelCard>
|
||||
<div class="col-span-full"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div v-show="noneDisplayModel" class="flex justify-center pt-20">
|
||||
<div class="select-none text-lg font-bold">No models found</div>
|
||||
</div>
|
||||
</ResponseScrollArea>
|
||||
<template #empty>
|
||||
<div class="flex flex-col items-center gap-4 pt-20 opacity-70">
|
||||
<i class="pi pi-box text-4xl"></i>
|
||||
<div class="select-none text-lg font-bold">No models found</div>
|
||||
</div>
|
||||
</template>
|
||||
</ResponseScroll>
|
||||
</div>
|
||||
|
||||
<DialogResizer
|
||||
:min-width="cardWidth * 2 + gutter + 42"
|
||||
:min-height="cardWidth * aspect * 0.5 + 162"
|
||||
:min-height="(cardWidth / aspect) * 0.5 + 162"
|
||||
></DialogResizer>
|
||||
</Dialog>
|
||||
</template>
|
||||
@@ -112,13 +121,15 @@ import DialogResizer from 'components/DialogResizer.vue'
|
||||
import DialogModelCard from 'components/DialogModelCard.vue'
|
||||
import ResponseInput from 'components/ResponseInput.vue'
|
||||
import ResponseSelect from 'components/ResponseSelect.vue'
|
||||
import ResponseScrollArea from 'components/ResponseScrollArea.vue'
|
||||
import ResponseScroll from 'components/ResponseScroll.vue'
|
||||
import Dialog from 'primevue/dialog'
|
||||
import Button from 'primevue/button'
|
||||
import { computed, ref } from 'vue'
|
||||
import { useToast } from 'hooks/toast'
|
||||
import { useDownload } from 'hooks/download'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { chunk } from 'lodash'
|
||||
import { defineResizeCallback } from 'hooks/resize'
|
||||
|
||||
const { isMobile, cardWidth, gutter, aspect, refreshSetting } = useConfig()
|
||||
|
||||
@@ -173,8 +184,11 @@ const sortOrderOptions = ref(
|
||||
}),
|
||||
)
|
||||
|
||||
const colSpan = ref(1)
|
||||
const colSpanWidth = ref(cardWidth)
|
||||
|
||||
const list = computed(() => {
|
||||
const filterList = data.value.map((model) => {
|
||||
const filterList = data.value.filter((model) => {
|
||||
const showAllModel = currentType.value === 'all'
|
||||
|
||||
const matchType = showAllModel || model.type === currentType.value
|
||||
@@ -182,9 +196,7 @@ const list = computed(() => {
|
||||
.toLowerCase()
|
||||
.includes(searchContent.value?.toLowerCase() || '')
|
||||
|
||||
model.visible = matchType && matchName
|
||||
|
||||
return model
|
||||
return matchType && matchName
|
||||
})
|
||||
|
||||
let sortStrategy = (a: Model, b: Model) => 0
|
||||
@@ -205,11 +217,9 @@ const list = computed(() => {
|
||||
break
|
||||
}
|
||||
|
||||
return filterList.sort(sortStrategy)
|
||||
})
|
||||
const sortedList = filterList.sort(sortStrategy)
|
||||
|
||||
const noneDisplayModel = computed(() => {
|
||||
return !list.value.some((model) => model.visible)
|
||||
return chunk(sortedList, colSpan.value)
|
||||
})
|
||||
|
||||
const refreshModels = async () => {
|
||||
@@ -220,4 +230,19 @@ const refreshModels = async () => {
|
||||
life: 2000,
|
||||
})
|
||||
}
|
||||
|
||||
const onContainerResize = defineResizeCallback((entries) => {
|
||||
const entry = entries[0]
|
||||
if (isMobile.value) {
|
||||
colSpan.value = 1
|
||||
} else {
|
||||
const containerWidth = entry.contentRect.width
|
||||
colSpan.value = Math.floor((containerWidth - gutter) / (cardWidth + gutter))
|
||||
colSpanWidth.value = colSpan.value * (cardWidth + gutter) - gutter
|
||||
}
|
||||
})
|
||||
|
||||
const genModelKey = (model: BaseModel) => {
|
||||
return `${model.type}:${model.pathIndex}:${model.fullname}`
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user