diff --git a/frontend/src/app/providers/layout/navigation/navigation.tsx b/frontend/src/app/providers/layout/navigation/navigation.tsx index 8e380fa..a081579 100644 --- a/frontend/src/app/providers/layout/navigation/navigation.tsx +++ b/frontend/src/app/providers/layout/navigation/navigation.tsx @@ -1,5 +1,6 @@ +import { useState, useRef, useEffect } from "react"; import { useNavigate, useLocation } from "react-router-dom"; -import { FaCode } from "react-icons/fa"; +import { FaCode, FaChevronDown } from "react-icons/fa"; import { FaHome, FaServer, @@ -8,32 +9,63 @@ import { FaRocket, FaKey, FaFileAlt, - FaSun, - FaMoon, + FaPalette, + FaSignOutAlt, + FaShieldAlt, } from "react-icons/fa"; import { useAuthStore } from "@/modules/auth/store/useAuthStore"; import { useThemeStore } from "@/modules/theme-bw/stores/theme.store"; +import { themes } from "@/modules/theme-changer/config/theme.config"; +import { + applyTheme, + getCurrentTheme, +} from "@/modules/theme-changer/utils/apply.theme"; export const Navigation = () => { const navigate = useNavigate(); const location = useLocation(); const { user, logout } = useAuthStore(); - const { toggleTheme, theme } = useThemeStore(); - - const isDark = theme === "dark"; + const { setTheme } = useThemeStore(); + const [dropdownOpen, setDropdownOpen] = useState(false); + const [themePickerOpen, setThemePickerOpen] = useState(false); + const dropdownRef = useRef(null); + const currentTheme = getCurrentTheme(); const navItems = [ - { path: "/", label: "Главная", icon: FaHome }, - { path: "/add-agents", label: "Агенты", icon: FaServer }, { path: "/templates", label: "Шаблоны", icon: FaCode }, { path: "/add-agents", label: "Деплой", icon: FaRocket }, { path: "/registration", label: "Регистрация", icon: FaKey }, { path: "/logs", label: "Логи", icon: FaFileAlt }, - { path: "/admin", label: "Админка", icon: FaUsers, adminOnly: true }, ]; const isActive = (path: string) => location.pathname === path; + // Закрытие дропдауна при клике вне + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(e.target as Node) + ) { + setDropdownOpen(false); + setThemePickerOpen(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const handleLogout = () => { + logout(); + navigate("/auth"); + }; + + const handleThemeChange = (themeId: string) => { + applyTheme(themeId); + setTheme(themeId as any); + setThemePickerOpen(false); + }; + return (
{ }} >
- {/* Навигация с горизонтальным скроллом */} + {/* Навигация */}
{navItems .filter((item) => { - if (item.adminOnly && !user?.permission_admin) return false; + if ((item as any).adminOnly && !user?.permission_admin) + return false; return true; }) .map((item) => { @@ -87,81 +120,210 @@ export const Navigation = () => {
- {/* Профиль пользователя */} -
- {user && ( -
+ {/* Профиль пользователя — дропдаун */} +
+ + + {/* Dropdown menu */} + {dropdownOpen && ( +
+ {/* User info */}
- +
+
+ +
+
+

+ {user?.name || user?.login} +

+

+ {user?.login} +

+
+
- + + + {/* Theme sub-dropdown */} + {themePickerOpen && ( +
+ {themes.map((t) => ( + + ))} +
+ )} +
+ + {/* Admin (if admin) */} + {user?.permission_admin && ( + + )} + + {/* Divider */} +
+ + {/* Logout */} +
)} - - {/* Переключатель темы */} - - - {/* Админка */} - - -