Skip to main content
Glama
Layout.tsx6.52 kB
import type { ReactNode } from 'react'; import { useState } from 'react'; import { Link, useLocation, useNavigate } from 'react-router-dom'; import { LayoutDashboard, Key, Terminal, Users, Cpu, Settings as SettingsIcon, Menu, X, BarChart3, Bell, Database, Zap, MessageSquare, SquareTerminal, MessagesSquare, LogOut, User, Wrench, Server, Network } from 'lucide-react'; interface LayoutProps { children: ReactNode; onLogout?: () => void; user?: any; authEnabled?: boolean; } const navigation = [ { name: 'Dashboard', href: '/', icon: LayoutDashboard }, { name: 'AI Chat', href: '/chat', icon: MessagesSquare }, { name: 'Analytics', href: '/analytics', icon: BarChart3 }, { name: 'Gateway Tokens', href: '/tokens', icon: Key }, { name: 'Docker Logs', href: '/logs', icon: Terminal }, { name: 'Providers', href: '/providers', icon: Users }, { name: 'Models', href: '/models', icon: Cpu }, { name: 'Database', href: '/database', icon: Database }, { name: 'Redis', href: '/redis', icon: Database }, { name: 'OpenRouter Info', href: '/openrouter', icon: Zap }, { name: 'GPT Plus', href: '/gpt-plus', icon: MessageSquare }, { name: 'Web Terminal', href: '/terminal', icon: SquareTerminal }, { name: 'MCP Tools', href: '/mcp-tools', icon: Wrench }, { name: 'MikroTik', href: '/mikrotik', icon: Network }, { name: 'Backends', href: '/backends', icon: Server }, { name: 'Alerts', href: '/alerts', icon: Bell }, { name: 'Settings', href: '/settings', icon: SettingsIcon }, ]; export default function Layout({ children, onLogout, user, authEnabled }: LayoutProps) { const location = useLocation(); const navigate = useNavigate(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const handleLogout = () => { if (onLogout) { onLogout(); } navigate('/login'); }; return ( <div className="min-h-screen bg-slate-900"> {/* Mobile menu */} <div className={`fixed inset-0 z-50 lg:hidden ${mobileMenuOpen ? '' : 'hidden'}`}> <div className="fixed inset-0 bg-black/50" onClick={() => setMobileMenuOpen(false)}></div> <div className="fixed left-0 top-0 bottom-0 w-64 bg-slate-800 shadow-xl"> <div className="flex items-center justify-between p-4 border-b border-slate-700"> <h2 className="text-lg font-semibold text-white">AI MCP Gateway</h2> <button onClick={() => setMobileMenuOpen(false)} className="text-slate-400 hover:text-white"> <X className="w-6 h-6" /> </button> </div> <nav className="p-4"> <ul className="space-y-2"> {navigation.map((item) => { const Icon = item.icon; const isActive = location.pathname === item.href; return ( <li key={item.name}> <Link to={item.href} onClick={() => setMobileMenuOpen(false)} className={`flex items-center gap-3 px-3 py-2 rounded-lg transition-colors ${ isActive ? 'bg-blue-600 text-white' : 'text-slate-300 hover:bg-slate-700 hover:text-white' }`} > <Icon className="w-5 h-5" /> {item.name} </Link> </li> ); })} </ul> </nav> </div> </div> {/* Desktop sidebar */} <div className="hidden lg:fixed lg:inset-y-0 lg:left-0 lg:w-64 lg:block"> <div className="flex flex-col h-full bg-slate-800 shadow-xl"> <div className="flex items-center p-6 border-b border-slate-700"> <h1 className="text-xl font-bold text-white">AI MCP Gateway</h1> </div> <nav className="flex-1 p-4 overflow-y-auto"> <ul className="space-y-2"> {navigation.map((item) => { const Icon = item.icon; const isActive = location.pathname === item.href; return ( <li key={item.name}> <Link to={item.href} className={`flex items-center gap-3 px-3 py-2 rounded-lg transition-colors ${ isActive ? 'bg-blue-600 text-white' : 'text-slate-300 hover:bg-slate-700 hover:text-white' }`} > <Icon className="w-5 h-5" /> {item.name} </Link> </li> ); })} </ul> </nav> {/* User info & Logout (only show when auth is enabled) */} {authEnabled && user && ( <div className="p-4 border-t border-slate-700"> <div className="flex items-center gap-3 mb-3 px-3"> <div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center"> <User className="w-4 h-4 text-white" /> </div> <div className="flex-1 min-w-0"> <p className="text-sm font-medium text-white truncate"> {user.display_name || user.username} </p> <p className="text-xs text-slate-400 truncate">{user.role}</p> </div> </div> <button onClick={handleLogout} className="w-full flex items-center gap-3 px-3 py-2 rounded-lg text-slate-300 hover:bg-red-600/20 hover:text-red-400 transition-colors" > <LogOut className="w-5 h-5" /> Sign Out </button> </div> )} </div> </div> {/* Main content */} <div className="lg:pl-64"> {/* Mobile header */} <div className="sticky top-0 z-40 lg:hidden"> <div className="flex items-center justify-between p-4 bg-slate-800 border-b border-slate-700"> <h1 className="text-lg font-semibold text-white">AI MCP Gateway</h1> <button onClick={() => setMobileMenuOpen(true)} className="text-slate-400 hover:text-white"> <Menu className="w-6 h-6" /> </button> </div> </div> <main className="p-6"> {children} </main> </div> </div> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/babasida246/ai-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server