[backport cloud/1.36] perf(AssetBrowserModal): virtualize asset grid to reduce network requests (#7922)

Backport of #7919 to `cloud/1.36`

Automatically created by backport workflow.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7922-backport-cloud-1-36-perf-AssetBrowserModal-virtualize-asset-grid-to-reduce-network-re-2e36d73d3650812ca602d496f4decec4)
by [Unito](https://www.unito.io)

Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Comfy Org PR Bot
2026-01-09 12:15:27 +09:00
committed by GitHub
parent be8ee3d228
commit ec7a3a9e20
2 changed files with 35 additions and 22 deletions

View File

@@ -82,7 +82,7 @@
{{ contentTitle }}
</h2>
<div
class="min-h-0 px-6 pt-0 pb-10 overflow-y-auto scrollbar-custom"
class="min-h-0 flex-1 px-6 pt-0 pb-10 overflow-y-auto scrollbar-custom"
>
<slot name="content"></slot>
</div>

View File

@@ -1,28 +1,21 @@
<template>
<div
data-component-id="AssetGrid"
:class="
cn('grid grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] gap-4 p-2')
"
class="h-full"
role="grid"
:aria-label="$t('assetBrowser.assetCollection')"
:aria-rowcount="-1"
:aria-colcount="-1"
:aria-setsize="assets.length"
>
<!-- Loading state -->
<div
v-if="loading"
class="col-span-full flex items-center justify-center py-20"
>
<div v-if="loading" class="flex h-full items-center justify-center py-20">
<i
class="icon-[lucide--loader] size-12 animate-spin text-muted-foreground"
/>
</div>
<!-- Empty state -->
<div
v-else-if="assets.length === 0"
class="col-span-full flex flex-col items-center justify-center py-16 text-muted-foreground"
class="flex h-full flex-col items-center justify-center py-16 text-muted-foreground"
>
<i class="mb-4 icon-[lucide--search] size-10" />
<h3 class="mb-2 text-lg font-medium">
@@ -30,24 +23,33 @@
</h3>
<p class="text-sm">{{ $t('assetBrowser.tryAdjustingFilters') }}</p>
</div>
<template v-else>
<AssetCard
v-for="asset in assets"
:key="asset.id"
:asset="asset"
:interactive="true"
@select="$emit('assetSelect', $event)"
/>
</template>
<VirtualGrid
v-else
:items="assetsWithKey"
:grid-style="gridStyle"
:default-item-height="320"
:default-item-width="240"
>
<template #item="{ item }">
<AssetCard
:asset="item"
:interactive="true"
@select="$emit('assetSelect', $event)"
/>
</template>
</VirtualGrid>
</div>
</template>
<script setup lang="ts">
import type { CSSProperties } from 'vue'
import { computed } from 'vue'
import VirtualGrid from '@/components/common/VirtualGrid.vue'
import AssetCard from '@/platform/assets/components/AssetCard.vue'
import type { AssetDisplayItem } from '@/platform/assets/composables/useAssetBrowser'
import { cn } from '@/utils/tailwindUtil'
defineProps<{
const { assets } = defineProps<{
assets: AssetDisplayItem[]
loading?: boolean
}>()
@@ -55,4 +57,15 @@ defineProps<{
defineEmits<{
assetSelect: [asset: AssetDisplayItem]
}>()
const assetsWithKey = computed(() =>
assets.map((asset) => ({ ...asset, key: asset.id }))
)
const gridStyle: Partial<CSSProperties> = {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(15rem, 1fr))',
gap: '1rem',
padding: '0.5rem'
}
</script>