173 lines
4.2 KiB
TypeScript
173 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback, useEffect } from "react";
|
|
|
|
export interface PanelState {
|
|
isOpen: boolean;
|
|
position: { x: number; y: number };
|
|
size: { width: number; height: number };
|
|
}
|
|
|
|
export interface PanelConfig {
|
|
id: string;
|
|
title: string;
|
|
defaultPosition: "left" | "right" | "top" | "bottom";
|
|
defaultWidth: number;
|
|
defaultHeight: number;
|
|
shortcutKey?: string;
|
|
}
|
|
|
|
export const usePanelState = (panels: PanelConfig[]) => {
|
|
const [panelStates, setPanelStates] = useState<Record<string, PanelState>>(() => {
|
|
const initialStates: Record<string, PanelState> = {};
|
|
|
|
panels.forEach((panel) => {
|
|
initialStates[panel.id] = {
|
|
isOpen: false,
|
|
position: { x: 0, y: 0 },
|
|
size: { width: panel.defaultWidth, height: panel.defaultHeight },
|
|
};
|
|
});
|
|
|
|
return initialStates;
|
|
});
|
|
|
|
// 패널 설정이 변경되었을 때 크기 업데이트
|
|
useEffect(() => {
|
|
setPanelStates((prev) => {
|
|
const newStates = { ...prev };
|
|
|
|
panels.forEach((panel) => {
|
|
if (newStates[panel.id]) {
|
|
// 기존 패널의 위치는 유지하고 크기만 업데이트
|
|
newStates[panel.id] = {
|
|
...newStates[panel.id],
|
|
size: { width: panel.defaultWidth, height: panel.defaultHeight },
|
|
};
|
|
} else {
|
|
// 새로운 패널이면 전체 초기화
|
|
newStates[panel.id] = {
|
|
isOpen: false,
|
|
position: { x: 0, y: 0 },
|
|
size: { width: panel.defaultWidth, height: panel.defaultHeight },
|
|
};
|
|
}
|
|
});
|
|
|
|
return newStates;
|
|
});
|
|
}, [panels]);
|
|
|
|
// 패널 토글
|
|
const togglePanel = useCallback((panelId: string) => {
|
|
setPanelStates((prev) => ({
|
|
...prev,
|
|
[panelId]: {
|
|
...prev[panelId],
|
|
isOpen: !prev[panelId]?.isOpen,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 패널 열기
|
|
const openPanel = useCallback((panelId: string) => {
|
|
console.log("📂 패널 열기:", {
|
|
panelId,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
setPanelStates((prev) => ({
|
|
...prev,
|
|
[panelId]: {
|
|
...prev[panelId],
|
|
isOpen: true,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 패널 닫기
|
|
const closePanel = useCallback((panelId: string) => {
|
|
console.log("📁 패널 닫기:", {
|
|
panelId,
|
|
timestamp: new Date().toISOString(),
|
|
});
|
|
setPanelStates((prev) => ({
|
|
...prev,
|
|
[panelId]: {
|
|
...prev[panelId],
|
|
isOpen: false,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 모든 패널 닫기
|
|
const closeAllPanels = useCallback(() => {
|
|
setPanelStates((prev) => {
|
|
const newStates = { ...prev };
|
|
Object.keys(newStates).forEach((panelId) => {
|
|
newStates[panelId] = {
|
|
...newStates[panelId],
|
|
isOpen: false,
|
|
};
|
|
});
|
|
return newStates;
|
|
});
|
|
}, []);
|
|
|
|
// 패널 위치 업데이트
|
|
const updatePanelPosition = useCallback((panelId: string, position: { x: number; y: number }) => {
|
|
setPanelStates((prev) => ({
|
|
...prev,
|
|
[panelId]: {
|
|
...prev[panelId],
|
|
position,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 패널 크기 업데이트
|
|
const updatePanelSize = useCallback((panelId: string, size: { width: number; height: number }) => {
|
|
setPanelStates((prev) => ({
|
|
...prev,
|
|
[panelId]: {
|
|
...prev[panelId],
|
|
size,
|
|
},
|
|
}));
|
|
}, []);
|
|
|
|
// 키보드 단축키 처리
|
|
useEffect(() => {
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
// Esc 키로 모든 패널 닫기
|
|
if (e.key === "Escape") {
|
|
closeAllPanels();
|
|
return;
|
|
}
|
|
|
|
// 단축키 처리
|
|
panels.forEach((panel) => {
|
|
if (panel.shortcutKey && e.key?.toLowerCase() === panel.shortcutKey?.toLowerCase()) {
|
|
// Ctrl/Cmd 키와 함께 사용
|
|
if (e.ctrlKey || e.metaKey) {
|
|
e.preventDefault();
|
|
togglePanel(panel.id);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
document.addEventListener("keydown", handleKeyDown);
|
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
}, [panels, togglePanel, closeAllPanels]);
|
|
|
|
return {
|
|
panelStates,
|
|
togglePanel,
|
|
openPanel,
|
|
closePanel,
|
|
closeAllPanels,
|
|
updatePanelPosition,
|
|
updatePanelSize,
|
|
};
|
|
};
|