Browse Source

fix: unify video handle, label, and edge colors to pink (#ec4899)

Video handles/edges/labels were inconsistent — using white, green, blue,
and hardcoded purple across different files. Standardize all to pink and
use the CSS variable var(--handle-color-video) for labels. Also adds the
missing .react-flow__handle[data-handletype="video"] CSS rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 3 months ago
parent
commit
ea8eb8a8d7
  1. 7
      src/app/globals.css
  2. 2
      src/components/edges/EditableEdge.tsx
  3. 2
      src/components/edges/SharedEdgeGradients.tsx
  4. 4
      src/components/nodes/EaseCurveNode.tsx
  5. 4
      src/components/nodes/GenerateAudioNode.tsx
  6. 2
      src/components/nodes/GenerateImageNode.tsx
  7. 4
      src/components/nodes/GenerateVideoNode.tsx
  8. 2
      src/components/nodes/OutputGalleryNode.tsx
  9. 2
      src/components/nodes/RouterNode.tsx
  10. 2
      src/components/nodes/SwitchNode.tsx
  11. 2
      src/components/nodes/VideoFrameGrabNode.tsx
  12. 4
      src/components/nodes/VideoStitchNode.tsx
  13. 4
      src/components/nodes/VideoTrimNode.tsx

7
src/app/globals.css

@ -12,7 +12,7 @@
--handle-color-text: #3b82f6;
--handle-color-3d: #f97316;
--handle-color-audio: #a855f7;
--handle-color-video: #a855f7;
--handle-color-video: #ec4899;
}
html {
@ -125,6 +125,11 @@ body {
background: #a855f7;
}
/* Video handles - pink */
.react-flow__handle[data-handletype="video"] {
background: #ec4899;
}
/* 3D handles - orange */
.react-flow__handle[data-handletype="3d"] {
background: #f97316;

2
src/components/edges/EditableEdge.tsx

@ -24,7 +24,7 @@ const EDGE_COLORS: Record<string, string> = {
default: "#64748b", // Gray for unknown
pause: "#ea580c", // Orange for paused edges
reference: "#52525b", // Gray for reference connections
video: "#a855f7", // Purple for video connections
video: "#ec4899", // Pink for video connections
audio: "#f97316", // Orange for audio connections
text: "#2563eb", // Blue for text connections
"3d": "#06b6d4", // Cyan for 3D connections

2
src/components/edges/SharedEdgeGradients.tsx

@ -10,7 +10,7 @@ const EDGE_COLORS: Record<string, string> = {
default: "#64748b",
pause: "#ea580c",
reference: "#52525b",
video: "#a855f7",
video: "#ec4899",
audio: "#f97316",
text: "#2563eb",
"3d": "#06b6d4",

4
src/components/nodes/EaseCurveNode.tsx

@ -57,7 +57,7 @@ export function EaseCurveNode({ id, data, selected }: NodeProps<EaseCurveNodeTyp
isConnectable={true}
style={{ top: "35%" }}
/>
<HandleLabel label="Video In" side="target" color="rgb(168, 85, 247)" top="calc(35% - 7px)" visible={showLabels} />
<HandleLabel label="Video In" side="target" color="var(--handle-color-video)" top="calc(35% - 7px)" visible={showLabels} />
{/* Video Out (source, right, 35%) */}
<Handle
@ -68,7 +68,7 @@ export function EaseCurveNode({ id, data, selected }: NodeProps<EaseCurveNodeTyp
isConnectable={true}
style={{ top: "35%" }}
/>
<HandleLabel label="Video Out" side="source" color="rgb(168, 85, 247)" top="calc(35% - 7px)" visible={showLabels} />
<HandleLabel label="Video Out" side="source" color="var(--handle-color-video)" top="calc(35% - 7px)" visible={showLabels} />
{/* Settings In (target, left, 75%) */}
<Handle

4
src/components/nodes/GenerateAudioNode.tsx

@ -248,7 +248,7 @@ export function GenerateAudioNode({ id, data, selected }: NodeProps<GenerateAudi
</React.Fragment>
);
});
}, [nodeData.inputSchema]);
}, [nodeData.inputSchema, showLabels]);
return (
<>
@ -429,7 +429,7 @@ export function GenerateAudioNode({ id, data, selected }: NodeProps<GenerateAudi
{/* Download button */}
<button
onClick={() => downloadMedia(nodeData.outputAudio!, "audio")}
onClick={() => downloadMedia(nodeData.outputAudio!, "audio").catch(() => {})}
className="absolute top-1 right-7 w-5 h-5 bg-black/60 hover:bg-black/80 text-white rounded text-xs opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center"
title="Download audio"
>

2
src/components/nodes/GenerateImageNode.tsx

@ -782,7 +782,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
{/* Download + Clear buttons */}
<div className="absolute top-1 right-1 flex items-center gap-0.5">
<button
onClick={() => downloadMedia(nodeData.outputImage!, "image")}
onClick={() => downloadMedia(nodeData.outputImage!, "image").catch(() => {})}
className="w-5 h-5 bg-neutral-900/80 hover:bg-neutral-700 rounded flex items-center justify-center text-neutral-400 hover:text-white transition-colors"
title="Download image"
>

4
src/components/nodes/GenerateVideoNode.tsx

@ -644,7 +644,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
style={{ zIndex: 10 }}
/>
{/* Output label */}
<HandleLabel label="Video" side="source" color="var(--handle-color-image)" visible={showLabels} />
<HandleLabel label="Video" side="source" color="var(--handle-color-video)" visible={showLabels} />
<div className="relative w-full h-full min-h-0 overflow-hidden rounded-lg">
{/* Preview area */}
@ -735,7 +735,7 @@ export function GenerateVideoNode({ id, data, selected }: NodeProps<GenerateVide
{/* Download + Clear buttons */}
<div className="absolute top-1 right-1 flex items-center gap-0.5">
<button
onClick={() => downloadMedia(nodeData.outputVideo!, "video")}
onClick={() => downloadMedia(nodeData.outputVideo!, "video").catch(() => {})}
className="w-5 h-5 bg-neutral-900/80 hover:bg-neutral-700 rounded flex items-center justify-center text-neutral-400 hover:text-white transition-colors"
title="Download video"
>

2
src/components/nodes/OutputGalleryNode.tsx

@ -197,7 +197,7 @@ export function OutputGalleryNode({ id, data, selected }: NodeProps<OutputGaller
data-handletype="video"
style={{ top: "60%" }}
/>
<HandleLabel label="Video" side="target" color="rgb(168, 85, 247)" top="calc(60% - 18px)" visible={showLabels} />
<HandleLabel label="Video" side="target" color="var(--handle-color-video)" top="calc(60% - 18px)" visible={showLabels} />
{displayMedia.length > 0 && (
<div className="flex items-center justify-between px-2 py-1">

2
src/components/nodes/RouterNode.tsx

@ -11,7 +11,7 @@ const ALL_HANDLE_TYPES = ["image", "text", "video", "audio", "3d", "easeCurve"]
const HANDLE_COLORS: Record<(typeof ALL_HANDLE_TYPES)[number], string> = {
image: "#10b981", // emerald — matches globals.css
text: "#3b82f6", // blue — matches globals.css
video: "#ffffff", // white — default handle style
video: "#ec4899", // pink — video handle style
audio: "rgb(167, 139, 250)", // violet — matches GenerateAudioNode/OutputNode
"3d": "#f97316", // orange — matches globals.css
easeCurve: "#ffffff", // white — default handle style

2
src/components/nodes/SwitchNode.tsx

@ -9,7 +9,7 @@ import type { WorkflowNode, SwitchNodeData, HandleType } from "@/types";
const HANDLE_COLORS: Record<HandleType, string> = {
image: "#10b981", // emerald — matches globals.css
text: "#3b82f6", // blue — matches globals.css
video: "#ffffff", // white — default handle style
video: "#ec4899", // pink — video handle style
audio: "rgb(167, 139, 250)", // violet — matches GenerateAudioNode/OutputNode
"3d": "#f97316", // orange — matches globals.css
easeCurve: "#ffffff", // white — default handle style

2
src/components/nodes/VideoFrameGrabNode.tsx

@ -59,7 +59,7 @@ export function VideoFrameGrabNode({ id, data, selected }: NodeProps<VideoFrameG
isConnectable={true}
style={{ top: "50%" }}
/>
<HandleLabel label="Video In" side="target" color="rgb(168, 85, 247)" top="calc(50% - 7px)" visible={showLabels} />
<HandleLabel label="Video In" side="target" color="var(--handle-color-video)" top="calc(50% - 7px)" visible={showLabels} />
{/* Image Out (source, right, 50%) */}
<Handle

4
src/components/nodes/VideoStitchNode.tsx

@ -315,7 +315,7 @@ export function VideoStitchNode({ id, data, selected }: NodeProps<VideoStitchNod
isConnectable={true}
style={{ top: `${topPercent}%` }}
/>
<HandleLabel label={`Video ${index + 1}`} side="target" color="rgb(96, 165, 250)" top={`calc(${topPercent}% - 9px)`} visible={showLabels} />
<HandleLabel label={`Video ${index + 1}`} side="target" color="var(--handle-color-video)" top={`calc(${topPercent}% - 9px)`} visible={showLabels} />
</React.Fragment>
);
})}
@ -339,7 +339,7 @@ export function VideoStitchNode({ id, data, selected }: NodeProps<VideoStitchNod
data-handletype="video"
isConnectable={true}
/>
<HandleLabel label="Output" side="source" color="rgb(96, 165, 250)" top="calc(50% - 9px)" visible={showLabels} />
<HandleLabel label="Output" side="source" color="var(--handle-color-video)" top="calc(50% - 9px)" visible={showLabels} />
</>
);

4
src/components/nodes/VideoTrimNode.tsx

@ -176,7 +176,7 @@ export function VideoTrimNode({ id, data, selected }: NodeProps<VideoTrimNodeTyp
isConnectable={true}
style={{ top: "50%" }}
/>
<HandleLabel label="Video In" side="target" color="rgb(168, 85, 247)" top="calc(50% - 7px)" visible={showLabels} />
<HandleLabel label="Video In" side="target" color="var(--handle-color-video)" top="calc(50% - 7px)" visible={showLabels} />
{/* Video Out (source, right, 50%) */}
<Handle
@ -187,7 +187,7 @@ export function VideoTrimNode({ id, data, selected }: NodeProps<VideoTrimNodeTyp
isConnectable={true}
style={{ top: "50%" }}
/>
<HandleLabel label="Video Out" side="source" color="rgb(168, 85, 247)" top="calc(50% - 7px)" visible={showLabels} />
<HandleLabel label="Video Out" side="source" color="var(--handle-color-video)" top="calc(50% - 7px)" visible={showLabels} />
</>
);

Loading…
Cancel
Save