feat: collapsible sidebar groups with favorites + chat visibility toggle

- Sidebar: collapsible groups (Основное/Цены/Сервис/Управление/Настройки/Разработчикам) with chevron headers, state persisted in localStorage 'sidebarGroups'
- Sidebar: Избранное group at top, star icon on nav item hover to add/remove favorites, stored in localStorage 'sidebarFavorites'
- Sidebar: active route auto-opens its group on navigation
- SettingsPage: 'Скрыть чат' toggle in Внешний вид section, stored in localStorage 'chatHidden'
- AppLayout: conditionally renders ChatWidget based on chatHidden, listens for storage events for reactive updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-26 10:39:33 +03:00
parent 7f906cb0a3
commit cbddbe6027
3 changed files with 340 additions and 85 deletions

View File

@@ -1,5 +1,5 @@
import { Outlet, Navigate } from 'react-router-dom'
import { useState } from 'react'
import { useState, useEffect } from 'react'
import { Sidebar } from '../components/layout/Sidebar'
import { Topbar } from '../components/layout/Topbar'
import { ChatWidget } from '../components/chat/ChatWidget'
@@ -8,6 +8,17 @@ import { useAuth } from '../contexts/AuthContext'
export function AppLayout() {
const { user } = useAuth()
const [sidebarOpen, setSidebarOpen] = useState(false)
const [chatHidden, setChatHidden] = useState(
() => localStorage.getItem('chatHidden') === 'true',
)
useEffect(() => {
const handleStorage = () => {
setChatHidden(localStorage.getItem('chatHidden') === 'true')
}
window.addEventListener('storage', handleStorage)
return () => window.removeEventListener('storage', handleStorage)
}, [])
if (!user) return <Navigate to="/login" replace />
@@ -22,7 +33,7 @@ export function AppLayout() {
</main>
</div>
<ChatWidget />
{!chatHidden && <ChatWidget />}
</div>
)
}