From 1116fb350aedf55370a8906530b896835e5813a8 Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Tue, 10 Feb 2026 18:02:30 +0900 Subject: [PATCH] =?UTF-8?q?=EB=94=94=EC=9E=90=EC=9D=B4=EB=84=88=20?= =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20UX=20=EA=B0=9C=EC=84=A0:=20?= =?UTF-8?q?=ED=97=A4=EB=8D=94=20=EC=A0=9C=EA=B1=B0=20+=20=EC=8B=A4?= =?UTF-8?q?=EC=A0=9C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EB=A0=8C=EB=8D=94?= =?UTF-8?q?=EB=A7=81=20+=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- .../components/pop/designer/PopDesigner.tsx | 3 + .../designer/panels/ComponentEditorPanel.tsx | 55 ++++++++++++++++++- .../pop/designer/renderers/PopRenderer.tsx | 52 +++++++----------- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/frontend/components/pop/designer/PopDesigner.tsx b/frontend/components/pop/designer/PopDesigner.tsx index 8bcc8f3a..f4dfd3fa 100644 --- a/frontend/components/pop/designer/PopDesigner.tsx +++ b/frontend/components/pop/designer/PopDesigner.tsx @@ -652,6 +652,9 @@ export default function PopDesigner({ ? (updates) => handleUpdateComponent(selectedComponentId, updates) : undefined } + allComponents={Object.values(layout.components)} + onSelectComponent={setSelectedComponentId} + selectedComponentId={selectedComponentId} /> diff --git a/frontend/components/pop/designer/panels/ComponentEditorPanel.tsx b/frontend/components/pop/designer/panels/ComponentEditorPanel.tsx index ddb7ac79..0a9d6037 100644 --- a/frontend/components/pop/designer/panels/ComponentEditorPanel.tsx +++ b/frontend/components/pop/designer/panels/ComponentEditorPanel.tsx @@ -7,7 +7,6 @@ import { PopGridPosition, GridMode, GRID_BREAKPOINTS, - PopComponentType, } from "../types/pop-layout"; import { Settings, @@ -16,6 +15,7 @@ import { Grid3x3, MoveHorizontal, MoveVertical, + Layers, } from "lucide-react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Label } from "@/components/ui/label"; @@ -36,12 +36,21 @@ interface ComponentEditorPanelProps { onUpdateComponent?: (updates: Partial) => void; /** 추가 className */ className?: string; + /** 그리드에 배치된 모든 컴포넌트 */ + allComponents?: PopComponentDefinitionV5[]; + /** 컴포넌트 선택 콜백 */ + onSelectComponent?: (componentId: string) => void; + /** 현재 선택된 컴포넌트 ID */ + selectedComponentId?: string | null; } // ======================================== // 컴포넌트 타입별 라벨 // ======================================== -const COMPONENT_TYPE_LABELS: Record = { +const COMPONENT_TYPE_LABELS: Record = { + "pop-sample": "샘플", + "pop-text": "텍스트", + "pop-dashboard": "대시보드", "pop-field": "필드", "pop-button": "버튼", "pop-list": "리스트", @@ -61,6 +70,9 @@ export default function ComponentEditorPanel({ currentMode, onUpdateComponent, className, + allComponents, + onSelectComponent, + selectedComponentId, }: ComponentEditorPanelProps) { const breakpoint = GRID_BREAKPOINTS[currentMode]; @@ -118,7 +130,44 @@ export default function ComponentEditorPanel({ {/* 위치 탭 */} - + + {/* 배치된 컴포넌트 목록 */} + {allComponents && allComponents.length > 0 && ( +
+
+ + + 배치된 컴포넌트 ({allComponents.length}) + +
+
+ {allComponents.map((comp) => { + const label = comp.label + || COMPONENT_TYPE_LABELS[comp.type] + || comp.type; + const isActive = comp.id === selectedComponentId; + return ( + + ); + })} +
+
+
+ )} + +
+ ); + } + + // 미등록: preview 컴포넌트 또는 기본 플레이스홀더 return ( -
- {/* 헤더 */} -
- - {component.label || typeLabel} +
+ {PreviewComponent ? ( + + ) : ( + + {typeLabel} -
- - {/* 내용: 등록된 preview 컴포넌트 또는 기본 플레이스홀더 */} -
- {PreviewComponent ? ( - - ) : ( - - {typeLabel} - - )} -
- - {/* 위치 정보 표시 (유효 위치 사용) */} -
- {effectivePosition.col},{effectivePosition.row} - ({effectivePosition.colSpan}×{effectivePosition.rowSpan}) -
+ )}
); }