88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
"use client";
|
|
|
|
import { useDrag } from "react-dnd";
|
|
import { Type, Barcode, Image, Minus, Square } from "lucide-react";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { BarcodeLabelComponent } from "@/types/barcode";
|
|
import { v4 as uuidv4 } from "uuid";
|
|
|
|
const ITEMS: { type: BarcodeLabelComponent["type"]; label: string; icon: React.ReactNode }[] = [
|
|
{ type: "text", label: "텍스트", icon: <Type className="h-4 w-4" /> },
|
|
{ type: "barcode", label: "바코드", icon: <Barcode className="h-4 w-4" /> },
|
|
{ type: "image", label: "이미지", icon: <Image className="h-4 w-4" /> },
|
|
{ type: "line", label: "선", icon: <Minus className="h-4 w-4" /> },
|
|
{ type: "rectangle", label: "사각형", icon: <Square className="h-4 w-4" /> },
|
|
];
|
|
|
|
const MM_TO_PX = 4;
|
|
|
|
function defaultComponent(type: BarcodeLabelComponent["type"]): BarcodeLabelComponent {
|
|
const id = `comp_${uuidv4()}`;
|
|
const base = { id, type, x: 10 * MM_TO_PX, y: 10 * MM_TO_PX, width: 80, height: 24, zIndex: 0 };
|
|
|
|
switch (type) {
|
|
case "text":
|
|
return { ...base, content: "텍스트", fontSize: 10, fontColor: "#000000" };
|
|
case "barcode":
|
|
return {
|
|
...base,
|
|
width: 120,
|
|
height: 40,
|
|
barcodeType: "CODE128",
|
|
barcodeValue: "123456789",
|
|
showBarcodeText: true,
|
|
};
|
|
case "image":
|
|
return { ...base, width: 60, height: 60, imageUrl: "", objectFit: "contain" };
|
|
case "line":
|
|
return { ...base, width: 100, height: 2, lineColor: "#000", lineWidth: 1 };
|
|
case "rectangle":
|
|
return { ...base, width: 80, height: 40, backgroundColor: "transparent", lineColor: "#000", lineWidth: 1 };
|
|
default:
|
|
return base;
|
|
}
|
|
}
|
|
|
|
function DraggableItem({
|
|
type,
|
|
label,
|
|
icon,
|
|
}: {
|
|
type: BarcodeLabelComponent["type"];
|
|
label: string;
|
|
icon: React.ReactNode;
|
|
}) {
|
|
const [{ isDragging }, drag] = useDrag(() => ({
|
|
type: "barcode-component",
|
|
item: { component: defaultComponent(type) },
|
|
collect: (m) => ({ isDragging: m.isDragging() }),
|
|
}));
|
|
|
|
return (
|
|
<div
|
|
ref={drag}
|
|
className={`flex cursor-move items-center gap-2 rounded border p-2 text-sm hover:border-blue-500 hover:bg-blue-50 ${
|
|
isDragging ? "opacity-50" : ""
|
|
}`}
|
|
>
|
|
{icon}
|
|
<span>{label}</span>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export function BarcodeComponentPalette() {
|
|
return (
|
|
<Card>
|
|
<CardHeader className="pb-2">
|
|
<CardTitle className="text-sm">요소 추가</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="space-y-2">
|
|
{ITEMS.map((item) => (
|
|
<DraggableItem key={item.type} type={item.type} label={item.label} icon={item.icon} />
|
|
))}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|