Files
moteva/frontend/src/domain/design.ts
T
root a1503a1687 feat(canvas): frame-based layer separation UI
Render and manage the separated layers produced by the edit-elements
action as a manual-frame container with attached image and text
children.

- canvasNodeOps: frame container/child helpers, render ordering,
  auto-attach nodes to containing frames, and layer reordering
- CanvasWorkspace wires frame-aware selection, drag, resize, hide/lock,
  and layer reorder through the new ops
- CanvasPanels: expandable layer tree with rename/reorder
- designGateway.submitGeneratorTask + GeneratorTaskSubmitResponse and
  bbox/generator_name artifact metadata in the domain
- ArtboardPreview shows a working state for generating frame layers
- i18n: expandLayer / renameLayer / layerTitlePlaceholder; styles

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 12:27:00 +08:00

363 lines
6.7 KiB
TypeScript

export type CanvasViewport = {
x: number;
y: number;
k: number;
};
export type CanvasNodeType = "brief" | "reference" | "image" | "text" | "frame";
export type CanvasNode = {
id: string;
type: CanvasNodeType;
title: string;
x: number;
y: number;
width: number;
height: number;
content: string;
tone: string;
status: string;
parentId?: string;
layerRole?: string;
fontSize?: number;
fontFamily?: string;
fontWeight?: string;
color?: string;
textAlign?: "left" | "center" | "right";
lineHeight?: number;
letterSpacing?: number;
textDecoration?: string;
textTransform?: string;
opacity?: number;
fillColor?: string;
strokeColor?: string;
strokeWidth?: number;
strokeStyle?: string;
flipX?: boolean;
flipY?: boolean;
rotation?: number;
imageAdjustments?: string;
mockupSurface?: MockupSurface;
mockupModel?: MockupModel;
mockupSourceContent?: string;
};
export type CanvasConnection = {
id: string;
fromNodeId: string;
toNodeId: string;
};
export type AgentMessage = {
id: string;
role: "user" | "assistant" | "system" | "tool" | "error";
type?: string;
title: string;
content: string;
threadId?: string;
actionId?: string;
stepId?: string;
toolCallId?: string;
name?: string;
toolHint?: string;
status?: string;
createdAt: string;
};
export type ProjectSummary = {
id: string;
userId?: string;
title: string;
brief: string;
status: string;
thumbnail: string;
updatedAt: string;
};
export type Project = ProjectSummary & {
version: string;
snapshotId: string;
canvas: string;
lastThreadId: string;
viewport: CanvasViewport;
nodes: CanvasNode[];
connections: CanvasConnection[];
messages: AgentMessage[];
};
export type QuickAction = {
id: string;
label: string;
prompt: string;
icon: string;
};
export type InspirationItem = {
id: string;
title: string;
category: string;
description: string;
accent: string;
};
export type Dashboard = {
credits: number;
quickActions: QuickAction[];
projects: ProjectSummary[];
inspiration: InspirationItem[];
};
export type ProjectListResponse = {
projects: ProjectSummary[];
nextOffset: number;
hasMore: boolean;
};
export type GenerateResult = {
project: Project;
message: AgentMessage;
generatedNodes: CanvasNode[];
};
export type NormalizedBox = {
x: number;
y: number;
width: number;
height: number;
};
export type RecognizeObjectResponse = {
id: string;
label: string;
confidence: number;
bbox: NormalizedBox;
};
export type GeneratorTaskInputArgs = {
aspect_ratio?: string;
image?: string[];
image_url?: string;
prompt?: string;
resolution?: string;
src_box?: NormalizedBox;
dst_box?: NormalizedBox;
};
export type GeneratorTaskArtifact = {
type: string;
content: string;
metadata: {
artifact_id?: string;
bbox?: number[];
format?: string;
generator_name?: string;
height?: number;
label?: string;
node_id?: string;
node_name?: string;
size_bytes?: number;
width?: number;
};
};
export type GeneratorTaskResponse = {
code: number;
message: string;
data: {
generator_task_id: string;
generator_name: string;
status: "submitted" | "completed" | "failed" | string;
original_input_args: GeneratorTaskInputArgs;
queue_info?: {
in_queue: boolean;
position: number;
total_queue_count: number;
estimated_end_time: string;
remaining_time_seconds: number;
};
artifacts?: GeneratorTaskArtifact[];
};
};
export type GeneratorTaskSubmitResponse = {
code: number;
message: string;
data: {
generator_task_id: string;
};
};
export type DeleteProjectResponse = {
id: string;
deleted: boolean;
};
export type DeleteProjectsResponse = {
deleted: number;
};
export type NodeActionRequest = {
action:
| "quick-edit"
| "upscale"
| "remove-background"
| "eraser"
| "edit-elements"
| "edit-text"
| "multi-angle"
| "move-object"
| "mockup"
| "expand"
| "adjust"
| "crop"
| "vectorize";
prompt?: string;
imageModel?: string;
imageSize?: string;
mask?: string;
selection?: string;
options?: Record<string, string>;
};
export type MockupPlacement = {
x: number;
y: number;
width: number;
height: number;
};
export type MockupPoint = {
x: number;
y: number;
};
export type MockupSurface = {
targetId: string;
polygon: MockupPoint[];
mesh?: MockupMesh;
};
export type MockupMesh = {
columns: number;
rows: number;
points: MockupPoint[];
};
export type MockupModelMap = {
dataId: string;
width: number;
height: number;
url?: string;
data?: number[];
};
export type MockupCameraIntrinsics = {
matrix: number[];
};
export type MockupModel = {
version: number;
depthMap: MockupModelMap;
depthScaleMin: number;
depthScaleMax: number;
shadeMap: MockupModelMap;
segmentationMap: MockupModelMap;
xOffsetMap: MockupModelMap;
yOffsetMap: MockupModelMap;
cameraIntrinsics: MockupCameraIntrinsics;
colorCorrection: string;
foregroundImage: string;
};
export type MockupModelResponse = {
code: number;
data: MockupModel;
msg: string;
};
export type ExtractedTextLayer = {
text: string;
originalText?: string;
x: number;
y: number;
width: number;
height: number;
fontSize?: number;
fontFamily?: string;
fontWeight?: string;
color?: string;
textAlign?: "left" | "center" | "right";
lineHeight?: number;
letterSpacing?: number;
strokeColor?: string;
strokeWidth?: number;
opacity?: number;
rotation?: number;
confidence?: number;
};
export type ExtractNodeTextResponse = {
items: ExtractedTextLayer[];
};
export type TextExtractionSource = "eitdortxt" | "edit-text";
export type MergeLayersRequest = {
nodeIds: string[];
title?: string;
};
export type AgentContent =
| {
type: "text";
text: string;
textSource?: string;
}
| {
type: "image";
imageUrl: string;
imageName?: string;
imageWidth?: number;
imageHeight?: number;
};
export type AgentChatPayload = {
threadId?: string;
threadIdType?: number;
mode?: string;
imageModel?: string;
imageSize?: string;
enableWebSearch?: boolean;
messages: Array<{
role: "user";
contents: AgentContent[];
}>;
toolConfig?: {
preferToolCategories?: {
SEARCH?: string[];
IMAGE?: string[];
};
};
};
export type AgentThreadResponse = {
threadId: string;
status: string;
threadIdType: number;
eventsUrl: string;
project: Project;
};
export type AgentThreadSummary = {
agentThreadId: string;
coverImageUrl: string;
text: string;
threadIdType: number;
updateTimestamp: number;
};
export type AgentThreadListResponse = {
projectId: string;
threads: AgentThreadSummary[];
};