"use client"; import React, { useState, useMemo } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Grid, Layout, LayoutDashboard, Table, Navigation, FileText, Building, Search, Plus } from "lucide-react"; import { LAYOUT_CATEGORIES, LayoutCategory } from "@/types/layout"; import { LayoutRegistry } from "@/lib/registry/LayoutRegistry"; import { calculateGridInfo, calculateWidthFromColumns } from "@/lib/utils/gridUtils"; // 카테고리 아이콘 매핑 const CATEGORY_ICONS = { basic: Grid, form: FileText, table: Table, dashboard: LayoutDashboard, navigation: Navigation, content: Layout, business: Building, }; // 카테고리 이름 매핑 const CATEGORY_NAMES = { basic: "기본", form: "폼", table: "테이블", dashboard: "대시보드", navigation: "네비게이션", content: "컨텐츠", business: "업무용", }; interface LayoutsPanelProps { onDragStart: (e: React.DragEvent, layoutData: any) => void; onLayoutSelect?: (layoutDefinition: any) => void; className?: string; gridSettings?: { columns: number; gap: number; padding: number; snapToGrid: boolean; }; screenResolution?: { width: number; height: number; }; } export default function LayoutsPanel({ onDragStart, onLayoutSelect, className, gridSettings, screenResolution, }: LayoutsPanelProps) { const [searchTerm, setSearchTerm] = useState(""); const [selectedCategory, setSelectedCategory] = useState("all"); // 레지스트리에서 레이아웃 조회 const allLayouts = useMemo(() => LayoutRegistry.getAllLayouts(), []); // 필터링된 레이아웃 const filteredLayouts = useMemo(() => { let layouts = allLayouts; // 카테고리 필터 if (selectedCategory !== "all") { layouts = layouts.filter((layout) => layout.category === selectedCategory); } // 검색 필터 if (searchTerm) { layouts = layouts.filter( (layout) => layout.name.toLowerCase().includes(searchTerm.toLowerCase()) || layout.nameEng?.toLowerCase().includes(searchTerm.toLowerCase()) || layout.description?.toLowerCase().includes(searchTerm.toLowerCase()), ); } return layouts; }, [allLayouts, selectedCategory, searchTerm]); // 카테고리별 개수 const categoryCounts = useMemo(() => { const counts: Record = {}; Object.values(LAYOUT_CATEGORIES).forEach((category) => { counts[category] = allLayouts.filter((layout) => layout.category === category).length; }); return counts; }, [allLayouts]); // 레이아웃 드래그 시작 핸들러 const handleDragStart = (e: React.DragEvent, layoutDefinition: any) => { // 격자 기반 동적 크기 계산 let calculatedSize = layoutDefinition.defaultSize || { width: 400, height: 300 }; if (gridSettings && screenResolution && layoutDefinition.id === "card-layout") { // 카드 레이아웃의 경우 8그리드 컬럼에 맞는 너비 계산 const gridInfo = calculateGridInfo(screenResolution.width, screenResolution.height, gridSettings); const calculatedWidth = calculateWidthFromColumns(8, gridInfo, gridSettings); calculatedSize = { width: Math.max(calculatedWidth, 400), // 최소 400px 보장 height: 400, // 높이는 고정 }; // console.log("🎯 카드 레이아웃 동적 크기 계산:", { // gridColumns: 8, // screenResolution, // gridSettings, // gridInfo, // calculatedWidth, // finalSize: calculatedSize, // }); } // 새 레이아웃 컴포넌트 데이터 생성 const layoutData = { id: `layout_${Date.now()}`, type: "layout", layoutType: layoutDefinition.id, layoutConfig: layoutDefinition.defaultConfig, zones: layoutDefinition.defaultZones, children: [], allowedComponentTypes: [], position: { x: 0, y: 0 }, size: calculatedSize, label: layoutDefinition.name, gridColumns: layoutDefinition.id === "card-layout" ? 8 : 1, // 카드 레이아웃은 기본 8그리드 }; // 드래그 데이터 설정 e.dataTransfer.setData("application/json", JSON.stringify(layoutData)); e.dataTransfer.setData("text/plain", layoutDefinition.name); e.dataTransfer.effectAllowed = "copy"; onDragStart(e, layoutData); }; // 레이아웃 선택 핸들러 const handleLayoutSelect = (layoutDefinition: any) => { onLayoutSelect?.(layoutDefinition); }; return (
{/* 헤더 */}

레이아웃

{/* 검색 */}
setSearchTerm(e.target.value)} className="pl-10" />
{/* 카테고리 탭 */} 전체 ({allLayouts.length}) 기본 ({categoryCounts.basic || 0}) 폼 ({categoryCounts.form || 0}) 탭 ({categoryCounts.navigation || 0}) {/* 레이아웃 목록 */}
{filteredLayouts.length === 0 ? (
{searchTerm ? "검색 결과가 없습니다." : "레이아웃이 없습니다."}
) : (
{filteredLayouts.map((layout) => { const CategoryIcon = CATEGORY_ICONS[layout.category as keyof typeof CATEGORY_ICONS]; return ( handleDragStart(e, layout)} onClick={() => handleLayoutSelect(layout)} >
{CATEGORY_NAMES[layout.category as keyof typeof CATEGORY_NAMES]}
{layout.name}
{layout.description && (

{layout.description}

)}
존 개수: {layout.defaultZones.length}개
); })}
)}
); }