Keep image jobs on the studio queue and confirm each job or library delete. Label stitch-frame slots when thumbs are hidden, and open output stills in a lightbox.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
<template>
|
||||
<div class="shrink-0">
|
||||
<span v-if="hidden" class="sensitive-glow block h-12 w-12 overflow-hidden rounded-lg" />
|
||||
<div v-else class="flex items-start gap-1.5">
|
||||
<button
|
||||
v-if="stillId && !failed.still"
|
||||
type="button"
|
||||
class="flex w-12 flex-col items-center gap-0.5"
|
||||
aria-label="Start still"
|
||||
@click.stop="openPreview(stillFull, 'Start')"
|
||||
>
|
||||
<span class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900">
|
||||
<div class="flex items-start gap-1.5">
|
||||
<div v-if="stillId && (hidden || !failed.still)" class="flex w-12 flex-col items-center gap-0.5">
|
||||
<span v-if="hidden" class="relative h-12 w-12 overflow-hidden rounded-lg">
|
||||
<span class="sensitive-glow block h-full w-full" />
|
||||
</span>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900"
|
||||
aria-label="Start still"
|
||||
@click.stop="openPreview(stillFull, 'Start')"
|
||||
>
|
||||
<img
|
||||
:src="stillThumb"
|
||||
alt=""
|
||||
@@ -18,17 +20,20 @@
|
||||
class="h-full w-full object-cover"
|
||||
@error="failed.still = true"
|
||||
>
|
||||
</span>
|
||||
</button>
|
||||
<span class="text-[10px] leading-none text-zinc-500">Start</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="fromClipId && !failed.from"
|
||||
type="button"
|
||||
class="flex w-12 flex-col items-center gap-0.5"
|
||||
aria-label="Last frame of previous clip"
|
||||
@click.stop="openPreview(fromFull, 'From prev')"
|
||||
>
|
||||
<span class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900">
|
||||
</div>
|
||||
<div v-if="fromClipId && (hidden || !failed.from)" class="flex w-12 flex-col items-center gap-0.5">
|
||||
<span v-if="hidden" class="relative h-12 w-12 overflow-hidden rounded-lg">
|
||||
<span class="sensitive-glow block h-full w-full" />
|
||||
</span>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900"
|
||||
aria-label="Last frame of previous clip"
|
||||
@click.stop="openPreview(fromFull, 'From prev')"
|
||||
>
|
||||
<img
|
||||
:src="fromThumb"
|
||||
alt=""
|
||||
@@ -37,17 +42,20 @@
|
||||
class="h-full w-full object-cover"
|
||||
@error="failed.from = true"
|
||||
>
|
||||
</span>
|
||||
</button>
|
||||
<span class="text-[10px] leading-none text-zinc-500">From prev</span>
|
||||
</button>
|
||||
<button
|
||||
v-if="showFirstFrame && clipId && !failed.first"
|
||||
type="button"
|
||||
class="flex w-12 flex-col items-center gap-0.5"
|
||||
aria-label="First frame of this clip"
|
||||
@click.stop="openPreview(firstFull, 'This clip')"
|
||||
>
|
||||
<span class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900">
|
||||
</div>
|
||||
<div v-if="showFirstFrame && clipId && (hidden || !failed.first)" class="flex w-12 flex-col items-center gap-0.5">
|
||||
<span v-if="hidden" class="relative h-12 w-12 overflow-hidden rounded-lg">
|
||||
<span class="sensitive-glow block h-full w-full" />
|
||||
</span>
|
||||
<button
|
||||
v-else
|
||||
type="button"
|
||||
class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900"
|
||||
aria-label="First frame of this clip"
|
||||
@click.stop="openPreview(firstFull, 'This clip')"
|
||||
>
|
||||
<img
|
||||
:src="firstThumb"
|
||||
alt=""
|
||||
@@ -56,9 +64,9 @@
|
||||
class="h-full w-full object-cover"
|
||||
@error="failed.first = true"
|
||||
>
|
||||
</span>
|
||||
</button>
|
||||
<span class="text-[10px] leading-none text-zinc-500">This clip</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Teleport to="body">
|
||||
@@ -90,12 +98,12 @@ const props = defineProps<{
|
||||
const failed = reactive({ still: false, from: false, first: false })
|
||||
const preview = ref<{ src: string; label: string } | null>(null)
|
||||
|
||||
const stillThumb = computed(() => props.stillId ? `/api/library/stills/${props.stillId}?thumb=1` : '')
|
||||
const stillFull = computed(() => props.stillId ? `/api/library/stills/${props.stillId}` : '')
|
||||
const fromThumb = computed(() => props.fromClipId ? `/api/library/clips/${props.fromClipId}/last-frame?thumb=1` : '')
|
||||
const fromFull = computed(() => props.fromClipId ? `/api/library/clips/${props.fromClipId}/last-frame` : '')
|
||||
const firstThumb = computed(() => props.clipId ? `/api/library/clips/${props.clipId}/first-frame?thumb=1` : '')
|
||||
const firstFull = computed(() => props.clipId ? `/api/library/clips/${props.clipId}/first-frame` : '')
|
||||
const stillThumb = computed(() => !props.hidden && props.stillId ? `/api/library/stills/${props.stillId}?thumb=1` : '')
|
||||
const stillFull = computed(() => !props.hidden && props.stillId ? `/api/library/stills/${props.stillId}` : '')
|
||||
const fromThumb = computed(() => !props.hidden && props.fromClipId ? `/api/library/clips/${props.fromClipId}/last-frame?thumb=1` : '')
|
||||
const fromFull = computed(() => !props.hidden && props.fromClipId ? `/api/library/clips/${props.fromClipId}/last-frame` : '')
|
||||
const firstThumb = computed(() => !props.hidden && props.clipId ? `/api/library/clips/${props.clipId}/first-frame?thumb=1` : '')
|
||||
const firstFull = computed(() => !props.hidden && props.clipId ? `/api/library/clips/${props.clipId}/first-frame` : '')
|
||||
|
||||
watch(
|
||||
() => [props.hidden, props.stillId, props.fromClipId, props.clipId, props.showFirstFrame],
|
||||
@@ -103,11 +111,12 @@ watch(
|
||||
failed.still = false
|
||||
failed.from = false
|
||||
failed.first = false
|
||||
if (props.hidden) closePreview()
|
||||
}
|
||||
)
|
||||
|
||||
function openPreview(src: string, label: string) {
|
||||
if (!src) return
|
||||
if (props.hidden || !src) return
|
||||
preview.value = { src, label }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user