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>
|
</div>
|
||||||
<button type="button" class="text-xs text-zinc-400 hover:text-white" @click="closeExtend">Close</button>
|
<button type="button" class="text-xs text-zinc-400 hover:text-white" @click="closeExtend">Close</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden rounded-xl bg-black/40">
|
<div class="relative overflow-hidden rounded-xl bg-black/40" style="min-height: 8rem">
|
||||||
<img v-if="lastFrameUrl" :src="lastFrameUrl" alt="Last frame" class="max-h-48 w-full object-contain">
|
<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">
|
<p v-else class="px-3 py-8 text-center text-xs text-zinc-500">
|
||||||
{{ lastFrameLoading ? 'Reading last frame…' : 'Last frame preview unavailable' }}
|
{{ lastFrameLoading ? 'Reading last frame…' : 'Last frame preview unavailable' }}
|
||||||
</p>
|
</p>
|
||||||
@@ -2448,6 +2462,7 @@ const extendPrompt = ref('')
|
|||||||
const extendDuration = ref(5)
|
const extendDuration = ref(5)
|
||||||
const lastFrameUrl = ref('')
|
const lastFrameUrl = ref('')
|
||||||
const lastFrameLoading = ref(false)
|
const lastFrameLoading = ref(false)
|
||||||
|
const lastFrameRevealed = ref(false)
|
||||||
const watchingLibrary = ref(false)
|
const watchingLibrary = ref(false)
|
||||||
let lastFrameObjectUrl = ''
|
let lastFrameObjectUrl = ''
|
||||||
let lastFrameGen = 0
|
let lastFrameGen = 0
|
||||||
@@ -2801,6 +2816,11 @@ const videoModelHint = computed(() => {
|
|||||||
const frameCount = computed(() => Math.max(5, Math.floor(duration.value * fps.value)))
|
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 cfgPct = computed(() => ((cfg.value - CFG_MIN) / (CFG_MAX - CFG_MIN)) * 100)
|
||||||
const currentClip = computed(() => clips.value.find(clip => clip.id === currentClipId.value))
|
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(
|
const canExtend = computed(() => Boolean(
|
||||||
videoUrl.value
|
videoUrl.value
|
||||||
&& !lockedSave.value
|
&& !lockedSave.value
|
||||||
@@ -3731,6 +3751,12 @@ watch(hideThumbnail, (value) => {
|
|||||||
} catch { /* ignore */ }
|
} 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) => {
|
watch(withSound, (value) => {
|
||||||
try {
|
try {
|
||||||
localStorage.setItem('aigen-generate-sound', String(value))
|
localStorage.setItem('aigen-generate-sound', String(value))
|
||||||
@@ -5153,6 +5179,7 @@ function concealFromOutsideTap(event: Event) {
|
|||||||
if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) {
|
if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) {
|
||||||
editAwaitingReveal.value = true
|
editAwaitingReveal.value = true
|
||||||
}
|
}
|
||||||
|
if (showPrivacyToggles.value) lastFrameRevealed.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function concealAndPause() {
|
function concealAndPause() {
|
||||||
@@ -5399,6 +5426,7 @@ function closeExtend() {
|
|||||||
lastFrameGen += 1
|
lastFrameGen += 1
|
||||||
extendOpen.value = false
|
extendOpen.value = false
|
||||||
lastFrameLoading.value = false
|
lastFrameLoading.value = false
|
||||||
|
lastFrameRevealed.value = false
|
||||||
if (lastFrameObjectUrl) {
|
if (lastFrameObjectUrl) {
|
||||||
URL.revokeObjectURL(lastFrameObjectUrl)
|
URL.revokeObjectURL(lastFrameObjectUrl)
|
||||||
lastFrameObjectUrl = ''
|
lastFrameObjectUrl = ''
|
||||||
@@ -5406,6 +5434,29 @@ function closeExtend() {
|
|||||||
lastFrameUrl.value = ''
|
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) {
|
async function openExtend(item?: LibraryClip) {
|
||||||
if (item) openClip(item)
|
if (item) openClip(item)
|
||||||
const id = item?.id || clipIdFromPlayer()
|
const id = item?.id || clipIdFromPlayer()
|
||||||
@@ -5418,23 +5469,12 @@ async function openExtend(item?: LibraryClip) {
|
|||||||
extendPrompt.value = clip?.prompt || prompt.value
|
extendPrompt.value = clip?.prompt || prompt.value
|
||||||
extendDuration.value = clampDuration(duration.value)
|
extendDuration.value = clampDuration(duration.value)
|
||||||
extendLoraStack.value = readLoraStack(clip)
|
extendLoraStack.value = readLoraStack(clip)
|
||||||
|
lastFrameRevealed.value = false
|
||||||
extendOpen.value = true
|
extendOpen.value = true
|
||||||
lastFrameLoading.value = true
|
|
||||||
lastFrameUrl.value = ''
|
lastFrameUrl.value = ''
|
||||||
|
lastFrameLoading.value = false
|
||||||
player.value?.pause()
|
player.value?.pause()
|
||||||
const gen = ++lastFrameGen
|
if (!hideExtendLastFrame.value) await loadLastFrame(id)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function generateExtension() {
|
async function generateExtension() {
|
||||||
|
|||||||
Reference in New Issue
Block a user