"use client"; import React, { useState, useMemo } from "react"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { ComponentRegistry } from "@/lib/registry/ComponentRegistry"; import { ComponentDefinition, ComponentCategory } from "@/types/component"; import { Search, Package, Grid, Layers, Palette, Zap, MousePointer } from "lucide-react"; interface ComponentsPanelProps { className?: string; } export function ComponentsPanel({ className }: ComponentsPanelProps) { const [searchQuery, setSearchQuery] = useState(""); const [selectedCategory, setSelectedCategory] = useState<"all" | "display" | "action" | "layout" | "utility">("all"); // 레지스트리에서 모든 컴포넌트 조회 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(() => { return { all: allComponents, display: allComponents.filter((c) => c.category === "display"), action: allComponents.filter((c) => c.category === "action"), layout: allComponents.filter((c) => c.category === "layout"), utility: allComponents.filter((c) => c.category === "utility"), }; }, [allComponents]); // 검색 및 필터링된 컴포넌트 const filteredComponents = useMemo(() => { let components = selectedCategory === "all" ? componentsByCategory.all : componentsByCategory[selectedCategory as keyof typeof componentsByCategory]; 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; }, [componentsByCategory, selectedCategory, searchQuery]); // 카테고리 아이콘 매핑 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"; }; return (
{/* 헤더 */}

컴포넌트

7개의 사용 가능한 컴포넌트

{/* 검색 */}
setSearchQuery(e.target.value)} className="pl-10 border-0 bg-white/80 backdrop-blur-sm shadow-sm focus:bg-white transition-colors" />
{/* 카테고리 필터 */}
{/* 컴포넌트 목록 */}
{filteredComponents.length > 0 ? ( filteredComponents.map((component) => (
{ 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 cursor-grab rounded-lg border border-gray-200/40 bg-white/90 backdrop-blur-sm p-6 shadow-sm transition-all duration-300 hover:bg-white hover:shadow-lg hover:shadow-purple-500/15 hover:scale-[1.02] hover:border-purple-300/60 hover:-translate-y-1 active:cursor-grabbing active:scale-[0.98] active:translate-y-0" >
{getCategoryIcon(component.category)}

{component.name}

신규

{component.description}

{component.defaultSize.width}×{component.defaultSize.height}
{component.category}
)) ) : (

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

검색어나 필터를 조정해보세요

)}
{/* 도움말 */}

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

); }