Hide the extend last-frame preview by default on xAIGen.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+56
-16
@@ -1311,8 +1311,22 @@
|
||||
</div>
|
||||
<button type="button" class="text-xs text-zinc-400 hover:text-white" @click="closeExtend">Close</button>
|
||||
</div>
|
||||
<div class="overflow-hidden rounded-xl bg-black/40">
|
||||
<img v-if="lastFrameUrl" :src="lastFrameUrl" alt="Last frame" class="max-h-48 w-full object-contain">
|
||||
<div class="relative overflow-hidden rounded-xl bg-black/40" style="min-height: 8rem">
|
||||
<img
|
||||
v-if="lastFrameUrl && !hideExtendLastFrame"
|
||||
:src="lastFrameUrl"
|
||||
alt="Last frame"
|
||||
class="max-h-48 w-full object-contain"
|
||||
>
|
||||
<button
|
||||
v-else-if="hideExtendLastFrame"
|
||||
type="button"
|
||||
class="sensitive-glow flex min-h-[8rem] w-full flex-col items-center justify-center gap-1 px-3 py-8 text-amber-100"
|
||||
@click="revealExtendLastFrame"
|
||||
>
|
||||
<span class="text-sm font-medium">Last frame ready</span>
|
||||
<span class="text-xs text-amber-100/80">Click to reveal · preview hidden</span>
|
||||
</button>
|
||||
<p v-else class="px-3 py-8 text-center text-xs text-zinc-500">
|
||||
{{ lastFrameLoading ? 'Reading last frame…' : 'Last frame preview unavailable' }}
|
||||
</p>
|
||||
@@ -2448,6 +2462,7 @@ const extendPrompt = ref('')
|
||||
const extendDuration = ref(5)
|
||||
const lastFrameUrl = ref('')
|
||||
const lastFrameLoading = ref(false)
|
||||
const lastFrameRevealed = ref(false)
|
||||
const watchingLibrary = ref(false)
|
||||
let lastFrameObjectUrl = ''
|
||||
let lastFrameGen = 0
|
||||
@@ -2801,6 +2816,11 @@ const videoModelHint = computed(() => {
|
||||
const frameCount = computed(() => Math.max(5, Math.floor(duration.value * fps.value)))
|
||||
const cfgPct = computed(() => ((cfg.value - CFG_MIN) / (CFG_MAX - CFG_MIN)) * 100)
|
||||
const currentClip = computed(() => clips.value.find(clip => clip.id === currentClipId.value))
|
||||
const hideExtendLastFrame = computed(() => (
|
||||
showPrivacyToggles.value
|
||||
&& !lastFrameRevealed.value
|
||||
&& (hideInputPreview.value || hideThumbnail.value || currentClip.value?.hideThumbnail === true)
|
||||
))
|
||||
const canExtend = computed(() => Boolean(
|
||||
videoUrl.value
|
||||
&& !lockedSave.value
|
||||
@@ -3731,6 +3751,12 @@ watch(hideThumbnail, (value) => {
|
||||
} catch { /* ignore */ }
|
||||
})
|
||||
|
||||
watch(hideExtendLastFrame, (hidden) => {
|
||||
if (hidden || !extendOpen.value) return
|
||||
const id = currentClipId.value || clipIdFromPlayer()
|
||||
if (id && !lastFrameUrl.value && !lastFrameLoading.value) void loadLastFrame(id)
|
||||
})
|
||||
|
||||
watch(withSound, (value) => {
|
||||
try {
|
||||
localStorage.setItem('aigen-generate-sound', String(value))
|
||||
@@ -5153,6 +5179,7 @@ function concealFromOutsideTap(event: Event) {
|
||||
if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) {
|
||||
editAwaitingReveal.value = true
|
||||
}
|
||||
if (showPrivacyToggles.value) lastFrameRevealed.value = false
|
||||
}
|
||||
|
||||
function concealAndPause() {
|
||||
@@ -5399,6 +5426,7 @@ function closeExtend() {
|
||||
lastFrameGen += 1
|
||||
extendOpen.value = false
|
||||
lastFrameLoading.value = false
|
||||
lastFrameRevealed.value = false
|
||||
if (lastFrameObjectUrl) {
|
||||
URL.revokeObjectURL(lastFrameObjectUrl)
|
||||
lastFrameObjectUrl = ''
|
||||
@@ -5406,6 +5434,29 @@ function closeExtend() {
|
||||
lastFrameUrl.value = ''
|
||||
}
|
||||
|
||||
async function loadLastFrame(id: string) {
|
||||
lastFrameLoading.value = true
|
||||
const gen = ++lastFrameGen
|
||||
try {
|
||||
const blob = await $fetch<Blob>(`/api/library/clips/${id}/last-frame`, { responseType: 'blob' })
|
||||
if (gen !== lastFrameGen) return
|
||||
if (lastFrameObjectUrl) URL.revokeObjectURL(lastFrameObjectUrl)
|
||||
lastFrameObjectUrl = URL.createObjectURL(blob)
|
||||
lastFrameUrl.value = lastFrameObjectUrl
|
||||
} catch (error: any) {
|
||||
if (gen !== lastFrameGen) return
|
||||
toast(error?.data?.statusMessage || 'Could not extract the last frame')
|
||||
} finally {
|
||||
if (gen === lastFrameGen) lastFrameLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function revealExtendLastFrame() {
|
||||
lastFrameRevealed.value = true
|
||||
const id = currentClipId.value || clipIdFromPlayer()
|
||||
if (id && !lastFrameUrl.value && !lastFrameLoading.value) void loadLastFrame(id)
|
||||
}
|
||||
|
||||
async function openExtend(item?: LibraryClip) {
|
||||
if (item) openClip(item)
|
||||
const id = item?.id || clipIdFromPlayer()
|
||||
@@ -5418,23 +5469,12 @@ async function openExtend(item?: LibraryClip) {
|
||||
extendPrompt.value = clip?.prompt || prompt.value
|
||||
extendDuration.value = clampDuration(duration.value)
|
||||
extendLoraStack.value = readLoraStack(clip)
|
||||
lastFrameRevealed.value = false
|
||||
extendOpen.value = true
|
||||
lastFrameLoading.value = true
|
||||
lastFrameUrl.value = ''
|
||||
lastFrameLoading.value = false
|
||||
player.value?.pause()
|
||||
const gen = ++lastFrameGen
|
||||
try {
|
||||
const blob = await $fetch<Blob>(`/api/library/clips/${id}/last-frame`, { responseType: 'blob' })
|
||||
if (gen !== lastFrameGen) return
|
||||
if (lastFrameObjectUrl) URL.revokeObjectURL(lastFrameObjectUrl)
|
||||
lastFrameObjectUrl = URL.createObjectURL(blob)
|
||||
lastFrameUrl.value = lastFrameObjectUrl
|
||||
} catch (error: any) {
|
||||
if (gen !== lastFrameGen) return
|
||||
toast(error?.data?.statusMessage || 'Could not extract the last frame')
|
||||
} finally {
|
||||
if (gen === lastFrameGen) lastFrameLoading.value = false
|
||||
}
|
||||
if (!hideExtendLastFrame.value) await loadLastFrame(id)
|
||||
}
|
||||
|
||||
async function generateExtension() {
|
||||
|
||||
Reference in New Issue
Block a user