From ea6c5ac43c9d26bb46b22284edb5b29a32715e20 Mon Sep 17 00:00:00 2001 From: kjs Date: Thu, 5 Mar 2026 21:41:53 +0900 Subject: [PATCH 1/2] fix: Remove unnecessary whitespace in SplitPanelLayoutComponent - Cleaned up the code by removing an unnecessary blank line in the SplitPanelLayoutComponent.tsx file. - This minor adjustment improves code readability without affecting functionality. --- .../v2-split-panel-layout/SplitPanelLayoutComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx b/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx index 0cdf6836..865e6c44 100644 --- a/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx +++ b/frontend/lib/registry/components/v2-split-panel-layout/SplitPanelLayoutComponent.tsx @@ -106,7 +106,7 @@ export const SplitPanelLayoutComponent: React.FC ...props }) => { const componentConfig = (component.componentConfig || {}) as SplitPanelLayoutConfig; - + // πŸ› 디버깅: λ‘œλ“œ μ‹œ rightPanel.components 확인 const rightComps = componentConfig.rightPanel?.components || []; const finishedTimeline = rightComps.find((c: any) => c.id === "finished_timeline"); From 7ab05aea72c32ae534cf43b523c8c47d83c2faea Mon Sep 17 00:00:00 2001 From: chpark Date: Thu, 5 Mar 2026 21:45:26 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=EB=B0=94=EC=BD=94=EB=93=9C=20=EC=97=85?= =?UTF-8?q?=EA=B7=B8=EB=A0=88=EC=9D=B4=EB=93=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/BarcodeComponentPalette.tsx | 33 +++-- .../designer/BarcodeDesignerRightPanel.tsx | 126 +++++++++++++++++- 2 files changed, 143 insertions(+), 16 deletions(-) diff --git a/frontend/components/barcode/designer/BarcodeComponentPalette.tsx b/frontend/components/barcode/designer/BarcodeComponentPalette.tsx index e28ff12d..947ee2ed 100644 --- a/frontend/components/barcode/designer/BarcodeComponentPalette.tsx +++ b/frontend/components/barcode/designer/BarcodeComponentPalette.tsx @@ -6,9 +6,10 @@ 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 }[] = [ +const ITEMS: { type: BarcodeLabelComponent["type"]; label: string; icon: React.ReactNode; barcodeType?: string }[] = [ { type: "text", label: "ν…μŠ€νŠΈ", icon: }, { type: "barcode", label: "λ°”μ½”λ“œ", icon: }, + { type: "barcode", label: "QR μ½”λ“œ", icon: , barcodeType: "QR" }, { type: "image", label: "이미지", icon: }, { type: "line", label: "μ„ ", icon: }, { type: "rectangle", label: "μ‚¬κ°ν˜•", icon: }, @@ -16,22 +17,24 @@ const ITEMS: { type: BarcodeLabelComponent["type"]; label: string; icon: React.R const MM_TO_PX = 4; -function defaultComponent(type: BarcodeLabelComponent["type"]): BarcodeLabelComponent { +function defaultComponent(type: BarcodeLabelComponent["type"], barcodeType?: string): 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": + case "barcode": { + const isQR = barcodeType === "QR"; return { ...base, - width: 120, - height: 40, - barcodeType: "CODE128", - barcodeValue: "123456789", - showBarcodeText: true, + width: isQR ? 100 : 120, + height: isQR ? 100 : 40, + barcodeType: barcodeType || "CODE128", + barcodeValue: isQR ? "" : "123456789", + showBarcodeText: !isQR, }; + } case "image": return { ...base, width: 60, height: 60, imageUrl: "", objectFit: "contain" }; case "line": @@ -47,14 +50,16 @@ function DraggableItem({ type, label, icon, + barcodeType, }: { type: BarcodeLabelComponent["type"]; label: string; icon: React.ReactNode; + barcodeType?: string; }) { const [{ isDragging }, drag] = useDrag(() => ({ type: "barcode-component", - item: { component: defaultComponent(type) }, + item: { component: defaultComponent(type, barcodeType) }, collect: (m) => ({ isDragging: m.isDragging() }), })); @@ -78,8 +83,14 @@ export function BarcodeComponentPalette() { μš”μ†Œ μΆ”κ°€ - {ITEMS.map((item) => ( - + {ITEMS.map((item, idx) => ( + ))} diff --git a/frontend/components/barcode/designer/BarcodeDesignerRightPanel.tsx b/frontend/components/barcode/designer/BarcodeDesignerRightPanel.tsx index aaa92d2c..beb04289 100644 --- a/frontend/components/barcode/designer/BarcodeDesignerRightPanel.tsx +++ b/frontend/components/barcode/designer/BarcodeDesignerRightPanel.tsx @@ -1,14 +1,125 @@ "use client"; +import { useState, useEffect } from "react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Button } from "@/components/ui/button"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; -import { Trash2 } from "lucide-react"; +import { Trash2, Plus } from "lucide-react"; +import { ScrollArea } from "@/components/ui/scroll-area"; import { useBarcodeDesigner } from "@/contexts/BarcodeDesignerContext"; import { BarcodeLabelComponent } from "@/types/barcode"; +// QR κΈ°λ³Έ ν‚€: ν’ˆλ²ˆ, ν’ˆλͺ…, 규격 +const DEFAULT_QR_JSON_KEYS = ["part_no", "part_name", "spec"]; + +function parseQRJsonValue(str: string): Record { + const trimmed = (str || "").trim(); + if (!trimmed) return {}; + try { + const o = JSON.parse(trimmed); + if (o && typeof o === "object" && !Array.isArray(o)) { + return Object.fromEntries( + Object.entries(o).map(([k, v]) => [String(k), v != null ? String(v) : ""]) + ); + } + } catch { + // ignore + } + return {}; +} + +function QRJsonFields({ + selected, + update, +}: { + selected: BarcodeLabelComponent; + update: (u: Partial) => void; +}) { + const [pairs, setPairs] = useState<{ key: string; value: string }[]>(() => { + const parsed = parseQRJsonValue(selected.barcodeValue || ""); + if (Object.keys(parsed).length > 0) { + return Object.entries(parsed).map(([key, value]) => ({ key, value })); + } + return DEFAULT_QR_JSON_KEYS.map((key) => ({ key, value: "" })); + }); + + // λ°”μ½”λ“œ 값이 λ°”κΉ₯μ—μ„œ λ°”λ€Œλ©΄ νŒŒμ‹±ν•΄μ„œ 동기화 + useEffect(() => { + const parsed = parseQRJsonValue(selected.barcodeValue || ""); + if (Object.keys(parsed).length > 0) { + setPairs(Object.entries(parsed).map(([key, value]) => ({ key, value: String(value ?? "") }))); + } + }, [selected.barcodeValue]); + + const applyJson = () => { + const obj: Record = {}; + pairs.forEach(({ key, value }) => { + const k = key.trim(); + if (k) obj[k] = value.trim(); + }); + update({ barcodeValue: JSON.stringify(obj) }); + }; + + const setPair = (index: number, field: "key" | "value", val: string) => { + setPairs((prev) => { + const next = [...prev]; + if (!next[index]) next[index] = { key: "", value: "" }; + next[index] = { ...next[index], [field]: val }; + return next; + }); + }; + + const addRow = () => setPairs((prev) => [...prev, { key: "", value: "" }]); + const removeRow = (index: number) => + setPairs((prev) => (prev.length <= 1 ? prev : prev.filter((_, i) => i !== index))); + + return ( +
+ +

ν‚€λŠ” 자유 μž…λ ₯, κ°’ μž…λ ₯ ν›„ 적용 λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ QR에 λ°˜μ˜λ©λ‹ˆλ‹€.

+
+ {pairs.map((p, i) => ( +
+ setPair(i, "key", e.target.value)} + /> + setPair(i, "value", e.target.value)} + /> + +
+ ))} +
+
+ + +
+
+ ); +} + export function BarcodeDesignerRightPanel() { const { components, @@ -56,8 +167,8 @@ export function BarcodeDesignerRightPanel() { updateComponent(selected.id, updates); return ( -
-
+
+
속성
+
@@ -161,12 +273,15 @@ export function BarcodeDesignerRightPanel() {
+ {selected.barcodeType === "QR" && ( + + )}
- + update({ barcodeValue: e.target.value })} - placeholder="123456789" + placeholder={selected.barcodeType === "QR" ? '{"part_no":"","part_name":"","spec":""}' : "123456789"} />
@@ -246,6 +361,7 @@ export function BarcodeDesignerRightPanel() {
)}
+
); }