diff --git a/.memory/worklog.json b/.memory/worklog.json index 08c5be8..f870514 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1808,6 +1808,13 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 2 项未提交变更 · 最近提交:auto-save 2026-05-13 15:33 (~4)", "files_changed": 2 + }, + { + "ts": "2026-05-13T15:39:25+08:00", + "type": "commit", + "message": "auto-save 2026-05-13 15:39 (~2)", + "hash": "5c3da23", + "files_changed": 2 } ] } diff --git a/web/components/storyboard-bar.tsx b/web/components/storyboard-bar.tsx index c83b91c..3065d8b 100644 --- a/web/components/storyboard-bar.tsx +++ b/web/components/storyboard-bar.tsx @@ -17,7 +17,7 @@ export function StoryboardBar({ job, selectedFrames, focusedFrame, onFocusFrame, const [collapsed, setCollapsed] = useState(false) const [mounted, setMounted] = useState(false) useEffect(() => setMounted(true), []) - const [hover, setHover] = useState<{ frame: KeyFrame; seq: number; rect: DOMRect } | null>(null) + const [hover, setHover] = useState<{ src: string; topLabel: string; subLabel: string; rect: DOMRect } | null>(null) const btnRefs = useRef>({}) if (!job) return null @@ -105,7 +105,12 @@ export function StoryboardBar({ job, selectedFrames, focusedFrame, onFocusFrame, onClick={() => onFocusFrame(f.index)} onMouseEnter={() => { const el = btnRefs.current[f.index] - if (el) setHover({ frame: f, seq: i + 1, rect: el.getBoundingClientRect() }) + if (el) setHover({ + src: effectiveFrameUrl(job.id, f), + topLabel: `分镜 ${i + 1}`, + subLabel: `${f.timestamp.toFixed(2)}s`, + rect: el.getBoundingClientRect(), + }) }} onMouseLeave={() => setHover(null)} title={`分镜 ${i + 1} · ${f.timestamp.toFixed(2)}s${cleaned ? " · 已清洗" : ""} · ${elementCount}/${totalElCount} 元素 · 点击进入编排`} @@ -213,18 +218,16 @@ export function StoryboardBar({ job, selectedFrames, focusedFrame, onFocusFrame, )} - {/* Hover 预览 · 浮在缩略图侧面(右侧优先 / 不够则左侧) */} + {/* Hover 预览 · 浮在缩略图正下方(bar 在顶部,下方是 DAG 画布区) */} {mounted && hover && (() => { const vidAspect = job.height > 0 ? job.height / job.width : 16 / 9 - const w = 320 + const w = 280 const h = w * vidAspect - const gap = 16 - let left = hover.rect.right + gap - if (left + w > window.innerWidth - 12) left = hover.rect.left - w - gap - if (left < 12) left = 12 - let top = hover.rect.top + hover.rect.height / 2 - h / 2 - if (top < 12) top = 12 - if (top + h > window.innerHeight - 12) top = window.innerHeight - h - 12 + const gap = 10 + // 水平居中到缩略图,clamp 视口内 + const centerX = hover.rect.left + hover.rect.width / 2 + const left = Math.max(12, Math.min(window.innerWidth - w - 12, centerX - w / 2)) + const top = hover.rect.bottom + gap return createPortal(
-
+
{`preview -
- 分镜 {hover.seq} · {hover.frame.timestamp.toFixed(2)}s +
+ 分镜 {hover.seq} + {hover.frame.timestamp.toFixed(2)}s
,