Browse Source

删除控制台功能,快捷键修改 增加拖拽组的功能

feature/new_node
TianYun 2 months ago
parent
commit
4e4f916e8c
  1. 59
      src/components/GroupsOverlay.tsx
  2. 25
      src/components/WorkflowCanvas.tsx
  3. 2
      src/components/__tests__/GenerationComposer.test.tsx
  4. 29
      src/components/__tests__/GroupsOverlay.test.tsx
  5. 5
      src/components/composer/GenerationComposer.tsx
  6. 2
      src/i18n/index.tsx

59
src/components/GroupsOverlay.tsx

@ -30,8 +30,58 @@ interface GroupBackgroundProps {
// Renders just the group background - displayed below nodes (z-index 1) // Renders just the group background - displayed below nodes (z-index 1)
function GroupBackground({ groupId }: GroupBackgroundProps) { function GroupBackground({ groupId }: GroupBackgroundProps) {
const { groups } = useWorkflowStore(); const { groups, updateGroup, moveGroupNodes } = useWorkflowStore();
const group = groups[groupId]; const group = groups[groupId];
const { zoom } = useViewport();
const [isDragging, setIsDragging] = useState(false);
const dragStartRef = useRef<{ x: number; y: number } | null>(null);
const handleBackgroundMouseDown = useCallback(
(e: React.MouseEvent) => {
if (e.button !== 0) return;
e.stopPropagation();
e.preventDefault();
setIsDragging(true);
dragStartRef.current = { x: e.clientX, y: e.clientY };
},
[]
);
useEffect(() => {
if (!isDragging || !group) return;
const handleMouseMove = (e: MouseEvent) => {
if (!dragStartRef.current) return;
const deltaX = (e.clientX - dragStartRef.current.x) / zoom;
const deltaY = (e.clientY - dragStartRef.current.y) / zoom;
if (Math.abs(deltaX) > 2 || Math.abs(deltaY) > 2) {
updateGroup(groupId, {
position: {
x: group.position.x + deltaX,
y: group.position.y + deltaY,
},
});
moveGroupNodes(groupId, { x: deltaX, y: deltaY });
dragStartRef.current = { x: e.clientX, y: e.clientY };
}
};
const handleMouseUp = () => {
setIsDragging(false);
dragStartRef.current = null;
};
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
return () => {
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
};
}, [isDragging, group, groupId, moveGroupNodes, updateGroup, zoom]);
if (!group) return null; if (!group) return null;
@ -39,7 +89,8 @@ function GroupBackground({ groupId }: GroupBackgroundProps) {
return ( return (
<div <div
className="absolute rounded-xl" className="absolute rounded-xl cursor-grab active:cursor-grabbing"
onMouseDown={handleBackgroundMouseDown}
style={{ style={{
left: group.position.x, left: group.position.x,
top: group.position.y, top: group.position.y,
@ -47,7 +98,7 @@ function GroupBackground({ groupId }: GroupBackgroundProps) {
height: group.size.height, height: group.size.height,
backgroundColor: `${bgColor}60`, backgroundColor: `${bgColor}60`,
border: group.isNbpInput ? `3px dashed rgba(255,255,255,0.25)` : `1px solid ${bgColor}`, border: group.isNbpInput ? `3px dashed rgba(255,255,255,0.25)` : `1px solid ${bgColor}`,
pointerEvents: "none", pointerEvents: "auto",
}} }}
/> />
); );
@ -531,7 +582,7 @@ export function GroupBackgroundsPortal() {
return ( return (
<ViewportPortal> <ViewportPortal>
<div style={{ position: "absolute", top: 0, left: 0, zIndex: -1, pointerEvents: "none" }}> <div style={{ position: "absolute", top: 0, left: 0, zIndex: -1, pointerEvents: "auto" }}>
{groupIds.map((groupId) => ( {groupIds.map((groupId) => (
<GroupBackground key={groupId} groupId={groupId} /> <GroupBackground key={groupId} groupId={groupId} />
))} ))}

25
src/components/WorkflowCanvas.tsx

@ -2586,29 +2586,14 @@ export function WorkflowCanvas() {
fitViewOptions={FIT_VIEW_OPTIONS} fitViewOptions={FIT_VIEW_OPTIONS}
deleteKeyCode={["Backspace", "Delete"]} deleteKeyCode={["Backspace", "Delete"]}
multiSelectionKeyCode="Shift" multiSelectionKeyCode="Shift"
selectionOnDrag={ selectionOnDrag={tutorialActive ? false : !isModalOpen}
canvasNavigationSettings.selectionMode === "altDrag" || canvasNavigationSettings.selectionMode === "shiftDrag" selectionKeyCode={null}
? false
: canvasNavigationSettings.panMode === "always"
? false
: isMacOSClient && !isModalOpen
}
selectionKeyCode={
isModalOpen ? null
: canvasNavigationSettings.selectionMode === "altDrag" ? "Alt"
: canvasNavigationSettings.selectionMode === "shiftDrag" ? "Shift"
: "Shift"
}
panOnDrag={ panOnDrag={
tutorialActive tutorialActive
? false ? false
: isModalOpen : isModalOpen
? false ? false
: canvasNavigationSettings.panMode === "always" : false
? true
: canvasNavigationSettings.panMode === "middleMouse"
? [2]
: !isMacOSClient
} }
selectNodesOnDrag={false} selectNodesOnDrag={false}
nodeDragThreshold={5} nodeDragThreshold={5}
@ -2623,9 +2608,7 @@ export function WorkflowCanvas() {
? null ? null
: isModalOpen : isModalOpen
? null ? null
: canvasNavigationSettings.panMode === "space" : "Space"
? "Space"
: null
} }
nodesDraggable={!isModalOpen} nodesDraggable={!isModalOpen}
nodesConnectable={!isModalOpen} nodesConnectable={!isModalOpen}

2
src/components/__tests__/GenerationComposer.test.tsx

@ -1187,7 +1187,6 @@ describe("GenerationComposer", () => {
}); });
render(<GenerationComposer />); render(<GenerationComposer />);
expect(screen.getByText("Video Stitch")).toBeInTheDocument();
expect(screen.getByText("2 video clips")).toBeInTheDocument(); expect(screen.getByText("2 video clips")).toBeInTheDocument();
expect(screen.getByText("Video inputs")).toBeInTheDocument(); expect(screen.getByText("Video inputs")).toBeInTheDocument();
expect(screen.getByText("Clip 1")).toBeInTheDocument(); expect(screen.getByText("Clip 1")).toBeInTheDocument();
@ -1224,7 +1223,6 @@ describe("GenerationComposer", () => {
}); });
render(<GenerationComposer />); render(<GenerationComposer />);
expect(screen.getByText("Ease Curve")).toBeInTheDocument();
expect(screen.getByText("Video connected")).toBeInTheDocument(); expect(screen.getByText("Video connected")).toBeInTheDocument();
expect(screen.getByText("Curve settings")).toBeInTheDocument(); expect(screen.getByText("Curve settings")).toBeInTheDocument();
expect(screen.getByText("easeInOutSine")).toBeInTheDocument(); expect(screen.getByText("easeInOutSine")).toBeInTheDocument();

29
src/components/__tests__/GroupsOverlay.test.tsx

@ -147,7 +147,7 @@ describe("GroupBackgroundsPortal", () => {
expect(style).toContain("border"); expect(style).toContain("border");
}); });
it("should set pointerEvents to none on backgrounds", () => { it("should make backgrounds interactive for group dragging", () => {
mockUseWorkflowStore.mockImplementation((selector) => { mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({ return selector(createDefaultState({
groups: { "group-1": createMockGroup() }, groups: { "group-1": createMockGroup() },
@ -156,7 +156,32 @@ describe("GroupBackgroundsPortal", () => {
const { container } = render(<GroupBackgroundsPortal />); const { container } = render(<GroupBackgroundsPortal />);
const background = container.querySelector(".rounded-xl"); const background = container.querySelector(".rounded-xl");
expect(background).toHaveStyle({ pointerEvents: "none" }); expect(background).toHaveStyle({ pointerEvents: "auto" });
});
it("should drag a group from its background", () => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
groups: { "group-1": createMockGroup() },
}));
});
const { container } = render(<GroupBackgroundsPortal />);
const background = container.querySelector(".rounded-xl") as HTMLElement;
fireEvent.mouseDown(background, { button: 0, clientX: 100, clientY: 100 });
act(() => {
fireEvent.mouseMove(window, { clientX: 130, clientY: 120 });
});
expect(mockUpdateGroup).toHaveBeenCalledWith("group-1", {
position: { x: 130, y: 120 },
});
expect(mockMoveGroupNodes).toHaveBeenCalledWith("group-1", { x: 30, y: 20 });
act(() => {
fireEvent.mouseUp(window);
});
}); });
}); });
}); });

5
src/components/composer/GenerationComposer.tsx

@ -1996,11 +1996,6 @@ export function GenerationComposer() {
) : ( ) : (
<> <>
<div className="flex items-center gap-2 px-4 pt-4"> <div className="flex items-center gap-2 px-4 pt-4">
<div className="mr-1 flex h-14 min-w-24 flex-col justify-center rounded-lg border border-neutral-700 bg-neutral-900/60 px-3">
<span className="text-[10px] text-neutral-500">{t("composer.console")}</span>
<span className="text-xs font-medium text-neutral-100">{modeLabel}</span>
</div>
{isProcessNode ? ( {isProcessNode ? (
isVideoStitchNode ? ( isVideoStitchNode ? (
<div className="flex h-14 items-center gap-3 rounded-lg border border-neutral-700 bg-neutral-900/50 px-3 text-xs text-neutral-300"> <div className="flex h-14 items-center gap-3 rounded-lg border border-neutral-700 bg-neutral-900/50 px-3 text-xs text-neutral-300">

2
src/i18n/index.tsx

@ -592,7 +592,6 @@ const en = {
"composer.uploadReferenceImage": "Upload reference image", "composer.uploadReferenceImage": "Upload reference image",
"composer.expand": "Expand composer", "composer.expand": "Expand composer",
"composer.collapse": "Collapse composer", "composer.collapse": "Collapse composer",
"composer.console": "Console",
"composer.style": "Style", "composer.style": "Style",
"composer.mark": "Mark", "composer.mark": "Mark",
"composer.focus": "Focus", "composer.focus": "Focus",
@ -1422,7 +1421,6 @@ const zhCN: Dictionary = {
"composer.uploadReferenceImage": "上传参考图片", "composer.uploadReferenceImage": "上传参考图片",
"composer.expand": "展开底部栏", "composer.expand": "展开底部栏",
"composer.collapse": "收起底部栏", "composer.collapse": "收起底部栏",
"composer.console": "控制台",
"composer.style": "风格", "composer.style": "风格",
"composer.mark": "标记", "composer.mark": "标记",
"composer.focus": "聚焦", "composer.focus": "聚焦",

Loading…
Cancel
Save