diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/PreviewWorkspace.tsx b/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/PreviewWorkspace.tsx index 33e636ce2..9e0ce683d 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/PreviewWorkspace.tsx +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/preview/PreviewWorkspace.tsx @@ -45,6 +45,7 @@ export function PreviewWorkspace({ const [spaceHeld, setSpaceHeld] = useState(false); const [renderMode, setRenderMode] = useState('editor-overlay'); + const [showFrame, setShowFrame] = useState(false); const tree = controller.treeForActiveImage ?? null; const logicalSize = useMemo(() => { if (!activeImage) return null; @@ -293,6 +294,16 @@ export function PreviewWorkspace({ 最终预览 + {renderMode === 'final-preview' ? ( + + ) : null} {Object.keys(controller.images).length} 张界面图 ·{' '} {Object.keys(controller.sprites).length} 项素材 @@ -352,6 +363,7 @@ export function PreviewWorkspace({ ; selectedNodeId: NodeId | null; resources: PreviewComponentResources; @@ -57,6 +58,7 @@ function RenderNode({ node, isRoot, renderMode, + showFrame, hiddenNodeIds, selectedNodeId, resources, @@ -80,6 +82,7 @@ function RenderNode({ } const isEditorOverlay = renderMode === 'editor-overlay'; + const isFrameVisible = isEditorOverlay || showFrame; const exclusiveVisibleChildId = node.children_display_mode === 'Exclusive' ? (node.children.find((child) => !hiddenNodeIds.has(child.id))?.id ?? @@ -91,7 +94,7 @@ function RenderNode({ className={`absolute min-h-0 min-w-0 ${isRoot ? 'cursor-default' : 'cursor-move'}`} style={{ ...geometry, - ...(isEditorOverlay + ...(isFrameVisible ? { outline: selectedNodeId === node.id @@ -113,9 +116,9 @@ function RenderNode({ onPointerMove={onNodePointerMove} onPointerUp={onNodePointerUp} onPointerCancel={onNodePointerUp} - title={isEditorOverlay ? node.metadata.name || undefined : undefined} + title={isFrameVisible ? node.metadata.name || undefined : undefined} > - {isEditorOverlay && node.metadata.name ? ( + {isFrameVisible && node.metadata.name ? ( {node.metadata.name} @@ -134,6 +137,7 @@ function RenderNode({ key={child.id} node={child} renderMode={renderMode} + showFrame={showFrame} hiddenNodeIds={hiddenNodeIds} selectedNodeId={selectedNodeId} resources={resources} @@ -148,7 +152,7 @@ function RenderNode({ /> ), )} - {isEditorOverlay && !isRoot && selectedNodeId === node.id + {isFrameVisible && !isRoot && selectedNodeId === node.id ? RESIZE_HANDLES.map((handle) => (
, + options: { showFrame?: boolean; selectedNodeId?: string | null } = {}, ) { return render( { + it('shows final-preview node frames and resize handles only when requested', () => { + const withoutFrames = renderTree('final-preview', new Set(), { + selectedNodeId: 'child', + }); + const plainChild = withoutFrames.container.querySelector( + '[data-node-id="child"]', + ) as HTMLDivElement; + expect(plainChild.style.outline).toBe(''); + expect(screen.queryByLabelText('nw 调整控制点')).toBeNull(); + withoutFrames.unmount(); + + const withFrames = renderTree('final-preview', new Set(), { + showFrame: true, + selectedNodeId: 'child', + }); + const framedChild = withFrames.container.querySelector( + '[data-node-id="child"]', + ) as HTMLDivElement; + expect(framedChild.style.outline).toBe('2px solid rgb(249 115 22)'); + expect(screen.getByText('child')).toBeTruthy(); + expect(screen.getAllByLabelText(/调整控制点$/)).toHaveLength(8); + }); + it('hides a node subtree in editor overlay and final preview', () => { const editorOverlay = renderTree('editor-overlay', new Set(['child'])); expect( @@ -98,6 +123,7 @@ describe('UI tree preview visibility', () => {