Persist the bench draft and hide input thumbs only.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
:aria-label="asset ? 'Replace photo' : 'Choose a photo'"
|
||||
@click="$emit('pick')"
|
||||
>
|
||||
<span v-if="asset && hidden" class="p-2 text-center text-[var(--type-sm)] text-[var(--muted)]">Still loaded · preview hidden</span>
|
||||
<span v-if="asset && hidden" class="p-2 text-center text-[var(--type-sm)] text-[var(--muted)]">Photo loaded</span>
|
||||
<img v-else-if="asset" :src="thumbSrc" alt="">
|
||||
<span v-else class="inline-flex flex-col items-center gap-1 px-2 text-center">
|
||||
<span>Choose a photo</span>
|
||||
|
||||
+253
-45
@@ -89,24 +89,13 @@
|
||||
>{{ hideInputs ? 'Show inputs' : 'Hide inputs' }}</button>
|
||||
</div>
|
||||
<p v-if="photosPlanState.handoffReadonly" class="text-[var(--type-sm)] text-[var(--muted)]">Continues from last frame</p>
|
||||
<template v-else-if="hideInputs">
|
||||
<p class="photos-collapsed">
|
||||
<span>{{ photoFilledCount }} photo{{ photoFilledCount===1 ? '' : 's' }}</span>
|
||||
<button
|
||||
v-if="form.photos.length < photosPlanState.max"
|
||||
type="button"
|
||||
class="photos-add-link"
|
||||
@click="hideInputs=false; addPhoto()"
|
||||
>+ Add photo</button>
|
||||
</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p v-if="!form.photos.length && photosPlanState.emptyHint" class="text-[var(--type-sm)] text-[var(--muted)]">{{ photosPlanState.emptyHint }}</p>
|
||||
<Studio2AssetSlot
|
||||
v-for="(card, index) in form.photos"
|
||||
:key="'photo-'+index+'-'+card.stillId"
|
||||
:asset="stillById(card.stillId)"
|
||||
:hidden="false"
|
||||
:hidden="hideInputs"
|
||||
:role="card.role"
|
||||
:role-options="photoRoleOptions"
|
||||
@pick="picker='photo:'+index"
|
||||
@@ -171,6 +160,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Studio2StyleChips v-if="!video && form.mode!=='music'" v-model="form.imageStyles" class="mt-1" />
|
||||
<Studio2PromptControls v-if="video" v-model="form.promptSections" class="mt-2" />
|
||||
|
||||
<div v-if="['flux','krea','qwen21'].includes(form.engine)">
|
||||
<span class="field-label">LoRA</span>
|
||||
<LoraSelect
|
||||
@@ -253,9 +245,12 @@
|
||||
class="stage-actions"
|
||||
aria-label="Selected still actions"
|
||||
>
|
||||
<button type="button" @click.stop="applyUseAsSource">Use as photo</button>
|
||||
<button type="button" @click.stop="applyUseImage">Use image</button>
|
||||
<button type="button" @click.stop="applyUsePrompt">Use prompt</button>
|
||||
<button type="button" @click.stop="copySelectedPrompt">Copy prompt</button>
|
||||
<button type="button" @click.stop="loadSelectedJob">Load</button>
|
||||
<button type="button" @click.stop="copySelectedRawPrompt">Copy raw prompt</button>
|
||||
<button type="button" @click.stop="loadInputUsed">Load input</button>
|
||||
<button type="button" @click.stop="loadInputRaw">Load input raw</button>
|
||||
<button type="button" class="stage-action-danger" @click.stop="deleteOutput">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -318,9 +313,12 @@
|
||||
:preview-hidden="!eyeOpen"
|
||||
@close="libraryOpen=false"
|
||||
@select="selectOutput"
|
||||
@use-as-photo="onLibraryUseAsPhoto"
|
||||
@use-image="onLibraryUseImage"
|
||||
@use-prompt="onLibraryUsePrompt"
|
||||
@copy-prompt="onLibraryCopyPrompt"
|
||||
@load="onLibraryLoad"
|
||||
@copy-raw-prompt="onLibraryCopyRawPrompt"
|
||||
@load-input="onLibraryLoadInput"
|
||||
@load-input-raw="onLibraryLoadInputRaw"
|
||||
@delete="onLibraryDelete"
|
||||
@toggle-preview="toggleReveal()"
|
||||
/>
|
||||
@@ -451,6 +449,8 @@ import {LOAD_GENERATION_PAYLOAD_KEY} from '~/utils/queuedJob'
|
||||
const NEG_STORAGE_KEY='studio2-negative-chips'
|
||||
const ENHANCE_STORAGE_KEY='studio2-qwen21-enhance-prompt'
|
||||
const TURBO_STORAGE_KEY='studio2-qwen21-turbo'
|
||||
const BENCH_DRAFT_KEY='aigen:bench-draft'
|
||||
let draftTimer:ReturnType<typeof setTimeout>|null=null
|
||||
function readStoredNegatives(){
|
||||
if(!import.meta.client)return [...defaultNegatives]
|
||||
try{
|
||||
@@ -480,6 +480,84 @@ function writeStoredTurbo(on:boolean){
|
||||
if(!import.meta.client)return
|
||||
try{localStorage.setItem(TURBO_STORAGE_KEY,on?'1':'0')}catch{/* ignore */}
|
||||
}
|
||||
function benchDraftPayload(){
|
||||
return {
|
||||
v:1,
|
||||
mode:form.mode,
|
||||
engine:form.engine,
|
||||
folderId:form.folderId,
|
||||
enhancePrompt:!!form.enhancePrompt,
|
||||
turbo:!!form.turbo,
|
||||
lockFace:!!form.lockFace,
|
||||
lockOutfit:!!form.lockOutfit,
|
||||
promptSections:structuredClone(form.promptSections||{}),
|
||||
photos:(form.photos||[]).filter((p:any)=>p?.stillId).map((p:any)=>({stillId:p.stillId,role:p.role})),
|
||||
imageStyles:structuredClone(form.imageStyles||{positive:[],negative:[]}),
|
||||
settings:{
|
||||
aspect:form.settings?.aspect||'auto',
|
||||
seed:form.settings?.seed ?? null,
|
||||
seedMode:form.settings?.seedMode||'random',
|
||||
steps:form.settings?.steps,
|
||||
cfg:form.settings?.cfg,
|
||||
duration:form.settings?.duration,
|
||||
fps:form.settings?.fps,
|
||||
loraStack:structuredClone(form.settings?.loraStack||[])
|
||||
},
|
||||
eyeOpen:!!eyeOpen.value,
|
||||
hideInputs:!!hideInputs.value,
|
||||
music:structuredClone({tags:music.tags,lyrics:music.lyrics,duration:music.duration,seed:music.seed,name:music.name})
|
||||
}
|
||||
}
|
||||
function saveBenchDraft(immediate=false){
|
||||
if(!import.meta.client)return
|
||||
const write=()=>{
|
||||
try{localStorage.setItem(BENCH_DRAFT_KEY,JSON.stringify(benchDraftPayload()))}catch{/* ignore */}
|
||||
}
|
||||
if(draftTimer)clearTimeout(draftTimer)
|
||||
if(immediate){write();return}
|
||||
draftTimer=setTimeout(write,400)
|
||||
}
|
||||
function restoreBenchDraft(){
|
||||
if(!import.meta.client)return
|
||||
let raw=''
|
||||
try{raw=localStorage.getItem(BENCH_DRAFT_KEY)||''}catch{return}
|
||||
if(!raw)return
|
||||
let draft:any
|
||||
try{draft=JSON.parse(raw)}catch{return}
|
||||
if(!draft||draft.v!==1)return
|
||||
if(draft.mode)form.mode=draft.mode
|
||||
if(draft.engine)form.engine=draft.engine
|
||||
if(draft.folderId)form.folderId=draft.folderId
|
||||
if(draft.enhancePrompt!=null)form.enhancePrompt=!!draft.enhancePrompt
|
||||
if(draft.turbo!=null)form.turbo=!!draft.turbo
|
||||
if(draft.lockFace!=null)form.lockFace=!!draft.lockFace
|
||||
if(draft.lockOutfit!=null)form.lockOutfit=!!draft.lockOutfit
|
||||
if(draft.promptSections)form.promptSections=sectionsFrom(draft.promptSections)
|
||||
if(Array.isArray(draft.photos))form.photos=draft.photos.filter((p:any)=>p?.stillId).map((p:any)=>({stillId:String(p.stillId),role:String(p.role||'change')}))
|
||||
if(draft.imageStyles)form.imageStyles={positive:draft.imageStyles.positive||[],negative:draft.imageStyles.negative||[]}
|
||||
if(draft.settings){
|
||||
Object.assign(form.settings,{
|
||||
aspect:draft.settings.aspect||form.settings.aspect,
|
||||
seed:draft.settings.seed ?? form.settings.seed,
|
||||
seedMode:draft.settings.seedMode||form.settings.seedMode,
|
||||
steps:draft.settings.steps ?? form.settings.steps,
|
||||
cfg:draft.settings.cfg ?? form.settings.cfg,
|
||||
duration:draft.settings.duration ?? form.settings.duration,
|
||||
fps:draft.settings.fps ?? form.settings.fps,
|
||||
loraStack:Array.isArray(draft.settings.loraStack)?draft.settings.loraStack:form.settings.loraStack
|
||||
})
|
||||
}
|
||||
if(draft.eyeOpen!=null)eyeOpen.value=!!draft.eyeOpen
|
||||
if(draft.hideInputs!=null)hideInputs.value=!!draft.hideInputs
|
||||
if(draft.music){
|
||||
music.tags=String(draft.music.tags||music.tags)
|
||||
music.lyrics=String(draft.music.lyrics||music.lyrics)
|
||||
if(draft.music.duration!=null)music.duration=Number(draft.music.duration)||music.duration
|
||||
if(draft.music.seed!=null)music.seed=String(draft.music.seed)
|
||||
if(draft.music.name!=null)music.name=String(draft.music.name)
|
||||
}
|
||||
syncPhotosBindings()
|
||||
}
|
||||
|
||||
const xaigen=isXaigenStudio(useRuntimeConfig().public)
|
||||
const instanceName=String(useRuntimeConfig().public.instanceName || 'AIGen')
|
||||
@@ -560,13 +638,19 @@ watch(()=>[form.mode,form.engine],([mode,engine])=>{
|
||||
form.lockOutfit=false
|
||||
}
|
||||
const plan=photosPlan({mode,engine})
|
||||
if(!plan.show){form.photos=[];form.imageAId='';form.imageBId='';if(engine==='qwen21')form.identityStillId='';return}
|
||||
if(!plan.show){
|
||||
if(engine==='qwen21')form.identityStillId=''
|
||||
// Keep photos + prompt; section may hide for this mode.
|
||||
saveBenchDraft(true)
|
||||
return
|
||||
}
|
||||
const allowed=new Set(plan.roles)
|
||||
form.photos=form.photos
|
||||
form.photos=(form.photos||[])
|
||||
.filter((p:any)=>p?.stillId)
|
||||
.slice(0,plan.max)
|
||||
.map((p:any)=>({stillId:p.stillId,role:allowed.has(p.role)?p.role:plan.defaultRole}))
|
||||
syncPhotosBindings()
|
||||
saveBenchDraft(true)
|
||||
})
|
||||
watch(()=>form.folderId,id=>{selected.value=null;form.imageAId='';form.imageBId='';form.photos=[];form.startClipId='';loadRevealed(id);if(import.meta.client && form.engine!=='qwen21')form.identityStillId=localStorage.getItem(`studio2-hero:${id}`)||''},{flush:'sync'})
|
||||
watch(()=>form.identityStillId,id=>{if(import.meta.client&&form.folderId&&form.engine!=='qwen21')localStorage.setItem(`studio2-hero:${form.folderId}`,id)})
|
||||
@@ -718,17 +802,20 @@ function addPhoto(){
|
||||
if(form.photos.length>=plan.max)return
|
||||
form.photos.push({stillId:'',role:plan.defaultRole||'change'})
|
||||
picker.value='photo:'+(form.photos.length-1)
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function removePhoto(index:number){
|
||||
if(!Number.isInteger(index)||index<0||index>=form.photos.length)return
|
||||
form.photos.splice(index,1)
|
||||
// Explicit empty photos array clears imageAId / imageBId / identityStillId.
|
||||
syncPhotosBindings()
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function setPhotoRole(index:number,role:string){
|
||||
if(!form.photos[index])return
|
||||
form.photos[index].role=role
|
||||
syncPhotosBindings()
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function setPhotoStill(index:number,stillId:string){
|
||||
if(!Number.isInteger(index)||!form.photos[index])return
|
||||
@@ -738,6 +825,7 @@ function setPhotoStill(index:number,stillId:string){
|
||||
form.photos[index].stillId=stillId
|
||||
}
|
||||
syncPhotosBindings()
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function discardEmptyPhotoDraft(index:number){
|
||||
if(!Number.isInteger(index)||!form.photos[index])return
|
||||
@@ -765,33 +853,118 @@ function mentionPhoto(index:number){
|
||||
promptCaret.value={start:next.selectionStart,end:next.selectionEnd}
|
||||
})
|
||||
}
|
||||
function applyUseAsSource(){
|
||||
if(!selected.value||selected.value.kind==='track')return
|
||||
function usedPromptOf(item:any){
|
||||
return String(
|
||||
item?.studio2?.prompt
|
||||
|| item?.prompt
|
||||
|| item?.studio2?.compiledPrompt
|
||||
|| item?.studio2?.promptSections?.action
|
||||
|| ''
|
||||
).trim()
|
||||
}
|
||||
function rawPromptOf(item:any){
|
||||
return String(item?.promptRaw || item?.studio2?.promptRaw || '').trim()
|
||||
}
|
||||
function sourceStillIdsOf(item:any){
|
||||
const meta=item?.studio2 || {}
|
||||
const ids:string[]=[]
|
||||
const push=(id:any)=>{const v=String(id||'').trim();if(v && !ids.includes(v))ids.push(v)}
|
||||
push(meta.sourceStillId)
|
||||
push(meta.imageAId)
|
||||
for(const card of meta.photos||[]) push(card?.stillId)
|
||||
if(meta.imageBId) push(meta.imageBId)
|
||||
return ids.filter(id=>stillById(id))
|
||||
}
|
||||
function useImageRole(){
|
||||
const plan=photosPlanState.value
|
||||
if(!plan.show||plan.handoffReadonly){
|
||||
Object.assign(form,useAsSource(form,selected.value))
|
||||
uploadMessage.value=`Using ${assetLabel(selected.value)}.`
|
||||
const filled=(form.photos||[]).filter((p:any)=>p?.stillId)
|
||||
if((form.mode==='edit' || video.value) && !filled.length && plan.roles.includes('change')) return 'change'
|
||||
if(plan.roles.includes('extra')) return 'extra'
|
||||
if(plan.roles.includes('outfit')) return 'outfit'
|
||||
return plan.defaultRole || 'change'
|
||||
}
|
||||
function applyUseImage(item?:any){
|
||||
const asset=item || selected.value
|
||||
if(!asset||asset.kind==='track')return
|
||||
const plan=photosPlanState.value
|
||||
const role=useImageRole()
|
||||
if(!plan.show){
|
||||
form.photos=[{stillId:asset.id,role}]
|
||||
syncPhotosBindings()
|
||||
uploadMessage.value=`Added ${assetLabel(asset)} to Photos.`
|
||||
saveBenchDraft(true)
|
||||
return
|
||||
}
|
||||
if(form.photos.length>=plan.max){
|
||||
form.photos[form.photos.length-1]={stillId:selected.value.id,role:plan.defaultRole||form.photos.at(-1)?.role||'change'}
|
||||
form.photos[form.photos.length-1]={stillId:asset.id,role}
|
||||
}else{
|
||||
form.photos.push({stillId:selected.value.id,role:plan.defaultRole||'change'})
|
||||
form.photos.push({stillId:asset.id,role})
|
||||
}
|
||||
syncPhotosBindings()
|
||||
uploadMessage.value=`Added ${assetLabel(selected.value)} to Photos.`
|
||||
uploadMessage.value=`Added ${assetLabel(asset)} to Photos.`
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
async function copySelectedPrompt(){
|
||||
const text=selected.value?.studio2?.prompt
|
||||
|| selected.value?.studio2?.compiledPrompt
|
||||
|| selected.value?.prompt
|
||||
|| selected.value?.studio2?.promptSections?.action
|
||||
|| ''
|
||||
function applyUsePrompt(item?:any){
|
||||
const asset=item || selected.value
|
||||
if(!asset)return
|
||||
const text=usedPromptOf(asset)
|
||||
form.promptSections.action=text
|
||||
uploadMessage.value=text?'Prompt set from this item.':'No Used prompt on this item.'
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
async function copySelectedPrompt(item?:any){
|
||||
const asset=item || selected.value
|
||||
const text=usedPromptOf(asset)
|
||||
try{
|
||||
if(import.meta.client && navigator.clipboard)await navigator.clipboard.writeText(String(text||''))
|
||||
uploadMessage.value=text?'Prompt copied.':'No prompt on this item.'
|
||||
}catch{error.value='Could not copy prompt.'}
|
||||
}
|
||||
async function copySelectedRawPrompt(item?:any){
|
||||
const asset=item || selected.value
|
||||
const raw=rawPromptOf(asset)
|
||||
const used=usedPromptOf(asset)
|
||||
const text=raw || used
|
||||
try{
|
||||
if(import.meta.client && navigator.clipboard)await navigator.clipboard.writeText(String(text||''))
|
||||
uploadMessage.value=raw?'Raw prompt copied.':(used?'Used prompt copied (no Typed on this item).':'No prompt on this item.')
|
||||
}catch{error.value='Could not copy prompt.'}
|
||||
}
|
||||
function loadInputPhotos(ids:string[]){
|
||||
if(!ids.length)return
|
||||
const plan=photosPlanState.value
|
||||
const roles=plan.roles?.length?plan.roles:['change']
|
||||
form.photos=ids.slice(0,plan.max || ids.length).map((id,i)=>({
|
||||
stillId:id,
|
||||
role:i===0 && roles.includes('change')?'change':(roles.includes('extra')?'extra':roles[Math.min(i,roles.length-1)]||'change')
|
||||
}))
|
||||
syncPhotosBindings()
|
||||
}
|
||||
function loadInputUsed(item?:any){
|
||||
const asset=item || selected.value
|
||||
if(!asset)return
|
||||
const ids=sourceStillIdsOf(asset)
|
||||
const text=usedPromptOf(asset)
|
||||
if(ids.length) loadInputPhotos(ids)
|
||||
if(text) form.promptSections.action=text
|
||||
uploadMessage.value=ids.length
|
||||
?(text?'Input photos and Used prompt loaded.':'Input photos loaded.')
|
||||
:(text?'Used prompt loaded (no source still on this item).':'Nothing to load from this item.')
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function loadInputRaw(item?:any){
|
||||
const asset=item || selected.value
|
||||
if(!asset)return
|
||||
const ids=sourceStillIdsOf(asset)
|
||||
const raw=rawPromptOf(asset)
|
||||
const used=usedPromptOf(asset)
|
||||
if(ids.length) loadInputPhotos(ids)
|
||||
form.promptSections.action=raw || used
|
||||
uploadMessage.value=ids.length
|
||||
?(raw?'Input photos and Typed prompt loaded.':(used?'Input photos loaded; Typed missing so Used was applied.':'Input photos loaded.'))
|
||||
:(raw?'Typed prompt loaded (no source still).':(used?'Used prompt loaded (no Typed / source still).':'Nothing to load from this item.'))
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function stillIdSet(){return new Set(stills.value.map((s:any)=>s.id))}
|
||||
function clipIdSet(){return new Set(clips.value.map((c:any)=>c.id))}
|
||||
function applyHydratedJob(saved:any,output?:any){
|
||||
@@ -806,6 +979,7 @@ function applyHydratedJob(saved:any,output?:any){
|
||||
error.value=missing||''
|
||||
if(missing)uploadMessage.value=missing
|
||||
else uploadMessage.value='Job loaded into the bench.'
|
||||
saveBenchDraft(true)
|
||||
}
|
||||
function loadSelectedJob(){
|
||||
if(!selected.value)return
|
||||
@@ -892,17 +1066,29 @@ function stepFamily(delta:number){
|
||||
const next=list[(from + delta + list.length) % list.length]
|
||||
if(next) selectOutput(next)
|
||||
}
|
||||
function onLibraryUseAsPhoto(item:any){
|
||||
function onLibraryUseImage(item:any){
|
||||
if(item)selectOutput(item)
|
||||
applyUseAsSource()
|
||||
applyUseImage(item)
|
||||
}
|
||||
function onLibraryUsePrompt(item:any){
|
||||
if(item)selectOutput(item)
|
||||
applyUsePrompt(item)
|
||||
}
|
||||
function onLibraryCopyPrompt(item:any){
|
||||
if(item)selectOutput(item)
|
||||
void copySelectedPrompt()
|
||||
void copySelectedPrompt(item)
|
||||
}
|
||||
function onLibraryLoad(item:any){
|
||||
function onLibraryCopyRawPrompt(item:any){
|
||||
if(item)selectOutput(item)
|
||||
loadSelectedJob()
|
||||
void copySelectedRawPrompt(item)
|
||||
}
|
||||
function onLibraryLoadInput(item:any){
|
||||
if(item)selectOutput(item)
|
||||
loadInputUsed(item)
|
||||
}
|
||||
function onLibraryLoadInputRaw(item:any){
|
||||
if(item)selectOutput(item)
|
||||
loadInputRaw(item)
|
||||
}
|
||||
function onLibraryDelete(item:any){
|
||||
if(item)selectOutput(item)
|
||||
@@ -1080,14 +1266,23 @@ async function refresh(){
|
||||
selected.value=next
|
||||
}
|
||||
|
||||
watch(()=>form.folderId,id=>{selected.value=null;form.imageAId='';form.imageBId='';form.photos=[];form.startClipId='';loadRevealed(id);if(import.meta.client && form.engine!=='qwen21')form.identityStillId=localStorage.getItem(`studio2-hero:${id}`)||''},{flush:'sync'})
|
||||
watch(()=>form.identityStillId,id=>{if(import.meta.client&&form.folderId&&form.engine!=='qwen21')localStorage.setItem(`studio2-hero:${form.folderId}`,id)})
|
||||
watch(()=>[
|
||||
form.mode,form.engine,form.folderId,form.enhancePrompt,form.turbo,form.lockFace,form.lockOutfit,
|
||||
form.promptSections,form.photos,form.imageStyles,form.settings,
|
||||
eyeOpen.value,hideInputs.value,
|
||||
music.tags,music.lyrics,music.duration,music.seed,music.name
|
||||
],()=>saveBenchDraft(),{deep:true})
|
||||
let timer:ReturnType<typeof setTimeout>,clock:ReturnType<typeof setInterval>,disposed=false
|
||||
onMounted(async()=>{
|
||||
let storage;try{storage=localStorage}catch{}
|
||||
loraMemory=createLoraMemory(xaigen,storage);loraMemory.sync(form);form.settings.seed=randomSeed()
|
||||
clock=setInterval(()=>{now.value=Date.now()},1000);void loadLoras(true)
|
||||
library.value=await $fetch('/api/studio-2/library');form.folderId=library.value.folders[0]?.id||'';loadRevealed(form.folderId)
|
||||
library.value=await $fetch('/api/studio-2/library')
|
||||
restoreBenchDraft()
|
||||
if(!form.folderId)form.folderId=library.value.folders[0]?.id||''
|
||||
// Folder watch may have cleared photos when folderId was assigned — re-apply draft photos/prompt.
|
||||
restoreBenchDraft()
|
||||
loadRevealed(form.folderId)
|
||||
await applyIncomingGenerationLoad()
|
||||
const id=String(route.query.still||route.query.clip||route.query.track||'')
|
||||
const asset=[...library.value.stills,...library.value.clips,...(library.value.tracks||[])].find((a:any)=>a.id===id)
|
||||
@@ -1098,7 +1293,11 @@ onMounted(async()=>{
|
||||
})
|
||||
onBeforeUnmount(()=>{
|
||||
disposed=true;clearTimeout(timer);clearInterval(clock)
|
||||
if(import.meta.client)window.removeEventListener('keydown',onStageHotkey)
|
||||
if(draftTimer)clearTimeout(draftTimer)
|
||||
if(import.meta.client){
|
||||
saveBenchDraft(true)
|
||||
window.removeEventListener('keydown',onStageHotkey)
|
||||
}
|
||||
})
|
||||
|
||||
function randomizeSeed(){form.settings.seedMode='random';form.settings.seed=randomSeed()}
|
||||
@@ -1128,7 +1327,7 @@ const mobileCtx=computed(()=>({
|
||||
photoFilledCount:photoFilledCount.value,
|
||||
openLibrary:()=>{libraryOpen.value=true},
|
||||
closeLibrary:()=>{libraryOpen.value=false},
|
||||
toggleHideInputs:()=>{hideInputs.value=!hideInputs.value},
|
||||
toggleHideInputs:()=>{hideInputs.value=!hideInputs.value;saveBenchDraft(true)},
|
||||
showInputsAndAddPhoto:()=>{hideInputs.value=false;addPhoto()},
|
||||
sourceSlot:sourceSlot.value,
|
||||
video:video.value,
|
||||
@@ -1168,12 +1367,21 @@ const mobileCtx=computed(()=>({
|
||||
removePhoto,
|
||||
setPhotoRole,
|
||||
mentionPhoto,
|
||||
applyUseAsSource,
|
||||
applyUseAsSource:applyUseImage,
|
||||
applyUseImage,
|
||||
applyUsePrompt,
|
||||
copySelectedPrompt,
|
||||
copySelectedRawPrompt,
|
||||
loadInputUsed,
|
||||
loadInputRaw,
|
||||
loadSelectedJob,
|
||||
onLibraryUseAsPhoto,
|
||||
onLibraryUseAsPhoto:onLibraryUseImage,
|
||||
onLibraryUseImage,
|
||||
onLibraryUsePrompt,
|
||||
onLibraryCopyPrompt,
|
||||
onLibraryLoad,
|
||||
onLibraryCopyRawPrompt,
|
||||
onLibraryLoadInput,
|
||||
onLibraryLoadInputRaw,
|
||||
onLibraryDelete,
|
||||
randomizeSeed,
|
||||
setPicker,
|
||||
|
||||
Reference in New Issue
Block a user