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>
This commit is contained in:
2026-07-09 12:27:00 +08:00
parent 039d166972
commit a1503a1687
9 changed files with 613 additions and 94 deletions
@@ -11,6 +11,7 @@ import type {
DeleteProjectsResponse,
ExtractNodeTextResponse,
GeneratorTaskResponse,
GeneratorTaskSubmitResponse,
GenerateResult,
MergeLayersRequest,
NodeActionRequest,
@@ -358,6 +359,18 @@ export const designGateway = {
return request<GeneratorTaskResponse>(`/api/generator/tasks?${params.toString()}`);
},
submitGeneratorTask(projectId: string, generatorName: string, inputArgs: Record<string, unknown>) {
return request<GeneratorTaskSubmitResponse>("/api/generator/tasks", {
method: "POST",
body: JSON.stringify({
cid: createClientId(),
project_id: projectId,
generator_name: generatorName,
input_args: inputArgs
})
});
},
recognizeObject(imageUrl: string, boundingBox: NormalizedBox, lang = "zh") {
return request<RecognizeObjectResponse>("/api/context/vision/recognize_object", {
method: "POST",