feat: Integrate react-router-dom for routing and enhance App component with new navigation structure
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 13m58s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 13m58s
This commit is contained in:
+71
-117
@@ -1,9 +1,9 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Container } from 'react-bootstrap';
|
||||
import {
|
||||
IconBrandTabler,
|
||||
IconWorld,
|
||||
IconNetwork,
|
||||
import {
|
||||
IconBrandTabler,
|
||||
IconWorld,
|
||||
IconNetwork,
|
||||
IconSettings,
|
||||
IconHome,
|
||||
IconFileText,
|
||||
@@ -22,140 +22,94 @@ import DataManager from './DataManager';
|
||||
import ServerManager from './ServerManager';
|
||||
import './App.css';
|
||||
import axios from 'axios';
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Routes,
|
||||
Route,
|
||||
Link,
|
||||
useLocation,
|
||||
Navigate
|
||||
} from 'react-router-dom';
|
||||
|
||||
function App() {
|
||||
const [activeTab, setActiveTab] = useState('dashboard');
|
||||
return (
|
||||
<Router>
|
||||
<MainLayout />
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
|
||||
function MainLayout() {
|
||||
const location = useLocation();
|
||||
const [notifications] = useState([
|
||||
{ id: 1, title: 'Новый домен добавлен', message: 'example.com был добавлен в список', time: '2 мин назад' },
|
||||
{ id: 2, title: 'Изменения сохранены', message: 'Список AS обновлен в S3', time: '5 мин назад' }
|
||||
]);
|
||||
|
||||
const navItems = [
|
||||
{ id: 'dashboard', title: 'Dashboard', icon: IconHome },
|
||||
{ id: 'domains', title: 'Домены', icon: IconWorld },
|
||||
{ id: 'asns', title: 'AS', icon: IconNetwork },
|
||||
{ id: 'servers', title: 'Серверы', icon: IconServer },
|
||||
{ id: 'files', title: 'Файлы', icon: IconFileText },
|
||||
{ id: 'cloud', title: 'Облако', icon: IconCloud },
|
||||
{ id: 'security', title: 'Безопасность', icon: IconShield },
|
||||
{ id: 'activity', title: 'Активность', icon: IconActivity },
|
||||
{ id: 'settings', title: 'Настройки', icon: IconSettings }
|
||||
{ id: 'domains', title: 'Домены', icon: IconWorld, path: '/domains' },
|
||||
{ id: 'asns', title: 'AS', icon: IconNetwork, path: '/asns' },
|
||||
{ id: 'servers', title: 'Серверы', icon: IconServer, path: '/servers' },
|
||||
{ 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 renderContent = () => {
|
||||
switch (activeTab) {
|
||||
case 'dashboard':
|
||||
return <Dashboard />;
|
||||
case 'domains':
|
||||
return (
|
||||
<DataManager
|
||||
entityName="домен"
|
||||
entityKey="domains"
|
||||
placeholder="example.com"
|
||||
/>
|
||||
);
|
||||
case 'asns':
|
||||
return (
|
||||
<DataManager
|
||||
entityName="AS"
|
||||
entityKey="asns"
|
||||
placeholder="AS12345"
|
||||
/>
|
||||
);
|
||||
case 'servers':
|
||||
return <ServerManager />;
|
||||
default:
|
||||
return <Dashboard />;
|
||||
}
|
||||
};
|
||||
// Определяем активную вкладку по адресу
|
||||
const activeTab = navItems.find(item => location.pathname.startsWith(item.path))?.id || 'domains';
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
{/* Верхнее меню Tabler Admin */}
|
||||
<header className="navbar navbar-expand-md navbar-light d-print-none" style={{boxShadow: '0 1px 0 0 #e9ecef'}}>
|
||||
<div className="container-xl">
|
||||
<a href="#" className="navbar-brand d-flex align-items-center">
|
||||
<Link to="/" className="navbar-brand d-flex align-items-center">
|
||||
<IconBrandTabler className="navbar-brand-icon me-2" />
|
||||
<span className="fw-bold">S3 Lists Manager</span>
|
||||
</a>
|
||||
<div className="collapse navbar-collapse show" id="navbar-menu">
|
||||
<ul className="navbar-nav me-auto">
|
||||
{navItems.map((item) => (
|
||||
<li key={item.id} className="nav-item">
|
||||
<a
|
||||
className={`nav-link d-flex align-items-center ${activeTab === item.id ? 'active fw-bold' : ''}`}
|
||||
href="#"
|
||||
onClick={e => { e.preventDefault(); setActiveTab(item.id); }}
|
||||
>
|
||||
<item.icon className="nav-link-icon me-1" size={20} />
|
||||
{item.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<ul className="navbar-nav ms-auto">
|
||||
<li className="nav-item dropdown">
|
||||
<a href="#" className="nav-link px-0" data-bs-toggle="dropdown" tabIndex="-1">
|
||||
<IconBell className="icon" />
|
||||
<span className="badge badge-sm bg-red"></span>
|
||||
</a>
|
||||
<div className="dropdown-menu dropdown-menu-arrow dropdown-menu-end dropdown-menu-card">
|
||||
<div className="card">
|
||||
<div className="card-header">
|
||||
<h3 className="card-title">Уведомления</h3>
|
||||
</div>
|
||||
<div className="list-group list-group-flush">
|
||||
{notifications.map((notification) => (
|
||||
<div key={notification.id} className="list-group-item">
|
||||
<div className="row align-items-center">
|
||||
<div className="col-auto">
|
||||
<span className="status-dot status-dot-animated bg-red d-block"></span>
|
||||
</div>
|
||||
<div className="col text-truncate">
|
||||
<a href="#" className="text-body d-block">{notification.title}</a>
|
||||
<div className="d-block text-muted text-truncate mt-n1">
|
||||
{notification.message}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="nav-item dropdown ms-3">
|
||||
<a href="#" className="nav-link d-flex lh-1 text-reset p-0" data-bs-toggle="dropdown">
|
||||
<span className="avatar avatar-sm" style={{backgroundImage: 'url(./static/avatars/000m.jpg)'}}></span>
|
||||
<span className="d-none d-xl-block ps-2">
|
||||
<span>Admin User</span>
|
||||
<IconChevronDown className="icon" />
|
||||
</span>
|
||||
</a>
|
||||
<div className="dropdown-menu dropdown-menu-end dropdown-menu-arrow">
|
||||
<a href="#" className="dropdown-item">
|
||||
<IconUser className="icon me-2" />
|
||||
Профиль
|
||||
</a>
|
||||
<a href="#" className="dropdown-item">
|
||||
<IconSettings className="icon me-2" />
|
||||
Настройки
|
||||
</a>
|
||||
<div className="dropdown-divider"></div>
|
||||
<a href="#" className="dropdown-item">
|
||||
Выйти
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
<main className="page-wrapper">
|
||||
<div className="container-xl mt-4">
|
||||
{renderContent()}
|
||||
<div className="container-xl mt-4">
|
||||
<div className="row">
|
||||
<div className="col-2">
|
||||
<nav className="nav flex-column nav-pills">
|
||||
{navItems.slice(0, 3).map(item => (
|
||||
<Link
|
||||
key={item.id}
|
||||
to={item.path}
|
||||
className={`nav-link${activeTab === item.id ? ' active' : ''}`}
|
||||
style={{display: 'flex', alignItems: 'center'}}>
|
||||
<item.icon className="me-2" />
|
||||
{item.title}
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
<div className="col-10">
|
||||
<Routes>
|
||||
<Route path="/domains" element={
|
||||
<DataManager
|
||||
entityName="домен"
|
||||
entityKey="domains"
|
||||
placeholder="example.com"
|
||||
/>
|
||||
} />
|
||||
<Route path="/asns" element={
|
||||
<DataManager
|
||||
entityName="AS"
|
||||
entityKey="asns"
|
||||
placeholder="AS12345"
|
||||
/>
|
||||
} />
|
||||
<Route path="/servers" element={<ServerManager />} />
|
||||
<Route path="/" element={<Navigate to="/domains" replace />} />
|
||||
{/* Можно добавить другие разделы по необходимости */}
|
||||
</Routes>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user