auto-save 2026-05-14 01:57 (+1, ~4)
This commit is contained in:
@@ -3,21 +3,23 @@ import { X } from "lucide-react"
|
||||
|
||||
/**
|
||||
* 视觉类节点统一大预览:
|
||||
* - **在 ReactFlow 节点 DOM 内**作为 absolute 元素,贴 thumb 上方边缘(bottom: calc(100% + 10px) + 居中)
|
||||
* - **在 ReactFlow 节点 DOM 内**作为 absolute 元素,贴节点卡片上边缘
|
||||
* - 跟随 ReactFlow 画布 pan/zoom 一起变化(属于"无限画布"的一部分)
|
||||
* - 媒体按"自然像素分辨率"渲染 + max-w/max-h 限制,避免占满整个画布
|
||||
* - 不 pinned 时:pointer-events-none,依赖 group-hover 显示/隐藏
|
||||
* - 媒体按"自然像素分辨率"渲染,不做 max 尺寸限制
|
||||
* - 不 pinned 时:pointer-events-none,依赖调用方传入 visible
|
||||
* - pinned=true:强制 visible,pointer-events 开启,可点 × 关闭
|
||||
* - 用法:父级容器要带 `group` class,HoverPreview 直接作为子元素
|
||||
* - 用法:渲染在节点根层,不要放进 overflow-x-auto 缩略图滚动条里
|
||||
*/
|
||||
interface Props {
|
||||
imgSrc?: string
|
||||
videoSrc?: string
|
||||
poster?: string
|
||||
aspect: string
|
||||
aspect?: string
|
||||
label?: string
|
||||
caption?: string
|
||||
borderClass?: string
|
||||
visible?: boolean
|
||||
anchorX?: number
|
||||
pinned?: boolean
|
||||
onClose?: () => void
|
||||
}
|
||||
@@ -26,19 +28,22 @@ export function HoverPreview({
|
||||
imgSrc, videoSrc, poster, aspect,
|
||||
label, caption,
|
||||
borderClass = "border-violet-300/55",
|
||||
visible = false,
|
||||
anchorX,
|
||||
pinned = false,
|
||||
onClose,
|
||||
}: Props) {
|
||||
const visibilityCls = pinned
|
||||
? "opacity-100 scale-100 pointer-events-auto"
|
||||
: "pointer-events-none opacity-0 group-hover:opacity-100 scale-95 group-hover:scale-100"
|
||||
const shown = pinned || visible
|
||||
const visibilityCls = shown
|
||||
? pinned ? "opacity-100 pointer-events-auto" : "opacity-100 pointer-events-none"
|
||||
: "pointer-events-none opacity-0"
|
||||
return (
|
||||
<div
|
||||
className={`absolute transition-all duration-150 z-[60] ${visibilityCls}`}
|
||||
className={`absolute transition-all duration-150 z-[120] ${visibilityCls}`}
|
||||
style={{
|
||||
bottom: "calc(100% + 10px)",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
bottom: "calc(100% + 8px)",
|
||||
left: typeof anchorX === "number" ? `${anchorX}px` : "50%",
|
||||
transform: `translateX(-50%) scale(${shown ? 1 : 0.96})`,
|
||||
transformOrigin: "bottom center",
|
||||
}}
|
||||
>
|
||||
@@ -54,14 +59,19 @@ export function HoverPreview({
|
||||
autoPlay
|
||||
preload="auto"
|
||||
className="block"
|
||||
style={{ maxWidth: "none" }}
|
||||
style={{ width: "auto", height: "auto", maxWidth: "none", maxHeight: "none" }}
|
||||
onLoadedMetadata={(e) => { e.currentTarget.play().catch(() => {}) }}
|
||||
onCanPlay={(e) => { e.currentTarget.play().catch(() => {}) }}
|
||||
/>
|
||||
) : imgSrc ? (
|
||||
<img src={imgSrc} alt="" className="block" style={{ maxWidth: "none" }} />
|
||||
<img
|
||||
src={imgSrc}
|
||||
alt=""
|
||||
className="block"
|
||||
style={{ width: "auto", height: "auto", maxWidth: "none", maxHeight: "none" }}
|
||||
/>
|
||||
) : (
|
||||
<div className="w-40 h-40 bg-black/40" />
|
||||
<div className="w-40 bg-black/40" style={{ aspectRatio: aspect ?? "1/1" }} />
|
||||
)}
|
||||
{(label || caption) && (
|
||||
<div className="px-2 py-1 bg-black/80 text-white text-[11px] flex items-center justify-between">
|
||||
|
||||
Reference in New Issue
Block a user