"use client"; import React, { useState, useCallback } from "react"; import { cn } from "@/lib/utils"; import { GridLayout, LayoutRow, RowComponent, CreateRowOptions } from "@/types/grid-system"; import { ComponentData } from "@/types/screen"; import { LayoutRowRenderer } from "./LayoutRowRenderer"; import { Button } from "@/components/ui/button"; import { Plus, Grid3x3 } from "lucide-react"; import { GAP_PRESETS } from "@/lib/constants/columnSpans"; interface GridLayoutBuilderProps { layout: GridLayout; onUpdateLayout: (layout: GridLayout) => void; selectedRowId?: string; selectedComponentId?: string; onSelectRow?: (rowId: string) => void; onSelectComponent?: (componentId: string) => void; showGridGuides?: boolean; } export const GridLayoutBuilder: React.FC = ({ layout, onUpdateLayout, selectedRowId, selectedComponentId, onSelectRow, onSelectComponent, showGridGuides = true, }) => { const [isDraggingOver, setIsDraggingOver] = useState(false); // 새 행 추가 const addNewRow = useCallback( (options?: CreateRowOptions) => { const newRow: LayoutRow = { id: `row-${Date.now()}`, rowIndex: layout.rows.length, height: options?.height || "auto", fixedHeight: options?.fixedHeight, gap: options?.gap || "sm", padding: options?.padding || "sm", alignment: options?.alignment || "start", verticalAlignment: "middle", components: [], }; onUpdateLayout({ ...layout, rows: [...layout.rows, newRow], }); // 새로 추가된 행 선택 if (onSelectRow) { onSelectRow(newRow.id); } }, [layout, onUpdateLayout, onSelectRow], ); // 행 삭제 const deleteRow = useCallback( (rowId: string) => { const updatedRows = layout.rows .filter((row) => row.id !== rowId) .map((row, index) => ({ ...row, rowIndex: index, })); onUpdateLayout({ ...layout, rows: updatedRows, }); }, [layout, onUpdateLayout], ); // 행 순서 변경 const moveRow = useCallback( (rowId: string, direction: "up" | "down") => { const rowIndex = layout.rows.findIndex((row) => row.id === rowId); if (rowIndex === -1) return; const newIndex = direction === "up" ? rowIndex - 1 : rowIndex + 1; if (newIndex < 0 || newIndex >= layout.rows.length) return; const updatedRows = [...layout.rows]; [updatedRows[rowIndex], updatedRows[newIndex]] = [updatedRows[newIndex], updatedRows[rowIndex]]; // 인덱스 재정렬 updatedRows.forEach((row, index) => { row.rowIndex = index; }); onUpdateLayout({ ...layout, rows: updatedRows, }); }, [layout, onUpdateLayout], ); // 행 업데이트 const updateRow = useCallback( (rowId: string, updates: Partial) => { const updatedRows = layout.rows.map((row) => (row.id === rowId ? { ...row, ...updates } : row)); onUpdateLayout({ ...layout, rows: updatedRows, }); }, [layout, onUpdateLayout], ); // 컴포넌트 선택 const handleSelectComponent = useCallback( (componentId: string) => { if (onSelectComponent) { onSelectComponent(componentId); } }, [onSelectComponent], ); // 행 선택 const handleSelectRow = useCallback( (rowId: string) => { if (onSelectRow) { onSelectRow(rowId); } }, [onSelectRow], ); // 컨테이너 클래스 const containerClasses = cn("w-full h-full overflow-auto bg-gray-50 relative", isDraggingOver && "bg-blue-50"); // 글로벌 컨테이너 클래스 const globalContainerClasses = cn( "mx-auto relative", layout.globalSettings.containerMaxWidth === "full" ? "w-full" : `max-w-${layout.globalSettings.containerMaxWidth}`, GAP_PRESETS[layout.globalSettings.containerPadding].class.replace("gap-", "px-"), ); return (
{/* 그리드 가이드라인 */} {showGridGuides && (
{Array.from({ length: 12 }).map((_, i) => (
))}
)} {/* 메인 컨테이너 */}
{layout.rows.length === 0 ? ( // 빈 레이아웃

레이아웃이 비어있습니다

첫 번째 행을 추가하여 시작하세요

) : ( // 행 목록
{layout.rows.map((row) => ( handleSelectRow(row.id)} onSelectComponent={handleSelectComponent} onUpdateRow={(updatedRow) => updateRow(row.id, updatedRow)} /> ))}
)} {/* 새 행 추가 버튼 */} {layout.rows.length > 0 && (
{/* 빠른 추가 버튼들 */}
)} {/* 레이아웃 정보 */}
행: {layout.rows.length} 컴포넌트: {layout.components.size} 컨테이너:{" "} {layout.globalSettings.containerMaxWidth === "full" ? "전체" : layout.globalSettings.containerMaxWidth}
12컬럼 그리드 {showGridGuides && 가이드 표시됨}
); };