속성창 줄이기
This commit is contained in:
parent
775fbf8903
commit
711e051b1c
|
|
@ -29,59 +29,6 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
|
||||
return (
|
||||
<div className={`space-y-6 p-6 ${className}`}>
|
||||
{/* 여백 섹션 */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Box className="text-primary h-4 w-4" />
|
||||
<h3 className="text-sm font-semibold">여백</h3>
|
||||
</div>
|
||||
<Separator className="my-2" />
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="margin" className="text-xs font-medium">
|
||||
외부 여백
|
||||
</Label>
|
||||
<Input
|
||||
id="margin"
|
||||
type="text"
|
||||
placeholder="10px"
|
||||
value={localStyle.margin || ""}
|
||||
onChange={(e) => handleStyleChange("margin", e.target.value)}
|
||||
className="h-8"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="padding" className="text-xs font-medium">
|
||||
내부 여백
|
||||
</Label>
|
||||
<Input
|
||||
id="padding"
|
||||
type="text"
|
||||
placeholder="10px"
|
||||
value={localStyle.padding || ""}
|
||||
onChange={(e) => handleStyleChange("padding", e.target.value)}
|
||||
className="h-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<Label htmlFor="gap" className="text-xs font-medium">
|
||||
간격
|
||||
</Label>
|
||||
<Input
|
||||
id="gap"
|
||||
type="text"
|
||||
placeholder="10px"
|
||||
value={localStyle.gap || ""}
|
||||
onChange={(e) => handleStyleChange("gap", e.target.value)}
|
||||
className="h-8"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 테두리 섹션 */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -101,7 +48,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
placeholder="1px"
|
||||
value={localStyle.borderWidth || ""}
|
||||
onChange={(e) => handleStyleChange("borderWidth", e.target.value)}
|
||||
className="h-8"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
|
|
@ -112,7 +59,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
value={localStyle.borderStyle || "solid"}
|
||||
onValueChange={(value) => handleStyleChange("borderStyle", value)}
|
||||
>
|
||||
<SelectTrigger className="h-8">
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -136,14 +83,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
type="color"
|
||||
value={localStyle.borderColor || "#000000"}
|
||||
onChange={(e) => handleStyleChange("borderColor", e.target.value)}
|
||||
className="h-8 w-14 p-1"
|
||||
className="h-8 w-14 p-1 text-xs"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
value={localStyle.borderColor || "#000000"}
|
||||
onChange={(e) => handleStyleChange("borderColor", e.target.value)}
|
||||
placeholder="#000000"
|
||||
className="h-8 flex-1"
|
||||
className="h-8 flex-1 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -157,7 +104,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
placeholder="5px"
|
||||
value={localStyle.borderRadius || ""}
|
||||
onChange={(e) => handleStyleChange("borderRadius", e.target.value)}
|
||||
className="h-8"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -182,14 +129,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
type="color"
|
||||
value={localStyle.backgroundColor || "#ffffff"}
|
||||
onChange={(e) => handleStyleChange("backgroundColor", e.target.value)}
|
||||
className="h-8 w-14 p-1"
|
||||
className="h-8 w-14 p-1 text-xs"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
value={localStyle.backgroundColor || "#ffffff"}
|
||||
onChange={(e) => handleStyleChange("backgroundColor", e.target.value)}
|
||||
placeholder="#ffffff"
|
||||
className="h-8 flex-1"
|
||||
className="h-8 flex-1 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -204,7 +151,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
placeholder="url('image.jpg')"
|
||||
value={localStyle.backgroundImage || ""}
|
||||
onChange={(e) => handleStyleChange("backgroundImage", e.target.value)}
|
||||
className="h-8"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -229,14 +176,14 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
type="color"
|
||||
value={localStyle.color || "#000000"}
|
||||
onChange={(e) => handleStyleChange("color", e.target.value)}
|
||||
className="h-8 w-14 p-1"
|
||||
className="h-8 w-14 p-1 text-xs"
|
||||
/>
|
||||
<Input
|
||||
type="text"
|
||||
value={localStyle.color || "#000000"}
|
||||
onChange={(e) => handleStyleChange("color", e.target.value)}
|
||||
placeholder="#000000"
|
||||
className="h-8 flex-1"
|
||||
className="h-8 flex-1 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -250,7 +197,7 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
placeholder="14px"
|
||||
value={localStyle.fontSize || ""}
|
||||
onChange={(e) => handleStyleChange("fontSize", e.target.value)}
|
||||
className="h-8"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -264,17 +211,31 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
value={localStyle.fontWeight || "normal"}
|
||||
onValueChange={(value) => handleStyleChange("fontWeight", value)}
|
||||
>
|
||||
<SelectTrigger className="h-6 w-full text-[10px] px-2">
|
||||
<SelectTrigger className="h-6 w-full px-2 text-[10px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="normal" className="text-[10px]">보통</SelectItem>
|
||||
<SelectItem value="bold" className="text-[10px]">굵게</SelectItem>
|
||||
<SelectItem value="100" className="text-[10px]">100</SelectItem>
|
||||
<SelectItem value="400" className="text-[10px]">400</SelectItem>
|
||||
<SelectItem value="500" className="text-[10px]">500</SelectItem>
|
||||
<SelectItem value="600" className="text-[10px]">600</SelectItem>
|
||||
<SelectItem value="700" className="text-[10px]">700</SelectItem>
|
||||
<SelectItem value="normal" className="text-[10px]">
|
||||
보통
|
||||
</SelectItem>
|
||||
<SelectItem value="bold" className="text-[10px]">
|
||||
굵게
|
||||
</SelectItem>
|
||||
<SelectItem value="100" className="text-[10px]">
|
||||
100
|
||||
</SelectItem>
|
||||
<SelectItem value="400" className="text-[10px]">
|
||||
400
|
||||
</SelectItem>
|
||||
<SelectItem value="500" className="text-[10px]">
|
||||
500
|
||||
</SelectItem>
|
||||
<SelectItem value="600" className="text-[10px]">
|
||||
600
|
||||
</SelectItem>
|
||||
<SelectItem value="700" className="text-[10px]">
|
||||
700
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
|
@ -286,14 +247,22 @@ export default function StyleEditor({ style, onStyleChange, className }: StyleEd
|
|||
value={localStyle.textAlign || "left"}
|
||||
onValueChange={(value) => handleStyleChange("textAlign", value)}
|
||||
>
|
||||
<SelectTrigger className="h-6 w-full text-[10px] px-2">
|
||||
<SelectTrigger className="h-6 w-full px-2 text-[10px]">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="left" className="text-[10px]">왼쪽</SelectItem>
|
||||
<SelectItem value="center" className="text-[10px]">가운데</SelectItem>
|
||||
<SelectItem value="right" className="text-[10px]">오른쪽</SelectItem>
|
||||
<SelectItem value="justify" className="text-[10px]">양쪽</SelectItem>
|
||||
<SelectItem value="left" className="text-[10px]">
|
||||
왼쪽
|
||||
</SelectItem>
|
||||
<SelectItem value="center" className="text-[10px]">
|
||||
가운데
|
||||
</SelectItem>
|
||||
<SelectItem value="right" className="text-[10px]">
|
||||
오른쪽
|
||||
</SelectItem>
|
||||
<SelectItem value="justify" className="text-[10px]">
|
||||
양쪽
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -515,94 +515,60 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
{/* 테이블 이력 보기 액션 설정 */}
|
||||
{(component.componentConfig?.action?.type || "save") === "view_table_history" && (
|
||||
<div className="mt-4 space-y-4">
|
||||
<h4 className="text-sm font-medium">📜 테이블 이력 보기 설정</h4>
|
||||
|
||||
<div>
|
||||
<Label>
|
||||
전체 이력 표시 컬럼 (필수) <span className="text-red-600">*</span>
|
||||
</Label>
|
||||
|
||||
{!config.action?.historyTableName && !currentTableName ? (
|
||||
<div className="mt-2 rounded-md border border-yellow-300 bg-yellow-50 p-3">
|
||||
<p className="text-xs text-yellow-800">
|
||||
⚠️ 먼저 <strong>테이블명</strong>을 입력하거나, 현재 화면에 테이블을 연결해주세요.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{!config.action?.historyTableName && currentTableName && (
|
||||
<div className="mt-2 rounded-md border border-green-300 bg-green-50 p-2">
|
||||
<p className="text-xs text-green-800">
|
||||
✓ 현재 화면의 테이블 <strong>{currentTableName}</strong>을(를) 자동으로 사용합니다.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Popover open={displayColumnOpen} onOpenChange={setDisplayColumnOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={displayColumnOpen}
|
||||
className="mt-2 h-10 w-full justify-between text-sm"
|
||||
disabled={columnsLoading || tableColumns.length === 0}
|
||||
>
|
||||
{columnsLoading
|
||||
? "로딩 중..."
|
||||
: config.action?.historyDisplayColumn
|
||||
? config.action.historyDisplayColumn
|
||||
: tableColumns.length === 0
|
||||
? "사용 가능한 컬럼이 없습니다"
|
||||
: "컬럼을 선택하세요"}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-sm" />
|
||||
<CommandList>
|
||||
<CommandEmpty className="text-sm">컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{tableColumns.map((column) => (
|
||||
<CommandItem
|
||||
key={column}
|
||||
value={column}
|
||||
onSelect={(currentValue) => {
|
||||
onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
|
||||
setDisplayColumnOpen(false);
|
||||
}}
|
||||
className="text-sm"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
config.action?.historyDisplayColumn === column ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{column}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
<p className="mt-2 text-xs text-gray-700">
|
||||
<strong>전체 테이블 이력</strong>에서 레코드를 구분하기 위한 컬럼입니다.
|
||||
<br />
|
||||
예: <code className="rounded bg-white px-1">device_code</code>를 설정하면 이력에 "DTG-001"로
|
||||
표시됩니다.
|
||||
<br />이 컬럼으로 검색도 가능합니다.
|
||||
</p>
|
||||
|
||||
{tableColumns.length === 0 && !columnsLoading && (
|
||||
<p className="mt-2 text-xs text-red-600">
|
||||
⚠️ ID 및 날짜 타입 컬럼을 제외한 사용 가능한 컬럼이 없습니다.
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Popover open={displayColumnOpen} onOpenChange={setDisplayColumnOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={displayColumnOpen}
|
||||
className="mt-2 h-8 w-full justify-between text-xs"
|
||||
disabled={columnsLoading || tableColumns.length === 0}
|
||||
>
|
||||
{columnsLoading
|
||||
? "로딩 중..."
|
||||
: config.action?.historyDisplayColumn
|
||||
? config.action.historyDisplayColumn
|
||||
: tableColumns.length === 0
|
||||
? "사용 가능한 컬럼이 없습니다"
|
||||
: "컬럼을 선택하세요"}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" style={{ width: "var(--radix-popover-trigger-width)" }} align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-sm" />
|
||||
<CommandList>
|
||||
<CommandEmpty className="text-sm">컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{tableColumns.map((column) => (
|
||||
<CommandItem
|
||||
key={column}
|
||||
value={column}
|
||||
onSelect={(currentValue) => {
|
||||
onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
|
||||
setDisplayColumnOpen(false);
|
||||
}}
|
||||
className="text-sm"
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
config.action?.historyDisplayColumn === column ? "opacity-100" : "opacity-0",
|
||||
)}
|
||||
/>
|
||||
{column}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -693,6 +659,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
setLocalInputs((prev) => ({ ...prev, targetUrl: newValue }));
|
||||
onUpdateProperty("componentConfig.action.targetUrl", newValue);
|
||||
}}
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-gray-500">URL을 입력하면 화면 선택보다 우선 적용됩니다</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ interface ComponentsPanelProps {
|
|||
placedColumns?: Set<string>; // 이미 배치된 컬럼명 집합
|
||||
}
|
||||
|
||||
export function ComponentsPanel({
|
||||
className,
|
||||
tables = [],
|
||||
searchTerm = "",
|
||||
onSearchChange,
|
||||
export function ComponentsPanel({
|
||||
className,
|
||||
tables = [],
|
||||
searchTerm = "",
|
||||
onSearchChange,
|
||||
onTableDragStart,
|
||||
selectedTableName,
|
||||
placedColumns
|
||||
placedColumns,
|
||||
}: ComponentsPanelProps) {
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
|
|
@ -176,8 +176,8 @@ export function ComponentsPanel({
|
|||
</div>
|
||||
|
||||
{/* 카테고리 탭 */}
|
||||
<Tabs defaultValue="input" className="flex flex-1 flex-col">
|
||||
<TabsList className="mb-3 grid h-8 w-full grid-cols-5">
|
||||
<Tabs defaultValue="input" className="flex min-h-0 flex-1 flex-col">
|
||||
<TabsList className="mb-3 grid h-8 w-full flex-shrink-0 grid-cols-5">
|
||||
<TabsTrigger value="tables" className="flex items-center gap-1 px-1 text-xs">
|
||||
<Database className="h-3 w-3" />
|
||||
<span className="hidden sm:inline">테이블</span>
|
||||
|
|
|
|||
|
|
@ -1150,7 +1150,7 @@ export const DetailSettingsPanel: React.FC<DetailSettingsPanelProps> = ({
|
|||
<div className="space-y-2">
|
||||
<label className="block text-sm font-medium text-gray-700">세부 타입 선택</label>
|
||||
<Select value={localDetailType} onValueChange={handleDetailTypeChange}>
|
||||
<SelectTrigger className="w-full bg-white">
|
||||
<SelectTrigger className="h-8 w-full bg-white text-xs">
|
||||
<SelectValue placeholder="세부 타입을 선택하세요" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
|
|||
|
|
@ -551,11 +551,6 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
|||
|
||||
{/* 액션 버튼들 */}
|
||||
<div className="flex flex-wrap gap-1.5">
|
||||
<Button size="sm" variant="outline" onClick={onCopyComponent} className="h-8 px-2.5 text-xs">
|
||||
<Copy className="mr-1 h-3 w-3" />
|
||||
복사
|
||||
</Button>
|
||||
|
||||
{canGroup && (
|
||||
<Button size="sm" variant="outline" onClick={onGroupComponents} className="h-8 px-2.5 text-xs">
|
||||
<Group className="mr-1 h-3 w-3" />
|
||||
|
|
@ -569,11 +564,6 @@ const PropertiesPanelComponent: React.FC<PropertiesPanelProps> = ({
|
|||
해제
|
||||
</Button>
|
||||
)}
|
||||
|
||||
<Button size="sm" variant="destructive" onClick={onDeleteComponent} className="h-8 px-2.5 text-xs">
|
||||
<Trash2 className="mr-1 h-3 w-3" />
|
||||
삭제
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
|
|||
<div className="space-y-4">
|
||||
{/* 프리셋 선택 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium">해상도 프리셋</Label>
|
||||
<Label className="text-xs font-medium">해상도 프리셋</Label>
|
||||
<Select value={selectedPreset} onValueChange={handlePresetChange}>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="해상도를 선택하세요" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -93,7 +93,7 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
|
|||
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
|
||||
<SelectItem key={resolution.name} value={resolution.name}>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Monitor className="h-4 w-4 text-primary" />
|
||||
<Monitor className="text-primary h-4 w-4" />
|
||||
<span>{resolution.name}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
|
|
@ -125,7 +125,7 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
|
|||
<div className="px-2 py-1 text-xs font-medium text-gray-500">사용자 정의</div>
|
||||
<SelectItem value="custom">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Settings className="h-4 w-4 text-muted-foreground" />
|
||||
<Settings className="text-muted-foreground h-4 w-4" />
|
||||
<span>사용자 정의</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
|
|
@ -139,43 +139,33 @@ const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, on
|
|||
<Label className="text-sm font-medium">사용자 정의 해상도</Label>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-muted-foreground">너비 (px)</Label>
|
||||
<Label className="text-muted-foreground text-xs">너비 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={customWidth}
|
||||
onChange={(e) => setCustomWidth(e.target.value)}
|
||||
placeholder="1920"
|
||||
min="1"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-muted-foreground">높이 (px)</Label>
|
||||
<Label className="text-muted-foreground text-xs">높이 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={customHeight}
|
||||
onChange={(e) => setCustomHeight(e.target.value)}
|
||||
placeholder="1080"
|
||||
min="1"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={handleCustomResolution} size="sm" className="w-full">
|
||||
<Button onClick={handleCustomResolution} size="sm" className="h-8 w-full text-xs">
|
||||
적용
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 해상도 정보 */}
|
||||
<div className="space-y-2 text-xs text-gray-500">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>화면 비율:</span>
|
||||
<span>{(currentResolution.width / currentResolution.height).toFixed(2)}:1</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span>총 픽셀:</span>
|
||||
<span>{(currentResolution.width * currentResolution.height).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -202,15 +202,6 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
|
||||
return (
|
||||
<div className="space-y-1.5">
|
||||
{/* 컴포넌트 정보 - 간소화 */}
|
||||
<div className="bg-muted flex items-center justify-between rounded px-2 py-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<Info className="text-muted-foreground h-2.5 w-2.5" />
|
||||
<span className="text-foreground text-[10px] font-medium">{selectedComponent.type}</span>
|
||||
</div>
|
||||
<span className="text-muted-foreground text-[9px]">{selectedComponent.id.slice(0, 8)}</span>
|
||||
</div>
|
||||
|
||||
{/* 라벨 + 최소 높이 (같은 행) */}
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
<div className="space-y-0.5">
|
||||
|
|
@ -300,24 +291,15 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* 위치 */}
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
<div>
|
||||
<Label>X {dragState?.isDragging && <Badge variant="secondary">드래그중</Badge>}</Label>
|
||||
<Input type="number" value={Math.round(currentPosition.x || 0)} disabled />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Y</Label>
|
||||
<Input type="number" value={Math.round(currentPosition.y || 0)} disabled />
|
||||
</div>
|
||||
<div>
|
||||
<Label>Z</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={currentPosition.z || 1}
|
||||
onChange={(e) => handleUpdate("position.z", parseInt(e.target.value) || 1)}
|
||||
/>
|
||||
</div>
|
||||
{/* Z-Index */}
|
||||
<div className="space-y-0.5">
|
||||
<Label className="text-[10px]">Z-Index (레이어)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={currentPosition.z || 1}
|
||||
onChange={(e) => handleUpdate("position.z", parseInt(e.target.value) || 1)}
|
||||
className="h-6 text-[10px]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 라벨 스타일 */}
|
||||
|
|
@ -389,33 +371,6 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 액션 버튼 */}
|
||||
<Separator />
|
||||
<div className="flex gap-2">
|
||||
{onCopyComponent && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onCopyComponent(selectedComponent.id)}
|
||||
className="flex-1"
|
||||
>
|
||||
<Copy className="mr-2 h-4 w-4" />
|
||||
복사
|
||||
</Button>
|
||||
)}
|
||||
{onDeleteComponent && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onDeleteComponent(selectedComponent.id)}
|
||||
className="flex-1 text-red-600 hover:bg-red-50 hover:text-red-700"
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -513,7 +468,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
<div>
|
||||
<Label>세부 타입</Label>
|
||||
<Select value={localComponentDetailType || webType} onValueChange={handleDetailTypeChange}>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="세부 타입 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -561,7 +516,7 @@ export const UnifiedPropertiesPanel: React.FC<UnifiedPropertiesPanelProps> = ({
|
|||
<div>
|
||||
<Label>입력 타입</Label>
|
||||
<Select value={widget.webType} onValueChange={(value) => handleUpdate("webType", value)}>
|
||||
<SelectTrigger>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
|
|||
|
|
@ -90,11 +90,11 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
|
|||
|
||||
const newConfig = JSON.parse(JSON.stringify(currentValues));
|
||||
// console.log("☑️ CheckboxTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// });
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
@ -122,7 +122,7 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
|
|||
라벨 위치
|
||||
</Label>
|
||||
<Select value={localValues.labelPosition} onValueChange={(value) => updateConfig("labelPosition", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="라벨 위치 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -218,7 +218,7 @@ export const CheckboxTypeConfigPanel: React.FC<CheckboxTypeConfigPanelProps> = (
|
|||
|
||||
{/* 안내 메시지 */}
|
||||
{localValues.indeterminate && (
|
||||
<div className="rounded-md bg-accent p-3">
|
||||
<div className="bg-accent rounded-md p-3">
|
||||
<div className="text-sm font-medium text-blue-900">불확정 상태</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
체크박스가 부분적으로 선택된 상태를 나타낼 수 있습니다. 주로 트리 구조에서 일부 하위 항목만 선택된 경우에
|
||||
|
|
|
|||
|
|
@ -105,10 +105,10 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
|
|||
// 실제 config 업데이트
|
||||
const newConfig = { ...safeConfig, [key]: value };
|
||||
// console.log("💻 CodeTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// });
|
||||
onConfigChange(newConfig);
|
||||
};
|
||||
|
|
@ -121,7 +121,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
|
|||
프로그래밍 언어
|
||||
</Label>
|
||||
<Select value={localValues.language} onValueChange={(value) => updateConfig("language", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="언어 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="max-h-60">
|
||||
|
|
@ -140,7 +140,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
|
|||
테마
|
||||
</Label>
|
||||
<Select value={localValues.theme} onValueChange={(value) => updateConfig("theme", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="테마 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -271,7 +271,7 @@ export const CodeTypeConfigPanel: React.FC<CodeTypeConfigPanelProps> = ({ config
|
|||
</div>
|
||||
|
||||
{/* 안내 메시지 */}
|
||||
<div className="rounded-md bg-accent p-3">
|
||||
<div className="bg-accent rounded-md p-3">
|
||||
<div className="text-sm font-medium text-blue-900">코드 에디터 설정</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
• 문법 강조 표시는 선택된 언어에 따라 적용됩니다
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
// 로컬 상태로 실시간 입력 관리
|
||||
const [localValues, setLocalValues] = useState(() => {
|
||||
// console.log("📅 DateTypeConfigPanel 초기 상태 설정:", {
|
||||
// config,
|
||||
// safeConfig,
|
||||
// config,
|
||||
// safeConfig,
|
||||
// });
|
||||
|
||||
return {
|
||||
|
|
@ -47,17 +47,17 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
const hasValidConfig = config && Object.keys(config).length > 0;
|
||||
|
||||
// console.log("📅 DateTypeConfigPanel config 변경 감지:", {
|
||||
// config,
|
||||
// configExists: !!config,
|
||||
// configKeys: config ? Object.keys(config) : [],
|
||||
// hasValidConfig,
|
||||
// safeConfig,
|
||||
// safeConfigKeys: Object.keys(safeConfig),
|
||||
// currentLocalValues: localValues,
|
||||
// configStringified: JSON.stringify(config),
|
||||
// safeConfigStringified: JSON.stringify(safeConfig),
|
||||
// willUpdateLocalValues: hasValidConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// config,
|
||||
// configExists: !!config,
|
||||
// configKeys: config ? Object.keys(config) : [],
|
||||
// hasValidConfig,
|
||||
// safeConfig,
|
||||
// safeConfigKeys: Object.keys(safeConfig),
|
||||
// currentLocalValues: localValues,
|
||||
// configStringified: JSON.stringify(config),
|
||||
// safeConfigStringified: JSON.stringify(safeConfig),
|
||||
// willUpdateLocalValues: hasValidConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// });
|
||||
|
||||
// config가 없거나 비어있으면 로컬 상태를 유지
|
||||
|
|
@ -85,17 +85,17 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
localValues.maxDate !== newLocalValues.maxDate;
|
||||
|
||||
// console.log("🔄 로컬 상태 업데이트 검사:", {
|
||||
// oldLocalValues: localValues,
|
||||
// newLocalValues,
|
||||
// hasChanges,
|
||||
// changes: {
|
||||
// format: localValues.format !== newLocalValues.format,
|
||||
// showTime: localValues.showTime !== newLocalValues.showTime,
|
||||
// defaultValue: localValues.defaultValue !== newLocalValues.defaultValue,
|
||||
// placeholder: localValues.placeholder !== newLocalValues.placeholder,
|
||||
// minDate: localValues.minDate !== newLocalValues.minDate,
|
||||
// maxDate: localValues.maxDate !== newLocalValues.maxDate,
|
||||
// },
|
||||
// oldLocalValues: localValues,
|
||||
// newLocalValues,
|
||||
// hasChanges,
|
||||
// changes: {
|
||||
// format: localValues.format !== newLocalValues.format,
|
||||
// showTime: localValues.showTime !== newLocalValues.showTime,
|
||||
// defaultValue: localValues.defaultValue !== newLocalValues.defaultValue,
|
||||
// placeholder: localValues.placeholder !== newLocalValues.placeholder,
|
||||
// minDate: localValues.minDate !== newLocalValues.minDate,
|
||||
// maxDate: localValues.maxDate !== newLocalValues.maxDate,
|
||||
// },
|
||||
// });
|
||||
|
||||
if (hasChanges) {
|
||||
|
|
@ -113,34 +113,34 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
// 실제 config 업데이트 - 현재 로컬 상태를 기반으로 새 객체 생성 (safeConfig 기본값 덮어쓰기 방지)
|
||||
const newConfig = JSON.parse(JSON.stringify({ ...localValues, [key]: value }));
|
||||
// console.log("📅 DateTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// changes: {
|
||||
// format: newConfig.format !== safeConfig.format,
|
||||
// showTime: newConfig.showTime !== safeConfig.showTime,
|
||||
// placeholder: newConfig.placeholder !== safeConfig.placeholder,
|
||||
// minDate: newConfig.minDate !== safeConfig.minDate,
|
||||
// maxDate: newConfig.maxDate !== safeConfig.maxDate,
|
||||
// defaultValue: newConfig.defaultValue !== safeConfig.defaultValue,
|
||||
// },
|
||||
// willCallOnConfigChange: true,
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// changes: {
|
||||
// format: newConfig.format !== safeConfig.format,
|
||||
// showTime: newConfig.showTime !== safeConfig.showTime,
|
||||
// placeholder: newConfig.placeholder !== safeConfig.placeholder,
|
||||
// minDate: newConfig.minDate !== safeConfig.minDate,
|
||||
// maxDate: newConfig.maxDate !== safeConfig.maxDate,
|
||||
// defaultValue: newConfig.defaultValue !== safeConfig.defaultValue,
|
||||
// },
|
||||
// willCallOnConfigChange: true,
|
||||
// });
|
||||
|
||||
// console.log("🔄 onConfigChange 호출 직전:", {
|
||||
// newConfig,
|
||||
// configStringified: JSON.stringify(newConfig),
|
||||
// newConfig,
|
||||
// configStringified: JSON.stringify(newConfig),
|
||||
// });
|
||||
|
||||
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
|
||||
setTimeout(() => {
|
||||
// console.log("✅ onConfigChange 호출 완료:", {
|
||||
// key,
|
||||
// newConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// key,
|
||||
// newConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// });
|
||||
onConfigChange(newConfig);
|
||||
}, 0);
|
||||
|
|
@ -157,9 +157,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
value={localValues.format}
|
||||
onValueChange={(value) => {
|
||||
// console.log("📅 날짜 형식 변경:", {
|
||||
// oldFormat: localValues.format,
|
||||
// newFormat: value,
|
||||
// oldShowTime: localValues.showTime,
|
||||
// oldFormat: localValues.format,
|
||||
// newFormat: value,
|
||||
// oldShowTime: localValues.showTime,
|
||||
// });
|
||||
|
||||
// format 변경 시 showTime도 자동 동기화
|
||||
|
|
@ -175,9 +175,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
);
|
||||
|
||||
// console.log("🔄 format+showTime 동시 업데이트:", {
|
||||
// newFormat: value,
|
||||
// newShowTime: hasTime,
|
||||
// newConfig,
|
||||
// newFormat: value,
|
||||
// newShowTime: hasTime,
|
||||
// newConfig,
|
||||
// });
|
||||
|
||||
// 로컬 상태도 동시 업데이트
|
||||
|
|
@ -193,7 +193,7 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
}, 0);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="날짜 형식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -215,9 +215,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
onCheckedChange={(checked) => {
|
||||
const newShowTime = !!checked;
|
||||
// console.log("⏰ 시간 표시 체크박스 변경:", {
|
||||
// oldShowTime: localValues.showTime,
|
||||
// newShowTime,
|
||||
// currentFormat: localValues.format,
|
||||
// oldShowTime: localValues.showTime,
|
||||
// newShowTime,
|
||||
// currentFormat: localValues.format,
|
||||
// });
|
||||
|
||||
// showTime 변경 시 format도 적절히 조정
|
||||
|
|
@ -231,9 +231,9 @@ export const DateTypeConfigPanel: React.FC<DateTypeConfigPanelProps> = ({ config
|
|||
}
|
||||
|
||||
// console.log("🔄 showTime+format 동시 업데이트:", {
|
||||
// newShowTime,
|
||||
// oldFormat: localValues.format,
|
||||
// newFormat,
|
||||
// newShowTime,
|
||||
// oldFormat: localValues.format,
|
||||
// newFormat,
|
||||
// });
|
||||
|
||||
// 한 번에 두 값을 모두 업데이트 - 현재 로컬 상태 기반으로 생성
|
||||
|
|
|
|||
|
|
@ -92,10 +92,10 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
// 실제 config 업데이트
|
||||
const newConfig = { ...safeConfig, [key]: value };
|
||||
// console.log("🏢 EntityTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// });
|
||||
onConfigChange(newConfig);
|
||||
};
|
||||
|
|
@ -233,7 +233,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
표시 형식
|
||||
</Label>
|
||||
<Select value={localValues.displayFormat} onValueChange={(value) => updateConfig("displayFormat", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="형식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -317,7 +317,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
<div className="mt-2">
|
||||
<div className="flex items-center space-x-2 rounded border bg-white p-2">
|
||||
<Search className="h-4 w-4 text-gray-400" />
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
<div className="text-muted-foreground flex-1 text-sm">
|
||||
{localValues.placeholder || `${localValues.referenceTable || "엔터티"}를 선택하세요`}
|
||||
</div>
|
||||
<Database className="h-4 w-4 text-gray-400" />
|
||||
|
|
@ -334,7 +334,7 @@ export const EntityTypeConfigPanel: React.FC<EntityTypeConfigPanelProps> = ({ co
|
|||
</div>
|
||||
|
||||
{/* 안내 메시지 */}
|
||||
<div className="rounded-md bg-accent p-3">
|
||||
<div className="bg-accent rounded-md p-3">
|
||||
<div className="text-sm font-medium text-blue-900">엔터티 타입 설정 가이드</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
• <strong>참조 테이블</strong>: 데이터를 가져올 다른 테이블 이름
|
||||
|
|
|
|||
|
|
@ -89,12 +89,12 @@ export const NumberTypeConfigPanel: React.FC<NumberTypeConfigPanelProps> = ({ co
|
|||
|
||||
const newConfig = JSON.parse(JSON.stringify(currentValues));
|
||||
// console.log("🔢 NumberTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// });
|
||||
|
||||
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
|
||||
|
|
@ -111,7 +111,7 @@ export const NumberTypeConfigPanel: React.FC<NumberTypeConfigPanelProps> = ({ co
|
|||
숫자 형식
|
||||
</Label>
|
||||
<Select value={localValues.format} onValueChange={(value) => updateConfig("format", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="숫자 형식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
|
|||
|
|
@ -82,11 +82,11 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
|
|||
// 실제 config 업데이트 - 깊은 복사로 새 객체 보장
|
||||
const newConfig = JSON.parse(JSON.stringify({ ...safeConfig, [key]: value }));
|
||||
// console.log("📋 SelectTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// });
|
||||
|
||||
// 약간의 지연을 두고 업데이트 (배치 업데이트 방지)
|
||||
|
|
@ -101,10 +101,10 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
|
|||
const updatedOptions = [...(safeConfig.options || []), newOptionData];
|
||||
|
||||
// console.log("➕ SelectType 옵션 추가:", {
|
||||
// newOption: newOptionData,
|
||||
// updatedOptions,
|
||||
// currentLocalOptions: localOptions,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// newOption: newOptionData,
|
||||
// updatedOptions,
|
||||
// currentLocalOptions: localOptions,
|
||||
// timestamp: new Date().toISOString(),
|
||||
// });
|
||||
|
||||
// 로컬 상태 즉시 업데이트
|
||||
|
|
@ -128,9 +128,9 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
|
|||
|
||||
const removeOption = (index: number) => {
|
||||
// console.log("➖ SelectType 옵션 삭제:", {
|
||||
// removeIndex: index,
|
||||
// currentOptions: safeConfig.options,
|
||||
// currentLocalOptions: localOptions,
|
||||
// removeIndex: index,
|
||||
// currentOptions: safeConfig.options,
|
||||
// currentLocalOptions: localOptions,
|
||||
// });
|
||||
|
||||
// 로컬 상태 즉시 업데이트
|
||||
|
|
@ -170,7 +170,7 @@ export const SelectTypeConfigPanel: React.FC<SelectTypeConfigPanelProps> = ({ co
|
|||
value={localValues.placeholder}
|
||||
onChange={(e) => updateConfig("placeholder", e.target.value)}
|
||||
placeholder="옵션을 선택하세요"
|
||||
className="mt-1"
|
||||
className="mt-1 h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -94,11 +94,11 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
|
|||
|
||||
const newConfig = JSON.parse(JSON.stringify(currentValues));
|
||||
// console.log("📝 TextTypeConfig 업데이트:", {
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// key,
|
||||
// value,
|
||||
// oldConfig: safeConfig,
|
||||
// newConfig,
|
||||
// localValues,
|
||||
// });
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
@ -114,7 +114,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
|
|||
입력 형식
|
||||
</Label>
|
||||
<Select value={localValues.format} onValueChange={(value) => updateConfig("format", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="입력 형식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -220,13 +220,13 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
|
|||
</div>
|
||||
|
||||
{localValues.autoInput && (
|
||||
<div className="space-y-3 border-l-2 border-primary/20 pl-4">
|
||||
<div className="border-primary/20 space-y-3 border-l-2 pl-4">
|
||||
<div>
|
||||
<Label htmlFor="autoValueType" className="text-sm font-medium">
|
||||
자동값 타입
|
||||
</Label>
|
||||
<Select value={localValues.autoValueType} onValueChange={(value) => updateConfig("autoValueType", value)}>
|
||||
<SelectTrigger className="mt-1">
|
||||
<SelectTrigger className="mt-1 h-8 text-xs">
|
||||
<SelectValue placeholder="자동값 타입 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
@ -256,7 +256,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div className="rounded-md bg-accent p-3">
|
||||
<div className="bg-accent rounded-md p-3">
|
||||
<div className="text-sm font-medium text-blue-900">자동입력 안내</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
자동입력이 활성화되면 해당 필드는 읽기 전용이 되며, 설정된 타입에 따라 자동으로 값이 입력됩니다.
|
||||
|
|
@ -280,7 +280,7 @@ export const TextTypeConfigPanel: React.FC<TextTypeConfigPanelProps> = ({ config
|
|||
|
||||
{/* 형식별 안내 메시지 */}
|
||||
{localValues.format !== "none" && (
|
||||
<div className="rounded-md bg-accent p-3">
|
||||
<div className="bg-accent rounded-md p-3">
|
||||
<div className="text-sm font-medium text-blue-900">형식 안내</div>
|
||||
<div className="mt-1 text-xs text-blue-800">
|
||||
{localValues.format === "email" && "유효한 이메일 주소를 입력해야 합니다 (예: user@example.com)"}
|
||||
|
|
|
|||
Loading…
Reference in New Issue