/
melissaaaz
/
MemoryOffice
Обзор
Документация
Войти
/
melissaaaz
/
MemoryOffice
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
front/src/components/Header.jsx
230 строк
14 KB
melissaaaz
upload files Frontend
19 дек 2025, 21:55
19 дек 2025, 21:55
bb001d3
Код
Авторство
О чём код?
import React, { useState } from 'react' import { Link, useNavigate, useLocation } from 'react-router-dom' import { useAuth } from '../App' import { MapPin, User, LogOut, Menu, X, Compass, BookOpen } from 'lucide-react' const Header = () => { const { user, logout, isAuthenticated } = useAuth() const navigate = useNavigate() const location = useLocation() const [mobileMenuOpen, setMobileMenuOpen] = useState(false) const cities = [ { name: 'Калининград', available: true, path: '/city/kaliningrad' }, { name: 'Москва', available: false, path: '/city/moscow' }, { name: 'Санкт-Петербург', available: false, path: '/city/saint-petersburg' }, { name: 'Казань', available: false, path: '/city/kazan' }, { name: 'Сочи', available: false, path: '/city/sochi' } ] const handleLogout = () => { logout() navigate('/') setMobileMenuOpen(false) } return ( <header className="sticky top-0 z-50 bg-gradient-to-r from-white/95 via-sky-50/95 to-emerald-50/95 backdrop-blur-lg border-b border-sky-300/50 shadow-lg"> <div className="container mx-auto px-4"> <div className="flex items-center justify-between h-20"> {/* Логотип - упрощенный */} <Link to="/home" className="flex items-center space-x-3 group"> <MapPin className="h-8 w-8 text-sky-700 group-hover:scale-110 transition-transform" /> <div> <h1 className="text-3xl font-mono font-bold text-slate-800 tracking-wide"> MEMORY OFFICE </h1> <p className="text-sm text-emerald-600 font-mono italic -mt-1 tracking-tight"> архив городской памяти </p> </div> </Link> {/* Навигация для десктопа */} <nav className="hidden md:flex items-center space-x-8"> <Link to="/home" className={`text-lg font-mono transition-all ${location.pathname === '/home' ? 'text-sky-700 border-b-2 border-sky-600 pb-1' : 'text-slate-700 hover:text-sky-600' }`} > ВСЕ МАРШРУТЫ </Link> {/* Dropdown с городами */} <div className="relative group"> <button className="text-lg font-mono text-slate-700 hover:text-sky-600 transition-all duration-200 group"> ГОРОДА <svg className="ml-2 w-4 h-4 inline transform group-hover:rotate-180 transition-transform duration-200" fill="currentColor" viewBox="0 0 20 20"> <path fillRule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clipRule="evenodd" /> </svg> </button> <div className="absolute hidden group-hover:block bg-gradient-to-b from-white to-sky-50/90 shadow-xl rounded-lg mt-3 py-3 w-72 border border-sky-200/70 z-50 backdrop-blur-sm"> <div className="px-4 py-2 border-b border-sky-100"> <p className="text-sm text-slate-500 font-mono uppercase tracking-wider">ДОСТУПНЫЕ ГОРОДА</p> </div> {cities.map((city) => ( <Link key={city.name} to={city.path} className="flex items-center justify-between px-4 py-4 text-slate-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 transition-all duration-150 border-t first:border-t-0 border-sky-100/50" > <div> <span className="font-mono font-medium tracking-wide text-base">{city.name}</span> <p className="text-sm text-slate-500 mt-1 font-mono"> {city.available ? 'Уникальные маршруты' : 'Скоро появится'} </p> </div> {city.available ? ( <span className="px-3 py-1.5 bg-gradient-to-r from-sky-500 to-teal-500 text-white text-sm rounded-full font-mono"> ДОСТУПНО </span> ) : ( <span className="px-3 py-1.5 bg-gradient-to-r from-gray-200 to-gray-300 text-gray-700 text-sm rounded-full font-mono"> СКОРО </span> )} </Link> ))} </div> </div> </nav> {/* Кнопки авторизации */} <div className="hidden md:flex items-center space-x-6"> {isAuthenticated ? ( <> <Link to="/account" className="text-lg font-mono text-slate-700 hover:text-sky-700 transition-all duration-200" > {user?.name} </Link> <button onClick={handleLogout} className="text-lg px-5 py-2.5 text-sky-700 hover:text-white hover:bg-gradient-to-r hover:from-sky-600 hover:to-teal-600 rounded-lg border border-sky-300 hover:border-transparent transition-all duration-200 shadow-sm font-mono font-medium" > ВЫЙТИ </button> </> ) : ( <> <Link to="/login" className="text-lg px-6 py-2.5 text-sky-700 hover:text-sky-800 font-mono font-medium transition-all duration-200 border-b-2 border-transparent hover:border-sky-600" > ВОЙТИ </Link> <Link to="/register" className="text-lg px-6 py-2.5 bg-gradient-to-r from-sky-600 to-teal-600 text-white font-mono font-medium rounded-lg hover:from-sky-700 hover:to-teal-700 active:scale-95 transition-all duration-200 shadow-lg" > СТАТЬ ПУТЕШЕСТВЕННИКОМ </Link> </> )} </div> {/* Кнопка мобильного меню */} <button className="md:hidden p-3 rounded-lg border border-sky-300 text-sky-600 hover:bg-sky-50 transition-all duration-200 shadow-sm" onClick={() => setMobileMenuOpen(!mobileMenuOpen)} > {mobileMenuOpen ? ( <X className="h-7 w-7" /> ) : ( <Menu className="h-7 w-7" /> )} </button> </div> {/* Мобильное меню */} {mobileMenuOpen && ( <div className="md:hidden pb-8 border-t border-sky-200/50 pt-6 bg-gradient-to-b from-white to-sky-50/90 backdrop-blur-sm"> <nav className="flex flex-col space-y-5"> <Link to="/home" className="text-xl px-6 py-4 text-slate-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 rounded-lg transition-all duration-200 font-mono font-medium border border-sky-200/50" onClick={() => setMobileMenuOpen(false)} > ВСЕ МАРШРУТЫ </Link> <div className="px-6"> <div className="flex items-center space-x-3 mb-4"> <p className="text-xl font-mono font-medium text-slate-700">ГОРОДА</p> </div> <div className="space-y-3"> {cities.map((city) => ( <Link key={city.name} to={city.path} className="flex items-center justify-between px-5 py-4 text-slate-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 rounded-lg border border-sky-200/70 transition-all duration-200" onClick={() => setMobileMenuOpen(false)} > <div> <span className="font-mono font-medium tracking-wide text-lg block">{city.name}</span> <span className="text-sm text-slate-500 font-mono mt-1 block"> {city.available ? 'Доступные маршруты' : 'В разработке'} </span> </div> {city.available ? ( <span className="px-4 py-1.5 bg-gradient-to-r from-sky-500 to-teal-500 text-white text-sm rounded-full font-mono"> ДОСТУПНО </span> ) : ( <span className="px-4 py-1.5 bg-gradient-to-r from-gray-200 to-gray-300 text-gray-700 text-sm rounded-full font-mono"> СКОРО </span> )} </Link> ))} </div> </div> <div className="border-t border-sky-200/50 pt-6 mt-3"> {isAuthenticated ? ( <> <Link to="/account" className="text-xl px-6 py-4 text-slate-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 rounded-lg transition-all duration-200 font-mono font-medium mb-4 border border-sky-200/50" onClick={() => setMobileMenuOpen(false)} > {user?.name} </Link> <button onClick={handleLogout} className="w-full text-xl px-6 py-4 text-sky-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 rounded-lg border border-sky-300 transition-all duration-200 font-mono font-medium" > ВЫЙТИ </button> </> ) : ( <> <Link to="/login" className="block text-xl px-6 py-4 text-center text-sky-700 hover:bg-gradient-to-r hover:from-sky-50/50 hover:to-emerald-50/50 rounded-lg transition-all duration-200 mb-4 border border-sky-200/50 font-mono font-medium" onClick={() => setMobileMenuOpen(false)} > ВОЙТИ </Link> <Link to="/register" className="block text-xl px-6 py-4 text-center bg-gradient-to-r from-sky-600 to-teal-600 text-white rounded-lg hover:from-sky-700 hover:to-teal-700 transition-all duration-200 font-mono font-medium shadow-sm" onClick={() => setMobileMenuOpen(false)} > РЕГИСТРАЦИЯ </Link> </> )} </div> </nav> </div> )} </div> </header> ) } export default Header