버튼 자동정렬기능 구현
This commit is contained in:
203
frontend/components/screen/dialogs/FlowButtonGroupDialog.tsx
Normal file
203
frontend/components/screen/dialogs/FlowButtonGroupDialog.tsx
Normal file
@@ -0,0 +1,203 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { ArrowRight, ArrowDown } from "lucide-react";
|
||||
|
||||
interface FlowButtonGroupDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
buttonCount: number;
|
||||
onConfirm: (settings: {
|
||||
direction: "horizontal" | "vertical";
|
||||
gap: number;
|
||||
align: "start" | "center" | "end" | "space-between" | "space-around";
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export const FlowButtonGroupDialog: React.FC<FlowButtonGroupDialogProps> = ({
|
||||
open,
|
||||
onOpenChange,
|
||||
buttonCount,
|
||||
onConfirm,
|
||||
}) => {
|
||||
const [direction, setDirection] = useState<"horizontal" | "vertical">("horizontal");
|
||||
const [gap, setGap] = useState<number>(8);
|
||||
const [align, setAlign] = useState<"start" | "center" | "end" | "space-between" | "space-around">("start");
|
||||
|
||||
const handleConfirm = () => {
|
||||
onConfirm({ direction, gap, align });
|
||||
onOpenChange(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-[95vw] sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-base sm:text-lg">플로우 버튼 그룹 생성</DialogTitle>
|
||||
<DialogDescription className="text-xs sm:text-sm">
|
||||
{buttonCount}개의 버튼을 하나의 그룹으로 묶습니다. 자동 정렬 설정을 지정하세요.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
{/* 정렬 방향 */}
|
||||
<div className="space-y-3">
|
||||
<Label className="text-sm font-medium">정렬 방향</Label>
|
||||
<RadioGroup value={direction} onValueChange={(value: any) => setDirection(value)}>
|
||||
<div className="flex items-center space-x-3">
|
||||
<RadioGroupItem value="horizontal" id="direction-horizontal" />
|
||||
<Label htmlFor="direction-horizontal" className="flex items-center gap-2 text-sm font-normal">
|
||||
<ArrowRight className="h-4 w-4 text-blue-600" />
|
||||
<span>가로 정렬</span>
|
||||
<Badge variant="secondary" className="ml-2 text-xs">
|
||||
← →
|
||||
</Badge>
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-3">
|
||||
<RadioGroupItem value="vertical" id="direction-vertical" />
|
||||
<Label htmlFor="direction-vertical" className="flex items-center gap-2 text-sm font-normal">
|
||||
<ArrowDown className="h-4 w-4 text-blue-600" />
|
||||
<span>세로 정렬</span>
|
||||
<Badge variant="secondary" className="ml-2 text-xs">
|
||||
↑ ↓
|
||||
</Badge>
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{/* 버튼 간격 */}
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="gap" className="text-sm font-medium">
|
||||
버튼 간격 (px)
|
||||
</Label>
|
||||
<div className="flex items-center gap-3">
|
||||
<Input
|
||||
id="gap"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
value={gap}
|
||||
onChange={(e) => setGap(Number(e.target.value))}
|
||||
className="h-9 text-sm sm:h-10"
|
||||
/>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{gap}px
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-[10px] text-muted-foreground sm:text-xs">버튼 사이의 간격을 설정합니다</p>
|
||||
</div>
|
||||
|
||||
{/* 정렬 방식 */}
|
||||
<div className="space-y-3">
|
||||
<Label htmlFor="align" className="text-sm font-medium">
|
||||
정렬 방식
|
||||
</Label>
|
||||
<Select value={align} onValueChange={(value: any) => setAlign(value)}>
|
||||
<SelectTrigger id="align" className="h-9 text-sm sm:h-10">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="start">
|
||||
<div className="flex items-center gap-2">
|
||||
<span>시작점 정렬</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{direction === "horizontal" ? "← 왼쪽" : "↑ 위"}
|
||||
</Badge>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="center">
|
||||
<div className="flex items-center gap-2">
|
||||
<span>중앙 정렬</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
↔ 가운데
|
||||
</Badge>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="end">
|
||||
<div className="flex items-center gap-2">
|
||||
<span>끝점 정렬</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
{direction === "horizontal" ? "→ 오른쪽" : "↓ 아래"}
|
||||
</Badge>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="space-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<span>양 끝 정렬</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
↔ 양끝
|
||||
</Badge>
|
||||
</div>
|
||||
</SelectItem>
|
||||
<SelectItem value="space-around">
|
||||
<div className="flex items-center gap-2">
|
||||
<span>균등 배분</span>
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
↔ 균등
|
||||
</Badge>
|
||||
</div>
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-[10px] text-muted-foreground sm:text-xs">
|
||||
버튼들이 그룹 내에서 어떻게 배치될지 결정합니다
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 미리보기 */}
|
||||
<div className="rounded-lg border border-blue-200 bg-blue-50 p-4">
|
||||
<p className="mb-3 text-xs font-medium text-blue-900">설정 미리보기</p>
|
||||
<div className="space-y-2 text-xs text-blue-700">
|
||||
<div className="flex items-center gap-2">
|
||||
{direction === "horizontal" ? <ArrowRight className="h-3 w-3" /> : <ArrowDown className="h-3 w-3" />}
|
||||
<span>
|
||||
{direction === "horizontal" ? "가로" : "세로"} 방향으로 {gap}px 간격
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span>•</span>
|
||||
<span>
|
||||
{align === "start" && "시작점"}
|
||||
{align === "center" && "중앙"}
|
||||
{align === "end" && "끝점"}
|
||||
{align === "space-between" && "양 끝"}
|
||||
{align === "space-around" && "균등"} 정렬
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter className="gap-2 sm:gap-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => onOpenChange(false)}
|
||||
className="h-9 flex-1 text-sm sm:h-10 sm:flex-none"
|
||||
>
|
||||
취소
|
||||
</Button>
|
||||
<Button onClick={handleConfirm} className="h-9 flex-1 text-sm sm:h-10 sm:flex-none">
|
||||
그룹 생성
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user