diff --git a/src/components/FilesLoadMoreSentinel.vue b/src/components/FilesLoadMoreSentinel.vue new file mode 100644 index 0000000..1bfc81f --- /dev/null +++ b/src/components/FilesLoadMoreSentinel.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/src/components/views/FilesDetailsView.vue b/src/components/views/FilesDetailsView.vue index ea14fa0..703f160 100644 --- a/src/components/views/FilesDetailsView.vue +++ b/src/components/views/FilesDetailsView.vue @@ -6,11 +6,11 @@ import { formatSize, formatDate } from '@/utils/fileHelpers' import FileActionsMenu from '@/components/FileActionsMenu.vue' import FilePreview from '@/components/FilePreview.vue' import FilePreviewPopover from '@/components/viewer/FilePreviewPopover.vue' +import FilesLoadMoreSentinel from '@/components/FilesLoadMoreSentinel.vue' -type ItemWithType = { - item: CollectionObject | EntityObject - type: 'collection' | 'entity' -} +type ItemWithType = + | { item: CollectionObject | EntityObject; type: 'collection' | 'entity' } + | { item: null; type: 'sentinel' } type PreviewSource = (item: { id: string; meta?: Record }) => string | Blob | Promise @@ -18,6 +18,8 @@ const props = defineProps<{ collections: CollectionObject[] entities: EntityObject[] selectedIds: Set + hasMore?: boolean + isLoadingMore?: boolean previewSource?: PreviewSource thumbnailSource?: PreviewSource }>() @@ -30,17 +32,25 @@ const emit = defineEmits<{ 'delete': [item: CollectionObject | EntityObject] 'download': [item: CollectionObject | EntityObject] 'show-details': [item: CollectionObject | EntityObject] + 'load-more': [] }>() -// Combine collections and entities into a single list for virtual scrolling +// Combine collections and entities into a single list for virtual scrolling; a +// trailing sentinel row (rendered only once virtual-scroll actually mounts it) +// drives the infinite-scroll "load more" trigger. const allItems = computed(() => [ ...props.collections.map(c => ({ item: c, type: 'collection' as const })), - ...props.entities.map(e => ({ item: e, type: 'entity' as const })) + ...props.entities.map(e => ({ item: e, type: 'entity' as const })), + ...(props.hasMore ? [{ item: null, type: 'sentinel' as const }] : []), ]) function isCollection(wrapped: ItemWithType): wrapped is { item: CollectionObject; type: 'collection' } { return wrapped.type === 'collection' } + +function isSentinel(wrapped: ItemWithType): wrapped is { item: null; type: 'sentinel' } { + return wrapped.type === 'sentinel' +}