Browse Source

fix: match VideoInputNode styling to ImageInputNode full-bleed pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
f2f24a0a5c
  1. 62
      src/components/nodes/VideoInputNode.tsx

62
src/components/nodes/VideoInputNode.tsx

@ -13,12 +13,6 @@ const MAX_FILE_SIZE = 200 * 1024 * 1024; // 200MB
const ACCEPTED_FORMATS = "video/mp4,video/webm,video/quicktime";
const ACCEPTED_MIME_TYPES = ACCEPTED_FORMATS.split(",");
function formatDuration(seconds: number): string {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, "0")}`;
}
export function VideoInputNode({ id, data, selected }: NodeProps<VideoInputNodeType>) {
const nodeData = data;
const updateNodeData = useWorkflowStore((state) => state.updateNodeData);
@ -119,8 +113,9 @@ export function VideoInputNode({ id, data, selected }: NodeProps<VideoInputNodeT
<BaseNode
id={id}
selected={selected}
minWidth={250}
minHeight={200}
contentClassName="flex-1 min-h-0"
aspectFitMedia={nodeData.video}
fullBleed
>
<input
ref={fileInputRef}
@ -131,47 +126,24 @@ export function VideoInputNode({ id, data, selected }: NodeProps<VideoInputNodeT
/>
{nodeData.video ? (
<div className="relative group flex-1 flex flex-col min-h-0 gap-2">
<div className="relative group w-full h-full overflow-clip rounded-lg">
<video
src={playbackUrl ?? undefined}
controls
className="w-full h-full object-cover rounded-lg"
preload="metadata"
/>
{nodeData.isOptional && (
<span className="absolute top-1 left-1 z-10 text-[9px] font-medium text-neutral-300 bg-black/50 px-1.5 py-0.5 rounded">
<span className="absolute bottom-2 left-2 text-[9px] font-medium text-neutral-300 bg-black/50 px-1.5 py-0.5 rounded">
Optional
</span>
)}
{/* Filename and duration */}
<div className="flex items-center justify-between shrink-0">
<span className="text-[10px] text-neutral-400 truncate max-w-[150px]" title={nodeData.filename || ""}>
{nodeData.filename}
</span>
<div className="flex items-center gap-1">
{nodeData.duration != null && (
<span className="text-[10px] text-neutral-500 bg-neutral-700/50 px-1.5 py-0.5 rounded">
{formatDuration(nodeData.duration)}
</span>
)}
{nodeData.dimensions && (
<span className="text-[10px] text-neutral-500 bg-neutral-700/50 px-1.5 py-0.5 rounded">
{nodeData.dimensions.width}x{nodeData.dimensions.height}
</span>
)}
</div>
</div>
{/* Video player */}
<div className="flex-1 min-h-[120px] bg-neutral-900/50 rounded overflow-hidden">
<video
src={playbackUrl ?? undefined}
controls
className="w-full h-full object-contain"
preload="metadata"
/>
</div>
{/* Remove button */}
<button
onClick={handleRemove}
className="absolute top-1 right-1 w-5 h-5 bg-black/60 text-white rounded text-xs opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center"
aria-label="Remove video"
className="absolute top-2 right-2 w-6 h-6 bg-black/60 hover:bg-red-600/80 text-white rounded text-xs opacity-0 group-hover:opacity-100 focus:opacity-100 focus:ring-1 focus:ring-red-400 transition-all flex items-center justify-center"
>
<svg className="w-3 h-3" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
@ -185,14 +157,12 @@ export function VideoInputNode({ id, data, selected }: NodeProps<VideoInputNodeT
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); fileInputRef.current?.click(); } }}
onDrop={handleDrop}
onDragOver={handleDragOver}
className={`w-full h-full bg-neutral-900/40 flex flex-col items-center justify-center cursor-pointer hover:bg-neutral-800/60 transition-colors ${nodeData.isOptional ? "border-2 border-dashed border-neutral-600" : ""}`}
className={`w-full h-full bg-neutral-900/40 flex flex-col items-center justify-center cursor-pointer hover:bg-neutral-900/60 transition-colors ${nodeData.isOptional ? "border-2 border-dashed border-neutral-600" : ""}`}
>
<svg className="w-8 h-8 text-neutral-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path strokeLinecap="round" strokeLinejoin="round" d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z" />
</svg>
<span className="text-xs text-neutral-500 mt-2">
{nodeData.isOptional ? "Optional" : "Drop video or click"}
</span>
<span className="text-xs text-neutral-500 mt-2">{nodeData.isOptional ? "Optional" : "Drop video or click"}</span>
</div>
)}

Loading…
Cancel
Save