更新 UI 编辑器布局与控件行为
优化侧栏组件结构 调整 TransformEditor 渲染位置, 改进预览模式切换交互。
This commit is contained in:
+33
-34
@@ -328,6 +328,34 @@ function NodeInspector({
|
||||
|
||||
return (
|
||||
<div className="mt-4 space-y-4">
|
||||
<div
|
||||
className="flex items-center rounded-lg border border-(--platform-subpanel-border) bg-white/70 p-0.5 text-[10px]"
|
||||
role="group"
|
||||
aria-label="子节点布局行为"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={!keepChildrenUnchanged}
|
||||
disabled={transformReadOnly || isReadOnly}
|
||||
onClick={() => {
|
||||
if (!isReadOnly) onKeepChildrenUnchangedChange(false);
|
||||
}}
|
||||
className={`flex-1 rounded-md px-2 py-1.5 transition ${!keepChildrenUnchanged ? 'bg-blue-600 text-white' : 'text-(--platform-text-soft) hover:bg-black/5'} disabled:cursor-not-allowed disabled:opacity-50`}
|
||||
>
|
||||
子节点跟随父节点变化
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={keepChildrenUnchanged}
|
||||
disabled={transformReadOnly || isReadOnly}
|
||||
onClick={() => {
|
||||
if (!isReadOnly) onKeepChildrenUnchangedChange(true);
|
||||
}}
|
||||
className={`flex-1 rounded-md px-2 py-1.5 transition ${keepChildrenUnchanged ? 'bg-orange-500 text-white' : 'text-(--platform-text-soft) hover:bg-black/5'} disabled:cursor-not-allowed disabled:opacity-50`}
|
||||
>
|
||||
子节点保持不变
|
||||
</button>
|
||||
</div>
|
||||
<label className="flex items-center gap-2 rounded-lg border border-(--platform-subpanel-border) bg-white/35 p-2 text-xs">
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -359,34 +387,6 @@ function NodeInspector({
|
||||
</select>
|
||||
</label>
|
||||
) : null}
|
||||
<div
|
||||
className="flex items-center rounded-lg border border-(--platform-subpanel-border) bg-white/70 p-0.5 text-[10px]"
|
||||
role="group"
|
||||
aria-label="子节点布局行为"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={!keepChildrenUnchanged}
|
||||
disabled={transformReadOnly || isReadOnly}
|
||||
onClick={() => {
|
||||
if (!isReadOnly) onKeepChildrenUnchangedChange(false);
|
||||
}}
|
||||
className={`flex-1 rounded-md px-2 py-1.5 transition ${!keepChildrenUnchanged ? 'bg-blue-600 text-white' : 'text-(--platform-text-soft) hover:bg-black/5'} disabled:cursor-not-allowed disabled:opacity-50`}
|
||||
>
|
||||
子节点跟随父节点变化
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
aria-pressed={keepChildrenUnchanged}
|
||||
disabled={transformReadOnly || isReadOnly}
|
||||
onClick={() => {
|
||||
if (!isReadOnly) onKeepChildrenUnchangedChange(true);
|
||||
}}
|
||||
className={`flex-1 rounded-md px-2 py-1.5 transition ${keepChildrenUnchanged ? 'bg-orange-500 text-white' : 'text-(--platform-text-soft) hover:bg-black/5'} disabled:cursor-not-allowed disabled:opacity-50`}
|
||||
>
|
||||
子节点保持不变
|
||||
</button>
|
||||
</div>
|
||||
<InspectorInput
|
||||
label="名称"
|
||||
value={node.metadata.name}
|
||||
@@ -470,17 +470,17 @@ function NodeInspector({
|
||||
允许 LLM 修改组件
|
||||
</label>
|
||||
</div>
|
||||
{parentIsContainer ? (
|
||||
<p className="m-0 rounded-lg bg-amber-50 p-2 text-xs text-amber-800">
|
||||
父 Container 管理此节点;Transform 已保留,但 Preview 会忽略它。
|
||||
</p>
|
||||
) : null}
|
||||
<TransformEditor
|
||||
transform={node.layout.transform}
|
||||
parentSize={parentSize}
|
||||
readOnly={transformReadOnly || isReadOnly}
|
||||
onChange={onTransformChange}
|
||||
/>
|
||||
{parentIsContainer ? (
|
||||
<p className="m-0 rounded-lg bg-amber-50 p-2 text-xs text-amber-800">
|
||||
父 Container 管理此节点;Transform 已保留,但 Preview 会忽略它。
|
||||
</p>
|
||||
) : null}
|
||||
<LayoutEditor
|
||||
node={node}
|
||||
readOnly={isReadOnly}
|
||||
@@ -589,7 +589,6 @@ function LayoutEditor({
|
||||
|
||||
return (
|
||||
<section className="space-y-2 rounded-lg border border-(--platform-subpanel-border) bg-white/35 p-3">
|
||||
<h3 className="m-0 text-xs font-semibold">Control 与 Container</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<InspectorInput
|
||||
label="最小宽度"
|
||||
|
||||
+1
-19
@@ -5,7 +5,6 @@ import {
|
||||
Crosshair,
|
||||
Info,
|
||||
Move,
|
||||
SlidersHorizontal,
|
||||
} from 'lucide-react';
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
@@ -375,25 +374,8 @@ export function TransformEditor({
|
||||
return (
|
||||
<section
|
||||
aria-readonly={readOnly}
|
||||
className={`w-full min-w-0 max-w-full overflow-visible rounded-2xl border text-(--platform-text-strong) shadow-[0_16px_40px_rgb(91_62_45/10%)] ${readOnly ? 'border-slate-300 bg-slate-100/90' : 'border-(--platform-subpanel-border) bg-(--platform-subpanel-fill)'}`}
|
||||
className={`w-full min-w-0 max-w-full overflow-visible rounded-lg border text-(--platform-text-strong) shadow-[0_16px_40px_rgb(91_62_45/10%)] ${readOnly ? 'border-slate-300 bg-slate-100/90' : 'border-(--platform-subpanel-border) bg-(--platform-subpanel-fill)'}`}
|
||||
>
|
||||
<header className="flex min-w-0 flex-wrap items-center justify-between gap-2 border-b border-(--platform-subpanel-border) px-4 py-3">
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<span className="grid size-8 place-items-center rounded-xl bg-orange-100 text-orange-600">
|
||||
<SlidersHorizontal size={15} aria-hidden="true" />
|
||||
</span>
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold">矩形变换</h2>
|
||||
<p
|
||||
className="text-[10px] text-(--platform-text-soft)"
|
||||
title="通过锚点比例和像素偏移控制元素在父容器中的位置与尺寸。"
|
||||
>
|
||||
锚点与偏移
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div className="grid gap-4 p-4">
|
||||
<div ref={presetRef} className="relative">
|
||||
<button
|
||||
|
||||
+31
-38
@@ -308,48 +308,41 @@ export function PreviewWorkspace({
|
||||
|
||||
return (
|
||||
<section className="flex h-full min-h-0 min-w-0 flex-col overflow-hidden bg-(--platform-body-fill)">
|
||||
<header className="flex min-w-0 shrink-0 flex-wrap items-center justify-between gap-2 border-b border-(--platform-subpanel-border) px-4 py-2">
|
||||
<h1 className="m-0 text-sm font-semibold">UI布局编辑器</h1>
|
||||
<div className="flex min-w-0 flex-wrap items-center justify-end gap-2">
|
||||
<div className="flex items-center rounded-lg border border-(--platform-subpanel-border) bg-white/70 p-0.5 text-[10px]">
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-md px-2 py-1 ${renderMode === 'editor-overlay' ? 'bg-blue-600 text-white' : 'text-(--platform-text-soft)'}`}
|
||||
aria-pressed={renderMode === 'editor-overlay'}
|
||||
onClick={() => setRenderMode('editor-overlay')}
|
||||
>
|
||||
编辑叠加
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-md px-2 py-1 ${renderMode === 'final-preview' ? 'bg-orange-500 text-white' : 'text-(--platform-text-soft)'}`}
|
||||
aria-pressed={renderMode === 'final-preview'}
|
||||
onClick={() => setRenderMode('final-preview')}
|
||||
>
|
||||
最终预览
|
||||
</button>
|
||||
</div>
|
||||
{renderMode === 'final-preview' ? (
|
||||
<label className="inline-flex cursor-pointer select-none items-center gap-1.5 text-[10px] text-(--platform-text-soft)">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showFrame}
|
||||
onChange={(event) => setShowFrame(event.target.checked)}
|
||||
className="size-3 accent-orange-500"
|
||||
/>
|
||||
<span>显示框线</span>
|
||||
</label>
|
||||
) : null}
|
||||
<span className="text-[10px] text-(--platform-text-soft)">
|
||||
{Object.keys(canvas.images).length} 张界面图 ·{' '}
|
||||
{Object.keys(canvas.sprites).length} 项素材
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
{activeImage &&
|
||||
logicalSize &&
|
||||
(renderMode === 'final-preview' || previewUrls[activeImageId ?? '']) ? (
|
||||
<div className="relative min-h-0 flex-1">
|
||||
<div className="pointer-events-auto absolute right-3 top-3 z-40 flex max-w-[calc(100%-1.5rem)] flex-wrap items-center justify-end gap-2 bg-transparent text-[10px]">
|
||||
{renderMode === 'final-preview' ? (
|
||||
<label className="inline-flex cursor-pointer select-none items-center gap-1.5 rounded-lg bg-white/70 px-2 py-1 text-(--platform-text-soft) shadow-sm backdrop-blur">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showFrame}
|
||||
onChange={(event) => setShowFrame(event.target.checked)}
|
||||
className="size-3 accent-orange-500"
|
||||
/>
|
||||
<span>显示框线</span>
|
||||
</label>
|
||||
) : null}
|
||||
<div className="flex items-center rounded-lg border border-(--platform-subpanel-border) bg-white/70 p-0.5 shadow-sm backdrop-blur">
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-md px-2 py-1 ${renderMode === 'editor-overlay' ? 'bg-blue-600 text-white' : 'text-(--platform-text-soft)'}`}
|
||||
aria-pressed={renderMode === 'editor-overlay'}
|
||||
onClick={() => setRenderMode('editor-overlay')}
|
||||
>
|
||||
编辑叠加
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`rounded-md px-2 py-1 ${renderMode === 'final-preview' ? 'bg-orange-500 text-white' : 'text-(--platform-text-soft)'}`}
|
||||
aria-pressed={renderMode === 'final-preview'}
|
||||
onClick={() => setRenderMode('final-preview')}
|
||||
>
|
||||
最终预览
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{renderMode === 'final-preview' && canvas.selectedNode ? (
|
||||
<ExclusiveChildrenTabs
|
||||
parent={canvas.selectedNode}
|
||||
|
||||
Reference in New Issue
Block a user