"use client"; import React, { useState, useMemo } from "react"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { ComponentRegistry } from "@/lib/registry/ComponentRegistry"; import { ComponentDefinition, ComponentCategory } from "@/types/component"; import { Search, Package, Grid, Layers, Palette, Zap, MousePointer, Edit3, BarChart3 } from "lucide-react"; interface ComponentsPanelProps { className?: string; } export function ComponentsPanel({ className }: ComponentsPanelProps) { const [searchQuery, setSearchQuery] = useState(""); // 레지스트리에서 모든 컴포넌트 조회 const allComponents = useMemo(() => { const components = ComponentRegistry.getAllComponents(); // 수동으로 table-list 컴포넌트 추가 (임시) const hasTableList = components.some((c) => c.id === "table-list"); if (!hasTableList) { components.push({ id: "table-list", name: "데이터 테이블 v2", description: "검색, 필터링, 페이징, CRUD 기능이 포함된 완전한 데이터 테이블 컴포넌트", category: "display", tags: ["table", "data", "crud"], defaultSize: { width: 1000, height: 680 }, } as ComponentDefinition); } return components; }, []); // 카테고리별 컴포넌트 그룹화 const componentsByCategory = useMemo(() => { // 숨길 컴포넌트 ID 목록 (기본 입력 컴포넌트들) const hiddenInputComponents = ["text-input", "number-input", "date-input", "textarea-basic"]; return { input: allComponents.filter( (c) => c.category === ComponentCategory.INPUT && !hiddenInputComponents.includes(c.id), ), action: allComponents.filter((c) => c.category === ComponentCategory.ACTION), display: allComponents.filter((c) => c.category === ComponentCategory.DISPLAY), layout: allComponents.filter((c) => c.category === ComponentCategory.LAYOUT), }; }, [allComponents]); // 카테고리별 검색 필터링 const getFilteredComponents = (category: keyof typeof componentsByCategory) => { let components = componentsByCategory[category]; if (searchQuery) { const query = searchQuery.toLowerCase(); components = components.filter( (component: ComponentDefinition) => component.name.toLowerCase().includes(query) || component.description.toLowerCase().includes(query) || component.tags?.some((tag: string) => tag.toLowerCase().includes(query)), ); } return components; }; // 카테고리 아이콘 매핑 const getCategoryIcon = (category: ComponentCategory) => { switch (category) { case "display": return ; case "action": return ; case "layout": return ; case "utility": return ; default: return ; } }; // 드래그 시작 핸들러 const handleDragStart = (e: React.DragEvent, component: ComponentDefinition) => { const dragData = { type: "component", component: component, }; e.dataTransfer.setData("application/json", JSON.stringify(dragData)); e.dataTransfer.effectAllowed = "copy"; }; // 컴포넌트 카드 렌더링 함수 const renderComponentCard = (component: ComponentDefinition) => (
{ handleDragStart(e, component); e.currentTarget.style.opacity = "0.6"; e.currentTarget.style.transform = "rotate(2deg) scale(0.98)"; }} onDragEnd={(e) => { e.currentTarget.style.opacity = "1"; e.currentTarget.style.transform = "none"; }} className="group bg-card hover:border-primary/50 cursor-grab rounded-lg border p-3 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:scale-[0.98] active:cursor-grabbing" >
{getCategoryIcon(component.category)}

{component.name}

{component.description}

{component.defaultSize.width}×{component.defaultSize.height}
); // 빈 상태 렌더링 const renderEmptyState = () => (

컴포넌트를 찾을 수 없습니다

검색어를 조정해보세요

); return (
{/* 헤더 */}

컴포넌트

{allComponents.length}개 사용 가능

{/* 검색 */}
setSearchQuery(e.target.value)} className="h-8 pl-8 text-xs" />
{/* 카테고리 탭 */} 입력 액션 표시 레이아웃 {/* 입력 컴포넌트 */} {getFilteredComponents("input").length > 0 ? getFilteredComponents("input").map(renderComponentCard) : renderEmptyState()} {/* 액션 컴포넌트 */} {getFilteredComponents("action").length > 0 ? getFilteredComponents("action").map(renderComponentCard) : renderEmptyState()} {/* 표시 컴포넌트 */} {getFilteredComponents("display").length > 0 ? getFilteredComponents("display").map(renderComponentCard) : renderEmptyState()} {/* 레이아웃 컴포넌트 */} {getFilteredComponents("layout").length > 0 ? getFilteredComponents("layout").map(renderComponentCard) : renderEmptyState()} {/* 도움말 */}

컴포넌트를 드래그하여 화면에 추가하세요

); }