Make keep-prompt snippets clickable and allow renaming the start still.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+95
-5
@@ -88,6 +88,30 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="file || inputStillId" class="mt-2 flex min-w-0 items-center gap-2">
|
||||
<input
|
||||
v-if="renamingInputStill"
|
||||
ref="inputStillRenameEl"
|
||||
v-model="inputStillNameDraft"
|
||||
class="min-w-0 flex-1 rounded-xl border border-amber-300/40 bg-zinc-950 px-3 py-1.5 text-sm outline-none ring-amber-300/40 focus:ring-2"
|
||||
maxlength="80"
|
||||
aria-label="Input still name"
|
||||
@keydown.enter.prevent="saveInputStillName"
|
||||
@keydown.escape.prevent="cancelInputStillRename"
|
||||
@click.stop
|
||||
@blur="saveInputStillName"
|
||||
>
|
||||
<p v-else class="min-w-0 flex-1 truncate text-sm text-zinc-300">{{ inputStillLabel }}</p>
|
||||
<button
|
||||
v-if="!renamingInputStill"
|
||||
type="button"
|
||||
class="shrink-0 text-xs text-amber-300 hover:text-amber-100"
|
||||
@click.stop="startInputStillRename"
|
||||
>
|
||||
Rename
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="studioMode === 'editv2'" class="flex flex-wrap gap-2">
|
||||
<button
|
||||
type="button"
|
||||
@@ -188,16 +212,14 @@
|
||||
|
||||
<div>
|
||||
<div class="mb-2 flex flex-wrap items-center justify-between gap-2">
|
||||
<div class="flex items-center gap-2">
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<label class="text-sm font-medium text-zinc-300">{{ studioMode === 'editv2' && v2Mode === 'generate' ? 'Generate prompt' : studioMode === 'editv2' && v2Mode === 'refine' ? 'Refine prompt' : studioMode === 'edit' || studioMode === 'editv2' ? 'Edit prompt' : 'Motion & scene prompt' }}</label>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<KeepPromptMenu
|
||||
:items="activeKeepPrompts"
|
||||
:heading="keepPromptHeading"
|
||||
align="left"
|
||||
align="right"
|
||||
@insert="insertKeepPrompt"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3">
|
||||
<button
|
||||
v-if="identityPrompting"
|
||||
type="button"
|
||||
@@ -291,6 +313,18 @@
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="activeKeepPrompts.length" class="mt-2 flex flex-wrap gap-1.5">
|
||||
<button
|
||||
v-for="item in activeKeepPrompts"
|
||||
:key="item.id"
|
||||
type="button"
|
||||
class="max-w-full truncate rounded-full border border-white/10 px-2.5 py-1 text-xs text-zinc-300 hover:border-amber-300/40 hover:text-amber-100"
|
||||
:title="item.text"
|
||||
@click="insertKeepPrompt(item)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="studioMode === 'editv2' && v2Mode === 'generate'" class="mt-3 text-xs text-zinc-500">No reference image. Prompt only.</p>
|
||||
<div v-if="studioMode === 'editv2' && v2Mode === 'refine'" class="mt-3 space-y-2">
|
||||
<p class="text-xs text-zinc-500">Prompt only what should change in the painted area.</p>
|
||||
@@ -2361,6 +2395,9 @@ const editLightbox = ref<HTMLElement | null>(null)
|
||||
const editLightboxUrl = ref('')
|
||||
const file = ref<File | null>(null)
|
||||
const inputStillId = ref('')
|
||||
const renamingInputStill = ref(false)
|
||||
const inputStillNameDraft = ref('')
|
||||
const inputStillRenameEl = ref<HTMLInputElement | null>(null)
|
||||
const preview = ref('')
|
||||
const dragging = ref(false)
|
||||
const prompt = ref('')
|
||||
@@ -4591,6 +4628,7 @@ async function copyPrompt(text: string) {
|
||||
}
|
||||
|
||||
function resetImage() {
|
||||
cancelInputStillRename()
|
||||
if (preview.value) URL.revokeObjectURL(preview.value)
|
||||
file.value = null
|
||||
inputStillId.value = ''
|
||||
@@ -4623,7 +4661,59 @@ function stillIdFromLibraryUrl(url: string) {
|
||||
return match ? decodeURIComponent(match[1]) : ''
|
||||
}
|
||||
|
||||
const inputStill = computed(() => stills.value.find(item => item.id === inputStillId.value) || null)
|
||||
|
||||
const inputStillLabel = computed(() => {
|
||||
if (inputStill.value) return stillTitle(inputStill.value)
|
||||
const name = file.value?.name || ''
|
||||
return name.replace(/\.[a-z0-9]+$/i, '') || 'Untitled still'
|
||||
})
|
||||
|
||||
function startInputStillRename() {
|
||||
renamingInputStill.value = true
|
||||
inputStillNameDraft.value = inputStillLabel.value
|
||||
nextTick(() => {
|
||||
inputStillRenameEl.value?.focus()
|
||||
inputStillRenameEl.value?.select()
|
||||
})
|
||||
}
|
||||
|
||||
function cancelInputStillRename() {
|
||||
renamingInputStill.value = false
|
||||
}
|
||||
|
||||
async function saveInputStillName() {
|
||||
if (!renamingInputStill.value) return
|
||||
const name = inputStillNameDraft.value.trim().slice(0, 80)
|
||||
if (!name) {
|
||||
toast('A name is required')
|
||||
return
|
||||
}
|
||||
if (name === inputStillLabel.value) {
|
||||
cancelInputStillRename()
|
||||
return
|
||||
}
|
||||
if (file.value) {
|
||||
const ext = (file.value.name.match(/\.[a-z0-9]+$/i) || ['.png'])[0]
|
||||
file.value = new File([file.value], `${clipFileName(name)}${ext}`, { type: file.value.type || 'image/png' })
|
||||
}
|
||||
const id = inputStillId.value
|
||||
if (id) {
|
||||
try {
|
||||
applyLibrary(await $fetch(`/api/library/stills/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: { name }
|
||||
}))
|
||||
} catch (error: any) {
|
||||
toast(error?.data?.statusMessage || 'Could not rename still')
|
||||
return
|
||||
}
|
||||
}
|
||||
cancelInputStillRename()
|
||||
}
|
||||
|
||||
function readFile(next: File, opts?: { keepThumbnailPref?: boolean; stillId?: string }) {
|
||||
cancelInputStillRename()
|
||||
if (preview.value) URL.revokeObjectURL(preview.value)
|
||||
file.value = next
|
||||
inputStillId.value = opts?.stillId || ''
|
||||
|
||||
Reference in New Issue
Block a user