Compare commits

...

1 Commits

Author SHA1 Message Date
k88936 d4796a90ab 布局重构:
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / Frontend tests (pull_request) Successful in 2m49s
Project CI / Native shell tests (pull_request) Failing after 15m15s
- 预览改为全区域背景层。
  - 左右面板、顶部流程条改为覆盖层,可遮挡预览。
  - 左右面板开合状态仅保存在当前 React 会话。
  - 增加左右面板“收起/展开”入口。
  - 编辑器关闭入口改为单独的 ×,继续通过 onBack 注入关闭逻辑。
  - 保留全局顶部栏与现有快捷键、业务状态、保存流程。
  - 底层页面仍由现有父级路由控制,不新增 URL 状态。
2026-09-12 19:13:02 +08:00
@@ -1,4 +1,4 @@
import { ChevronLeft, Redo2, Undo2 } from 'lucide-react';
import { Redo2, Undo2, X } from 'lucide-react';
import { type ReactNode, useEffect, useMemo, useState } from 'react';
import { ThemedModal } from '../../components/modal/ThemedModal';
@@ -71,6 +71,8 @@ export default function UiEditorPage({
const [generateAfterWarning, setGenerateAfterWarning] = useState(false);
const [generateSuccess, setGenerateSuccess] = useState<string | null>(null);
const [returnConfirmOpen, setReturnConfirmOpen] = useState(false);
const [leftPanelOpen, setLeftPanelOpen] = useState(true);
const [rightPanelOpen, setRightPanelOpen] = useState(true);
const saveDisabled =
session.save.isSaving ||
session.save.isGenerating ||
@@ -162,16 +164,16 @@ export default function UiEditorPage({
}
return (
<main className="flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-(--platform-body-fill) text-(--platform-text-strong)">
<main className="relative flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-(--platform-body-fill) text-(--platform-text-strong)">
{resourceId ? (
<header className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-b border-(--platform-subpanel-border) bg-(--platform-subpanel-fill) px-4 py-2">
<button
type="button"
className="inline-flex items-center gap-1 rounded-lg px-2 py-1.5 text-sm hover:bg-black/4"
aria-label="关闭 UI 编辑器"
className="rounded-lg p-1.5 hover:bg-black/4"
onClick={requestBack}
>
<ChevronLeft size={17} aria-hidden="true" />
<X size={18} aria-hidden="true" />
</button>
<strong className="text-sm">{resourceLabel ?? 'UI 设计'}</strong>
<div className="game-workbench-editor-actions">
@@ -244,44 +246,69 @@ export default function UiEditorPage({
{generateSuccess}
</div>
) : null}
<ToolNavigation
activeStep={session.workflow.activeStep}
furthestStepIndex={session.workflow.furthestStepIndex}
disabled={session.workflow.isBusy}
onChange={session.workflow.requestStepChange}
/>
<div className="grid min-h-0 min-w-0 flex-1 grid-cols-[minmax(0,24fr)_minmax(0,44fr)_minmax(0,32fr)] overflow-hidden">
<InputSidebar input={session.input} />
<div className="flex min-h-0 min-w-0 flex-col overflow-hidden">
<WorkflowActionCard workflow={session.workflow} />
<PreviewWorkspace canvas={session.canvas} />
<div className="absolute inset-0 min-h-0 min-w-0 overflow-hidden">
<PreviewWorkspace canvas={session.canvas} />
</div>
<div className="pointer-events-none absolute inset-0 z-10">
<div className="pointer-events-auto absolute left-0 top-0 w-[min(24rem,24vw)] max-w-[24rem] overflow-hidden">
{leftPanelOpen ? <InputSidebar input={session.input} /> : null}
<button
type="button"
className="absolute right-1 top-1 rounded bg-(--platform-subpanel-fill)/90 px-2 py-1 text-xs"
onClick={() => setLeftPanelOpen((value) => !value)}
>
{leftPanelOpen ? '收起' : '展开'}
</button>
</div>
<div className="flex min-h-0 min-w-0 flex-col overflow-hidden">
{session.input.activeStep === 'structure-recognition' ? (
<RecognitionOverview
uiTrees={session.input.uiTrees}
onFocusStatusNode={(treeId, nodeId) => {
session.input.focusNode(treeId, nodeId);
session.input.highlightStatusField(nodeId, 'layout_status');
}}
/>
) : session.input.activeStep === 'asset-separation' ? (
<SeparationOverview
uiTrees={session.input.uiTrees}
sprites={session.input.sprites}
onFocusStatusNode={(treeId, nodeId) => {
session.input.focusNode(treeId, nodeId);
session.input.highlightStatusField(nodeId, 'component_status');
}}
/>
) : (
<ImportOverview
images={session.input.images}
sprites={session.input.sprites}
uiTrees={session.input.uiTrees}
/>
)}
<InspectorSidebar inspector={session.inspector} />
<div className="pointer-events-auto absolute left-1/2 top-0 w-[min(44rem,44vw)] -translate-x-1/2">
<ToolNavigation
activeStep={session.workflow.activeStep}
furthestStepIndex={session.workflow.furthestStepIndex}
disabled={session.workflow.isBusy}
onChange={session.workflow.requestStepChange}
/>
<WorkflowActionCard workflow={session.workflow} />
</div>
<div className="pointer-events-auto absolute right-0 top-0 w-[min(32rem,32vw)] max-w-[32rem] overflow-hidden">
{rightPanelOpen ? (
<>
{session.input.activeStep === 'structure-recognition' ? (
<RecognitionOverview
uiTrees={session.input.uiTrees}
onFocusStatusNode={(treeId, nodeId) => {
session.input.focusNode(treeId, nodeId);
session.input.highlightStatusField(nodeId, 'layout_status');
}}
/>
) : session.input.activeStep === 'asset-separation' ? (
<SeparationOverview
uiTrees={session.input.uiTrees}
sprites={session.input.sprites}
onFocusStatusNode={(treeId, nodeId) => {
session.input.focusNode(treeId, nodeId);
session.input.highlightStatusField(
nodeId,
'component_status',
);
}}
/>
) : (
<ImportOverview
images={session.input.images}
sprites={session.input.sprites}
uiTrees={session.input.uiTrees}
/>
)}
<InspectorSidebar inspector={session.inspector} />
</>
) : null}
<button
type="button"
className="absolute left-1 top-1 rounded bg-(--platform-subpanel-fill)/90 px-2 py-1 text-xs"
onClick={() => setRightPanelOpen((value) => !value)}
>
{rightPanelOpen ? '收起' : '展开'}
</button>
</div>
</div>
<EditorDialogs dialogs={session.dialogs} />