Highlight the library row that is open in Output.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-30 15:07:52 -05:00
co-authored by Cursor
parent bfe94e4bb1
commit 4d411f83d4
+59 -4
View File
@@ -1529,8 +1529,10 @@
<li <li
v-for="entry in libraryEntries" v-for="entry in libraryEntries"
:key="entry.key" :key="entry.key"
class="rounded-2xl border p-3" class="cursor-pointer rounded-2xl border p-3"
:class="selectedKeys.includes(entry.key) ? 'border-amber-300/30 bg-amber-400/5' : 'border-white/5 bg-zinc-950/40'" :class="libraryEntryClass(entry)"
:aria-current="isLibraryEntryFocused(entry) ? 'true' : undefined"
@click="onLibraryCardClick(entry, $event)"
> >
<template v-if="entry.kind === 'clip'"> <template v-if="entry.kind === 'clip'">
<div class="flex gap-3"> <div class="flex gap-3">
@@ -1632,7 +1634,10 @@
<li <li
v-for="(item, partIndex) in chronologicalParts(entry.group.parts)" v-for="(item, partIndex) in chronologicalParts(entry.group.parts)"
:key="item.id" :key="item.id"
class="flex flex-wrap items-start gap-3 rounded-xl border border-white/5 bg-black/20 p-2" class="flex cursor-pointer flex-wrap items-start gap-3 rounded-xl border p-2"
:class="item.id === reviewingClipId ? 'border-amber-300/80 bg-amber-400/15 ring-1 ring-amber-300/60' : 'border-white/5 bg-black/20'"
:aria-current="item.id === reviewingClipId ? 'true' : undefined"
@click="onLibraryClipPartClick(item, $event)"
> >
<ClipFrameThumbs <ClipFrameThumbs
:hidden="item.hideThumbnail" :hidden="item.hideThumbnail"
@@ -1794,7 +1799,10 @@
<li <li
v-for="item in chronologicalStills(entry.stillGroup.parts)" v-for="item in chronologicalStills(entry.stillGroup.parts)"
:key="item.id" :key="item.id"
class="flex gap-3 rounded-xl border border-white/5 bg-black/20 p-2" class="flex cursor-pointer gap-3 rounded-xl border p-2"
:class="item.id === reviewingStillId ? 'border-amber-300/80 bg-amber-400/15 ring-1 ring-amber-300/60' : 'border-white/5 bg-black/20'"
:aria-current="item.id === reviewingStillId ? 'true' : undefined"
@click="onLibraryStillPartClick(item, $event)"
> >
<button type="button" class="relative h-12 w-12 shrink-0 overflow-hidden rounded-lg bg-zinc-900" @click="openStill(item)"> <button type="button" class="relative h-12 w-12 shrink-0 overflow-hidden rounded-lg bg-zinc-900" @click="openStill(item)">
<span v-if="item.hideInput" class="sensitive-glow block h-full w-full" /> <span v-if="item.hideInput" class="sensitive-glow block h-full w-full" />
@@ -2962,6 +2970,53 @@ const libraryEntries = computed(() => {
})) }))
return [...videos, ...images].sort((a, b) => b.createdAt - a.createdAt) return [...videos, ...images].sort((a, b) => b.createdAt - a.createdAt)
}) })
const reviewingClipId = computed(() => {
if (outputPreviewKind.value !== 'video' || lockedSave.value) return ''
const fromUrl = String(videoUrl.value || '').match(/\/api\/library\/clips\/([^/?#]+)\/video/)
return currentClipId.value || fromUrl?.[1] || ''
})
const reviewingStillId = computed(() => {
if (outputPreviewKind.value !== 'edit' || editLockedSave.value) return ''
return stillIdFromLibraryUrl(editResultUrl.value)
})
type LibraryEntry = (typeof libraryEntries.value)[number]
function isLibraryEntryFocused(entry: LibraryEntry) {
if (entry.kind === 'clip' && reviewingClipId.value) {
return entry.group.parts.some(part => part.id === reviewingClipId.value)
}
if (entry.kind === 'still' && reviewingStillId.value && entry.stillGroup) {
return entry.stillGroup.parts.some(part => part.id === reviewingStillId.value)
}
return false
}
function libraryEntryClass(entry: LibraryEntry) {
if (isLibraryEntryFocused(entry)) {
return 'border-amber-300 bg-amber-400/15 ring-2 ring-amber-300/70'
}
if (selectedKeys.value.includes(entry.key)) {
return 'border-amber-300/30 bg-amber-400/5'
}
return 'border-white/5 bg-zinc-950/40'
}
function libraryClickIgnored(event: MouseEvent) {
const target = event.target as HTMLElement | null
return Boolean(target?.closest('button, a, input, select, textarea, label'))
}
function onLibraryCardClick(entry: LibraryEntry, event: MouseEvent) {
if (libraryClickIgnored(event)) return
if (entry.kind === 'clip') openClip(entry.group.head)
else if (entry.stillGroup) openStill(entry.stillGroup.head)
}
function onLibraryClipPartClick(item: LibraryClip, event: MouseEvent) {
event.stopPropagation()
if (libraryClickIgnored(event)) return
openClip(item)
}
function onLibraryStillPartClick(item: LibraryStill, event: MouseEvent) {
event.stopPropagation()
if (libraryClickIgnored(event)) return
openStill(item)
}
const libraryEmptyLabel = computed(() => { const libraryEmptyLabel = computed(() => {
if (libraryFilter.value === 'images') return 'No generated stills in this folder yet.' if (libraryFilter.value === 'images') return 'No generated stills in this folder yet.'
if (libraryFilter.value === 'videos') return 'No generated clips in this folder yet.' if (libraryFilter.value === 'videos') return 'No generated clips in this folder yet.'