refactor: extract canvas marking popover

This commit is contained in:
2026-06-05 18:19:24 +08:00
parent d68064f529
commit d09e5e673e
2 changed files with 75 additions and 82 deletions
@@ -0,0 +1,40 @@
interface CanvasMarkingPopoverProps {
value?: string;
placeholder: string;
onChange: (value: string) => void;
onClear: () => void;
onDone: () => void;
}
export function CanvasMarkingPopover({
value,
placeholder,
onChange,
onClear,
onDone,
}: CanvasMarkingPopoverProps) {
return (
<div
className="studio-canvas-marking-popover"
onMouseDown={(event) => event.stopPropagation()}
onClick={(event) => event.stopPropagation()}
>
<textarea
className="studio-canvas-marking-input"
placeholder={placeholder}
value={value || ""}
onChange={(event) => onChange(event.target.value)}
/>
<div className="studio-canvas-marking-actions">
{value ? (
<button type="button" className="studio-canvas-marking-clear" onClick={onClear}>
</button>
) : null}
<button type="button" className="studio-canvas-marking-done" onClick={onDone}>
</button>
</div>
</div>
);
}
+35 -82
View File
@@ -186,6 +186,7 @@ import {
} from "./canvasWorkflowDeserialize";
import { CanvasNodeToolbar, CanvasNodeVideoPlayer, CanvasSelectChip } from "./canvasComponents";
import type { CanvasNodeToolbarAction } from "./canvasComponents";
import { CanvasMarkingPopover } from "./CanvasMarkingPopover";
import { CanvasPromptMentionTextarea, CanvasTextPromptComposer } from "./CanvasTextPromptComposer";
import { CanvasMultiGridPanel, CanvasUpscalePanel, CanvasInpaintPanel } from "./canvasToolPanels";
import { CanvasSmoothedProgressRing } from "./CanvasSmoothedProgressRing";
@@ -4472,47 +4473,23 @@ function CanvasPage({
>
<FileImageOutlined /><span></span>
</button>
{markingPopoverNodeId === imageNode.id && (
<div
className="studio-canvas-marking-popover"
onMouseDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
>
<textarea
className="studio-canvas-marking-input"
placeholder="描述标记内容,如:主角站在桥上,远处是城市天际线"
value={imageNode.marking || ""}
onChange={(e) => {
const val = e.target.value;
setImageNodes((nodes) =>
nodes.map((n) => (n.id === imageNode.id ? { ...n, marking: val } : n)),
);
}}
/>
<div className="studio-canvas-marking-actions">
{imageNode.marking && (
<button
type="button"
className="studio-canvas-marking-clear"
onClick={() => {
setImageNodes((nodes) =>
nodes.map((n) => (n.id === imageNode.id ? { ...n, marking: "" } : n)),
);
}}
>
</button>
)}
<button
type="button"
className="studio-canvas-marking-done"
onClick={() => setMarkingPopoverNodeId(null)}
>
</button>
</div>
</div>
)}
{markingPopoverNodeId === imageNode.id ? (
<CanvasMarkingPopover
value={imageNode.marking}
placeholder="描述标记内容,如:主角站在桥上,远处是城市天际线"
onChange={(value) => {
setImageNodes((nodes) =>
nodes.map((node) => (node.id === imageNode.id ? { ...node, marking: value } : node)),
);
}}
onClear={() => {
setImageNodes((nodes) =>
nodes.map((node) => (node.id === imageNode.id ? { ...node, marking: "" } : node)),
);
}}
onDone={() => setMarkingPopoverNodeId(null)}
/>
) : null}
<button
type="button"
title="多宫格生成"
@@ -4843,47 +4820,23 @@ function CanvasPage({
>
{videoNode.cameraMotion ? ` ${CAMERA_MOTION_PRESETS.find((p) => p.value === videoNode.cameraMotion)?.label || ""}` : ""}
</button>
{markingPopoverNodeId === videoNode.id && (
<div
className="studio-canvas-marking-popover"
onMouseDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
>
<textarea
className="studio-canvas-marking-input"
placeholder="描述标记内容,如:主角在城市街头行走"
value={videoNode.marking || ""}
onChange={(e) => {
const val = e.target.value;
setVideoNodes((nodes) =>
nodes.map((n) => (n.id === videoNode.id ? { ...n, marking: val } : n)),
);
}}
/>
<div className="studio-canvas-marking-actions">
{videoNode.marking && (
<button
type="button"
className="studio-canvas-marking-clear"
onClick={() => {
setVideoNodes((nodes) =>
nodes.map((n) => (n.id === videoNode.id ? { ...n, marking: "" } : n)),
);
}}
>
</button>
)}
<button
type="button"
className="studio-canvas-marking-done"
onClick={() => setMarkingPopoverNodeId(null)}
>
</button>
</div>
</div>
)}
{markingPopoverNodeId === videoNode.id ? (
<CanvasMarkingPopover
value={videoNode.marking}
placeholder="描述标记内容,如:主角在城市街头行走"
onChange={(value) => {
setVideoNodes((nodes) =>
nodes.map((node) => (node.id === videoNode.id ? { ...node, marking: value } : node)),
);
}}
onClear={() => {
setVideoNodes((nodes) =>
nodes.map((node) => (node.id === videoNode.id ? { ...node, marking: "" } : node)),
);
}}
onDone={() => setMarkingPopoverNodeId(null)}
/>
) : null}
{cameraMotionDropdownNodeId === videoNode.id && (
<div
className="studio-canvas-camera-dropdown"