Show family branches in plain English with Start as the card head.
Collapsed cards use parts/forks/longest instead of pN codes; expanded Studio and Library trees get fork headers and from/branch labels. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+33
-34
@@ -1725,7 +1725,7 @@
|
||||
/>
|
||||
</div>
|
||||
<p class="truncate text-xs text-zinc-500">{{ clipMetaLine(entry.group.head) }}</p>
|
||||
<p v-if="familyBranchHint(entry.group.parts)" class="mt-1 truncate text-[11px] text-amber-200/80">{{ familyBranchHint(entry.group.parts) }}</p>
|
||||
<p v-if="familyBranchSummary(entry.group.parts)" class="mt-1 truncate text-[11px] text-amber-200/80">{{ familyBranchSummary(entry.group.parts) }}</p>
|
||||
<p v-if="entry.group.head.globalLocks" class="mt-1 text-[11px] text-zinc-600">Global locks saved with this collection.</p>
|
||||
<PermanenceRefStrip
|
||||
v-if="entry.group.parts.length === 1 && !entry.group.head.hideThumbnail"
|
||||
@@ -1782,19 +1782,26 @@
|
||||
</div>
|
||||
</div>
|
||||
<ul v-if="expandedFamilies[entry.group.key] && entry.group.parts.length > 1" class="mt-3 space-y-2 border-t border-white/5 pt-3">
|
||||
<li
|
||||
v-for="node in treeOrderedParts(entry.group.parts)"
|
||||
:key="node.clip.id"
|
||||
class="flex cursor-pointer flex-wrap items-start gap-3 rounded-xl border p-2"
|
||||
:class="node.clip.id === reviewingClipId
|
||||
? 'border-amber-300/80 bg-amber-400/15 ring-1 ring-amber-300/60'
|
||||
: extendOpen && node.clip.id === extendClipId
|
||||
? 'border-amber-300/40 bg-amber-400/5'
|
||||
: 'border-white/5 bg-black/20'"
|
||||
:style="node.depth ? { marginLeft: `${Math.min(node.depth, 6) * 0.85}rem` } : undefined"
|
||||
:aria-current="node.clip.id === reviewingClipId ? 'true' : undefined"
|
||||
@click="onLibraryClipPartClick(node.clip, $event)"
|
||||
>
|
||||
<template v-for="node in familyDisplayNodes(entry.group.parts)" :key="node.key">
|
||||
<li
|
||||
v-if="node.type === 'fork'"
|
||||
class="rounded-lg px-2 py-1 text-[11px] font-medium uppercase tracking-wide text-amber-200/70"
|
||||
:style="node.depth ? { marginLeft: `${Math.min(node.depth, 6) * 0.85}rem` } : undefined"
|
||||
>
|
||||
{{ node.label }}
|
||||
</li>
|
||||
<li
|
||||
v-else
|
||||
class="flex cursor-pointer flex-wrap items-start gap-3 rounded-xl border p-2"
|
||||
:class="node.clip.id === reviewingClipId
|
||||
? 'border-amber-300/80 bg-amber-400/15 ring-1 ring-amber-300/60'
|
||||
: extendOpen && node.clip.id === extendClipId
|
||||
? 'border-amber-300/40 bg-amber-400/5'
|
||||
: 'border-white/5 bg-black/20'"
|
||||
:style="node.depth ? { marginLeft: `${Math.min(node.depth, 6) * 0.85}rem` } : undefined"
|
||||
:aria-current="node.clip.id === reviewingClipId ? 'true' : undefined"
|
||||
@click="onLibraryClipPartClick(node.clip, $event)"
|
||||
>
|
||||
<ClipFrameThumbs
|
||||
:hidden="node.clip.hideThumbnail"
|
||||
:revealed="!!stitchReveal[node.clip.id]"
|
||||
@@ -1817,7 +1824,8 @@
|
||||
>
|
||||
<p v-else class="min-w-0 flex-1 truncate text-sm font-medium">
|
||||
{{ node.clip.name || node.clip.prompt }}
|
||||
<span v-if="clipBranchFromLabel(node.clip, entry.group.parts)" class="ml-1.5 text-[11px] font-normal text-amber-200/80">{{ clipBranchFromLabel(node.clip, entry.group.parts) }}</span>
|
||||
<span v-if="node.fromLabel" class="ml-1.5 text-[11px] font-normal text-amber-200/80">{{ node.fromLabel }}</span>
|
||||
<span v-if="node.branchLabel" class="ml-1.5 text-[11px] font-normal text-zinc-400">{{ node.branchLabel }}</span>
|
||||
<span v-if="extendOpen && node.clip.id === extendClipId" class="ml-1.5 text-[10px] font-semibold uppercase tracking-wide text-amber-200">extending</span>
|
||||
</p>
|
||||
<PromptPreviewTip
|
||||
@@ -1878,7 +1886,8 @@
|
||||
empty="No generator settings were saved with this clip."
|
||||
/>
|
||||
</div>
|
||||
</li>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</template>
|
||||
<template v-else-if="entry.kind === 'still' && entry.stillGroup">
|
||||
@@ -2249,13 +2258,12 @@ import { parseImageAspect, generateSizeForAspect } from '~/utils/imageAspect'
|
||||
import { buildOutputBaseName, nextUniqueName } from '~/utils/outputNames'
|
||||
import { emptyKeepPrompts, insertKeepSnippet, normalizeKeepPrompts, type KeepPrompt, type KeepPromptLists } from '~/utils/keepPrompts'
|
||||
import {
|
||||
clipBranchFromLabel,
|
||||
clipPartLabel,
|
||||
familyBaseName,
|
||||
familyBranchCount,
|
||||
familyBranchHint,
|
||||
nextClipPartName,
|
||||
treeOrderedParts
|
||||
familyBranchSummary,
|
||||
familyDisplayNodes,
|
||||
familyRootClip,
|
||||
nextClipPartName
|
||||
} from '~/utils/libraryBrowse'
|
||||
import {
|
||||
IMAGE_V2_CFG_DEFAULT,
|
||||
@@ -3355,8 +3363,8 @@ const libraryGroups = computed(() => {
|
||||
}
|
||||
return [...groups.entries()]
|
||||
.map(([key, parts]) => {
|
||||
const sorted = [...parts].sort(sortClipParts)
|
||||
return { key, head: sorted[0], parts: sorted }
|
||||
const head = familyRootClip(parts)
|
||||
return { key, head, parts: [...parts] }
|
||||
})
|
||||
.sort((a, b) => b.head.createdAt - a.head.createdAt)
|
||||
})
|
||||
@@ -3501,14 +3509,6 @@ function chronologicalStills(parts: LibraryStill[]) {
|
||||
})
|
||||
}
|
||||
|
||||
function sortClipParts(a: LibraryClip, b: LibraryClip) {
|
||||
const durationDelta = (Number(b.duration) || 0) - (Number(a.duration) || 0)
|
||||
if (durationDelta) return durationDelta
|
||||
const chainDelta = (b.chainIndex || 0) - (a.chainIndex || 0)
|
||||
if (chainDelta) return chainDelta
|
||||
return a.createdAt - b.createdAt
|
||||
}
|
||||
|
||||
function chronologicalParts(parts: LibraryClip[]) {
|
||||
return [...parts].sort((a, b) => {
|
||||
const chain = (a.chainIndex || 0) - (b.chainIndex || 0)
|
||||
@@ -3531,9 +3531,8 @@ function previousClipIdFor(item: LibraryClip, parts: LibraryClip[]) {
|
||||
|
||||
function familyExpandLabel(parts: LibraryClip[], expanded?: boolean) {
|
||||
if (expanded) return 'Collapse'
|
||||
const branches = familyBranchCount(parts)
|
||||
if (branches) return `Expand ${parts.length} parts · ${branches} branch${branches === 1 ? '' : 'es'}`
|
||||
return `Expand ${parts.length} parts`
|
||||
const summary = familyBranchSummary(parts)
|
||||
return summary ? `Expand · ${summary}` : `Expand ${parts.length} parts`
|
||||
}
|
||||
|
||||
function ensureFamilyExpanded(item: LibraryClip) {
|
||||
|
||||
Reference in New Issue
Block a user