74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { Rect, Text } from "react-konva";
|
|
import type Konva from "konva";
|
|
|
|
import type { Layer } from "@/lib/studio-types";
|
|
|
|
function getVideoSrc(props: Layer["props"]): string | undefined {
|
|
return typeof props.src === "string" && props.src.length > 0
|
|
? props.src
|
|
: undefined;
|
|
}
|
|
|
|
export interface VideoLayerNodeProps {
|
|
layer: Layer;
|
|
onSelect: () => void;
|
|
onDragEnd: (x: number, y: number) => void;
|
|
onTransformEnd: (node: Konva.Node) => void;
|
|
registerNode: (id: string, node: Konva.Node | null) => void;
|
|
}
|
|
|
|
export function VideoLayerNode({
|
|
layer,
|
|
onSelect,
|
|
onDragEnd,
|
|
onTransformEnd,
|
|
registerNode,
|
|
}: VideoLayerNodeProps) {
|
|
const hasVideo = Boolean(getVideoSrc(layer.props));
|
|
const fileName =
|
|
typeof layer.props.fileName === "string" ? layer.props.fileName : "Video";
|
|
|
|
return (
|
|
<>
|
|
<Rect
|
|
ref={(node) => registerNode(layer.id, node)}
|
|
x={layer.x}
|
|
y={layer.y}
|
|
width={layer.width}
|
|
height={layer.height}
|
|
rotation={layer.rotation}
|
|
opacity={layer.opacity}
|
|
fill={hasVideo ? "#1F2937" : "#374151"}
|
|
stroke="#6B7280"
|
|
strokeWidth={1}
|
|
dash={hasVideo ? undefined : [8, 4]}
|
|
draggable
|
|
onMouseDown={(event) => {
|
|
event.cancelBubble = true;
|
|
onSelect();
|
|
}}
|
|
onTap={(event) => {
|
|
event.cancelBubble = true;
|
|
onSelect();
|
|
}}
|
|
onDragEnd={(event) => onDragEnd(event.target.x(), event.target.y())}
|
|
onTransformEnd={(event) => onTransformEnd(event.target)}
|
|
/>
|
|
<Text
|
|
x={layer.x}
|
|
y={layer.y + layer.height / 2 - 10}
|
|
width={layer.width}
|
|
height={20}
|
|
rotation={layer.rotation}
|
|
text={hasVideo ? fileName : "Video clip"}
|
|
fontSize={14}
|
|
fill="#E5E7EB"
|
|
align="center"
|
|
listening={false}
|
|
/>
|
|
</>
|
|
);
|
|
}
|