Make family branches readable and fix Library part previews.

Lead rows with Start/pN labels and fork headers, collapse hidden frame strips to one glow, and stop Library part thumbs from leaking or cloning the Start frame.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-03 20:32:40 -05:00
co-authored by Cursor
parent 8f80cbd39b
commit 47f14d7be2
4 changed files with 67 additions and 26 deletions
+17 -12
View File
@@ -1,6 +1,18 @@
<template>
<div class="shrink-0">
<div class="flex items-start gap-1.5">
<div v-if="concealed" class="flex w-[6.5rem] flex-col items-center gap-0.5">
<button
type="button"
class="relative h-12 w-full overflow-hidden rounded-lg bg-zinc-900"
aria-label="Click to reveal frames"
title="Click to reveal"
@click.stop="revealed = true"
>
<span class="sensitive-glow block h-full w-full" />
</button>
<span class="text-[10px] leading-none text-zinc-500">Hidden</span>
</div>
<div v-else class="flex items-start gap-1.5">
<div
v-for="slot in visibleSlots"
:key="slot.key"
@@ -9,13 +21,11 @@
<button
type="button"
class="relative h-12 w-12 overflow-hidden rounded-lg bg-zinc-900"
:aria-label="concealed ? `Click to reveal ${slot.label}` : slot.aria"
:title="concealed ? 'Click to reveal' : slot.label"
:aria-label="slot.aria"
:title="slot.label"
@click.stop="onSlotClick(slot)"
>
<span v-if="concealed" class="sensitive-glow block h-full w-full" />
<img
v-else
:src="slot.thumb"
alt=""
loading="lazy"
@@ -92,6 +102,7 @@ const revealed = computed({
const concealed = computed(() => props.hidden === true && !revealed.value)
const visibleSlots = computed(() => {
if (concealed.value) return [] as FrameSlot[]
const list: FrameSlot[] = []
if (props.stillId) {
list.push({
@@ -120,11 +131,10 @@ const visibleSlots = computed(() => {
full: frameFull('first')
})
}
return list.filter(slot => concealed.value || !failed[slot.key])
return list.filter(slot => !failed[slot.key])
})
function frameThumb(key: SlotKey) {
if (concealed.value) return ''
if (key === 'still' && props.stillId) return `/api/library/stills/${props.stillId}?thumb=1`
if (key === 'from' && props.fromClipId) return `/api/library/clips/${props.fromClipId}/last-frame?thumb=1&v=parent`
if (key === 'first' && props.clipId) return `/api/library/clips/${props.clipId}/first-frame?thumb=1&v=join`
@@ -132,7 +142,6 @@ function frameThumb(key: SlotKey) {
}
function frameFull(key: SlotKey) {
if (concealed.value) return ''
if (key === 'still' && props.stillId) return `/api/library/stills/${props.stillId}`
if (key === 'from' && props.fromClipId) return `/api/library/clips/${props.fromClipId}/last-frame?v=parent`
if (key === 'first' && props.clipId) return `/api/library/clips/${props.clipId}/first-frame?v=join`
@@ -162,10 +171,6 @@ watch(
)
function onSlotClick(slot: FrameSlot) {
if (concealed.value) {
revealed.value = true
return
}
if (!slot.full) return
preview.value = { src: slot.full, label: slot.label }
}