Re-hide image-edit output on click-away when Hide output preview is on, matching video.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-08-27 10:02:31 -05:00
co-authored by Cursor
parent 860aeafb1e
commit e715c77605
2 changed files with 26 additions and 11 deletions
+20 -6
View File
@@ -316,7 +316,7 @@
<span class="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition peer-checked:translate-x-5" /> <span class="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition peer-checked:translate-x-5" />
</span> </span>
</label> </label>
<p v-if="showPrivacyToggles" class="text-xs text-zinc-500">Output preview hides library thumbs and autoplay. Click the player to reveal; click anywhere else on the page to hide it again. Folder default applies to output preview when you pick a new still.</p> <p v-if="showPrivacyToggles" class="text-xs text-zinc-500">Output preview hides library thumbs and autoplay. Click the player or still to reveal; click anywhere else on the page to hide it again. Folder default applies to output preview when you pick a new still.</p>
</div> </div>
</div> </div>
@@ -1351,6 +1351,7 @@ let lastFrameObjectUrl = ''
let lastFrameGen = 0 let lastFrameGen = 0
const awaitingReveal = ref(false) const awaitingReveal = ref(false)
const concealOutput = ref(false) const concealOutput = ref(false)
const concealEditOutput = ref(false)
const lockedSave = ref(false) const lockedSave = ref(false)
const playerSize = ref({ width: 1344, height: 768 }) const playerSize = ref({ width: 1344, height: 768 })
const toasts = ref<{ id: string; message: string }[]>([]) const toasts = ref<{ id: string; message: string }[]>([])
@@ -2150,6 +2151,7 @@ async function resumeTrack(kind: 'video' | 'edit', id: string, hidden: boolean,
const snap = await $fetch<Record<string, any>>(`/api/generate/${id}`) const snap = await $fetch<Record<string, any>>(`/api/generate/${id}`)
if (kind === 'edit') { if (kind === 'edit') {
editJobId.value = id editJobId.value = id
concealEditOutput.value = hidden
editSettledUi = false editSettledUi = false
} else { } else {
videoJobId.value = id videoJobId.value = id
@@ -2211,12 +2213,16 @@ async function resumeActiveJob() {
} }
function onSitePointerDown(event: PointerEvent) { function onSitePointerDown(event: PointerEvent) {
if (!concealOutput.value || awaitingReveal.value || lockedSave.value || !videoUrl.value) return
const root = outputPanel.value const root = outputPanel.value
const target = event.target as Node | null const target = event.target as Node | null
if (root && target && root.contains(target)) return if (root && target && root.contains(target)) return
if (concealOutput.value && !awaitingReveal.value && !lockedSave.value && videoUrl.value) {
concealAndPause() concealAndPause()
} }
if (concealEditOutput.value && !editAwaitingReveal.value && !editLockedSave.value && editResultUrl.value) {
editAwaitingReveal.value = true
}
}
function concealAndPause() { function concealAndPause() {
awaitingReveal.value = true awaitingReveal.value = true
@@ -2532,6 +2538,7 @@ function openStill(still: LibraryStill) {
studioMode.value = 'edit' studioMode.value = 'edit'
browseFolderId.value = still.folderId browseFolderId.value = still.folderId
editResultUrl.value = `/api/library/stills/${still.id}` editResultUrl.value = `/api/library/stills/${still.id}`
concealEditOutput.value = still.hideInput === true
editAwaitingReveal.value = still.hideInput === true editAwaitingReveal.value = still.hideInput === true
editLockedSave.value = false editLockedSave.value = false
editDownloadName.value = clipFileName(stillTitle(still)) editDownloadName.value = clipFileName(stillTitle(still))
@@ -2567,6 +2574,7 @@ async function removeStill(still: LibraryStill, family = false) {
if ([...ids].some(id => editResultUrl.value.includes(id))) { if ([...ids].some(id => editResultUrl.value.includes(id))) {
editResultUrl.value = '' editResultUrl.value = ''
editAwaitingReveal.value = false editAwaitingReveal.value = false
concealEditOutput.value = false
editLockedSave.value = false editLockedSave.value = false
} }
await loadLibrary() await loadLibrary()
@@ -2780,6 +2788,7 @@ async function editImage() {
editProgress.value = 2 editProgress.value = 2
editResultUrl.value = '' editResultUrl.value = ''
editAwaitingReveal.value = false editAwaitingReveal.value = false
concealEditOutput.value = hideThumbnail.value
editLockedSave.value = false editLockedSave.value = false
editStatusMessage.value = 'Checking Beast ComfyUI...' editStatusMessage.value = 'Checking Beast ComfyUI...'
editMaxStep.value = editSteps.value editMaxStep.value = editSteps.value
@@ -2804,6 +2813,7 @@ async function editImage() {
body.append('seed', seedInput.value || 'random') body.append('seed', seedInput.value || 'random')
body.append('folderId', folderId.value) body.append('folderId', folderId.value)
body.append('hideInput', String(showPrivacyToggles.value && hideInputPreview.value)) body.append('hideInput', String(showPrivacyToggles.value && hideInputPreview.value))
body.append('hideThumbnail', String(showPrivacyToggles.value && hideThumbnail.value))
body.append('name', clipName.value.trim()) body.append('name', clipName.value.trim())
if (extraPasses.length) body.append('passes', JSON.stringify(extraPasses)) if (extraPasses.length) body.append('passes', JSON.stringify(extraPasses))
editDownloadName.value = clipFileName(clipName.value.trim() || prompt.value.split(/[.!?\n]/)[0] || 'aigen-edit') editDownloadName.value = clipFileName(clipName.value.trim() || prompt.value.split(/[.!?\n]/)[0] || 'aigen-edit')
@@ -2813,8 +2823,8 @@ async function editImage() {
}) })
editJobId.value = started.jobId editJobId.value = started.jobId
editMaxStep.value = started.steps editMaxStep.value = started.steps
persistActiveJob('edit', started.jobId, started.hideThumbnail === true || hideInputPreview.value, started.folderLocked === true) persistActiveJob('edit', started.jobId, started.hideThumbnail === true || hideThumbnail.value, started.folderLocked === true)
listen('edit', started.jobId, started.hideThumbnail === true || hideInputPreview.value, started.folderLocked === true) listen('edit', started.jobId, started.hideThumbnail === true || hideThumbnail.value, started.folderLocked === true)
void pollComfyHealth() void pollComfyHealth()
} catch (error: any) { } catch (error: any) {
editSettledUi = true editSettledUi = true
@@ -2971,7 +2981,10 @@ function applyEditEvent(payload: Record<string, any>, hidden: boolean, folderLoc
if (payload.stillId && !locked) { if (payload.stillId && !locked) {
editResultUrl.value = `/api/library/stills/${payload.stillId}` editResultUrl.value = `/api/library/stills/${payload.stillId}`
editLockedSave.value = false editLockedSave.value = false
if (payload.hideThumbnail || hidden) editAwaitingReveal.value = payload.type !== 'checkpoint' if (payload.hideThumbnail || hidden) {
concealEditOutput.value = true
if (payload.type !== 'checkpoint') editAwaitingReveal.value = true
}
} }
if (payload.type === 'checkpoint' && payload.stillId) { if (payload.type === 'checkpoint' && payload.stillId) {
@@ -3010,7 +3023,8 @@ function applyEditEvent(payload: Record<string, any>, hidden: boolean, folderLoc
editStatusMessage.value = 'Saved to the locked folder. Unlock it to view.' editStatusMessage.value = 'Saved to the locked folder. Unlock it to view.'
} else { } else {
editResultUrl.value = `/api/library/stills/${payload.stillId}` editResultUrl.value = `/api/library/stills/${payload.stillId}`
editAwaitingReveal.value = Boolean(payload.hideThumbnail || hidden) concealEditOutput.value = Boolean(payload.hideThumbnail || hidden)
editAwaitingReveal.value = concealEditOutput.value
editLockedSave.value = false editLockedSave.value = false
editStatusMessage.value = total > 1 ? 'Edit chain finished' : 'Edit finished' editStatusMessage.value = total > 1 ? 'Edit chain finished' : 'Edit finished'
editCompletedChainStep.value = total editCompletedChainStep.value = total
+5 -4
View File
@@ -75,6 +75,7 @@ export default defineEventHandler(async (event) => {
const destFolder = library.folders.find(folder => folder.id === folderId) const destFolder = library.folders.find(folder => folder.id === folderId)
const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked) const folderLocked = Boolean(destFolder?.protected && !destFolder.unlocked)
const hideInput = fields.hideInput === 'true' const hideInput = fields.hideInput === 'true'
const hideThumbnail = fields.hideThumbnail === 'true'
const steps = parseSteps(fields.steps) const steps = parseSteps(fields.steps)
const cfg = parseCfg(fields.cfg) const cfg = parseCfg(fields.cfg)
const seed = fields.seed && fields.seed !== 'random' const seed = fields.seed && fields.seed !== 'random'
@@ -107,11 +108,11 @@ export default defineEventHandler(async (event) => {
const job = createJob() const job = createJob()
job.kind = 'edit' job.kind = 'edit'
job.maxStep = steps job.maxStep = steps
job.hideThumbnail = hideInput job.hideThumbnail = hideThumbnail
job.library = { job.library = {
ownerKey, ownerKey,
folderId, folderId,
hideThumbnail: hideInput, hideThumbnail,
hideInput, hideInput,
folderLocked, folderLocked,
name: (fields.name || '').trim().slice(0, 80), name: (fields.name || '').trim().slice(0, 80),
@@ -161,7 +162,7 @@ export default defineEventHandler(async (event) => {
jobId: job.id, jobId: job.id,
seed, seed,
steps, steps,
hideThumbnail: hideInput, hideThumbnail,
folderLocked, folderLocked,
dual: Boolean(reference), dual: Boolean(reference),
chainTotal chainTotal
@@ -294,7 +295,7 @@ async function runEdit(
data: buffer, data: buffer,
width: size?.width || 0, width: size?.width || 0,
height: size?.height || 0, height: size?.height || 0,
hideInput: job.hideThumbnail === true || library.hideInput === true, hideInput: job.hideThumbnail === true,
role: 'output', role: 'output',
name: passName || undefined, name: passName || undefined,
prompt, prompt,