From 0a0c8eb75c4182c5e687b4ebfb112a2f775ca95f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 18 Aug 2026 17:44:09 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80Inspector=E9=94=81=E5=AE=9A?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在Inspector根层提供共享只读状态与锁定视觉 禁用节点、素材、组件和九宫格的锁定态修改入口 同步更新UI Editor Inspector锁定态实施约定 --- .../Inspector/Components/ComponentPanel.tsx | 9 +- .../Inspector/InspectorReadOnlyContext.ts | 7 + .../components/Inspector/InspectorSidebar.tsx | 230 +++++++++++++----- .../SpriteBorder/SpriteBorderEditor.tsx | 16 +- .../SpriteBorder/SpriteBorderFields.tsx | 15 +- .../SpriteBorder/SpriteBorderGuideEditor.tsx | 9 + .../Inspector/Transform/TransformEditor.tsx | 19 +- ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 6 + 8 files changed, 220 insertions(+), 91 deletions(-) create mode 100644 apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorReadOnlyContext.ts diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ComponentPanel.tsx b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ComponentPanel.tsx index b6052efa1..081431a48 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ComponentPanel.tsx +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/Components/ComponentPanel.tsx @@ -10,6 +10,7 @@ import { useEffect, useState } from 'react'; import type { Component } from '../../../../../features/ui-editor/types/Component'; import type { UiEditorOperationResult } from '../../../../../features/ui-editor/useUiEditorState'; +import { useInspectorReadOnly } from '../InspectorReadOnlyContext'; import type { ComponentPanelProps } from './componentEditorTypes'; import { ImagePanel } from './ImagePanel'; import { createDefaultImageComponent } from './ImagePanelDefaults'; @@ -19,12 +20,14 @@ import { createDefaultTextComponent } from './TextPanelDefaults'; export function ComponentPanel(props: ComponentPanelProps) { const { components, - readOnly, + readOnly: propReadOnly, onSetComponents, onInsertComponent, onDeleteComponent, onMoveComponent, } = props; + const inspectorReadOnly = useInspectorReadOnly(); + const readOnly = propReadOnly || inspectorReadOnly; const [addKind, setAddKind] = useState<'Image' | 'Text'>('Image'); const [expandedIndexes, setExpandedIndexes] = useState>( () => new Set(), @@ -42,6 +45,7 @@ export function ComponentPanel(props: ComponentPanelProps) { }, [components.length]); const updateComponent = (index: number, next: Component) => { + if (readOnly) return undefined; const nextComponents = components.slice(); nextComponents[index] = next; const result = onSetComponents(nextComponents); @@ -51,6 +55,7 @@ export function ComponentPanel(props: ComponentPanelProps) { }; function addComponent() { + if (readOnly) return; let component: Component; switch (addKind) { case 'Image': @@ -70,6 +75,7 @@ export function ComponentPanel(props: ComponentPanelProps) { } function deleteComponentAt(index: number) { + if (readOnly) return; const result = onDeleteComponent(index); if (result?.ok) { setExpandedIndexes((current) => { @@ -88,6 +94,7 @@ export function ComponentPanel(props: ComponentPanelProps) { } function moveComponent(index: number, direction: 'up' | 'down') { + if (readOnly) return; // Components are rendered in array order. The last item therefore sits // visually at the top of the stack. let nextIndex: number; diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorReadOnlyContext.ts b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorReadOnlyContext.ts new file mode 100644 index 000000000..04c215a3a --- /dev/null +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorReadOnlyContext.ts @@ -0,0 +1,7 @@ +import { createContext, useContext } from 'react'; + +export const InspectorReadOnlyContext = createContext(false); + +export function useInspectorReadOnly() { + return useContext(InspectorReadOnlyContext); +} diff --git a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorSidebar.tsx b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorSidebar.tsx index d66efb0d4..e9b528a42 100644 --- a/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorSidebar.tsx +++ b/apps/ai-game-creator-shell/src/view/ui-editor/components/Inspector/InspectorSidebar.tsx @@ -1,4 +1,4 @@ -import { Boxes, Trash2 } from 'lucide-react'; +import { Boxes, LockKeyhole, Trash2, Unlock } from 'lucide-react'; import type { InputHTMLAttributes, ReactNode, @@ -12,6 +12,10 @@ import { uiEditorPrivateFontFamily } from '../../../../features/ui-editor/useUiE import { UI_DESIGN_IMAGE_ROLES } from '../../model'; import type { UiEditorPageController } from '../../useUiEditorPage'; import { ComponentPanel } from './Components/ComponentPanel'; +import { + InspectorReadOnlyContext, + useInspectorReadOnly, +} from './InspectorReadOnlyContext'; import { SpriteBorderEditor } from './SpriteBorder/SpriteBorderEditor'; import TransformEditor from './Transform/TransformEditor'; @@ -154,15 +158,37 @@ export function InspectorSidebar({ } return ( - + + + ); } @@ -264,13 +290,19 @@ function NodeInspector({ onDeleteComponent: UiEditorPageController['deleteNodeComponent']; onMoveComponent: UiEditorPageController['moveNodeComponent']; }) { + const inspectorReadOnly = useInspectorReadOnly(); + const isReadOnly = readOnly || inspectorReadOnly; + return (
@@ -280,12 +312,14 @@ function NodeInspector({ - onMetadataChange({ allow_llm_edit_layout: event.target.checked }) - } + disabled={isReadOnly} + onChange={(event) => { + if (!isReadOnly) { + onMetadataChange({ + allow_llm_edit_layout: event.target.checked, + }); + } + }} /> 允许 LLM 修改布局 @@ -368,12 +415,14 @@ function NodeInspector({ - onMetadataChange({ - allow_llm_edit_component: event.target.checked, - }) - } + disabled={isReadOnly} + onChange={(event) => { + if (!isReadOnly) { + onMetadataChange({ + allow_llm_edit_component: event.target.checked, + }); + } + }} /> 允许 LLM 修改组件 @@ -381,7 +430,7 @@ function NodeInspector({ void; }) { + const readOnly = useInspectorReadOnly(); const kind = typeof value === 'string' ? value @@ -424,8 +474,9 @@ function NodeStageSelect({ + ); } @@ -690,9 +776,15 @@ type InspectorInputProps = Omit< > & { label: string }; function InspectorTextarea({ label, ...props }: InspectorTextareaProps) { + const readOnly = useInspectorReadOnly(); return ( -