Browse Source

默认尺寸修改

feature/071
yun 1 week ago
parent
commit
bfb4ac2a64
  1. 14
      src/components/__tests__/GenerationComposer.test.tsx
  2. 44
      src/constants/nodeDimensions.ts
  3. 8
      src/store/__tests__/generationPreferenceStore.test.ts
  4. 26
      src/store/__tests__/workflowStore.integration.test.ts
  5. 4
      src/utils/__tests__/nodeSizing.test.ts
  6. 26
      src/utils/nodeDimensions.ts

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

@ -1500,9 +1500,7 @@ describe("GenerationComposer", () => {
nodes: [ nodes: [
{ {
...imageNode("img-1", true, { aspectRatio: "16:9", parameters: {} }), ...imageNode("img-1", true, { aspectRatio: "16:9", parameters: {} }),
width: 360, style: { width: 615, height: 346 },
height: 203,
measured: { width: 360, height: 203 },
} as WorkflowNode, } as WorkflowNode,
], ],
}); });
@ -1516,8 +1514,7 @@ describe("GenerationComposer", () => {
const data = node.data as NanoBananaNodeData; const data = node.data as NanoBananaNodeData;
expect(data.aspectRatio).toBe("9:16"); expect(data.aspectRatio).toBe("9:16");
expect(data.parameters).toEqual({ ratio: "9:16" }); expect(data.parameters).toEqual({ ratio: "9:16" });
expect(node.width).toBe(203); expect(node.style).toMatchObject({ width: 346, height: 615 });
expect(node.height).toBe(360);
}); });
}); });
@ -1546,9 +1543,7 @@ describe("GenerationComposer", () => {
nodes: [ nodes: [
{ {
...imageNode("img-1", true, { aspectRatio: "16:9", parameters: {} }), ...imageNode("img-1", true, { aspectRatio: "16:9", parameters: {} }),
width: 360, style: { width: 615, height: 346 },
height: 203,
measured: { width: 360, height: 203 },
} as WorkflowNode, } as WorkflowNode,
], ],
}); });
@ -1560,8 +1555,7 @@ describe("GenerationComposer", () => {
const data = node.data as NanoBananaNodeData; const data = node.data as NanoBananaNodeData;
expect(data.parameters).toEqual({ ratio: "9:16" }); expect(data.parameters).toEqual({ ratio: "9:16" });
expect(data.aspectRatio).toBe("9:16"); expect(data.aspectRatio).toBe("9:16");
expect(node.width).toBe(203); expect(node.style).toMatchObject({ width: 346, height: 615 });
expect(node.height).toBe(360);
}); });
}); });

44
src/constants/nodeDimensions.ts

@ -3,34 +3,34 @@ import type { NodeType } from "@/types";
export type NodeDimensions = { width: number; height: number }; export type NodeDimensions = { width: number; height: number };
export const defaultNodeDimensions: Record<NodeType, NodeDimensions> = { export const defaultNodeDimensions: Record<NodeType, NodeDimensions> = {
group: { width: 400, height: 300 }, group: { width: 420, height: 300 },
imageInput: { width: 300, height: 280 }, imageInput: { width: 300, height: 280 },
smartImage: { width: 300, height: 280 }, smartImage: { width: 300, height: 280 },
audioInput: { width: 300, height: 280 }, audioInput: { width: 320, height: 180 },
smartAudio: { width: 300, height: 280 }, smartAudio: { width: 360, height: 180 },
videoInput: { width: 300, height: 280 }, videoInput: { width: 300, height: 280 },
annotation: { width: 300, height: 280 }, annotation: { width: 520, height: 360 },
smartVideo: { width: 300, height: 280 }, smartVideo: { width: 300, height: 280 },
prompt: { width: 300, height: 200 }, prompt: { width: 320, height: 180 },
smartText: { width: 300, height: 200 }, smartText: { width: 360, height: 220 },
array: { width: 300, height: 280 }, array: { width: 320, height: 220 },
promptConstructor: { width: 300, height: 280 }, promptConstructor: { width: 420, height: 280 },
nanoBanana: { width: 300, height: 280 }, nanoBanana: { width: 300, height: 280 },
generateVideo: { width: 300, height: 280 }, generateVideo: { width: 300, height: 280 },
generate3d: { width: 300, height: 300 }, generate3d: { width: 360, height: 300 },
generateAudio: { width: 300, height: 280 }, generateAudio: { width: 360, height: 180 },
llmGenerate: { width: 300, height: 200 }, llmGenerate: { width: 360, height: 240 },
output: { width: 300, height: 280 }, output: { width: 360, height: 260 },
outputGallery: { width: 300, height: 280 }, outputGallery: { width: 420, height: 320 },
imageCompare: { width: 400, height: 360 }, imageCompare: { width: 520, height: 360 },
videoStitch: { width: 400, height: 280 }, videoStitch: { width: 420, height: 280 },
easeCurve: { width: 340, height: 280 }, easeCurve: { width: 340, height: 260 },
videoTrim: { width: 360, height: 360 }, videoTrim: { width: 420, height: 280 },
videoFrameGrab: { width: 320, height: 320 }, videoFrameGrab: { width: 360, height: 240 },
router: { width: 200, height: 80 }, router: { width: 280, height: 180 },
switch: { width: 220, height: 120 }, switch: { width: 280, height: 180 },
conditionalSwitch: { width: 260, height: 180 }, conditionalSwitch: { width: 340, height: 240 },
glbViewer: { width: 360, height: 380 }, glbViewer: { width: 420, height: 360 },
}; };
export const DEFAULT_NODE_DIMENSIONS: NodeDimensions = { width: 300, height: 280 }; export const DEFAULT_NODE_DIMENSIONS: NodeDimensions = { width: 300, height: 280 };

8
src/store/__tests__/generationPreferenceStore.test.ts

@ -128,7 +128,7 @@ describe("generationPreferenceStore", () => {
await expect(buildDefaultGenerationNodeCreation("nanoBanana")).resolves.toEqual({ await expect(buildDefaultGenerationNodeCreation("nanoBanana")).resolves.toEqual({
data: expect.any(Object), data: expect.any(Object),
size: { width: 360, height: 203 }, size: { width: 615, height: 346 },
}); });
}); });
@ -147,7 +147,7 @@ describe("generationPreferenceStore", () => {
await expect(buildDefaultGenerationNodeCreation("generateVideo")).resolves.toEqual({ await expect(buildDefaultGenerationNodeCreation("generateVideo")).resolves.toEqual({
data: expect.any(Object), data: expect.any(Object),
size: { width: 360, height: 203 }, size: { width: 615, height: 346 },
}); });
}); });
@ -166,7 +166,7 @@ describe("generationPreferenceStore", () => {
aspectRatio: "4:5", aspectRatio: "4:5",
parameters: { ratio: "4:5" }, parameters: { ratio: "4:5" },
}), }),
size: { width: 256, height: 320 }, size: { width: 346, height: 432 },
}); });
}); });
@ -245,7 +245,7 @@ describe("generationPreferenceStore", () => {
parameters: { ratio: "9:16" }, parameters: { ratio: "9:16" },
selectedModel: expect.objectContaining({ modelId: "44", billingMethod: 2 }), selectedModel: expect.objectContaining({ modelId: "44", billingMethod: 2 }),
}), }),
size: { width: 203, height: 360 }, size: { width: 346, height: 615 },
}); });
}); });

26
src/store/__tests__/workflowStore.integration.test.ts

@ -634,7 +634,7 @@ describe("workflowStore integration tests", () => {
}); });
const node = useWorkflowStore.getState().nodes[0]; const node = useWorkflowStore.getState().nodes[0];
expect(node).toMatchObject({ style: { width: 203, height: 360 } }); expect(node).toMatchObject({ style: { width: 346, height: 615 } });
expect(useWorkflowStore.getState().hasUnsavedChanges).toBe(true); expect(useWorkflowStore.getState().hasUnsavedChanges).toBe(true);
}); });
@ -685,7 +685,7 @@ describe("workflowStore integration tests", () => {
); );
const node = useWorkflowStore.getState().nodes.find((candidate) => candidate.id === nodeId); const node = useWorkflowStore.getState().nodes.find((candidate) => candidate.id === nodeId);
expect(node?.style).toMatchObject({ width: 203, height: 360 }); expect(node?.style).toMatchObject({ width: 346, height: 615 });
}); });
it("infers generation node dimensions from model parameter ratio", () => { it("infers generation node dimensions from model parameter ratio", () => {
@ -696,7 +696,7 @@ describe("workflowStore integration tests", () => {
); );
const node = useWorkflowStore.getState().nodes.find((candidate) => candidate.id === nodeId); const node = useWorkflowStore.getState().nodes.find((candidate) => candidate.id === nodeId);
expect(node?.style).toMatchObject({ width: 360, height: 203 }); expect(node?.style).toMatchObject({ width: 615, height: 346 });
}); });
it("infers media node dimensions from initial media dimensions", () => { it("infers media node dimensions from initial media dimensions", () => {
@ -2130,7 +2130,7 @@ describe("workflowStore integration tests", () => {
}); });
describe("createGroup bounding box calculation", () => { describe("createGroup bounding box calculation", () => {
it("should correctly calculate bounding box for easeCurve nodes (340x280)", () => { it("should correctly calculate bounding box for easeCurve nodes (340x260)", () => {
useWorkflowStore.setState({ useWorkflowStore.setState({
nodes: [ nodes: [
createTestNode("ease-1", "easeCurve", { createTestNode("ease-1", "easeCurve", {
@ -2173,13 +2173,13 @@ describe("workflowStore integration tests", () => {
expect(groupId).toBeTruthy(); expect(groupId).toBeTruthy();
const group = useWorkflowStore.getState().groups[groupId]; const group = useWorkflowStore.getState().groups[groupId];
// easeCurve is 340x280, so maxX = 500 + 340 = 840, maxY = 100 + 280 = 380 // easeCurve is 340x260, so maxX = 500 + 340 = 840, maxY = 100 + 260 = 360
// With padding=20: position.x = 100-20=80, width = 840-100+40=780 // With padding=20: position.x = 100-20=80, width = 840-100+40=780
expect(group.size.width).toBeGreaterThanOrEqual(740); // Must account for 340px wide nodes expect(group.size.width).toBeGreaterThanOrEqual(740); // Must account for 340px wide nodes
expect(group.size.height).toBeGreaterThanOrEqual(280); // Must account for 280px tall nodes expect(group.size.height).toBeGreaterThanOrEqual(260); // Must account for 260px tall nodes
}); });
it("should correctly calculate bounding box for videoStitch nodes (400x280)", () => { it("should correctly calculate bounding box for videoStitch nodes (420x280)", () => {
useWorkflowStore.setState({ useWorkflowStore.setState({
nodes: [ nodes: [
createTestNode("vs-1", "videoStitch", { createTestNode("vs-1", "videoStitch", {
@ -2208,8 +2208,8 @@ describe("workflowStore integration tests", () => {
const groupId = store.createGroup(["vs-1"]); const groupId = store.createGroup(["vs-1"]);
const group = useWorkflowStore.getState().groups[groupId]; const group = useWorkflowStore.getState().groups[groupId];
// videoStitch is 400x280, with padding=20: width = 400+40=440 // videoStitch is 420x280, with padding=20: width = 420+40=460
expect(group.size.width).toBeGreaterThanOrEqual(400); // Must account for 400px wide node expect(group.size.width).toBeGreaterThanOrEqual(420); // Must account for 420px wide node
expect(group.size.height).toBeGreaterThanOrEqual(280); // Must account for 280px tall node expect(group.size.height).toBeGreaterThanOrEqual(280); // Must account for 280px tall node
}); });
@ -2241,7 +2241,7 @@ describe("workflowStore integration tests", () => {
expect(imageNode?.position).toEqual({ x: 0, y: 0 }); expect(imageNode?.position).toEqual({ x: 0, y: 0 });
}); });
it("should correctly calculate bounding box for audioInput nodes (300x200)", () => { it("should correctly calculate bounding box for audioInput nodes (320x180)", () => {
useWorkflowStore.setState({ useWorkflowStore.setState({
nodes: [ nodes: [
createTestNode("audio-1", "audioInput", { createTestNode("audio-1", "audioInput", {
@ -2259,9 +2259,9 @@ describe("workflowStore integration tests", () => {
const groupId = store.createGroup(["audio-1"]); const groupId = store.createGroup(["audio-1"]);
const group = useWorkflowStore.getState().groups[groupId]; const group = useWorkflowStore.getState().groups[groupId];
// audioInput is 300x200, with padding=20: width = 300+40=340 // audioInput is 320x180, with padding=20: width = 320+40=360
expect(group.size.width).toBeGreaterThanOrEqual(300); expect(group.size.width).toBeGreaterThanOrEqual(320);
expect(group.size.height).toBeGreaterThanOrEqual(200); expect(group.size.height).toBeGreaterThanOrEqual(180);
}); });
it("should replace selected existing groups when creating a new group", () => { it("should replace selected existing groups when creating a new group", () => {

4
src/utils/__tests__/nodeSizing.test.ts

@ -30,7 +30,7 @@ describe("resolveNodeAutoSize", () => {
aspectRatio: "9:16", aspectRatio: "9:16",
dimensions: null, dimensions: null,
}) })
).toEqual({ width: 203, height: 360 }); ).toEqual({ width: 346, height: 615 });
}); });
it("reads model ratio from parameters when no media url exists", () => { it("reads model ratio from parameters when no media url exists", () => {
@ -39,7 +39,7 @@ describe("resolveNodeAutoSize", () => {
outputVideo: null, outputVideo: null,
parameters: { ratio: "16:9" }, parameters: { ratio: "16:9" },
}) })
).toEqual({ width: 360, height: 203 }); ).toEqual({ width: 615, height: 346 });
}); });
}); });

26
src/utils/nodeDimensions.ts

@ -193,28 +193,20 @@ export function calculateMediaNodeSizeByShortSide(
}; };
} }
const GENERATION_NODE_SIZE_BY_ASPECT_RATIO: Record<string, { width: number; height: number }> = { function parseAspectRatioValue(value: string): number | null {
"1:1": { width: 300, height: 300 }, const [widthText, heightText] = value.trim().split(":");
"16:9": { width: 360, height: 203 }, const width = Number(widthText);
"9:16": { width: 203, height: 360 }, const height = Number(heightText);
"21:9": { width: 420, height: 180 }, if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
"2:3": { width: 227, height: 340 }, return width / height;
"3:2": { width: 340, height: 227 }, }
"3:4": { width: 255, height: 340 },
"4:3": { width: 340, height: 255 },
"4:5": { width: 256, height: 320 },
"5:4": { width: 320, height: 256 },
"1:4": { width: 140, height: 420 },
"4:1": { width: 420, height: 140 },
"1:8": { width: 100, height: 420 },
"8:1": { width: 420, height: 100 },
};
export function getGenerationNodeSizeForAspectRatio( export function getGenerationNodeSizeForAspectRatio(
value: unknown value: unknown
): { width: number; height: number } | null { ): { width: number; height: number } | null {
if (typeof value !== "string") return null; if (typeof value !== "string") return null;
return GENERATION_NODE_SIZE_BY_ASPECT_RATIO[value.trim()] ?? null; const aspectRatio = parseAspectRatioValue(value);
return aspectRatio ? calculateMediaNodeSizeByShortSide(aspectRatio) : null;
} }
// Node sizing constraints // Node sizing constraints

Loading…
Cancel
Save