From 69424692598f600abedfcd660845e1ba1595dca9 Mon Sep 17 00:00:00 2001 From: Sebastian Krupinski Date: Sat, 5 Sep 2026 20:14:40 -0400 Subject: [PATCH] feat: pagination Signed-off-by: Sebastian Krupinski --- src/components/FilesLoadMoreSentinel.vue | 79 ++++++++ src/components/views/FilesDetailsView.vue | 32 +++- src/components/views/FilesGridView.vue | 10 + src/components/views/FilesListView.vue | 32 +++- src/composables/useFileUpload.ts | 13 +- src/pages/Main.vue | 135 ++++++------- src/stores/documentsStore.ts | 222 ---------------------- src/stores/index.ts | 1 - src/types/index.ts | 2 +- 9 files changed, 200 insertions(+), 326 deletions(-) create mode 100644 src/components/FilesLoadMoreSentinel.vue delete mode 100644 src/stores/documentsStore.ts delete mode 100644 src/stores/index.ts 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' +}