Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m18s
CI/CD Pipeline / Security Scanning (push) Successful in 2m53s
CI/CD Pipeline / Lint and Format (push) Failing after 49s
CI/CD Pipeline / Terraform Validation (push) Failing after 24s
CI/CD Pipeline / Kubernetes Validation (push) Successful in 26s
Deploy ChainID 138 / Deploy ChainID 138 (push) Failing after 42s
HYBX OMNL TypeScript & anchor / token-aggregation build + reconcile artifact (push) Failing after 39s
Validation / validate-genesis (push) Successful in 33s
Validation / validate-terraform (push) Failing after 28s
Validation / validate-kubernetes (push) Failing after 12s
Validation / validate-smart-contracts (push) Failing after 13s
Validation / validate-security (push) Failing after 1m21s
Validation / validate-documentation (push) Failing after 22s
Verify Deployment / Verify Deployment (push) Failing after 1m0s
104 lines
4.2 KiB
TypeScript
104 lines
4.2 KiB
TypeScript
import { Outlet, Link, useLocation } from 'react-router-dom';
|
|
import { useState } from 'react';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
import { LogOut, Key, Network, Factory, BarChart3, Menu } from 'lucide-react';
|
|
import toast from 'react-hot-toast';
|
|
|
|
export default function Layout() {
|
|
const { user, logout } = useAuthStore();
|
|
const location = useLocation();
|
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
|
|
const handleLogout = () => {
|
|
logout();
|
|
toast.success('Logged out successfully');
|
|
};
|
|
|
|
const navigation = [
|
|
{ name: 'Dashboard', href: '/', icon: BarChart3 },
|
|
{ name: 'API Keys', href: '/api-keys', icon: Key },
|
|
{ name: 'Endpoints', href: '/endpoints', icon: Network },
|
|
{ name: 'DEX Factories', href: '/dex-factories', icon: Factory },
|
|
];
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50">
|
|
<nav className="bg-white shadow-sm border-b border-gray-200 sticky top-0 z-40">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex justify-between h-14 sm:h-16">
|
|
<div className="flex items-center gap-2 min-w-0 flex-1">
|
|
<button
|
|
type="button"
|
|
className="sm:hidden p-2 rounded-md text-gray-600 hover:bg-gray-100 min-h-[44px] min-w-[44px] flex items-center justify-center"
|
|
aria-label="Open menu"
|
|
aria-expanded={menuOpen}
|
|
onClick={() => setMenuOpen(!menuOpen)}
|
|
>
|
|
<Menu className="h-6 w-6" />
|
|
</button>
|
|
<h1 className="text-base sm:text-xl font-bold text-gray-900 truncate">
|
|
Token Aggregation
|
|
</h1>
|
|
<div className="hidden sm:ml-6 sm:flex sm:space-x-6">
|
|
{navigation.map((item) => {
|
|
const Icon = item.icon;
|
|
const isActive = location.pathname === item.href;
|
|
return (
|
|
<Link
|
|
key={item.name}
|
|
to={item.href}
|
|
className={`inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium min-h-[44px] ${
|
|
isActive
|
|
? 'border-primary-500 text-gray-900'
|
|
: 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700'
|
|
}`}
|
|
>
|
|
<Icon className="mr-2 h-4 w-4 shrink-0" />
|
|
{item.name}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
<div className="flex items-center gap-2 sm:gap-4 shrink-0">
|
|
<span className="text-xs sm:text-sm text-gray-700 truncate max-w-[6rem] sm:max-w-none">{user?.username}</span>
|
|
<button
|
|
onClick={handleLogout}
|
|
className="inline-flex items-center px-2 sm:px-3 py-2 border border-transparent text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 min-h-[44px]"
|
|
>
|
|
<LogOut className="h-4 w-4 sm:mr-2" />
|
|
<span className="hidden sm:inline">Logout</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
{menuOpen && (
|
|
<div className="sm:hidden border-t border-gray-200 py-2 pb-3">
|
|
{navigation.map((item) => {
|
|
const Icon = item.icon;
|
|
const isActive = location.pathname === item.href;
|
|
return (
|
|
<Link
|
|
key={item.name}
|
|
to={item.href}
|
|
onClick={() => setMenuOpen(false)}
|
|
className={`flex items-center px-3 py-3 text-sm font-medium rounded-md min-h-[44px] ${
|
|
isActive ? 'bg-primary-50 text-primary-700' : 'text-gray-600 hover:bg-gray-50'
|
|
}`}
|
|
>
|
|
<Icon className="mr-3 h-5 w-5" />
|
|
{item.name}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</nav>
|
|
|
|
<main className="max-w-7xl mx-auto py-4 sm:py-6 px-4 sm:px-6 lg:px-8 w-full min-w-0">
|
|
<Outlet />
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|