Files
vexplor/frontend/components/screen/panels/ResolutionPanel.tsx
kjs 44def0979c fix: 화면 편집기 높이 입력 필드 1px 단위 조절 가능하도록 수정
- 문제: 높이 입력 시 10 단위로만 입력 가능 (예: 1080 입력 불가)
- 원인: 격자 스냅 로직이 onChange마다 높이를 10/20 단위로 강제 반올림
- 해결:
  1. 모든 number input 필드에 step="1" 추가
  2. ScreenDesigner.tsx의 격자 스냅 로직 수정 (높이 스냅 제거)
  3. UnifiedPropertiesPanel.tsx에 로컬 상태 추가하여 입력 중 스냅 방지
  4. onBlur/Enter 시에만 실제 값 업데이트

수정 파일:
- frontend/components/screen/ScreenDesigner.tsx
- frontend/components/screen/panels/UnifiedPropertiesPanel.tsx
- frontend/components/screen/panels/PropertiesPanel.tsx
- frontend/components/screen/panels/ResolutionPanel.tsx
- frontend/components/screen/panels/RowSettingsPanel.tsx
- frontend/components/screen/panels/webtype-configs/NumberTypeConfigPanel.tsx
- frontend/components/screen/panels/webtype-configs/TextTypeConfigPanel.tsx
2025-11-06 10:37:20 +09:00

183 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import React, { useState } from "react";
import { Monitor, Tablet, Smartphone, Settings } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Button } from "@/components/ui/button";
import { ScreenResolution, SCREEN_RESOLUTIONS } from "@/types/screen";
interface ResolutionPanelProps {
currentResolution: ScreenResolution;
onResolutionChange: (resolution: ScreenResolution) => void;
}
const ResolutionPanel: React.FC<ResolutionPanelProps> = ({ currentResolution, onResolutionChange }) => {
const [customWidth, setCustomWidth] = useState(currentResolution.width.toString());
const [customHeight, setCustomHeight] = useState(currentResolution.height.toString());
const [selectedPreset, setSelectedPreset] = useState<string>(
SCREEN_RESOLUTIONS.find((r) => r.width === currentResolution.width && r.height === currentResolution.height)
?.name || "custom",
);
const handlePresetChange = (presetName: string) => {
setSelectedPreset(presetName);
if (presetName === "custom") {
return;
}
const preset = SCREEN_RESOLUTIONS.find((r) => r.name === presetName);
if (preset) {
setCustomWidth(preset.width.toString());
setCustomHeight(preset.height.toString());
onResolutionChange(preset);
}
};
const handleCustomResolution = () => {
const width = parseInt(customWidth);
const height = parseInt(customHeight);
if (width > 0 && height > 0) {
const customResolution: ScreenResolution = {
width,
height,
name: `사용자 정의 (${width}×${height})`,
category: "custom",
};
onResolutionChange(customResolution);
setSelectedPreset("custom");
}
};
const getCategoryIcon = (category: string) => {
switch (category) {
case "desktop":
return <Monitor className="h-4 w-4" />;
case "tablet":
return <Tablet className="h-4 w-4" />;
case "mobile":
return <Smartphone className="h-4 w-4" />;
default:
return <Settings className="h-4 w-4" />;
}
};
const getCategoryColor = (category: string) => {
switch (category) {
case "desktop":
return "text-primary";
case "tablet":
return "text-green-600";
case "mobile":
return "text-purple-600";
default:
return "text-muted-foreground";
}
};
return (
<div className="space-y-4">
{/* 프리셋 선택 */}
<div className="space-y-2">
<Label className="text-xs font-medium"> </Label>
<Select value={selectedPreset} onValueChange={handlePresetChange}>
<SelectTrigger className="h-6 w-full px-2 py-0" style={{ fontSize: "12px" }}>
<SelectValue placeholder="해상도를 선택하세요" />
</SelectTrigger>
<SelectContent>
{/* Desktop */}
<div className="px-2 py-1 text-xs font-medium text-gray-500"></div>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
<SelectItem key={resolution.name} value={resolution.name}>
<div className="flex items-center space-x-2">
<Monitor className="text-primary h-4 w-4" />
<span>{resolution.name}</span>
</div>
</SelectItem>
))}
{/* Tablet */}
<div className="px-2 py-1 text-xs font-medium text-gray-500">릿</div>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "tablet").map((resolution) => (
<SelectItem key={resolution.name} value={resolution.name}>
<div className="flex items-center space-x-2">
<Tablet className="h-4 w-4 text-green-600" />
<span>{resolution.name}</span>
</div>
</SelectItem>
))}
{/* Mobile */}
<div className="px-2 py-1 text-xs font-medium text-gray-500"></div>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "mobile").map((resolution) => (
<SelectItem key={resolution.name} value={resolution.name}>
<div className="flex items-center space-x-2">
<Smartphone className="h-4 w-4 text-purple-600" />
<span>{resolution.name}</span>
</div>
</SelectItem>
))}
{/* Custom */}
<div className="px-2 py-1 text-xs font-medium text-gray-500"> </div>
<SelectItem value="custom">
<div className="flex items-center space-x-2">
<Settings className="text-muted-foreground h-4 w-4" />
<span> </span>
</div>
</SelectItem>
</SelectContent>
</Select>
</div>
{/* 사용자 정의 해상도 */}
{selectedPreset === "custom" && (
<div className="space-y-3 rounded-lg border bg-gray-50 p-3">
<Label className="text-sm font-medium"> </Label>
<div className="grid grid-cols-2 gap-3">
<div className="space-y-1">
<Label className="text-muted-foreground text-xs"> (px)</Label>
<Input
type="number"
value={customWidth}
onChange={(e) => setCustomWidth(e.target.value)}
placeholder="1920"
min="1"
step="1"
className="h-6 w-full px-2 py-0 text-xs" style={{ fontSize: "12px" }}
style={{ fontSize: "12px" }}
/>
</div>
<div className="space-y-1">
<Label className="text-muted-foreground text-xs"> (px)</Label>
<Input
type="number"
value={customHeight}
onChange={(e) => setCustomHeight(e.target.value)}
placeholder="1080"
min="1"
step="1"
className="h-6 w-full px-2 py-0 text-xs" style={{ fontSize: "12px" }}
style={{ fontSize: "12px" }}
/>
</div>
</div>
<Button
onClick={handleCustomResolution}
size="sm"
className="h-6 w-full px-2 py-0 text-xs" style={{ fontSize: "12px" }}
style={{ fontSize: "12px" }}
>
</Button>
</div>
)}
</div>
);
};
export default ResolutionPanel;