diff --git a/VERSION b/VERSION index e0d9923..d03dd2c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.13.5 +4.13.6 diff --git a/play-life-web/package.json b/play-life-web/package.json index 344a672..63376bd 100644 --- a/play-life-web/package.json +++ b/play-life-web/package.json @@ -1,6 +1,6 @@ { "name": "play-life-web", - "version": "4.13.5", + "version": "4.13.6", "type": "module", "scripts": { "dev": "vite", diff --git a/play-life-web/src/App.jsx b/play-life-web/src/App.jsx index f7d1d2f..1681cdb 100644 --- a/play-life-web/src/App.jsx +++ b/play-life-web/src/App.jsx @@ -130,8 +130,6 @@ function AppContent() { const [wordsRefreshTrigger, setWordsRefreshTrigger] = useState(0) const [wishlistRefreshTrigger, setWishlistRefreshTrigger] = useState(0) - // Состояние для сохранения позиции скролла каждого таба - const [scrollPositions, setScrollPositions] = useState({}) // Восстанавливаем последний выбранный таб после перезагрузки @@ -710,15 +708,6 @@ function AppContent() { setTabParams({}) updateUrl('full', {}, activeTab) } else if (tab !== activeTab || tab === 'task-form' || tab === 'wishlist-form' || (tab === 'words' && Object.keys(params).length > 0)) { - // Сохраняем позицию скролла для текущего таба перед переходом - const scrollContainer = document.querySelector('.flex-1.overflow-y-auto') - if (scrollContainer && mainTabs.includes(activeTab)) { - setScrollPositions(prev => ({ - ...prev, - [activeTab]: scrollContainer.scrollTop - })) - } - // Для task-form и wishlist-form всегда обновляем параметры, даже если это тот же таб markTabAsLoaded(tab) @@ -865,20 +854,6 @@ function AppContent() { } }, [selectedProject, activeTab]) - // Восстанавливаем позицию скролла при возвращении на таб - useEffect(() => { - if (mainTabs.includes(activeTab) && scrollPositions[activeTab] !== undefined) { - // Используем setTimeout, чтобы DOM успел обновиться - const timeoutId = setTimeout(() => { - const scrollContainer = document.querySelector('.flex-1.overflow-y-auto') - if (scrollContainer) { - scrollContainer.scrollTop = scrollPositions[activeTab] - } - }, 0) - - return () => clearTimeout(timeoutId) - } - }, [activeTab, scrollPositions]) // Определяем общее состояние загрузки и ошибок для кнопки Refresh @@ -897,45 +872,47 @@ function AppContent() { // Определяем, нужно ли скрывать нижнюю панель (для fullscreen экранов) const isFullscreenTab = activeTab === 'test' || activeTab === 'add-words' || activeTab === 'task-form' || activeTab === 'wishlist-form' || activeTab === 'wishlist-detail' || activeTab === 'todoist-integration' || activeTab === 'telegram-integration' || activeTab === 'full' || activeTab === 'priorities' || activeTab === 'words' || activeTab === 'dictionaries' - // Определяем отступы для контейнера - const getContainerPadding = () => { - if (!isFullscreenTab) { - // Для tasks, wishlist и profile на широких экранах увеличиваем отступ - if (activeTab === 'tasks' || activeTab === 'wishlist' || activeTab === 'profile') { - return 'p-4 md:p-8' - } - return 'p-4 md:p-6' + // Функция для получения классов скролл-контейнера для каждого таба + // Каждый таб имеет свой изолированный скролл-контейнер для автоматического сохранения позиции скролла + const getTabContainerClasses = (tabName) => { + const isActive = activeTab === tabName + const baseClasses = 'absolute inset-0 overflow-y-auto' + // Активный таб: z-10 (сверху), неактивные: z-0 + invisible + opacity-0 (мгновенное скрытие) + const visibilityClasses = isActive ? 'z-10' : 'z-0 invisible opacity-0 pointer-events-none' + + // Определяем padding для каждого таба + let paddingClasses = '' + if (tabName === 'current' || tabName === 'tasks' || tabName === 'wishlist' || tabName === 'profile') { + paddingClasses = 'pb-20' + } else if (tabName === 'words' || tabName === 'dictionaries') { + paddingClasses = 'pb-16' } - // Для экрана статистики используем такие же отступы как для приоритетов - if (activeTab === 'full') { - return 'px-4 md:px-8 py-0' + + return `${baseClasses} ${paddingClasses} ${visibilityClasses}`.trim() + } + + // Функция для определения отступов внутреннего контейнера + const getInnerContainerClasses = (tabName) => { + if (tabName === 'tasks' || tabName === 'wishlist' || tabName === 'profile') { + return 'max-w-7xl mx-auto p-4 md:p-8' } - // Для экрана приоритетов используем такие же отступы как для profile - if (activeTab === 'priorities') { - return 'px-4 md:px-8 py-0' + if (tabName === 'current') { + return 'max-w-7xl mx-auto p-4 md:p-6' } - // Для экрана словарей используем такие же отступы как для приоритетов - if (activeTab === 'dictionaries') { - return 'px-4 md:px-8 py-0' + if (tabName === 'full' || tabName === 'priorities' || tabName === 'dictionaries' || tabName === 'words') { + return 'max-w-7xl mx-auto px-4 md:px-8 py-0' } - // Для экрана списка слов используем такие же отступы как для словарей - if (activeTab === 'words') { - return 'px-4 md:px-8 py-0' - } - // Для экрана желаний используем такие же отступы как для словарей - if (activeTab === 'wishlist') { - return 'px-4 md:px-8 py-0' - } - // Для остальных fullscreen экранов без отступов - return 'p-0' + // Fullscreen табы без отступов + return 'max-w-7xl mx-auto p-0' } return (