Добавлена возможность изменения ширины AI Drawer

- Добавлен resize handle (полоска для перетаскивания) слева от drawer
- Реализовано изменение ширины перетаскиванием (от 300px до 50% экрана)
- Сохранение ширины в localStorage
- Автоматическое обновление margin для main-container
- Обработка изменения размера окна браузера
- Скрытие resize handle на мобильных устройствах
This commit is contained in:
Fedor
2025-11-11 15:24:27 +03:00
parent 43e760aad6
commit 75912e5cfb
2 changed files with 150 additions and 0 deletions

View File

@@ -4,6 +4,8 @@
right: -400px; /* Начально скрыт */
top: 0;
width: 400px;
min-width: 300px; /* Минимальная ширина */
max-width: 50vw; /* Максимальная ширина - половина экрана */
height: 100vh;
background: #ffffff; /* Чистый белый фон */
box-shadow: -2px 0 15px rgba(0,0,0,0.1);
@@ -15,6 +17,38 @@
border-left: 1px solid #e9ecef;
}
/* Полоска для изменения ширины */
.ai-drawer-resize-handle {
position: absolute;
left: 0;
top: 0;
width: 4px;
height: 100%;
cursor: ew-resize;
background: transparent;
z-index: 1000000;
transition: background 0.2s ease;
}
.ai-drawer-resize-handle:hover {
background: #007bff;
}
.ai-drawer-resize-handle:active {
background: #0056b3;
}
/* Визуальная индикация при перетаскивании */
.ai-drawer.resizing {
transition: none !important;
user-select: none;
}
.ai-drawer.resizing .ai-drawer-resize-handle {
background: #007bff;
width: 4px;
}
.ai-drawer.open {
right: 0;
}
@@ -192,6 +226,11 @@ body.ai-drawer-open .ai-drawer-toggle {
margin-right: 400px;
}
/* Динамический margin для main-container при изменении ширины drawer */
.main-container.drawer-open[data-drawer-width] {
margin-right: var(--drawer-width, 400px);
}
/* Плавающий индикатор загрузки */
.ai-loading-overlay {
position: fixed;
@@ -476,6 +515,13 @@ body.ai-drawer-open .ai-drawer-toggle {
height: 100dvh; /* Динамическая высота viewport для мобильных */
display: flex;
flex-direction: column;
min-width: 100%;
max-width: 100%;
}
/* Скрываем resize handle на мобильных */
.ai-drawer-resize-handle {
display: none;
}
.main-container.drawer-open {
@@ -683,6 +729,8 @@ body.ai-drawer-open .ai-drawer-toggle {
/* Десктопная версия drawer */
.ai-drawer {
width: 400px;
min-width: 300px;
max-width: 50vw;
right: -400px;
height: 100vh;
display: flex;

View File

@@ -5,6 +5,8 @@ class AIDrawer {
this.avatarType = 'default';
this.sessionId = null;
this.currentEventSource = null; // Для SSE соединения
this.drawerWidth = 400; // Текущая ширина drawer
this.isResizing = false; // Флаг перетаскивания
this.init();
// Загружаем историю сразу при инициализации (при загрузке страницы)
@@ -21,6 +23,7 @@ class AIDrawer {
const drawerHTML =
'<button class="ai-drawer-toggle">AI</button>' +
'<div class="ai-drawer font-normal">' +
'<div class="ai-drawer-resize-handle"></div>' +
'<div class="ai-drawer-header">' +
'<span>AI Ассистент</span>' +
'<button class="ai-drawer-close">&times;</button>' +
@@ -73,6 +76,7 @@ class AIDrawer {
this.avatarButtons = document.querySelectorAll('.avatar-btn');
this.chatInput = document.querySelector('#ai-chat-input');
this.sendButton = document.querySelector('#ai-send-button');
this.resizeHandle = document.querySelector('.ai-drawer-resize-handle');
// Обработчики событий
if (this.toggleBtn) {
@@ -119,8 +123,91 @@ class AIDrawer {
// Восстанавливаем настройки
this.restoreSettings();
// Инициализируем изменение размера
this.initResize();
// Обработчик изменения размера окна - ограничиваем ширину если нужно
window.addEventListener('resize', () => {
if (this.drawerWidth > window.innerWidth / 2) {
const maxWidth = window.innerWidth / 2;
this.setDrawerWidth(maxWidth);
}
});
console.log('AI Drawer: Простая инициализация завершена');
}
initResize() {
if (!this.resizeHandle || !this.drawer) return;
// Загружаем сохраненную ширину
const savedWidth = localStorage.getItem('ai-drawer-width');
if (savedWidth) {
const width = parseInt(savedWidth, 10);
if (width >= 300 && width <= window.innerWidth / 2) {
this.setDrawerWidth(width);
}
}
// Обработчики для перетаскивания
this.resizeHandle.addEventListener('mousedown', (e) => {
e.preventDefault();
this.startResize(e);
});
}
startResize(e) {
this.isResizing = true;
this.drawer.classList.add('resizing');
document.body.style.cursor = 'ew-resize';
document.body.style.userSelect = 'none';
const startX = e.clientX;
const startWidth = this.drawerWidth;
const doResize = (e) => {
if (!this.isResizing) return;
const diff = startX - e.clientX; // Инвертируем, т.к. drawer справа
const newWidth = Math.max(300, Math.min(window.innerWidth / 2, startWidth + diff));
this.setDrawerWidth(newWidth);
};
const stopResize = () => {
this.isResizing = false;
this.drawer.classList.remove('resizing');
document.body.style.cursor = '';
document.body.style.userSelect = '';
document.removeEventListener('mousemove', doResize);
document.removeEventListener('mouseup', stopResize);
// Сохраняем ширину
localStorage.setItem('ai-drawer-width', this.drawerWidth.toString());
};
document.addEventListener('mousemove', doResize);
document.addEventListener('mouseup', stopResize);
}
setDrawerWidth(width) {
if (this.drawer) {
// Ограничиваем ширину максимум до половины экрана и минимум 300px
const maxWidth = window.innerWidth / 2;
const finalWidth = Math.max(300, Math.min(maxWidth, width));
this.drawerWidth = finalWidth;
this.drawer.style.width = finalWidth + 'px';
// Обновляем margin для main-container
const mainContainer = document.querySelector('.main-container');
if (mainContainer && this.isOpen) {
mainContainer.style.setProperty('--drawer-width', finalWidth + 'px');
mainContainer.style.marginRight = finalWidth + 'px';
mainContainer.setAttribute('data-drawer-width', finalWidth);
}
}
}
toggle() {
if (this.isOpen) {
@@ -139,6 +226,14 @@ class AIDrawer {
document.body.classList.add('ai-drawer-open');
this.isOpen = true;
// Обновляем margin для main-container с текущей шириной
const mainContainer = document.querySelector('.main-container');
if (mainContainer) {
mainContainer.style.setProperty('--drawer-width', this.drawerWidth + 'px');
mainContainer.style.marginRight = this.drawerWidth + 'px';
mainContainer.setAttribute('data-drawer-width', this.drawerWidth);
}
// История уже загружена при инициализации страницы
// Не нужно дополнительных запросов при открытии
}
@@ -151,6 +246,13 @@ class AIDrawer {
document.body.classList.remove('ai-drawer-open');
this.isOpen = false;
// Убираем margin у main-container
const mainContainer = document.querySelector('.main-container');
if (mainContainer) {
mainContainer.style.marginRight = '';
mainContainer.removeAttribute('data-drawer-width');
}
}
setFontSize(size) {