diff --git a/.memory/worklog.json b/.memory/worklog.json index bda3b95..ea14199 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1788,6 +1788,13 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 4 项未提交变更 · 最近提交:auto-save 2026-05-13 15:22 (~5)", "files_changed": 4 + }, + { + "ts": "2026-05-13T15:28:21+08:00", + "type": "commit", + "message": "auto-save 2026-05-13 15:28 (~4)", + "hash": "ad895f9", + "files_changed": 4 } ] } diff --git a/web/app/page.tsx b/web/app/page.tsx index 69e8fda..dcd5383 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -317,8 +317,8 @@ export default function Home() { <>
- {/* 主题切换 — 左下角 */} -
+ {/* 主题切换 — 左下角 Controls 上方(错开) */} +
diff --git a/web/components/nodes/index.tsx b/web/components/nodes/index.tsx index ac9149c..07d2e75 100644 --- a/web/components/nodes/index.tsx +++ b/web/components/nodes/index.tsx @@ -479,19 +479,25 @@ export function KeyframeNode({ data, selected }: any) { )} - {/* Portal hover 预览 — 固定视口右下角,不遮挡 */} + {/* Portal hover 预览 — 缩略图正上方展开(DAG 画布上方空旷) */} {mounted && hover && jobId && (() => { const hf = frames.find((x) => x.index === hover.idx) if (!hf) return null const vidAspect = d.job && d.job.height > 0 ? d.job.height / d.job.width : 16 / 9 - const w = 280 - const h = w * vidAspect + const gap = 12 + // 高度优先:不超过缩略图上方可用空间,也不超过视口 80vh + const maxH = Math.max(160, Math.min(window.innerHeight * 0.8, hover.rect.top - gap - 12)) + const maxW = Math.min(window.innerWidth * 0.45, 480) + let h = maxH, w = h / vidAspect + if (w > maxW) { w = maxW; h = w * vidAspect } + 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.top - h - gap return createPortal(
@@ -717,21 +723,26 @@ export function ImageGenNode({ data, selected }: any) { )} - {/* Portal hover 预览 — 固定视口右下角,不遮挡 */} + {/* Portal hover 预览 — 缩略图正上方展开 */} {mounted && hover && job && (() => { const [fi, ei] = hover.key.split("_") const frameIdx = parseInt(fi, 10) const p = elementCrops.find((x) => x.frameIdx === frameIdx && x.elementId === ei) if (!p) return null const vidAspect = job.height > 0 ? job.height / job.width : 16 / 9 - const w = 280 - const h = w * vidAspect + const gap = 12 + const maxH = Math.max(160, Math.min(window.innerHeight * 0.8, hover.rect.top - gap - 12)) + const maxW = Math.min(window.innerWidth * 0.45, 480) + let h = maxH, w = h / vidAspect + if (w > maxW) { w = maxW; h = w * vidAspect } + 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.top - h - gap return createPortal(
diff --git a/web/components/storyboard-bar.tsx b/web/components/storyboard-bar.tsx index a6fcac3..c83b91c 100644 --- a/web/components/storyboard-bar.tsx +++ b/web/components/storyboard-bar.tsx @@ -213,17 +213,23 @@ export function StoryboardBar({ job, selectedFrames, focusedFrame, onFocusFrame,
)} - {/* Hover 预览 · 固定视口右下角,不遮挡 */} + {/* Hover 预览 · 浮在缩略图侧面(右侧优先 / 不够则左侧) */} {mounted && hover && (() => { const vidAspect = job.height > 0 ? job.height / job.width : 16 / 9 - const w = 280 + const w = 320 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 return createPortal(