Fix text module composer replica
This commit is contained in:
parent
37b7e58f2a
commit
193b03d677
@ -387,6 +387,8 @@ const OFFICIAL_ZOOM_DOCK_SCALE = 0.5;
|
||||
const PROMPT_COMPOSER_BASE_WIDTH = 895;
|
||||
const PROMPT_COMPOSER_BASE_HEIGHT = 286;
|
||||
const PRESET_COMPOSER_BASE_HEIGHT = 238;
|
||||
const TEXT_MODULE_COMPOSER_WIDTH = 1274;
|
||||
const TEXT_MODULE_COMPOSER_HEIGHT = 270;
|
||||
const MULTI_VIEW_NINE_GRID_PROMPT =
|
||||
"以选中图片为角色/主体参考,生成多视角 3x3 九宫格分镜图。保持主体一致,九个镜头包含远景、全身、侧身、背面、半身、近景、局部细节等视角,使用清晰黑色分割线分隔每一格,白色或干净背景。";
|
||||
const NINE_GRID_CELL_VISUALS: GridCellVisual[] = [
|
||||
@ -2080,23 +2082,15 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
|
||||
|
||||
switch (actionLabel) {
|
||||
case "自己编写内容": {
|
||||
anchorUpdates = {
|
||||
kind: "script",
|
||||
title: "文本",
|
||||
subtitle: "文本资源",
|
||||
inputType: "text",
|
||||
width: OFFICIAL_TEXT_RESOURCE_WIDTH,
|
||||
height: OFFICIAL_TEXT_RESOURCE_HEIGHT,
|
||||
};
|
||||
draftUpdates = {
|
||||
action: "TEXT_RESOURCE",
|
||||
content: [],
|
||||
action: "TEXT_GENERATE",
|
||||
content: Array.isArray(anchor.draftValues?.content) ? anchor.draftValues?.content : [],
|
||||
manualEditing: true,
|
||||
manualTextComposer: true,
|
||||
nodeType: "text",
|
||||
scriptRole: "resource",
|
||||
viewMode: undefined,
|
||||
};
|
||||
toast.success("已切换为文本编写节点");
|
||||
selectedId = anchor.id;
|
||||
toast.success("已打开文本编写对话框");
|
||||
break;
|
||||
}
|
||||
case "文生视频": {
|
||||
@ -3321,6 +3315,8 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
|
||||
const selectedPresetControlNode = isOfficialImageControlNode(selectedNode) ? selectedNode : null;
|
||||
const selectedPresetMode = getPresetMode(selectedPresetControlNode);
|
||||
const selectedTargetModuleKind = selectedNode ? getTargetModuleKind(selectedNode) : null;
|
||||
const selectedTextResourceNode =
|
||||
selectedNode && getDraftString(selectedNode, "action") === "TEXT_RESOURCE" ? selectedNode : null;
|
||||
const selectedPresetAnchor = useMemo<PresetControlAnchor | null>(() => {
|
||||
if (!selectedPresetControlNode) return null;
|
||||
return {
|
||||
@ -3330,6 +3326,15 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
|
||||
zoom: viewport.zoom,
|
||||
};
|
||||
}, [selectedPresetControlNode, viewport.x, viewport.y, viewport.zoom]);
|
||||
const selectedTargetAnchor = useMemo<PresetControlAnchor | null>(() => {
|
||||
if (!selectedNode || !selectedTargetModuleKind) return null;
|
||||
return {
|
||||
bottomY: Math.round(viewport.y + (selectedNode.y + selectedNode.height) * viewport.zoom),
|
||||
centerX: Math.round(viewport.x + (selectedNode.x + selectedNode.width / 2) * viewport.zoom),
|
||||
topY: Math.round(viewport.y + selectedNode.y * viewport.zoom),
|
||||
zoom: viewport.zoom,
|
||||
};
|
||||
}, [selectedNode, selectedTargetModuleKind, viewport.x, viewport.y, viewport.zoom]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -3459,6 +3464,35 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{selectedNode && selectedTargetModuleKind === "text" && selectedTargetAnchor ? (
|
||||
<TextTargetModuleComposer
|
||||
anchor={selectedTargetAnchor}
|
||||
node={selectedNode}
|
||||
onSubmit={(prompt) => {
|
||||
setNodes((current) =>
|
||||
current.map((node) =>
|
||||
node.id === selectedNode.id
|
||||
? {
|
||||
...node,
|
||||
draftValues: {
|
||||
...(node.draftValues || {}),
|
||||
content: prompt ? [prompt] : [],
|
||||
manualEditing: true,
|
||||
manualTextComposer: true,
|
||||
params: {
|
||||
...((node.draftValues?.params as Record<string, unknown> | undefined) || {}),
|
||||
prompt,
|
||||
},
|
||||
},
|
||||
}
|
||||
: node
|
||||
)
|
||||
);
|
||||
toast.success("文本内容已写入当前模块");
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<TopBar
|
||||
draftTitle={draftTitle}
|
||||
isTitleEditing={isTitleEditing}
|
||||
@ -3514,7 +3548,7 @@ export function LiblibVideoCanvasReplica({ canvasId, isLoading = false }: Liblib
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{selectedNode && !selectedPresetControlNode && !selectedTargetModuleKind ? (
|
||||
{selectedNode && !selectedPresetControlNode && !selectedTargetModuleKind && !selectedTextResourceNode ? (
|
||||
<InspectorPanel
|
||||
node={selectedNode}
|
||||
onChangeProperty={updateNodeDraft}
|
||||
@ -4242,6 +4276,67 @@ function PresetWorkflowControls({
|
||||
);
|
||||
}
|
||||
|
||||
function TextTargetModuleComposer({
|
||||
anchor,
|
||||
node,
|
||||
onSubmit,
|
||||
}: {
|
||||
anchor: PresetControlAnchor;
|
||||
node: CloneNode;
|
||||
onSubmit: (prompt: string) => void;
|
||||
}) {
|
||||
const contentValues = node.draftValues?.content;
|
||||
const initialPrompt =
|
||||
Array.isArray(contentValues) && typeof contentValues[0] === "string" ? contentValues[0] : "";
|
||||
const [prompt, setPrompt] = useState(initialPrompt);
|
||||
|
||||
useEffect(() => {
|
||||
setPrompt(initialPrompt);
|
||||
}, [initialPrompt, node.id]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="pointer-events-auto absolute z-30 overflow-visible"
|
||||
data-canvas-overlay="true"
|
||||
style={{
|
||||
height: TEXT_MODULE_COMPOSER_HEIGHT,
|
||||
left: anchor.centerX,
|
||||
top: anchor.bottomY + 24,
|
||||
transform: "translateX(-50%)",
|
||||
width: TEXT_MODULE_COMPOSER_WIDTH,
|
||||
}}
|
||||
>
|
||||
<div className="relative h-[270px] w-[1274px] rounded-[16px] border border-white/8 bg-[#262626]/98 p-6 text-white shadow-[0_24px_84px_rgba(0,0,0,0.48)]">
|
||||
<textarea
|
||||
className="h-[148px] w-full resize-none bg-transparent text-[24px] leading-[34px] text-white/74 outline-none placeholder:text-white/40"
|
||||
onChange={(event) => setPrompt(event.target.value)}
|
||||
onPointerDown={(event) => event.stopPropagation()}
|
||||
placeholder="写下你想讲的故事、场景或角色设定。例如:一个来自未来的机器人,在城市屋顶看星星。"
|
||||
value={prompt}
|
||||
/>
|
||||
<div className="absolute bottom-5 left-6 right-[86px] flex items-center gap-8 overflow-hidden text-[24px] text-white/82">
|
||||
<ComposerControl
|
||||
label="GVLM 3.1"
|
||||
icon="⌘"
|
||||
dropdown
|
||||
onClick={() => toast.info("文本模型选择后端待接入。")}
|
||||
/>
|
||||
<div className="min-w-0 flex-1" />
|
||||
<ComposerControl label="文" onClick={() => toast.info("翻译接口待接入。")} />
|
||||
<ComposerControl label="6" icon="⚡" muted onClick={() => toast.info("积分估算接入本地积分系统。")} />
|
||||
</div>
|
||||
<button
|
||||
className="absolute bottom-5 right-5 flex h-14 w-14 items-center justify-center rounded-[14px] bg-white/76 text-[34px] leading-none text-black transition hover:bg-white"
|
||||
onClick={() => onSubmit(prompt)}
|
||||
type="button"
|
||||
>
|
||||
↑
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function CharacterPresetToolbar({
|
||||
anchor,
|
||||
onToolAction,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user