fix: open detail popup on right monitor using Window Management API
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,7 @@ interface DashboardHeaderProps {
|
||||
stats: Stats;
|
||||
activeStatus: string;
|
||||
onStatusChange: (status: string) => void;
|
||||
onOpenDetailWindow: () => void;
|
||||
onOpenDetailWindow: () => void | Promise<void>;
|
||||
onOpenTaskManager: () => void;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user