2025-09-02 16:18:38 +09:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import React from "react";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
2025-09-03 15:23:12 +09:00
|
|
|
import {
|
|
|
|
|
Menu,
|
|
|
|
|
Database,
|
|
|
|
|
Settings,
|
|
|
|
|
Palette,
|
|
|
|
|
Grid3X3,
|
|
|
|
|
Save,
|
|
|
|
|
Undo,
|
|
|
|
|
Redo,
|
|
|
|
|
Play,
|
|
|
|
|
ArrowLeft,
|
|
|
|
|
Cog,
|
|
|
|
|
Layout,
|
2025-09-04 15:20:26 +09:00
|
|
|
Monitor,
|
2025-09-10 18:36:28 +09:00
|
|
|
Square,
|
2025-09-03 15:23:12 +09:00
|
|
|
} from "lucide-react";
|
2025-09-02 16:18:38 +09:00
|
|
|
import { cn } from "@/lib/utils";
|
|
|
|
|
|
|
|
|
|
interface DesignerToolbarProps {
|
|
|
|
|
screenName?: string;
|
|
|
|
|
tableName?: string;
|
|
|
|
|
onBack: () => void;
|
|
|
|
|
onSave: () => void;
|
|
|
|
|
onUndo: () => void;
|
|
|
|
|
onRedo: () => void;
|
|
|
|
|
onPreview: () => void;
|
|
|
|
|
onTogglePanel: (panelId: string) => void;
|
|
|
|
|
panelStates: Record<string, { isOpen: boolean }>;
|
|
|
|
|
canUndo: boolean;
|
|
|
|
|
canRedo: boolean;
|
|
|
|
|
isSaving?: boolean;
|
2025-09-10 18:36:28 +09:00
|
|
|
showZoneBorders?: boolean;
|
|
|
|
|
onToggleZoneBorders?: () => void;
|
2025-09-02 16:18:38 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const DesignerToolbar: React.FC<DesignerToolbarProps> = ({
|
|
|
|
|
screenName,
|
|
|
|
|
tableName,
|
|
|
|
|
onBack,
|
|
|
|
|
onSave,
|
|
|
|
|
onUndo,
|
|
|
|
|
onRedo,
|
|
|
|
|
onPreview,
|
|
|
|
|
onTogglePanel,
|
|
|
|
|
panelStates,
|
|
|
|
|
canUndo,
|
|
|
|
|
canRedo,
|
|
|
|
|
isSaving = false,
|
2025-09-10 18:36:28 +09:00
|
|
|
showZoneBorders = true,
|
|
|
|
|
onToggleZoneBorders,
|
2025-09-02 16:18:38 +09:00
|
|
|
}) => {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center justify-between border-b border-gray-200 bg-white px-4 py-3 shadow-sm">
|
|
|
|
|
{/* 좌측: 네비게이션 및 화면 정보 */}
|
|
|
|
|
<div className="flex items-center space-x-4">
|
|
|
|
|
<Button variant="ghost" size="sm" onClick={onBack} className="flex items-center space-x-2">
|
|
|
|
|
<ArrowLeft className="h-4 w-4" />
|
|
|
|
|
<span>목록으로</span>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<div className="h-6 w-px bg-gray-300" />
|
|
|
|
|
|
|
|
|
|
<div className="flex items-center space-x-3">
|
|
|
|
|
<Menu className="h-5 w-5 text-gray-600" />
|
|
|
|
|
<div>
|
|
|
|
|
<h1 className="text-lg font-semibold text-gray-900">{screenName || "화면 설계"}</h1>
|
|
|
|
|
{tableName && (
|
|
|
|
|
<div className="mt-0.5 flex items-center space-x-1">
|
|
|
|
|
<Database className="h-3 w-3 text-gray-500" />
|
|
|
|
|
<span className="font-mono text-xs text-gray-500">{tableName}</span>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 중앙: 패널 토글 버튼들 */}
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Button
|
|
|
|
|
variant={panelStates.tables?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("tables")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.tables?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Database className="h-4 w-4" />
|
|
|
|
|
<span>테이블</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
T
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
2025-09-03 15:23:12 +09:00
|
|
|
<Button
|
|
|
|
|
variant={panelStates.templates?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("templates")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.templates?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Layout className="h-4 w-4" />
|
|
|
|
|
<span>템플릿</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
M
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
2025-09-09 17:42:23 +09:00
|
|
|
<Button
|
|
|
|
|
variant={panelStates.components?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("components")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.components?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Cog className="h-4 w-4" />
|
|
|
|
|
<span>컴포넌트</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
C
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
2025-09-02 16:18:38 +09:00
|
|
|
<Button
|
|
|
|
|
variant={panelStates.properties?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("properties")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.properties?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Settings className="h-4 w-4" />
|
|
|
|
|
<span>속성</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
P
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant={panelStates.styles?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("styles")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.styles?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Palette className="h-4 w-4" />
|
|
|
|
|
<span>스타일</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
S
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant={panelStates.grid?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("grid")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.grid?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Grid3X3 className="h-4 w-4" />
|
|
|
|
|
<span>격자</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
2025-09-03 11:32:09 +09:00
|
|
|
R
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
|
2025-09-10 18:36:28 +09:00
|
|
|
{/* 구역 경계 표시 토글 버튼 */}
|
|
|
|
|
{onToggleZoneBorders && (
|
|
|
|
|
<Button
|
|
|
|
|
variant={showZoneBorders ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={onToggleZoneBorders}
|
|
|
|
|
className={cn("flex items-center space-x-2", showZoneBorders && "bg-green-600 text-white")}
|
|
|
|
|
title="구역 경계 표시/숨김"
|
|
|
|
|
>
|
|
|
|
|
<Square className="h-4 w-4" />
|
|
|
|
|
<span>구역</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
Z
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-09-03 11:32:09 +09:00
|
|
|
<Button
|
|
|
|
|
variant={panelStates.detailSettings?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("detailSettings")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.detailSettings?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Cog className="h-4 w-4" />
|
|
|
|
|
<span>상세</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
D
|
2025-09-02 16:18:38 +09:00
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
2025-09-04 15:20:26 +09:00
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant={panelStates.resolution?.isOpen ? "default" : "outline"}
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={() => onTogglePanel("resolution")}
|
|
|
|
|
className={cn("flex items-center space-x-2", panelStates.resolution?.isOpen && "bg-blue-600 text-white")}
|
|
|
|
|
>
|
|
|
|
|
<Monitor className="h-4 w-4" />
|
|
|
|
|
<span>해상도</span>
|
|
|
|
|
<Badge variant="secondary" className="ml-1 text-xs">
|
|
|
|
|
E
|
|
|
|
|
</Badge>
|
|
|
|
|
</Button>
|
2025-09-02 16:18:38 +09:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 우측: 액션 버튼들 */}
|
|
|
|
|
<div className="flex items-center space-x-2">
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={onUndo}
|
|
|
|
|
disabled={!canUndo}
|
|
|
|
|
className="flex items-center space-x-1"
|
|
|
|
|
>
|
|
|
|
|
<Undo className="h-4 w-4" />
|
|
|
|
|
<span className="hidden sm:inline">실행취소</span>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
variant="outline"
|
|
|
|
|
size="sm"
|
|
|
|
|
onClick={onRedo}
|
|
|
|
|
disabled={!canRedo}
|
|
|
|
|
className="flex items-center space-x-1"
|
|
|
|
|
>
|
|
|
|
|
<Redo className="h-4 w-4" />
|
|
|
|
|
<span className="hidden sm:inline">다시실행</span>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<div className="h-6 w-px bg-gray-300" />
|
|
|
|
|
|
|
|
|
|
<Button variant="outline" size="sm" onClick={onPreview} className="flex items-center space-x-2">
|
|
|
|
|
<Play className="h-4 w-4" />
|
|
|
|
|
<span>미리보기</span>
|
|
|
|
|
</Button>
|
|
|
|
|
|
|
|
|
|
<Button onClick={onSave} disabled={isSaving} className="flex items-center space-x-2">
|
|
|
|
|
<Save className="h-4 w-4" />
|
|
|
|
|
<span>{isSaving ? "저장 중..." : "저장"}</span>
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default DesignerToolbar;
|