fix: open detail popup on right monitor using Window Management API

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
EENE Dashboard
2026-06-05 10:27:14 +09:00
parent 7c600b2176
commit 0da56b505c
2 changed files with 68 additions and 15 deletions

View File

@@ -11,7 +11,7 @@ interface DashboardHeaderProps {
stats: Stats;
activeStatus: string;
onStatusChange: (status: string) => void;
onOpenDetailWindow: () => void;
onOpenDetailWindow: () => void | Promise<void>;
onOpenTaskManager: () => void;
}

View File

@@ -14,6 +14,63 @@ type DualMonitorEvent =
let channel: BroadcastChannel | null = null;
let detailWindow: Window | null = null;
interface ScreenDetailed {
left: number;
top: number;
width: number;
height: number;
availLeft?: number;
availTop?: number;
availWidth?: number;
availHeight?: number;
}
interface ScreenDetails {
currentScreen: ScreenDetailed;
screens: ScreenDetailed[];
}
interface WindowWithScreenDetails extends Window {
getScreenDetails?: () => Promise<ScreenDetails>;
}
/** 참조 대시보드와 동일: 우측 모니터 좌표·크기 계산 */
async function getDetailWindowFeatures(): Promise<string> {
let left = window.screenX + window.outerWidth;
let top = window.screenY;
let width = window.screen.availWidth;
let height = window.screen.availHeight;
try {
const win = window as WindowWithScreenDetails;
if (win.getScreenDetails) {
const details = await win.getScreenDetails();
const current = details.currentScreen;
let target = details.screens.find((s) => s.left >= current.left + current.width);
target ||= details.screens.find((s) => s !== current);
if (target) {
left = target.availLeft ?? target.left;
top = target.availTop ?? target.top;
width = target.availWidth ?? target.width;
height = target.availHeight ?? target.height;
} else {
left = window.screenX + window.outerWidth;
width = window.screen.availWidth - left;
if (width < 800) {
width = 1920;
left = window.screen.availWidth;
}
height = window.screen.availHeight;
}
}
} catch (err) {
console.warn('Window Management API failed or denied, using fallback', err);
}
return `left=${left},top=${top},width=${width},height=${height},menubar=no,toolbar=no,location=no,status=no,resizable=yes,scrollbars=yes`;
}
function getChannel(): BroadcastChannel {
if (!channel) {
channel = new BroadcastChannel(CHANNEL_NAME);
@@ -27,33 +84,29 @@ export function isDetailWindowOpen(): boolean {
}
/** 상세 창 토글 — 열려 있으면 닫고, 닫혀 있으면 오른쪽 모니터에 열기 */
export function openDetailWindow(): Window | null {
export async function openDetailWindow(): Promise<Window | null> {
if (isDetailWindowOpen()) {
detailWindow!.close();
detailWindow = null;
return null;
}
// 현재 창이 왼쪽 모니터에 있다고 가정하고
// 오른쪽 모니터의 시작 X 좌표 = 현재 창 X + 현재 화면 너비
const screenW = window.screen.width;
const screenH = window.screen.height;
const rightMonitorLeft = window.screenX + screenW;
const detailUrl = `${window.location.origin}/detail`;
const features = await getDetailWindowFeatures();
detailWindow = window.open(
detailUrl,
DETAIL_WINDOW_NAME,
`width=${screenW},height=${screenH},left=${rightMonitorLeft},top=0,resizable=yes,scrollbars=yes`,
);
detailWindow = window.open(detailUrl, DETAIL_WINDOW_NAME, features);
try {
detailWindow?.focus();
} catch {
// popup-blocked 등
}
return detailWindow;
}
/** 좌측 → 우측: 업무 선택 이벤트 전송 (창이 닫혀 있으면 열고 전송) */
export function sendTaskSelected(taskId: string): void {
export async function sendTaskSelected(taskId: string): Promise<void> {
if (!isDetailWindowOpen()) {
openDetailWindow();
await openDetailWindow();
// 창이 로드될 때까지 잠시 대기 후 전송
setTimeout(() => {
getChannel().postMessage({ type: 'TASK_SELECTED', taskId } satisfies DualMonitorEvent);