모달창 올리기
This commit is contained in:
@@ -173,6 +173,7 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
// 현재 버튼에 설정 적용 (그룹 설정은 ScreenDesigner에서 자동으로 일괄 적용됨)
|
||||
onUpdateProperty("webTypeConfig.flowVisibilityConfig", config);
|
||||
};
|
||||
|
||||
@@ -235,11 +236,13 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-1">
|
||||
<h4 className="flex items-center gap-2 text-sm font-medium">
|
||||
<h4 className="flex items-center gap-2 text-xs font-medium" style={{ fontSize: "12px" }}>
|
||||
<Workflow className="h-4 w-4" />
|
||||
플로우 단계별 표시 설정
|
||||
</h4>
|
||||
<p className="text-muted-foreground text-xs">플로우의 특정 단계에서만 이 버튼을 표시하거나 숨길 수 있습니다</p>
|
||||
<p className="text-muted-foreground text-xs" style={{ fontSize: "12px" }}>
|
||||
플로우의 특정 단계에서만 이 버튼을 표시하거나 숨길 수 있습니다
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
@@ -253,7 +256,7 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
/>
|
||||
<Label htmlFor="flow-control-enabled" className="text-sm font-medium">
|
||||
<Label htmlFor="flow-control-enabled" className="text-xs font-medium" style={{ fontSize: "12px" }}>
|
||||
플로우 단계에 따라 버튼 표시 제어
|
||||
</Label>
|
||||
</div>
|
||||
@@ -262,7 +265,9 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
<>
|
||||
{/* 대상 플로우 선택 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium">대상 플로우</Label>
|
||||
<Label className="text-xs font-medium" style={{ fontSize: "12px" }}>
|
||||
대상 플로우
|
||||
</Label>
|
||||
<Select
|
||||
value={selectedFlowComponentId || ""}
|
||||
onValueChange={(value) => {
|
||||
@@ -270,7 +275,7 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-6 text-xs sm:h-10 sm:text-xs" style={{ fontSize: "12px" }}>
|
||||
<SelectTrigger className="h-6 text-xs" style={{ fontSize: "12px" }}>
|
||||
<SelectValue placeholder="플로우 위젯 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -278,7 +283,7 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
const flowConfig = (fw as any).componentConfig || {};
|
||||
const flowName = flowConfig.flowName || `플로우 ${fw.id}`;
|
||||
return (
|
||||
<SelectItem key={fw.id} value={fw.id}>
|
||||
<SelectItem key={fw.id} value={fw.id} style={{ fontSize: "12px" }}>
|
||||
{flowName}
|
||||
</SelectItem>
|
||||
);
|
||||
@@ -290,261 +295,106 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
||||
{/* 플로우가 선택되면 스텝 목록 표시 */}
|
||||
{selectedFlowComponentId && flowSteps.length > 0 && (
|
||||
<>
|
||||
{/* 모드 선택 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium">표시 모드</Label>
|
||||
<RadioGroup
|
||||
value={mode}
|
||||
onValueChange={(value: any) => {
|
||||
setMode(value);
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="whitelist" id="mode-whitelist" />
|
||||
<Label htmlFor="mode-whitelist" className="text-sm font-normal">
|
||||
선택한 단계에서만 표시
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="all" id="mode-all" />
|
||||
<Label htmlFor="mode-all" className="text-sm font-normal">
|
||||
모든 단계에서 표시
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{/* 단계 선택 (all 모드가 아닐 때만) */}
|
||||
{mode !== "all" && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm font-medium">표시할 단계</Label>
|
||||
<div className="flex gap-1">
|
||||
<Button variant="ghost" size="sm" onClick={selectAll} className="h-7 px-2 text-xs">
|
||||
모두 선택
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={selectNone} className="h-7 px-2 text-xs">
|
||||
모두 해제
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={invertSelection} className="h-7 px-2 text-xs">
|
||||
반전
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 스텝 체크박스 목록 */}
|
||||
<div className="bg-muted/30 space-y-2 rounded-lg border p-3">
|
||||
{flowSteps.map((step) => {
|
||||
const isChecked = visibleSteps.includes(step.id);
|
||||
|
||||
return (
|
||||
<div key={step.id} className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id={`step-${step.id}`}
|
||||
checked={isChecked}
|
||||
onCheckedChange={() => toggleStep(step.id)}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`step-${step.id}`}
|
||||
className="flex flex-1 items-center gap-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
Step {step.stepOrder}
|
||||
</Badge>
|
||||
<span>{step.stepName}</span>
|
||||
{isChecked && <CheckCircle className="ml-auto h-4 w-4 text-green-500" />}
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 레이아웃 옵션 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium">레이아웃 동작</Label>
|
||||
<RadioGroup
|
||||
value={layoutBehavior}
|
||||
onValueChange={(value: any) => {
|
||||
setLayoutBehavior(value);
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="preserve-position" id="layout-preserve" />
|
||||
<Label htmlFor="layout-preserve" className="text-sm font-normal">
|
||||
원래 위치 유지 (빈 공간 가능)
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="auto-compact" id="layout-compact" />
|
||||
<Label htmlFor="layout-compact" className="text-sm font-normal">
|
||||
자동 정렬 (빈 공간 제거) ⭐ 권장
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{/* 🆕 그룹 설정 (auto-compact 모드일 때만 표시) */}
|
||||
{layoutBehavior === "auto-compact" && (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Badge variant="secondary" className="text-xs">
|
||||
그룹 설정
|
||||
</Badge>
|
||||
<p className="text-muted-foreground text-xs">같은 그룹 ID를 가진 버튼들이 자동으로 정렬됩니다</p>
|
||||
</div>
|
||||
|
||||
{/* 그룹 ID */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="group-id" className="text-sm font-medium">
|
||||
그룹 ID
|
||||
</Label>
|
||||
<Input
|
||||
id="group-id"
|
||||
value={groupId}
|
||||
onChange={(e) => setGroupId(e.target.value)}
|
||||
placeholder="group-1"
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
{/* 단계 선택 */}
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-xs font-medium" style={{ fontSize: "12px" }}>
|
||||
표시할 단계
|
||||
</Label>
|
||||
<div className="flex gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={selectAll}
|
||||
className="h-7 px-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
/>
|
||||
<p className="text-muted-foreground text-[10px]">
|
||||
같은 그룹 ID를 가진 버튼들이 하나의 그룹으로 묶입니다
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 정렬 방향 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-sm font-medium">정렬 방향</Label>
|
||||
<RadioGroup
|
||||
value={groupDirection}
|
||||
onValueChange={(value: any) => {
|
||||
setGroupDirection(value);
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<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" />
|
||||
가로 정렬
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<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" />
|
||||
세로 정렬
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{/* 버튼 간격 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="group-gap" className="text-sm font-medium">
|
||||
버튼 간격 (px)
|
||||
</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Input
|
||||
id="group-gap"
|
||||
type="number"
|
||||
min={0}
|
||||
max={100}
|
||||
value={groupGap}
|
||||
onChange={(e) => {
|
||||
setGroupGap(Number(e.target.value));
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
/>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{groupGap}px
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 정렬 방식 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="group-align" className="text-sm font-medium">
|
||||
정렬 방식
|
||||
</Label>
|
||||
<Select
|
||||
value={groupAlign}
|
||||
onValueChange={(value: any) => {
|
||||
setGroupAlign(value);
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
모두 선택
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={selectNone}
|
||||
className="h-7 px-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<SelectTrigger
|
||||
id="group-align"
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="start">시작점 정렬</SelectItem>
|
||||
<SelectItem value="center">중앙 정렬</SelectItem>
|
||||
<SelectItem value="end">끝점 정렬</SelectItem>
|
||||
<SelectItem value="space-between">양 끝 정렬</SelectItem>
|
||||
<SelectItem value="space-around">균등 배분</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
모두 해제
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={invertSelection}
|
||||
className="h-7 px-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
반전
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 미리보기 */}
|
||||
<Alert>
|
||||
<Info className="h-4 w-4" />
|
||||
<AlertDescription className="text-xs">
|
||||
{mode === "whitelist" && visibleSteps.length > 0 && (
|
||||
<div>
|
||||
<p className="font-medium">표시 단계:</p>
|
||||
<div className="mt-1 flex flex-wrap gap-1">
|
||||
{visibleSteps.map((stepId) => {
|
||||
const step = flowSteps.find((s) => s.id === stepId);
|
||||
return (
|
||||
<Badge key={stepId} variant="secondary" className="text-xs">
|
||||
{step?.stepName || `Step ${stepId}`}
|
||||
</Badge>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{mode === "blacklist" && hiddenSteps.length > 0 && (
|
||||
<div>
|
||||
<p className="font-medium">숨김 단계:</p>
|
||||
<div className="mt-1 flex flex-wrap gap-1">
|
||||
{hiddenSteps.map((stepId) => {
|
||||
const step = flowSteps.find((s) => s.id === stepId);
|
||||
return (
|
||||
<Badge key={stepId} variant="destructive" className="text-xs">
|
||||
{step?.stepName || `Step ${stepId}`}
|
||||
</Badge>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{mode === "all" && <p>이 버튼은 모든 단계에서 표시됩니다.</p>}
|
||||
{mode === "whitelist" && visibleSteps.length === 0 && <p>표시할 단계를 선택해주세요.</p>}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
{/* 스텝 체크박스 목록 */}
|
||||
<div className="bg-muted/30 space-y-2 rounded-lg border p-3">
|
||||
{flowSteps.map((step) => {
|
||||
const isChecked = visibleSteps.includes(step.id);
|
||||
|
||||
{/* 🆕 자동 저장 안내 */}
|
||||
<Alert className="border-green-200 bg-green-50">
|
||||
<CheckCircle className="h-4 w-4 text-green-600" />
|
||||
<AlertDescription className="text-xs text-green-800">
|
||||
설정이 자동으로 저장됩니다. 화면 저장 시 함께 적용됩니다.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
return (
|
||||
<div key={step.id} className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id={`step-${step.id}`}
|
||||
checked={isChecked}
|
||||
onCheckedChange={() => toggleStep(step.id)}
|
||||
/>
|
||||
<Label
|
||||
htmlFor={`step-${step.id}`}
|
||||
className="flex flex-1 items-center gap-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<Badge variant="outline" className="text-xs" style={{ fontSize: "12px" }}>
|
||||
Step {step.stepOrder}
|
||||
</Badge>
|
||||
<span>{step.stepName}</span>
|
||||
{isChecked && <CheckCircle className="ml-auto h-4 w-4 text-green-500" />}
|
||||
</Label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 정렬 방식 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="group-align" className="text-xs font-medium" style={{ fontSize: "12px" }}>
|
||||
정렬 방식
|
||||
</Label>
|
||||
<Select
|
||||
value={groupAlign}
|
||||
onValueChange={(value: any) => {
|
||||
setGroupAlign(value);
|
||||
onUpdateProperty("webTypeConfig.flowVisibilityConfig.groupAlign", value);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger id="group-align" className="h-6 text-xs" style={{ fontSize: "12px" }}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="start" style={{ fontSize: "12px" }}>
|
||||
시작점 정렬
|
||||
</SelectItem>
|
||||
<SelectItem value="center" style={{ fontSize: "12px" }}>
|
||||
중앙 정렬
|
||||
</SelectItem>
|
||||
<SelectItem value="end" style={{ fontSize: "12px" }}>
|
||||
끝점 정렬
|
||||
</SelectItem>
|
||||
<SelectItem value="space-between" style={{ fontSize: "12px" }}>
|
||||
양 끝 정렬
|
||||
</SelectItem>
|
||||
<SelectItem value="space-around" style={{ fontSize: "12px" }}>
|
||||
균등 배분
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user