/
aaronair
/
Test_task_rt_solution
Обзор
Документация
Войти
/
aaronair
/
Test_task_rt_solution
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/components/Header.tsx
117 строк
5 KB
aaronair
Решение
03 июн 2026, 15:04
03 июн 2026, 15:04
72ced40
Код
Авторство
О чём код?
import { NavLink, useLocation } from "react-router-dom"; import { NavDropdown } from "./NavDropdown"; import { cn } from "@/lib/cn"; const mainNavBase = [ { to: "/", label: "Главная", end: true }, { to: "/initiatives", label: "Реестр инициатив", end: false }, ] as const; const resourceItems = [ { to: "/steps", label: "Шаги реализации" }, { to: "/funding", label: "Как получить бюджет" }, { to: "/knowledge", label: "Библиотека знаний" }, ]; export function Header() { const location = useLocation(); // Динамически считываем состояние авторизации прямо в компоненте шапки const token = localStorage.getItem('token'); const role = localStorage.getItem('role'); // Формируем итоговый массив навигации в зависимости от роли пользователя const navigationMenu = [...mainNavBase]; // Пункт 4 ТЗ: Если токен есть — добавляем вкладку "Личный кабинет" if (token) { navigationMenu.push({ to: "/dashboard", label: "Личный кабинет", end: false }); } // Пункт 3 ТЗ: Если роль админ — добавляем вкладку "Панель администратора" if (token && role === 'admin') { navigationMenu.push({ to: "/admin", label: "Панель администратора", end: false }); } const triggerAuthModal = () => { if ((window as any).openAuthModal) (window as any).openAuthModal(); }; const triggerLogout = () => { if ((window as any).handleLogoutGlobal) (window as any).handleLogoutGlobal(); }; return ( <header className="border-b border-ink-300/40 bg-surface-card/80 backdrop-blur sticky top-0 z-30"> <div className="container-page flex items-center justify-between h-34 gap-2"> {/* Левая часть: Логотип */} <NavLink to="/" className="flex items-center gap-3 group shrink-0"> <span className="inline-flex items-center justify-center h-9 w-9 rounded-lg bg-gradient-to-br from-primary-600 to-accent-violet text-white font-bold"> AI </span> <div className="leading-tight hidden sm:block"> <div className="font-semibold text-ink-900">AI-портал</div> <div className="text-xs text-ink-500">Реестр инициатив</div> </div> </NavLink> {/* Правая часть: Навигация и Авторизация */} <div className="flex items-center gap-4 flex-wrap justify-end pb-1"> <nav className="flex items-center gap-1 flex-wrap justify-end"> {navigationMenu.map((item) => ( <NavLink key={item.to} to={item.to} end={item.end} className={({ isActive }) => cn( "px-3 py-2 rounded-lg text-sm font-medium transition-colors whitespace-nowrap", isActive ? item.to === "/admin" ? "bg-red-50 text-red-700" // Выделяем админку красным акцентом при активности : "bg-primary-50 text-primary-700" : item.to === "/admin" ? "text-red-600 hover:bg-red-50/50" // Выделяем админку в обычном состоянии : "text-ink-700 hover:bg-surface-muted", ) } > {item.label} </NavLink> ))} <NavDropdown label="Ресурсы" items={resourceItems} /> </nav> {/* Вертикальный разделитель дизайна */} <div className="h-6 w-px bg-ink-300/40 hidden xs:block" /> {/* Блок управления сессией (Вход / Выход) */} <div className="flex items-center gap-3"> {token ? ( <div className="flex items-center gap-3 text-xs md:text-sm"> <span className="text-ink-500 hidden lg:inline"> Роль: <strong className="text-ink-900 uppercase font-bold">{role}</strong> </span> <button onClick={triggerLogout} className="text-red-600 hover:text-red-700 font-semibold border border-red-200/60 px-3 py-1.5 rounded-lg hover:bg-red-50/50 transition-colors text-sm" > Выйти </button> </div> ) : ( <button onClick={triggerAuthModal} className="bg-primary-600 text-white font-semibold text-sm px-4 py-2 rounded-lg hover:bg-primary-500 shadow-sm transition-all transform active:scale-95 whitespace-nowrap" > Вход / Регистрация </button> )} </div> </div> </div> </header> ); }