헤더로 해상도 설정 이동
This commit is contained in:
@@ -1,9 +1,48 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Database, ArrowLeft, Save, Monitor, Smartphone } from "lucide-react";
|
||||
import { ScreenResolution } from "@/types/screen";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Database,
|
||||
ArrowLeft,
|
||||
Save,
|
||||
Monitor,
|
||||
Smartphone,
|
||||
Tablet,
|
||||
ChevronDown,
|
||||
Settings,
|
||||
Grid3X3,
|
||||
Eye,
|
||||
EyeOff,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { ScreenResolution, SCREEN_RESOLUTIONS } from "@/types/screen";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
|
||||
interface GridSettings {
|
||||
columns: number;
|
||||
gap: number;
|
||||
padding: number;
|
||||
snapToGrid: boolean;
|
||||
showGrid: boolean;
|
||||
gridColor?: string;
|
||||
gridOpacity?: number;
|
||||
}
|
||||
|
||||
interface SlimToolbarProps {
|
||||
screenName?: string;
|
||||
@@ -13,6 +52,9 @@ interface SlimToolbarProps {
|
||||
onSave: () => void;
|
||||
isSaving?: boolean;
|
||||
onPreview?: () => void;
|
||||
onResolutionChange?: (resolution: ScreenResolution) => void;
|
||||
gridSettings?: GridSettings;
|
||||
onGridSettingsChange?: (settings: GridSettings) => void;
|
||||
}
|
||||
|
||||
export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||
@@ -23,7 +65,52 @@ export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||
onSave,
|
||||
isSaving = false,
|
||||
onPreview,
|
||||
onResolutionChange,
|
||||
gridSettings,
|
||||
onGridSettingsChange,
|
||||
}) => {
|
||||
// 사용자 정의 해상도 상태
|
||||
const [customWidth, setCustomWidth] = useState("");
|
||||
const [customHeight, setCustomHeight] = useState("");
|
||||
const [showCustomInput, setShowCustomInput] = useState(false);
|
||||
|
||||
const getCategoryIcon = (category: string) => {
|
||||
switch (category) {
|
||||
case "desktop":
|
||||
return <Monitor className="h-4 w-4 text-blue-600" />;
|
||||
case "tablet":
|
||||
return <Tablet className="h-4 w-4 text-green-600" />;
|
||||
case "mobile":
|
||||
return <Smartphone className="h-4 w-4 text-purple-600" />;
|
||||
default:
|
||||
return <Monitor className="h-4 w-4 text-blue-600" />;
|
||||
}
|
||||
};
|
||||
|
||||
const handleCustomResolution = () => {
|
||||
const width = parseInt(customWidth);
|
||||
const height = parseInt(customHeight);
|
||||
if (width > 0 && height > 0 && onResolutionChange) {
|
||||
const customResolution: ScreenResolution = {
|
||||
width,
|
||||
height,
|
||||
name: `사용자 정의 (${width}×${height})`,
|
||||
category: "custom",
|
||||
};
|
||||
onResolutionChange(customResolution);
|
||||
setShowCustomInput(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateGridSetting = (key: keyof GridSettings, value: boolean) => {
|
||||
if (onGridSettingsChange && gridSettings) {
|
||||
onGridSettingsChange({
|
||||
...gridSettings,
|
||||
[key]: value,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-14 items-center justify-between border-b border-gray-200 bg-gradient-to-r from-gray-50 to-white px-4 shadow-sm">
|
||||
{/* 좌측: 네비게이션 및 화면 정보 */}
|
||||
@@ -47,16 +134,149 @@ export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 해상도 정보 표시 */}
|
||||
{/* 해상도 선택 드롭다운 */}
|
||||
{screenResolution && (
|
||||
<>
|
||||
<div className="h-6 w-px bg-gray-300" />
|
||||
<div className="flex items-center space-x-2 rounded-md bg-blue-50 px-3 py-1.5">
|
||||
<Monitor className="h-4 w-4 text-blue-600" />
|
||||
<span className="text-sm font-medium text-blue-900">{screenResolution.name}</span>
|
||||
<span className="text-xs text-blue-600">
|
||||
({screenResolution.width} × {screenResolution.height})
|
||||
</span>
|
||||
<Popover open={showCustomInput} onOpenChange={setShowCustomInput}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button className="flex items-center space-x-2 rounded-md bg-blue-50 px-3 py-1.5 transition-colors hover:bg-blue-100">
|
||||
{getCategoryIcon(screenResolution.category || "desktop")}
|
||||
<span className="text-sm font-medium text-blue-900">{screenResolution.name}</span>
|
||||
<span className="text-xs text-blue-600">
|
||||
({screenResolution.width} × {screenResolution.height})
|
||||
</span>
|
||||
{onResolutionChange && <ChevronDown className="h-3 w-3 text-blue-600" />}
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
{onResolutionChange && (
|
||||
<DropdownMenuContent align="start" className="w-64">
|
||||
<DropdownMenuLabel className="text-xs text-gray-500">데스크톱</DropdownMenuLabel>
|
||||
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
|
||||
<DropdownMenuItem
|
||||
key={resolution.name}
|
||||
onClick={() => onResolutionChange(resolution)}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Monitor className="h-4 w-4 text-blue-600" />
|
||||
<span className="flex-1">{resolution.name}</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{resolution.width}×{resolution.height}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel className="text-xs text-gray-500">태블릿</DropdownMenuLabel>
|
||||
{SCREEN_RESOLUTIONS.filter((r) => r.category === "tablet").map((resolution) => (
|
||||
<DropdownMenuItem
|
||||
key={resolution.name}
|
||||
onClick={() => onResolutionChange(resolution)}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Tablet className="h-4 w-4 text-green-600" />
|
||||
<span className="flex-1">{resolution.name}</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{resolution.width}×{resolution.height}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel className="text-xs text-gray-500">모바일</DropdownMenuLabel>
|
||||
{SCREEN_RESOLUTIONS.filter((r) => r.category === "mobile").map((resolution) => (
|
||||
<DropdownMenuItem
|
||||
key={resolution.name}
|
||||
onClick={() => onResolutionChange(resolution)}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Smartphone className="h-4 w-4 text-purple-600" />
|
||||
<span className="flex-1">{resolution.name}</span>
|
||||
<span className="text-xs text-gray-400">
|
||||
{resolution.width}×{resolution.height}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuLabel className="text-xs text-gray-500">사용자 정의</DropdownMenuLabel>
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
setCustomWidth(screenResolution.width.toString());
|
||||
setCustomHeight(screenResolution.height.toString());
|
||||
setShowCustomInput(true);
|
||||
}}
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Settings className="h-4 w-4 text-gray-600" />
|
||||
<span className="flex-1">사용자 정의...</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
)}
|
||||
</DropdownMenu>
|
||||
<PopoverContent align="start" className="w-64 p-3">
|
||||
<div className="space-y-3">
|
||||
<div className="text-sm font-medium">사용자 정의 해상도</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-gray-500">너비 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={customWidth}
|
||||
onChange={(e) => setCustomWidth(e.target.value)}
|
||||
placeholder="1920"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs text-gray-500">높이 (px)</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={customHeight}
|
||||
onChange={(e) => setCustomHeight(e.target.value)}
|
||||
placeholder="1080"
|
||||
className="h-8 text-xs"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={handleCustomResolution} size="sm" className="w-full">
|
||||
적용
|
||||
</Button>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* 격자 설정 */}
|
||||
{gridSettings && onGridSettingsChange && (
|
||||
<>
|
||||
<div className="h-6 w-px bg-gray-300" />
|
||||
<div className="flex items-center space-x-2 rounded-md bg-gray-50 px-3 py-1.5">
|
||||
<Grid3X3 className="h-4 w-4 text-gray-600" />
|
||||
<div className="flex items-center space-x-3">
|
||||
<label className="flex cursor-pointer items-center space-x-1.5">
|
||||
{gridSettings.showGrid ? (
|
||||
<Eye className="h-3.5 w-3.5 text-primary" />
|
||||
) : (
|
||||
<EyeOff className="h-3.5 w-3.5 text-gray-400" />
|
||||
)}
|
||||
<Checkbox
|
||||
checked={gridSettings.showGrid}
|
||||
onCheckedChange={(checked) => updateGridSetting("showGrid", checked as boolean)}
|
||||
className="h-3.5 w-3.5"
|
||||
/>
|
||||
<span className="text-xs text-gray-600">격자 표시</span>
|
||||
</label>
|
||||
<label className="flex cursor-pointer items-center space-x-1.5">
|
||||
<Zap className={`h-3.5 w-3.5 ${gridSettings.snapToGrid ? "text-primary" : "text-gray-400"}`} />
|
||||
<Checkbox
|
||||
checked={gridSettings.snapToGrid}
|
||||
onCheckedChange={(checked) => updateGridSetting("snapToGrid", checked as boolean)}
|
||||
className="h-3.5 w-3.5"
|
||||
/>
|
||||
<span className="text-xs text-gray-600">격자 스냅</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user