From 4546aa5f61b9ca4b9258c629e182ed2634d660d6 Mon Sep 17 00:00:00 2001 From: Towsty Date: Wed, 2 Sep 2026 15:05:04 -0500 Subject: [PATCH] Make library hide/reveal instant instead of rewriting the whole catalog. Co-authored-by: Cursor --- components/ImagePickerModal.vue | 24 ++++++++-- pages/index.vue | 24 +++++++++- pages/library.vue | 64 +++++++++++++++++++++++-- server/api/library/clips/[id].patch.ts | 2 +- server/api/library/stills/[id].patch.ts | 5 +- server/utils/library.ts | 1 - 6 files changed, 108 insertions(+), 12 deletions(-) diff --git a/components/ImagePickerModal.vue b/components/ImagePickerModal.vue index 57f45d6..07995e4 100644 --- a/components/ImagePickerModal.vue +++ b/components/ImagePickerModal.vue @@ -109,7 +109,6 @@ type="button" class="rounded-full bg-zinc-950/80 p-1.5 text-amber-100 hover:bg-zinc-900 disabled:opacity-50" :title="still.hideInput ? 'Show thumbnail' : 'Hide thumbnail'" - :disabled="hidingId === still.id" @click.stop="toggleHidden(still)" > @@ -237,6 +236,7 @@ const activeFolderId = ref(props.folderId) const tab = ref<'input' | 'output'>('input') const revealAll = ref(false) const revealedIds = ref([]) +const forceHiddenIds = ref([]) const picking = ref(false) const keepingId = ref('') const hidingId = ref('') @@ -285,28 +285,42 @@ function isRevealed(id: string) { } function thumbBlurred(still: PickerStill) { + if (forceHiddenIds.value.includes(still.id)) return true return stillHidden(still) && !isRevealed(still.id) } async function toggleHidden(still: PickerStill) { - if (hidingId.value) return + if (hidingId.value === still.id) return + const nextHide = still.hideInput !== true + const previous = still.hideInput === true + still.hideInput = nextHide + if (nextHide) { + revealedIds.value = revealedIds.value.filter(id => id !== still.id) + if (revealAll.value && !forceHiddenIds.value.includes(still.id)) { + forceHiddenIds.value = [...forceHiddenIds.value, still.id] + } + } else { + forceHiddenIds.value = forceHiddenIds.value.filter(id => id !== still.id) + } hidingId.value = still.id try { emit('updated', await $fetch(`/api/library/stills/${still.id}`, { method: 'PATCH', - body: { hideInput: still.hideInput !== true } + body: { hideInput: nextHide } })) - revealedIds.value = revealedIds.value.filter(id => id !== still.id) } catch (error: any) { + still.hideInput = previous + forceHiddenIds.value = forceHiddenIds.value.filter(id => id !== still.id) emit('error', error?.data?.statusMessage || 'Could not update thumbnail') } finally { - hidingId.value = '' + if (hidingId.value === still.id) hidingId.value = '' } } function toggleRevealAll() { revealAll.value = !revealAll.value revealedIds.value = [] + forceHiddenIds.value = [] } async function unlock() { diff --git a/pages/index.vue b/pages/index.vue index 747f87f..4cf096e 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -3626,7 +3626,29 @@ function applyInstancePrivacy() { } function applyLibrary(data: { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record; loraTriggers?: Record; keepPrompts?: KeepPromptLists } | unknown) { - const payload = (data || {}) as { folders?: LibraryFolder[]; clips?: LibraryClip[]; stills?: LibraryStill[]; drafts?: RetryDraft[]; loraAliases?: Record; loraTriggers?: Record; keepPrompts?: KeepPromptLists } + const payload = (data || {}) as { + id?: string + hideInput?: boolean + hideThumbnail?: boolean + folders?: LibraryFolder[] + clips?: LibraryClip[] + stills?: LibraryStill[] + drafts?: RetryDraft[] + loraAliases?: Record + loraTriggers?: Record + keepPrompts?: KeepPromptLists + } + if (payload.id && !payload.folders && !payload.clips && !payload.stills) { + if (typeof payload.hideInput === 'boolean') { + const still = stills.value.find(item => item.id === payload.id) + if (still) still.hideInput = payload.hideInput + } + if (typeof payload.hideThumbnail === 'boolean') { + const clip = clips.value.find(item => item.id === payload.id) + if (clip) clip.hideThumbnail = payload.hideThumbnail + } + return + } folders.value = payload.folders || [] clips.value = payload.clips || [] stills.value = payload.stills || [] diff --git a/pages/library.vue b/pages/library.vue index ea39bf8..9ad31f1 100644 --- a/pages/library.vue +++ b/pages/library.vue @@ -215,6 +215,7 @@ v-else-if="focused.kind === 'still' && previewStillSrc" :src="previewStillSrc" alt="" + decoding="async" class="aspect-video w-full object-contain" >