fix: stabilize flow board node insertion
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-04-11 23:36:46 +08:00
parent 3ad76b5c54
commit 0870739a7d
3 changed files with 58 additions and 60 deletions

View File

@ -359,6 +359,7 @@ function buildEnhanceSourcePayload(
interface EnhanceProWorkspaceProps {
sourceImageUrl?: string | null;
onRequestAddImage?: () => void;
onApplyResult: (payload: {
imageUrl: string;
prompt: string;
@ -371,6 +372,7 @@ interface EnhanceProWorkspaceProps {
export function EnhanceProWorkspace({
sourceImageUrl,
onRequestAddImage,
onApplyResult,
}: EnhanceProWorkspaceProps) {
const [isSubmitting, setIsSubmitting] = useState(false);
@ -734,47 +736,21 @@ export function EnhanceProWorkspace({
</div>
</div>
) : (
<div className="relative w-full max-w-[42rem] px-6">
<div className="relative rounded-[38px] border border-[#e6e6e6] bg-white px-8 py-8 shadow-[0_0_0_1px_rgba(0,0,0,0.03),0_30px_60px_rgba(0,0,0,0.06)] backdrop-blur-sm">
<div className="flex items-start gap-4">
<div className="flex h-16 w-16 shrink-0 items-center justify-center rounded-[24px] border border-[#ececec] bg-[#fafafa] text-[#111111] shadow-[0_14px_28px_rgba(0,0,0,0.06)]">
<Sparkles className="h-8 w-8" />
</div>
<div className="min-w-0 text-left">
<div className={SECTION_EYEBROW_CLASS}>Enhance Pro Studio</div>
<div className="mt-3 font-semibold text-[34px] tracking-[-0.05em] text-[#111111] leading-[1.02]">
还没有可增强的图片
</div>
<div className="mt-3 max-w-[30rem] text-[#666666] text-[15px] leading-7">
先在主画布里选中一张图片,或者先在实时画布模式里生成结果,
再切回这里进行精修、增强和细节重建。
</div>
</div>
</div>
<div className="mt-7 grid gap-3 md:grid-cols-2">
<div className="rounded-[24px] border border-[#efefef] bg-[#fafafa] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.92)]">
<div className="text-[11px] font-semibold tracking-[0.16em] text-[#666666] uppercase">
Step 01
</div>
<div className="mt-2 font-semibold text-[18px] tracking-[-0.03em] text-[#111111]">
选中一张图
</div>
<div className="mt-1 text-[13px] leading-6 text-[#666666]">
从主画布中选择要增强的图片,系统会自动把它带入当前工作台。
</div>
</div>
<div className="rounded-[24px] border border-[#efefef] bg-[#fafafa] p-4 shadow-[inset_0_1px_0_rgba(255,255,255,0.92)]">
<div className="text-[11px] font-semibold tracking-[0.16em] text-[#666666] uppercase">
Step 02
</div>
<div className="mt-2 font-semibold text-[18px] tracking-[-0.03em] text-[#111111]">
调参后开始增强
</div>
<div className="mt-1 text-[13px] leading-6 text-[#666666]">
使用右侧工具卡片快速选择模式、强度和增强范围,生成后可直接发回画布。
</div>
</div>
</div>
<div className="relative flex flex-col items-center justify-center gap-3 px-6 text-center">
<Button
className={cn(
"h-14 rounded-[22px] px-8 text-[15px] font-semibold tracking-[-0.02em]",
PRIMARY_ACTION_BUTTON_CLASS
)}
disabled={!onRequestAddImage}
onClick={onRequestAddImage}
type="button"
>
<ImageIcon className="mr-2 h-5 w-5" />
添加图片
</Button>
<div className="text-[#666666] text-[13px] leading-6">
选择本地图片后即可开始图像增强 Pro
</div>
</div>
)}

View File

@ -3336,9 +3336,27 @@ export function RealtimeCanvasDialog({
</div>
) : null}
<input
accept="image/*"
className="hidden"
multiple
onChange={handleSketchUpload}
ref={uploadInputRef}
type="file"
/>
<input
accept="image/*"
className="hidden"
multiple
onChange={handleLayerSplitUpload}
ref={splitUploadInputRef}
type="file"
/>
{workspaceMode === "enhance-pro" ? (
<EnhanceProWorkspace
onApplyResult={handleApplyEnhanceResult}
onRequestAddImage={() => uploadInputRef.current?.click()}
sourceImageUrl={enhanceSourceImageUrl}
/>
) : (
@ -3592,22 +3610,6 @@ export function RealtimeCanvasDialog({
</div>
</div>
<input
accept="image/*"
className="hidden"
multiple
onChange={handleSketchUpload}
ref={uploadInputRef}
type="file"
/>
<input
accept="image/*"
className="hidden"
multiple
onChange={handleLayerSplitUpload}
ref={splitUploadInputRef}
type="file"
/>
<div className="-translate-x-1/2 pointer-events-none absolute bottom-4 left-1/2 z-30 flex w-[min(600px,calc(100vw-2rem))] flex-col items-center gap-2.5">
<TooltipProvider delayDuration={120}>
<div

View File

@ -319,9 +319,20 @@ function normalizeFlowBoardElementText(element: unknown): PlaitElement {
}
function normalizeFlowBoardChildren(children: unknown): PlaitElement[] {
return Array.isArray(children)
? children.map((element) => normalizeFlowBoardElementText(element))
: [];
if (!Array.isArray(children)) {
return [];
}
let changed = false;
const nextChildren = children.map((element) => {
const nextElement = normalizeFlowBoardElementText(element);
if (nextElement !== element) {
changed = true;
}
return nextElement;
});
return changed ? nextChildren : (children as PlaitElement[]);
}
function seedFlowBoardDefaultTextColor() {
@ -1009,6 +1020,9 @@ export function DrawnixWorkspace({
const handleValueChange = useCallback(
(children: PlaitElement[]) => {
if (snapshotRef.current.children === children) {
return;
}
updateSnapshot({ children });
refreshMarkerSelectionState();
},
@ -1017,6 +1031,9 @@ export function DrawnixWorkspace({
const handleViewportChange = useCallback(
(viewport: Viewport) => {
if (snapshotRef.current.viewport === viewport) {
return;
}
updateSnapshot({ viewport });
},
[updateSnapshot]
@ -1024,6 +1041,9 @@ export function DrawnixWorkspace({
const handleThemeChange = useCallback(
(themeColorMode: ThemeColorMode) => {
if (snapshotRef.current.theme?.themeColorMode === themeColorMode) {
return;
}
updateSnapshot({ theme: { themeColorMode } });
},
[updateSnapshot]