ERP-node/frontend/components/admin/dashboard/ResolutionSelector.tsx

164 lines
5.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Monitor } from "lucide-react";
export type Resolution = "hd" | "fhd" | "qhd" | "uhd";
export interface ResolutionConfig {
width: number;
height: number;
label: string;
}
export const RESOLUTIONS: Record<Resolution, ResolutionConfig> = {
hd: {
width: 1280 - 360,
height: 720 - 312,
label: "HD (1280x720)",
},
fhd: {
width: 1920 - 360,
height: 1080 - 312,
label: "Full HD (1920x1080)",
},
qhd: {
width: 2560 - 360,
height: 1440 - 312,
label: "QHD (2560x1440)",
},
uhd: {
width: 3840 - 360,
height: 2160 - 312,
label: "4K UHD (3840x2160)",
},
};
interface ResolutionSelectorProps {
value: Resolution;
onChange: (resolution: Resolution) => void;
currentScreenResolution?: Resolution;
}
/**
* 현재 화면 해상도 감지
*/
export function detectScreenResolution(): Resolution {
if (typeof window === "undefined") return "fhd";
// 1. 브라우저 뷰포트 크기 (실제 사용 가능한 공간)
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
// 2. 화면 해상도 + devicePixelRatio (Retina 디스플레이 대응)
const pixelRatio = window.devicePixelRatio || 1;
const physicalWidth = window.screen.width;
const physicalHeight = window.screen.height;
const logicalWidth = physicalWidth / pixelRatio;
const logicalHeight = physicalHeight / pixelRatio;
let detectedResolution: Resolution;
// 뷰포트와 논리적 해상도 중 더 큰 값을 기준으로 결정
// (크램쉘 모드나 특수한 경우에도 대응)
const effectiveWidth = Math.max(viewportWidth, logicalWidth);
const effectiveHeight = Math.max(viewportHeight, logicalHeight);
// 캔버스가 여유있게 들어갈 수 있는 크기로 결정
// 여유 공간: 좌우 패딩, 사이드바 등을 고려하여 약 400-500px 여유
if (effectiveWidth >= 3400) {
// UHD 캔버스 2940px + 여유 460px
detectedResolution = "uhd";
} else if (effectiveWidth >= 2400) {
// QHD 캔버스 1960px + 여유 440px
detectedResolution = "qhd";
} else if (effectiveWidth >= 1900) {
// FHD 캔버스 1560px + 여유 340px
detectedResolution = "fhd";
} else {
// HD 캔버스 1160px 이하
detectedResolution = "hd";
}
console.log("🖥️ 화면 해상도 자동 감지:", {
viewportWidth,
viewportHeight,
physicalWidth,
physicalHeight,
pixelRatio,
logicalWidth: Math.round(logicalWidth),
logicalHeight: Math.round(logicalHeight),
effectiveWidth: Math.round(effectiveWidth),
effectiveHeight: Math.round(effectiveHeight),
detectedResolution,
canvasSize: RESOLUTIONS[detectedResolution],
});
return detectedResolution;
}
/**
* 해상도 선택 컴포넌트
* - HD, Full HD, QHD, 4K UHD 지원
* - 12칸 그리드 유지, 셀 크기만 변경
* - 현재 화면 해상도 감지 및 경고 표시
*/
export function ResolutionSelector({ value, onChange, currentScreenResolution }: ResolutionSelectorProps) {
const currentConfig = RESOLUTIONS[value];
const screenConfig = currentScreenResolution ? RESOLUTIONS[currentScreenResolution] : null;
// 현재 선택된 해상도가 화면보다 큰지 확인
const isTooLarge =
screenConfig &&
(currentConfig.width > screenConfig.width + 360 || currentConfig.height > screenConfig.height + 312);
return (
<div className="flex items-center gap-2">
<Monitor className="h-4 w-4 text-gray-500" />
<Select value={value} onValueChange={(v) => onChange(v as Resolution)}>
<SelectTrigger className={`w-[180px] ${isTooLarge ? "border-orange-500" : ""}`}>
<SelectValue />
</SelectTrigger>
<SelectContent className="z-[99999]">
<SelectGroup>
<SelectLabel> </SelectLabel>
<SelectItem value="hd">
<div className="flex items-center gap-2">
<span>HD</span>
<span className="text-xs text-gray-500">1280x720</span>
</div>
</SelectItem>
<SelectItem value="fhd">
<div className="flex items-center gap-2">
<span>Full HD</span>
<span className="text-xs text-gray-500">1920x1080</span>
</div>
</SelectItem>
<SelectItem value="qhd">
<div className="flex items-center gap-2">
<span>QHD</span>
<span className="text-xs text-gray-500">2560x1440</span>
</div>
</SelectItem>
<SelectItem value="uhd">
<div className="flex items-center gap-2">
<span>4K UHD</span>
<span className="text-xs text-gray-500">3840x2160</span>
</div>
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
{isTooLarge && <span className="text-xs text-orange-600"> </span>}
</div>
);
}