// layout.ts let resizer: HTMLElement | null = null; let leftPanel: HTMLElement | null = null; let rightPanel: HTMLElement | null = null; let isOpen: boolean = false; let lastLeftWidth: number = 0; let lastRightWidth: number = 0; export function initResize(): void { resizer = document.getElementById("dragBar"); leftPanel = document.getElementById("leftPanel"); rightPanel = document.getElementById("rightPanel"); if (!resizer || !leftPanel || !rightPanel) { console.warn("[layout] Элементы не найдены"); return; } // Проверяем видимость при инициализации updateResizerVisibility(); let isDragging = false; // Обработчик начала перетаскивания resizer.addEventListener("mousedown", (e: MouseEvent) => { // Сохраняем ссылки на элементы в локальные переменные const left = leftPanel; const right = rightPanel; // Проверяем, что элементы существуют if (!left || !right) { console.warn("[layout] Панели не найдены"); return; } // Проверяем, что правая панель видима if (right.classList.contains("hidden")) { return; } isDragging = true; document.body.style.cursor = "col-resize"; document.body.style.userSelect = "none"; // Сохраняем начальные размеры const startX = e.clientX; const leftWidth = left.getBoundingClientRect().width; const rightWidth = right.getBoundingClientRect().width; const totalWidth = leftWidth + rightWidth; function onMouseMove(moveEvent: MouseEvent): void { if (!isDragging) return; // Проверяем, что элементы всё ещё существуют if (!left || !right) return; const deltaX = moveEvent.clientX - startX; let newLeftWidth = leftWidth + deltaX; // Ограничиваем минимальные размеры const minWidth = 200; newLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth)); const newRightWidth = totalWidth - newLeftWidth; left.style.flex = `0 0 ${newLeftWidth}px`; right.style.flex = `0 0 ${newRightWidth}px`; // Сохраняем последние размеры lastLeftWidth = newLeftWidth; lastRightWidth = newRightWidth; } function onMouseUp(): void { isDragging = false; document.body.style.cursor = ""; document.body.style.userSelect = ""; document.removeEventListener("mousemove", onMouseMove); document.removeEventListener("mouseup", onMouseUp); } document.addEventListener("mousemove", onMouseMove); document.addEventListener("mouseup", onMouseUp); }); // Обработчик изменения размера окна window.addEventListener("resize", () => { handleWindowResize(); }); } /** * Обработка изменения размера окна */ function handleWindowResize(): void { if (!leftPanel || !rightPanel) return; // Если правая панель видима, пересчитываем размеры if (!rightPanel.classList.contains("hidden")) { // Если есть сохраненные размеры, используем их пропорционально if (lastLeftWidth > 0 && lastRightWidth > 0) { const totalWidth = window.innerWidth; const ratio = lastLeftWidth / (lastLeftWidth + lastRightWidth); const newLeftWidth = totalWidth * ratio; const newRightWidth = totalWidth - newLeftWidth; // Ограничиваем минимальные размеры const minWidth = 200; const finalLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth)); const finalRightWidth = totalWidth - finalLeftWidth; leftPanel.style.flex = `0 0 ${finalLeftWidth}px`; rightPanel.style.flex = `0 0 ${finalRightWidth}px`; lastLeftWidth = finalLeftWidth; lastRightWidth = finalRightWidth; } else { // Если нет сохраненных размеров, делим пополам const totalWidth = window.innerWidth; const halfWidth = totalWidth / 2; leftPanel.style.flex = `0 0 ${halfWidth}px`; rightPanel.style.flex = `0 0 ${halfWidth}px`; lastLeftWidth = halfWidth; lastRightWidth = halfWidth; } } } /** * Обновление видимости разделителя в зависимости от состояния правой панели */ export function updateResizerVisibility(): void { if (!resizer || !rightPanel) return; // Если правая панель скрыта - скрываем разделитель if (rightPanel.classList.contains("hidden")) { resizer.classList.add("hidden"); } else { resizer.classList.remove("hidden"); } } /** * Открыть правую панель */ export function openRightPanel(): void { if (!leftPanel || !rightPanel) return; // Убираем класс hidden rightPanel.classList.remove("hidden"); // Обновляем разделитель updateResizerVisibility(); // Устанавливаем размеры const totalWidth = window.innerWidth; const halfWidth = totalWidth / 2; // Проверяем, есть ли сохраненные размеры if (lastLeftWidth > 0 && lastRightWidth > 0) { // Используем сохраненные пропорции const ratio = lastLeftWidth / (lastLeftWidth + lastRightWidth); const newLeftWidth = totalWidth * ratio; const newRightWidth = totalWidth - newLeftWidth; const minWidth = 200; const finalLeftWidth = Math.max(minWidth, Math.min(totalWidth - minWidth, newLeftWidth)); const finalRightWidth = totalWidth - finalLeftWidth; leftPanel.style.flex = `0 0 ${finalLeftWidth}px`; rightPanel.style.flex = `0 0 ${finalRightWidth}px`; lastLeftWidth = finalLeftWidth; lastRightWidth = finalRightWidth; } else { // Делим пополам leftPanel.style.flex = `0 0 ${halfWidth}px`; rightPanel.style.flex = `0 0 ${halfWidth}px`; lastLeftWidth = halfWidth; lastRightWidth = halfWidth; } } /** * Закрыть правую панель */ export function closeRightPanel(): void { if (!rightPanel) return; // Добавляем класс hidden rightPanel.classList.add("hidden"); // Обновляем разделитель updateResizerVisibility(); // Сбрасываем flex для левой панели if (leftPanel) { leftPanel.style.flex = "1 1 auto"; } } // ============================================ // ПУБЛИЧНЫЕ ФУНКЦИИ (используются в других модулях) // ============================================ /** * Установить видимость разделителя вручную * @param visible - показывать или скрыть */ // noinspection JSUnusedGlobalSymbols export function setResizerVisible(visible: boolean): void { if (resizer) { if (visible) { resizer.classList.remove("hidden"); } else { resizer.classList.add("hidden"); } } } /** * Переключить состояние правой панели */ // noinspection JSUnusedGlobalSymbols export function toggleRightPanel(): void { if (!rightPanel) return; if (rightPanel.classList.contains("hidden")) { openRightPanel(); } else { closeRightPanel(); } }