ERP-node/frontend/components/barcode/designer/BarcodeComponentPalette.tsx

99 lines
3.1 KiB
TypeScript
Raw Normal View History

2026-03-04 20:51:00 +09:00
"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";
2026-03-05 21:45:26 +09:00
const ITEMS: { type: BarcodeLabelComponent["type"]; label: string; icon: React.ReactNode; barcodeType?: string }[] = [
2026-03-04 20:51:00 +09:00
{ type: "text", label: "텍스트", icon: <Type className="h-4 w-4" /> },
{ type: "barcode", label: "바코드", icon: <Barcode className="h-4 w-4" /> },
2026-03-05 21:45:26 +09:00
{ type: "barcode", label: "QR 코드", icon: <Barcode className="h-4 w-4" />, barcodeType: "QR" },
2026-03-04 20:51:00 +09:00
{ 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;
2026-03-05 21:45:26 +09:00
function defaultComponent(type: BarcodeLabelComponent["type"], barcodeType?: string): BarcodeLabelComponent {
2026-03-04 20:51:00 +09:00
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" };
2026-03-05 21:45:26 +09:00
case "barcode": {
const isQR = barcodeType === "QR";
2026-03-04 20:51:00 +09:00
return {
...base,
2026-03-05 21:45:26 +09:00
width: isQR ? 100 : 120,
height: isQR ? 100 : 40,
barcodeType: barcodeType || "CODE128",
barcodeValue: isQR ? "" : "123456789",
showBarcodeText: !isQR,
2026-03-04 20:51:00 +09:00
};
2026-03-05 21:45:26 +09:00
}
2026-03-04 20:51:00 +09:00
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,
2026-03-05 21:45:26 +09:00
barcodeType,
2026-03-04 20:51:00 +09:00
}: {
type: BarcodeLabelComponent["type"];
label: string;
icon: React.ReactNode;
2026-03-05 21:45:26 +09:00
barcodeType?: string;
2026-03-04 20:51:00 +09:00
}) {
const [{ isDragging }, drag] = useDrag(() => ({
type: "barcode-component",
2026-03-05 21:45:26 +09:00
item: { component: defaultComponent(type, barcodeType) },
2026-03-04 20:51:00 +09:00
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">
2026-03-05 21:45:26 +09:00
{ITEMS.map((item, idx) => (
<DraggableItem
key={item.barcodeType ? `${item.type}_${item.barcodeType}` : `${item.type}_${idx}`}
type={item.type}
label={item.label}
icon={item.icon}
barcodeType={item.barcodeType}
/>
2026-03-04 20:51:00 +09:00
))}
</CardContent>
</Card>
);
}