ERP-node/frontend/components/pop/designer/panels/ComponentPaletteV4.tsx

160 lines
4.0 KiB
TypeScript
Raw Normal View History

"use client";
import { useDrag } from "react-dnd";
import {
Type,
MousePointer,
List,
Activity,
ScanLine,
Calculator,
GripVertical,
Space,
WrapText,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { PopComponentType } from "../types/pop-layout";
import { DND_ITEM_TYPES, DragItemComponent } from "./PopPanel";
// ========================================
// 컴포넌트 팔레트 정의
// ========================================
const COMPONENT_PALETTE: {
type: PopComponentType;
label: string;
icon: React.ElementType;
description: string;
}[] = [
{
type: "pop-field",
label: "필드",
icon: Type,
description: "텍스트, 숫자 등 데이터 입력",
},
{
type: "pop-button",
label: "버튼",
icon: MousePointer,
description: "저장, 삭제 등 액션 실행",
},
{
type: "pop-list",
label: "리스트",
icon: List,
description: "데이터 목록 (카드 템플릿 지원)",
},
{
type: "pop-indicator",
label: "인디케이터",
icon: Activity,
description: "KPI, 상태 표시",
},
{
type: "pop-scanner",
label: "스캐너",
icon: ScanLine,
description: "바코드/QR 스캔",
},
{
type: "pop-numpad",
label: "숫자패드",
icon: Calculator,
description: "숫자 입력 전용",
},
{
type: "pop-spacer",
label: "스페이서",
icon: Space,
description: "빈 공간 (정렬용)",
},
{
type: "pop-break",
label: "줄바꿈",
icon: WrapText,
description: "강제 줄바꿈 (flex-basis: 100%)",
},
];
// ========================================
// v4 컴포넌트 팔레트
// ========================================
export function ComponentPaletteV4() {
return (
<div className="flex h-full flex-col">
{/* 헤더 */}
<div className="border-b p-3">
<div className="text-sm font-medium text-muted-foreground">
: v4 ( )
</div>
<div className="text-xs text-muted-foreground mt-1">
</div>
</div>
{/* 컴포넌트 목록 */}
<div className="flex-1 overflow-auto p-3">
<div className="text-xs font-medium text-muted-foreground mb-2">
</div>
<div className="space-y-1">
{COMPONENT_PALETTE.map((item) => (
<DraggableComponentV4
key={item.type}
type={item.type}
label={item.label}
icon={item.icon}
description={item.description}
/>
))}
</div>
<div className="mt-4 text-xs text-muted-foreground">
</div>
</div>
</div>
);
}
// ========================================
// 드래그 가능한 컴포넌트 아이템
// ========================================
interface DraggableComponentV4Props {
type: PopComponentType;
label: string;
icon: React.ElementType;
description: string;
}
function DraggableComponentV4({ type, label, icon: Icon, description }: DraggableComponentV4Props) {
const [{ isDragging }, drag] = useDrag(
() => ({
type: DND_ITEM_TYPES.COMPONENT,
item: { type: DND_ITEM_TYPES.COMPONENT, componentType: type } as DragItemComponent,
collect: (monitor) => ({
isDragging: monitor.isDragging(),
}),
}),
[type]
);
return (
<div
ref={drag}
className={cn(
"flex items-center gap-2 rounded-lg border p-2 cursor-grab transition-all",
"hover:bg-accent hover:border-primary/30",
isDragging && "opacity-50 cursor-grabbing"
)}
>
<GripVertical className="h-4 w-4 text-muted-foreground" />
<Icon className="h-4 w-4 shrink-0" />
<div className="flex-1 min-w-0">
<div className="text-sm font-medium truncate">{label}</div>
<div className="text-xs text-muted-foreground truncate">{description}</div>
</div>
</div>
);
}
export default ComponentPaletteV4;