223 lines
7.6 KiB
TypeScript
223 lines
7.6 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
/**
|
||
|
|
* UnifiedGroup 설정 패널
|
||
|
|
* 통합 그룹 컴포넌트의 세부 설정을 관리합니다.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import React from "react";
|
||
|
|
import { Label } from "@/components/ui/label";
|
||
|
|
import { Input } from "@/components/ui/input";
|
||
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||
|
|
import { Separator } from "@/components/ui/separator";
|
||
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
import { Plus, Trash2 } from "lucide-react";
|
||
|
|
|
||
|
|
interface UnifiedGroupConfigPanelProps {
|
||
|
|
config: Record<string, any>;
|
||
|
|
onChange: (config: Record<string, any>) => void;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const UnifiedGroupConfigPanel: React.FC<UnifiedGroupConfigPanelProps> = ({
|
||
|
|
config,
|
||
|
|
onChange,
|
||
|
|
}) => {
|
||
|
|
// 설정 업데이트 핸들러
|
||
|
|
const updateConfig = (field: string, value: any) => {
|
||
|
|
onChange({ ...config, [field]: value });
|
||
|
|
};
|
||
|
|
|
||
|
|
// 탭 관리
|
||
|
|
const tabs = config.tabs || [];
|
||
|
|
|
||
|
|
const addTab = () => {
|
||
|
|
const newTabs = [...tabs, { id: `tab-${Date.now()}`, label: "새 탭", content: "" }];
|
||
|
|
updateConfig("tabs", newTabs);
|
||
|
|
};
|
||
|
|
|
||
|
|
const updateTab = (index: number, field: string, value: string) => {
|
||
|
|
const newTabs = [...tabs];
|
||
|
|
newTabs[index] = { ...newTabs[index], [field]: value };
|
||
|
|
updateConfig("tabs", newTabs);
|
||
|
|
};
|
||
|
|
|
||
|
|
const removeTab = (index: number) => {
|
||
|
|
const newTabs = tabs.filter((_: any, i: number) => i !== index);
|
||
|
|
updateConfig("tabs", newTabs);
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="space-y-4">
|
||
|
|
{/* 그룹 타입 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label className="text-xs font-medium">그룹 타입</Label>
|
||
|
|
<Select
|
||
|
|
value={config.groupType || config.type || "section"}
|
||
|
|
onValueChange={(value) => updateConfig("groupType", value)}
|
||
|
|
>
|
||
|
|
<SelectTrigger className="h-8 text-xs">
|
||
|
|
<SelectValue placeholder="타입 선택" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
<SelectItem value="section">섹션</SelectItem>
|
||
|
|
<SelectItem value="tabs">탭</SelectItem>
|
||
|
|
<SelectItem value="accordion">아코디언</SelectItem>
|
||
|
|
<SelectItem value="card">카드 섹션</SelectItem>
|
||
|
|
<SelectItem value="modal">모달</SelectItem>
|
||
|
|
<SelectItem value="form-modal">폼 모달</SelectItem>
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Separator />
|
||
|
|
|
||
|
|
{/* 제목 */}
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label className="text-xs font-medium">제목</Label>
|
||
|
|
<Input
|
||
|
|
value={config.title || ""}
|
||
|
|
onChange={(e) => updateConfig("title", e.target.value)}
|
||
|
|
placeholder="그룹 제목"
|
||
|
|
className="h-8 text-xs"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* 탭 설정 */}
|
||
|
|
{config.groupType === "tabs" && (
|
||
|
|
<div className="space-y-2">
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<Label className="text-xs font-medium">탭 목록</Label>
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="ghost"
|
||
|
|
size="sm"
|
||
|
|
onClick={addTab}
|
||
|
|
className="h-6 px-2 text-xs"
|
||
|
|
>
|
||
|
|
<Plus className="h-3 w-3 mr-1" />
|
||
|
|
추가
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
<div className="space-y-2 max-h-40 overflow-y-auto">
|
||
|
|
{tabs.map((tab: any, index: number) => (
|
||
|
|
<div key={index} className="flex items-center gap-2">
|
||
|
|
<Input
|
||
|
|
value={tab.id || ""}
|
||
|
|
onChange={(e) => updateTab(index, "id", e.target.value)}
|
||
|
|
placeholder="ID"
|
||
|
|
className="h-7 text-xs flex-1"
|
||
|
|
/>
|
||
|
|
<Input
|
||
|
|
value={tab.label || ""}
|
||
|
|
onChange={(e) => updateTab(index, "label", e.target.value)}
|
||
|
|
placeholder="라벨"
|
||
|
|
className="h-7 text-xs flex-1"
|
||
|
|
/>
|
||
|
|
<Button
|
||
|
|
type="button"
|
||
|
|
variant="ghost"
|
||
|
|
size="sm"
|
||
|
|
onClick={() => removeTab(index)}
|
||
|
|
className="h-7 w-7 p-0 text-destructive"
|
||
|
|
>
|
||
|
|
<Trash2 className="h-3 w-3" />
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
{tabs.length === 0 && (
|
||
|
|
<p className="text-xs text-muted-foreground text-center py-2">
|
||
|
|
탭을 추가해주세요
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 섹션/아코디언 옵션 */}
|
||
|
|
{(config.groupType === "section" || config.groupType === "accordion" || !config.groupType) && (
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="collapsible"
|
||
|
|
checked={config.collapsible || false}
|
||
|
|
onCheckedChange={(checked) => updateConfig("collapsible", checked)}
|
||
|
|
/>
|
||
|
|
<label htmlFor="collapsible" className="text-xs">접기/펴기 가능</label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{config.collapsible && (
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="defaultOpen"
|
||
|
|
checked={config.defaultOpen !== false}
|
||
|
|
onCheckedChange={(checked) => updateConfig("defaultOpen", checked)}
|
||
|
|
/>
|
||
|
|
<label htmlFor="defaultOpen" className="text-xs">기본으로 펼침</label>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 모달 옵션 */}
|
||
|
|
{(config.groupType === "modal" || config.groupType === "form-modal") && (
|
||
|
|
<div className="space-y-3">
|
||
|
|
<div className="space-y-2">
|
||
|
|
<Label className="text-xs font-medium">모달 크기</Label>
|
||
|
|
<Select
|
||
|
|
value={config.modalSize || "md"}
|
||
|
|
onValueChange={(value) => updateConfig("modalSize", value)}
|
||
|
|
>
|
||
|
|
<SelectTrigger className="h-8 text-xs">
|
||
|
|
<SelectValue />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
<SelectItem value="sm">작게 (400px)</SelectItem>
|
||
|
|
<SelectItem value="md">보통 (600px)</SelectItem>
|
||
|
|
<SelectItem value="lg">크게 (800px)</SelectItem>
|
||
|
|
<SelectItem value="xl">매우 크게 (1000px)</SelectItem>
|
||
|
|
<SelectItem value="full">전체 화면</SelectItem>
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="closeable"
|
||
|
|
checked={config.closeable !== false}
|
||
|
|
onCheckedChange={(checked) => updateConfig("closeable", checked)}
|
||
|
|
/>
|
||
|
|
<label htmlFor="closeable" className="text-xs">닫기 버튼 표시</label>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="backdrop"
|
||
|
|
checked={config.backdrop !== false}
|
||
|
|
onCheckedChange={(checked) => updateConfig("backdrop", checked)}
|
||
|
|
/>
|
||
|
|
<label htmlFor="backdrop" className="text-xs">배경 클릭으로 닫기</label>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* 헤더 표시 여부 */}
|
||
|
|
<Separator />
|
||
|
|
<div className="flex items-center space-x-2">
|
||
|
|
<Checkbox
|
||
|
|
id="showHeader"
|
||
|
|
checked={config.showHeader !== false}
|
||
|
|
onCheckedChange={(checked) => updateConfig("showHeader", checked)}
|
||
|
|
/>
|
||
|
|
<label htmlFor="showHeader" className="text-xs">헤더 표시</label>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
UnifiedGroupConfigPanel.displayName = "UnifiedGroupConfigPanel";
|
||
|
|
|
||
|
|
export default UnifiedGroupConfigPanel;
|
||
|
|
|
||
|
|
|