151 lines
4.8 KiB
TypeScript
151 lines
4.8 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useState, useCallback } from "react";
|
||
|
|
import { DndProvider } from "react-dnd";
|
||
|
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||
|
|
import {
|
||
|
|
PopLayoutDataV4,
|
||
|
|
createEmptyPopLayoutV4,
|
||
|
|
addComponentToV4Layout,
|
||
|
|
removeComponentFromV4Layout,
|
||
|
|
updateComponentInV4Layout,
|
||
|
|
updateContainerV4,
|
||
|
|
findContainerV4,
|
||
|
|
PopComponentType,
|
||
|
|
PopComponentDefinitionV4,
|
||
|
|
PopContainerV4,
|
||
|
|
} from "@/components/pop/designer/types/pop-layout";
|
||
|
|
import { PopCanvasV4 } from "@/components/pop/designer/PopCanvasV4";
|
||
|
|
import { PopPanel } from "@/components/pop/designer/panels/PopPanel";
|
||
|
|
import { ComponentEditorPanelV4 } from "@/components/pop/designer/panels/ComponentEditorPanelV4";
|
||
|
|
|
||
|
|
// ========================================
|
||
|
|
// v4 테스트 페이지
|
||
|
|
//
|
||
|
|
// 목적: v4 렌더러, 캔버스, 속성 패널 테스트
|
||
|
|
// 경로: /pop/test-v4
|
||
|
|
// ========================================
|
||
|
|
|
||
|
|
export default function TestV4Page() {
|
||
|
|
// 레이아웃 상태
|
||
|
|
const [layout, setLayout] = useState<PopLayoutDataV4>(() => {
|
||
|
|
// 초기 테스트 데이터
|
||
|
|
const initial = createEmptyPopLayoutV4();
|
||
|
|
return initial;
|
||
|
|
});
|
||
|
|
|
||
|
|
// 선택 상태
|
||
|
|
const [selectedComponentId, setSelectedComponentId] = useState<string | null>(null);
|
||
|
|
const [selectedContainerId, setSelectedContainerId] = useState<string | null>(null);
|
||
|
|
|
||
|
|
// 컴포넌트 ID 카운터
|
||
|
|
const [idCounter, setIdCounter] = useState(1);
|
||
|
|
|
||
|
|
// 선택된 컴포넌트/컨테이너 가져오기
|
||
|
|
const selectedComponent = selectedComponentId
|
||
|
|
? layout.components[selectedComponentId]
|
||
|
|
: null;
|
||
|
|
const selectedContainer = selectedContainerId
|
||
|
|
? findContainerV4(layout.root, selectedContainerId)
|
||
|
|
: null;
|
||
|
|
|
||
|
|
// 컴포넌트 드롭
|
||
|
|
const handleDropComponent = useCallback(
|
||
|
|
(type: PopComponentType, containerId: string) => {
|
||
|
|
const componentId = `comp_${idCounter}`;
|
||
|
|
setIdCounter((prev) => prev + 1);
|
||
|
|
|
||
|
|
setLayout((prev) =>
|
||
|
|
addComponentToV4Layout(prev, componentId, type, containerId, `${type} ${idCounter}`)
|
||
|
|
);
|
||
|
|
setSelectedComponentId(componentId);
|
||
|
|
setSelectedContainerId(null);
|
||
|
|
},
|
||
|
|
[idCounter]
|
||
|
|
);
|
||
|
|
|
||
|
|
// 컴포넌트 삭제
|
||
|
|
const handleDeleteComponent = useCallback((componentId: string) => {
|
||
|
|
setLayout((prev) => removeComponentFromV4Layout(prev, componentId));
|
||
|
|
setSelectedComponentId(null);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
// 컴포넌트 업데이트
|
||
|
|
const handleUpdateComponent = useCallback(
|
||
|
|
(componentId: string, updates: Partial<PopComponentDefinitionV4>) => {
|
||
|
|
setLayout((prev) => updateComponentInV4Layout(prev, componentId, updates));
|
||
|
|
},
|
||
|
|
[]
|
||
|
|
);
|
||
|
|
|
||
|
|
// 컨테이너 업데이트
|
||
|
|
const handleUpdateContainer = useCallback(
|
||
|
|
(containerId: string, updates: Partial<PopContainerV4>) => {
|
||
|
|
setLayout((prev) => ({
|
||
|
|
...prev,
|
||
|
|
root: updateContainerV4(prev.root, containerId, updates),
|
||
|
|
}));
|
||
|
|
},
|
||
|
|
[]
|
||
|
|
);
|
||
|
|
|
||
|
|
// 선택
|
||
|
|
const handleSelectComponent = useCallback((id: string | null) => {
|
||
|
|
setSelectedComponentId(id);
|
||
|
|
if (id) setSelectedContainerId(null);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const handleSelectContainer = useCallback((id: string | null) => {
|
||
|
|
setSelectedContainerId(id);
|
||
|
|
if (id) setSelectedComponentId(null);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<DndProvider backend={HTML5Backend}>
|
||
|
|
<div className="flex h-screen w-screen overflow-hidden bg-gray-100">
|
||
|
|
{/* 왼쪽: 컴포넌트 팔레트 */}
|
||
|
|
<div className="w-64 shrink-0 border-r bg-white">
|
||
|
|
<div className="border-b px-4 py-3">
|
||
|
|
<h2 className="text-sm font-semibold">v4 테스트</h2>
|
||
|
|
<p className="text-xs text-muted-foreground">컴포넌트를 드래그하세요</p>
|
||
|
|
</div>
|
||
|
|
<PopPanel />
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 중앙: 캔버스 */}
|
||
|
|
<div className="flex-1 overflow-hidden">
|
||
|
|
<PopCanvasV4
|
||
|
|
layout={layout}
|
||
|
|
selectedComponentId={selectedComponentId}
|
||
|
|
selectedContainerId={selectedContainerId}
|
||
|
|
onSelectComponent={handleSelectComponent}
|
||
|
|
onSelectContainer={handleSelectContainer}
|
||
|
|
onDropComponent={handleDropComponent}
|
||
|
|
onUpdateComponent={handleUpdateComponent}
|
||
|
|
onUpdateContainer={handleUpdateContainer}
|
||
|
|
onDeleteComponent={handleDeleteComponent}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 오른쪽: 속성 패널 */}
|
||
|
|
<div className="w-72 shrink-0 border-l bg-white">
|
||
|
|
<ComponentEditorPanelV4
|
||
|
|
component={selectedComponent}
|
||
|
|
container={selectedContainer}
|
||
|
|
onUpdateComponent={
|
||
|
|
selectedComponentId
|
||
|
|
? (updates) => handleUpdateComponent(selectedComponentId, updates)
|
||
|
|
: undefined
|
||
|
|
}
|
||
|
|
onUpdateContainer={
|
||
|
|
selectedContainerId
|
||
|
|
? (updates) => handleUpdateContainer(selectedContainerId, updates)
|
||
|
|
: undefined
|
||
|
|
}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</DndProvider>
|
||
|
|
);
|
||
|
|
}
|