From 3168964cde832077bc2aa4383245642da686e492 Mon Sep 17 00:00:00 2001 From: Denis Shatskiy Date: Tue, 5 Aug 2025 20:14:38 +0700 Subject: [PATCH] feat: Revamp navigation structure in App component with dropdown menus and enhanced styling for improved user experience --- frontend/src/App.css | 184 +++++++++++++++++++++++++++++++++++ frontend/src/App.jsx | 227 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 378 insertions(+), 33 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index 97e403c..8496465 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -6,6 +6,190 @@ background-image: url('data:image/svg+xml,'); } +/* Navbar styles */ +.navbar { + position: relative; + z-index: 1030; +} + +.navbar-nav .nav-item.dropdown { + position: relative; +} + +.navbar-nav .nav-link { + display: flex; + align-items: center; + padding: 0.5rem 1rem; + color: var(--tblr-body-color); + text-decoration: none; + transition: color 0.15s ease-in-out; +} + +.navbar-nav .nav-link:hover { + color: var(--tblr-primary); +} + +.navbar-nav .nav-link.active { + color: var(--tblr-primary); + font-weight: 600; +} + +.navbar-nav .nav-link .icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; +} + +.navbar-nav .dropdown-toggle::after { + margin-left: 0.5rem; + vertical-align: middle; +} + +.navbar-nav .dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0; + font-size: 0.875rem; + color: var(--tblr-body-color); + text-align: left; + list-style: none; + background-color: var(--tblr-bg-surface); + background-clip: padding-box; + border: 1px solid var(--tblr-border-color); + border-radius: 0.375rem; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15); +} + +.navbar-nav .dropdown-menu.show { + display: block; +} + +.navbar-nav .dropdown-menu-columns { + display: flex; + flex-wrap: wrap; + min-width: 16rem; +} + +.navbar-nav .dropdown-menu-column { + flex: 1; + min-width: 8rem; +} + +.navbar-nav .dropdown-item { + display: flex; + align-items: center; + width: 100%; + padding: 0.5rem 1rem; + clear: both; + font-weight: 400; + color: var(--tblr-body-color); + text-align: inherit; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out; +} + +.navbar-nav .dropdown-item:hover { + color: var(--tblr-primary); + background-color: var(--tblr-bg-surface-hover); +} + +.navbar-nav .dropdown-item.active { + color: var(--tblr-primary); + background-color: var(--tblr-primary-lt); +} + +.navbar-nav .dropdown-item .icon { + margin-right: 0.5rem; + width: 1rem; + height: 1rem; +} + +/* Navbar brand */ +.navbar-brand { + display: flex; + align-items: center; + padding-top: 0.3125rem; + padding-bottom: 0.3125rem; + margin-right: 1rem; + font-size: 1.25rem; + line-height: inherit; + white-space: nowrap; + text-decoration: none; + color: var(--tblr-body-color); +} + +.navbar-brand:hover { + color: var(--tblr-primary); + text-decoration: none; +} + +.navbar-brand-icon { + margin-right: 0.5rem; +} + +/* User menu */ +.navbar-nav .nav-item.dropdown .nav-link { + padding: 0.25rem 0.5rem; +} + +.navbar-nav .nav-item.dropdown .avatar { + width: 2rem; + height: 2rem; + border-radius: 50%; + background-size: cover; + background-position: center; +} + +/* Badge styles */ +.badge { + display: inline-block; + padding: 0.35em 0.65em; + font-size: 0.75em; + font-weight: 700; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.375rem; +} + +.badge.bg-red { + background-color: #d63939 !important; +} + +/* Responsive navbar */ +@media (max-width: 991.98px) { + .navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; + } + + .navbar-nav { + flex-direction: column; + width: 100%; + } + + .navbar-nav .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } +} + /* Custom animations */ @keyframes fadeIn { from { diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 2a7c5a0..6f89527 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -19,7 +19,12 @@ import { IconServer, IconFilter, IconDownload, - IconCreditCard + IconCreditCard, + IconMoon, + IconGrid, + IconHeart, + IconCode, + IconGear } from '@tabler/icons-react'; import DataManager from './DataManager'; import ServerManager from './ServerManager'; @@ -55,46 +60,202 @@ function MainLayout() { { id: 2, title: 'Изменения сохранены', message: 'Список AS обновлен в S3', time: '5 мин назад' } ]); - const navItems = [ - { id: 'domains', title: 'Домены', icon: IconWorld, path: '/domains' }, - { id: 'domains-new', title: 'Домены New', icon: IconWorld, path: '/domains-new' }, - { id: 'ip-ranges', title: 'IP-диапазоны', icon: IconNetwork, path: '/ip-ranges' }, - { id: 'asns', title: 'AS', icon: IconNetwork, path: '/asns' }, - { id: 'auto-urls', title: 'Авто URL', icon: IconDownload, path: '/auto-urls' }, - { id: 'servers', title: 'Серверы', icon: IconServer, path: '/servers' }, - { id: 'billing', title: 'Биллинг', icon: IconCreditCard, path: '/billing' }, - { id: 'filters', title: 'Фильтры', icon: IconFilter, path: '/filters' }, - { id: 'files', title: 'Файлы', icon: IconFileText, path: '/files' }, - { id: 'cloud', title: 'Облако', icon: IconCloud, path: '/cloud' }, - { id: 'security', title: 'Безопасность', icon: IconShield, path: '/security' }, - { id: 'activity', title: 'Активность', icon: IconActivity, path: '/activity' }, - { id: 'settings', title: 'Настройки', icon: IconSettings, path: '/settings' } + // Состояние для управления выпадающими меню + const [dropdownStates, setDropdownStates] = useState({ + data: false, + management: false, + tools: false, + settings: false + }); + + const toggleDropdown = (dropdown) => { + setDropdownStates(prev => ({ + ...prev, + [dropdown]: !prev[dropdown] + })); + }; + + const navCategories = [ + { + id: 'home', + title: 'Главная', + icon: IconHome, + path: '/', + single: true + }, + { + id: 'data', + title: 'Данные', + icon: IconDatabase, + items: [ + { id: 'domains', title: 'Домены', path: '/domains', icon: IconWorld }, + { id: 'domains-new', title: 'Домены New', path: '/domains-new', icon: IconWorld }, + { id: 'ip-ranges', title: 'IP-диапазоны', path: '/ip-ranges', icon: IconNetwork }, + { id: 'asns', title: 'AS', path: '/asns', icon: IconNetwork } + ] + }, + { + id: 'management', + title: 'Управление', + icon: IconServer, + items: [ + { id: 'servers', title: 'Серверы', path: '/servers', icon: IconServer }, + { id: 'filters', title: 'Фильтры', path: '/filters', icon: IconFilter }, + { id: 'billing', title: 'Биллинг', path: '/billing', icon: IconCreditCard } + ] + }, + { + id: 'tools', + title: 'Инструменты', + icon: IconSettings, + items: [ + { id: 'auto-urls', title: 'Авто URL', path: '/auto-urls', icon: IconDownload }, + { id: 'files', title: 'Файлы', path: '/files', icon: IconFileText }, + { id: 'cloud', title: 'Облако', path: '/cloud', icon: IconCloud }, + { id: 'security', title: 'Безопасность', path: '/security', icon: IconShield }, + { id: 'activity', title: 'Активность', path: '/activity', icon: IconActivity } + ] + }, + { + id: 'settings', + title: 'Настройки', + icon: IconSettings, + path: '/settings', + single: true + } ]; // Определяем активную вкладку по адресу - const activeTab = navItems.find(item => location.pathname.startsWith(item.path))?.id || 'domains'; + const getActiveTab = () => { + for (const category of navCategories) { + if (category.single && location.pathname === category.path) { + return category.id; + } + if (category.items) { + for (const item of category.items) { + if (location.pathname.startsWith(item.path)) { + return item.id; + } + } + } + } + return 'home'; + }; + + const activeTab = getActiveTab(); return (
{/* Верхнее меню Tabler Admin */}
-
- - - S3 Lists Manager - - +
+ {/* Логотип */} +
+ + + S3 Lists Manager + +
+ + {/* Основное меню */} + + + {/* Правая часть навбара */} +
+ {/* Иконки */} +
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+ + + {/* Пользователь */} + +