feat(ui): batch initial showcase/gallery loads into smaller chunks
Showcase and gallery were fetching the full initial batch (60 / 50 items) in a single API call. Operator-flagged 2026-05-30: items should stream in as small batches so they render progressively rather than blocking on one big response. - showcase store: PAGE 60 → 5, INITIAL_BATCHES = 12 (5 × 12 = 60, same total). loadInitial() fetches PAGE chunks in sequence; shuffle() delegates. fetchPage() still returns one PAGE-sized chunk so infinite-scroll also pulls 5 per trigger. - gallery store: loadMore() limit 50 → PAGE (5), INITIAL_BATCHES = 10. loadInitial() loops loadMore() up to INITIAL_BATCHES times, stopping early when nextCursor becomes null (end of data). - ShowcaseView: onMounted calls loadInitial() instead of fetchPage(). Gallery/setTagFilter/setPostFilter already routed through loadInitial. Net visual effect: each ~5-item batch lands and renders independently; combined with MasonryGrid's animateFromIndex logic, the showcase now cascades batches in as they arrive instead of one big pop-in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,13 @@ import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import { useApi } from '../composables/useApi.js'
|
||||
|
||||
// Operator-confirmed 2026-05-30: fetch PAGE-sized chunks instead of one
|
||||
// 50-item request so items render as each batch lands. Total initial
|
||||
// count is unchanged (PAGE * INITIAL_BATCHES = 50). Infinite-scroll also
|
||||
// pulls PAGE per trigger to keep appends progressive.
|
||||
const PAGE = 5
|
||||
const INITIAL_BATCHES = 10
|
||||
|
||||
export const useGalleryStore = defineStore('gallery', () => {
|
||||
const api = useApi()
|
||||
|
||||
@@ -21,7 +28,13 @@ export const useGalleryStore = defineStore('gallery', () => {
|
||||
images.value = []
|
||||
dateGroups.value = []
|
||||
nextCursor.value = null
|
||||
await loadMore()
|
||||
// Sequentially fetch INITIAL_BATCHES chunks so items render as each
|
||||
// batch lands rather than blocking on one big response. Stop early
|
||||
// when the backend reports no more pages.
|
||||
for (let i = 0; i < INITIAL_BATCHES; i++) {
|
||||
if (i > 0 && nextCursor.value === null) break
|
||||
await loadMore()
|
||||
}
|
||||
}
|
||||
|
||||
async function loadMore() {
|
||||
@@ -30,7 +43,7 @@ export const useGalleryStore = defineStore('gallery', () => {
|
||||
error.value = null
|
||||
const myId = ++inflightId
|
||||
try {
|
||||
const params = { limit: 50, ...activeFilterParam() }
|
||||
const params = { limit: PAGE, ...activeFilterParam() }
|
||||
if (nextCursor.value) params.cursor = nextCursor.value
|
||||
const body = await api.get('/api/gallery/scroll', { params })
|
||||
if (myId !== inflightId) return // stale response
|
||||
|
||||
@@ -70,7 +70,7 @@ function onKeydown(e) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (store.images.length === 0) store.fetchPage()
|
||||
if (store.images.length === 0) store.loadInitial()
|
||||
window.addEventListener('keydown', onKeydown)
|
||||
})
|
||||
onUnmounted(() => window.removeEventListener('keydown', onKeydown))
|
||||
|
||||
Reference in New Issue
Block a user