228 lines
8.8 KiB
TypeScript
228 lines
8.8 KiB
TypeScript
"use client";
|
|
|
|
import React from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectLabel,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { Save, Trash2, Palette } from "lucide-react";
|
|
import { ElementType, ElementSubtype } from "./types";
|
|
import { ResolutionSelector, Resolution } from "./ResolutionSelector";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
|
|
|
interface DashboardTopMenuProps {
|
|
onSaveLayout: () => void;
|
|
onClearCanvas: () => void;
|
|
dashboardTitle?: string;
|
|
onAddElement?: (type: ElementType, subtype: ElementSubtype) => void;
|
|
resolution?: Resolution;
|
|
onResolutionChange?: (resolution: Resolution) => void;
|
|
currentScreenResolution?: Resolution;
|
|
backgroundColor?: string;
|
|
onBackgroundColorChange?: (color: string) => void;
|
|
}
|
|
|
|
/**
|
|
* 대시보드 편집 화면 상단 메뉴바
|
|
* - 차트/위젯 선택 (셀렉트박스)
|
|
* - 저장/초기화 버튼
|
|
*/
|
|
export function DashboardTopMenu({
|
|
onSaveLayout,
|
|
onClearCanvas,
|
|
dashboardTitle,
|
|
onAddElement,
|
|
resolution = "fhd",
|
|
onResolutionChange,
|
|
currentScreenResolution,
|
|
backgroundColor = "#f9fafb",
|
|
onBackgroundColorChange,
|
|
}: DashboardTopMenuProps) {
|
|
const [chartValue, setChartValue] = React.useState<string>("");
|
|
const [widgetValue, setWidgetValue] = React.useState<string>("");
|
|
|
|
// 차트 선택 시 캔버스 중앙에 추가
|
|
const handleChartSelect = (value: string) => {
|
|
if (onAddElement) {
|
|
onAddElement("chart", value as ElementSubtype);
|
|
// 선택 후 즉시 리셋하여 같은 항목을 연속으로 선택 가능하게
|
|
setTimeout(() => setChartValue(""), 0);
|
|
}
|
|
};
|
|
|
|
// 위젯 선택 시 캔버스 중앙에 추가
|
|
const handleWidgetSelect = (value: string) => {
|
|
if (onAddElement) {
|
|
onAddElement("widget", value as ElementSubtype);
|
|
// 선택 후 즉시 리셋하여 같은 항목을 연속으로 선택 가능하게
|
|
setTimeout(() => setWidgetValue(""), 0);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex h-16 items-center justify-between border-b bg-white px-6 shadow-sm">
|
|
{/* 좌측: 대시보드 제목 */}
|
|
<div className="flex items-center gap-4">
|
|
{dashboardTitle && (
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-lg font-semibold text-gray-900">{dashboardTitle}</span>
|
|
<span className="rounded bg-blue-100 px-2 py-0.5 text-xs font-medium text-blue-700">편집 중</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* 중앙: 해상도 선택 & 요소 추가 */}
|
|
<div className="flex items-center gap-3">
|
|
{/* 해상도 선택 */}
|
|
{onResolutionChange && (
|
|
<ResolutionSelector
|
|
value={resolution}
|
|
onChange={onResolutionChange}
|
|
currentScreenResolution={currentScreenResolution}
|
|
/>
|
|
)}
|
|
|
|
<div className="h-6 w-px bg-gray-300" />
|
|
|
|
{/* 배경색 선택 */}
|
|
{onBackgroundColorChange && (
|
|
<Popover>
|
|
<PopoverTrigger asChild>
|
|
<Button variant="outline" size="sm" className="gap-2">
|
|
<Palette className="h-4 w-4" />
|
|
<div className="h-4 w-4 rounded border border-gray-300" style={{ backgroundColor }} />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="z-[99999] w-64">
|
|
<div className="space-y-3">
|
|
<div>
|
|
<label className="text-sm font-medium">캔버스 배경색</label>
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<Input
|
|
type="color"
|
|
value={backgroundColor}
|
|
onChange={(e) => onBackgroundColorChange(e.target.value)}
|
|
className="h-10 w-20 cursor-pointer"
|
|
/>
|
|
<Input
|
|
type="text"
|
|
value={backgroundColor}
|
|
onChange={(e) => onBackgroundColorChange(e.target.value)}
|
|
placeholder="#f9fafb"
|
|
className="flex-1"
|
|
/>
|
|
</div>
|
|
<div className="grid grid-cols-6 gap-2">
|
|
{[
|
|
"#ffffff",
|
|
"#f9fafb",
|
|
"#f3f4f6",
|
|
"#e5e7eb",
|
|
"#1f2937",
|
|
"#111827",
|
|
"#fef3c7",
|
|
"#fde68a",
|
|
"#dbeafe",
|
|
"#bfdbfe",
|
|
"#fecaca",
|
|
"#fca5a5",
|
|
].map((color) => (
|
|
<button
|
|
key={color}
|
|
className="h-8 w-8 rounded border-2 transition-transform hover:scale-110"
|
|
style={{
|
|
backgroundColor: color,
|
|
borderColor: backgroundColor === color ? "#3b82f6" : "#d1d5db",
|
|
}}
|
|
onClick={() => onBackgroundColorChange(color)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
)}
|
|
|
|
<div className="h-6 w-px bg-gray-300" />
|
|
{/* 차트 선택 */}
|
|
<Select value={chartValue} onValueChange={handleChartSelect}>
|
|
<SelectTrigger className="w-[200px]">
|
|
<SelectValue placeholder="차트 추가" />
|
|
</SelectTrigger>
|
|
<SelectContent className="z-[99999]">
|
|
<SelectGroup>
|
|
<SelectLabel>차트</SelectLabel>
|
|
<SelectItem value="bar">바 차트</SelectItem>
|
|
<SelectItem value="horizontal-bar">수평 바 차트</SelectItem>
|
|
<SelectItem value="stacked-bar">누적 바 차트</SelectItem>
|
|
<SelectItem value="line">꺾은선 차트</SelectItem>
|
|
<SelectItem value="area">영역 차트</SelectItem>
|
|
<SelectItem value="pie">원형 차트</SelectItem>
|
|
<SelectItem value="donut">도넛 차트</SelectItem>
|
|
<SelectItem value="combo">콤보 차트</SelectItem>
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
|
|
{/* 위젯 선택 */}
|
|
<Select value={widgetValue} onValueChange={handleWidgetSelect}>
|
|
<SelectTrigger className="w-[200px]">
|
|
<SelectValue placeholder="위젯 추가" />
|
|
</SelectTrigger>
|
|
<SelectContent className="z-[99999]">
|
|
<SelectGroup>
|
|
<SelectLabel>데이터 위젯</SelectLabel>
|
|
<SelectItem value="list">리스트 위젯</SelectItem>
|
|
<SelectItem value="custom-metric">사용자 커스텀 카드</SelectItem>
|
|
<SelectItem value="yard-management-3d">야드 관리 3D</SelectItem>
|
|
{/* <SelectItem value="transport-stats">커스텀 통계 카드</SelectItem> */}
|
|
<SelectItem value="map-summary">커스텀 지도 카드</SelectItem>
|
|
{/* <SelectItem value="status-summary">커스텀 상태 카드</SelectItem> */}
|
|
</SelectGroup>
|
|
<SelectGroup>
|
|
<SelectLabel>일반 위젯</SelectLabel>
|
|
<SelectItem value="weather">날씨</SelectItem>
|
|
{/* <SelectItem value="weather-map">날씨 지도</SelectItem> */}
|
|
<SelectItem value="exchange">환율</SelectItem>
|
|
<SelectItem value="calculator">계산기</SelectItem>
|
|
<SelectItem value="calendar">달력</SelectItem>
|
|
<SelectItem value="clock">시계</SelectItem>
|
|
<SelectItem value="todo">일정관리 위젯</SelectItem>
|
|
{/* <SelectItem value="booking-alert">예약 알림</SelectItem> */}
|
|
<SelectItem value="document">문서</SelectItem>
|
|
<SelectItem value="risk-alert">리스크 알림</SelectItem>
|
|
</SelectGroup>
|
|
{/* 범용 위젯으로 대체 가능하여 주석처리 */}
|
|
{/* <SelectGroup>
|
|
<SelectLabel>차량 관리</SelectLabel>
|
|
<SelectItem value="vehicle-status">차량 상태</SelectItem>
|
|
<SelectItem value="vehicle-list">차량 목록</SelectItem>
|
|
<SelectItem value="vehicle-map">차량 위치</SelectItem>
|
|
</SelectGroup> */}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* 우측: 액션 버튼 */}
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="outline" size="sm" onClick={onClearCanvas} className="gap-2 text-red-600 hover:text-red-700">
|
|
<Trash2 className="h-4 w-4" />
|
|
초기화
|
|
</Button>
|
|
<Button size="sm" onClick={onSaveLayout} className="gap-2">
|
|
<Save className="h-4 w-4" />
|
|
저장
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|