From af89be505c19389fa720d638ce3f4a4ddc9a53bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=9D=D0=B0=D0=B4=D0=B5?= =?UTF-8?q?=D0=B8=D0=BD?= Date: Mon, 8 Dec 2025 11:17:59 +0300 Subject: [PATCH] feat: improve employee scroller UX - pause only at edges Changed auto-scroller behavior for new employees: - Removed pause on card hover - cards now only scale on hover (CSS) - Added edge detection (20% zones on left/right sides) - Scroller pauses ONLY when mouse is near container edges - When paused at edge, centers nearest card for better visibility - Mouse in center zone keeps auto-scroll running - Smoother interaction - no interruption when browsing cards --- .../js/components/autoScrollerHandler.js | 70 ++++++++++++++++++- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/backend/static/js/components/autoScrollerHandler.js b/backend/static/js/components/autoScrollerHandler.js index 4f6e1c50..f61f5ef2 100644 --- a/backend/static/js/components/autoScrollerHandler.js +++ b/backend/static/js/components/autoScrollerHandler.js @@ -211,14 +211,71 @@ function initSingleScroller(wrapper, options = {}) { * Обработчик наведения на элемент. */ function handleItemMouseEnter(event) { - paused = true; - centerItemInView(wrapper, event.currentTarget); + // Больше НЕ ставим на паузу при наведении на карточку + // Просто применяется CSS hover эффект (увеличение) + // Пауза и центрирование сработают только при наведении у краев (см. handleWrapperMouseMove) } /** * Обработчик ухода курсора с элемента. */ function handleItemMouseLeave() { + // Пауза контролируется через handleWrapperMouseMove + } + + /** + * Обработчик движения мыши по контейнеру - логика паузы у краев. + */ + function handleWrapperMouseMove(event) { + const containerRect = wrapper.getBoundingClientRect(); + const mouseX = event.clientX - containerRect.left; + const containerWidth = containerRect.width; + + // Зона края (20% от ширины контейнера) + const edgeZone = containerWidth * 0.2; + + const isNearLeftEdge = mouseX < edgeZone; + const isNearRightEdge = mouseX > (containerWidth - edgeZone); + + if (isNearLeftEdge || isNearRightEdge) { + // Мышь у края - останавливаем скролл + if (!paused) { + paused = true; + + // Находим ближайший элемент к курсору + const items = Array.from(rail.querySelectorAll('.join-item')); + let closestItem = null; + let minDistance = Infinity; + + items.forEach(item => { + const itemRect = item.getBoundingClientRect(); + const itemCenterX = itemRect.left + itemRect.width / 2; + const distance = Math.abs(event.clientX - itemCenterX); + + if (distance < minDistance) { + minDistance = distance; + closestItem = item; + } + }); + + // Центрируем ближайший элемент + if (closestItem) { + centerItemInView(wrapper, closestItem); + } + } + } else { + // Мышь в центральной зоне - возобновляем скролл + if (paused) { + paused = false; + } + } + } + + /** + * Обработчик ухода курсора с контейнера. + */ + function handleWrapperMouseLeave() { + // Когда мышь покидает весь контейнер - снимаем паузу paused = false; } @@ -291,6 +348,10 @@ function initSingleScroller(wrapper, options = {}) { item.addEventListener('focusout', handleItemFocusOut); }); + // Обработчики на контейнер для отслеживания позиции мыши + wrapper.addEventListener('mousemove', handleWrapperMouseMove); + wrapper.addEventListener('mouseleave', handleWrapperMouseLeave); + // Глобальные обработчики window.addEventListener('resize', handleResize); document.addEventListener('visibilitychange', handleVisibilityChange); @@ -319,12 +380,15 @@ function initSingleScroller(wrapper, options = {}) { item.removeEventListener('focusout', handleItemFocusOut); }); + wrapper.removeEventListener('mousemove', handleWrapperMouseMove); + wrapper.removeEventListener('mouseleave', handleWrapperMouseLeave); + window.removeEventListener('resize', handleResize); document.removeEventListener('visibilitychange', handleVisibilityChange); cancelAnimationFrame(resizeFrame); // Удаляем клонированные элементы - clones.forEach(clone => clone.remove()); + allClones.forEach(clone => clone.remove()); } return { start, stop, destroy };