Skip to main content
Glama
AdminLayout.tsx6.15 kB
import React, { useState } from 'react'; import { NavLink, useNavigate } from 'react-router-dom'; import { useAuth } from '@/context/AuthContext'; import { LayoutDashboard, Settings, Users, Menu, X, LogOut, Shield } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { getInitials } from '@/lib/utils'; interface AdminLayoutProps { children: React.ReactNode; } const AdminLayout: React.FC<AdminLayoutProps> = ({ children }) => { const { user, logout } = useAuth(); const navigate = useNavigate(); const [isOpen, setIsOpen] = useState(false); const handleLogout = () => { logout(); navigate('/login'); }; const navItems = [ { name: 'Dashboard', path: '/admin/dashboard', icon: <LayoutDashboard className="w-5 h-5" /> }, { name: 'Tenants', path: '/admin/tenants', icon: <Users className="w-5 h-5" /> }, { name: 'Settings', path: '/admin/settings', icon: <Settings className="w-5 h-5" /> }, ]; return ( <div className="flex h-screen bg-gray-50"> {/* Sidebar - desktop */} <aside className="hidden md:flex flex-col w-64 bg-gray-900 text-white"> <div className="p-6"> <div className="flex items-center space-x-2"> <div className="bg-primary text-white p-2 rounded-md"> <Shield className="h-6 w-6" /> </div> <span className="text-xl font-bold">MCP Admin</span> </div> </div> <nav className="flex-1 px-4 py-2 space-y-1"> {navItems.map((item) => ( <NavLink key={item.path} to={item.path} className={({ isActive }) => `flex items-center px-4 py-3 text-sm rounded-md transition-colors ${ isActive ? "bg-primary text-white font-medium" : "text-gray-300 hover:bg-gray-800" }` } > {item.icon} <span className="ml-3">{item.name}</span> </NavLink> ))} </nav> <div className="p-4 border-t border-gray-800"> <div className="flex items-center space-x-3"> <Avatar> <AvatarImage src={user?.avatar} alt={user?.name} /> <AvatarFallback className="bg-primary/20">{user ? getInitials(user.name) : 'A'}</AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-medium text-white truncate">{user?.name}</p> <p className="text-xs text-gray-400 truncate">{user?.email}</p> </div> <button onClick={handleLogout} className="text-gray-400 hover:text-white" aria-label="Logout" > <LogOut className="w-5 h-5" /> </button> </div> </div> </aside> {/* Mobile header */} <div className="md:hidden fixed top-0 left-0 right-0 bg-gray-900 text-white z-10"> <div className="flex items-center justify-between px-4 py-3"> <div className="flex items-center space-x-2"> <div className="bg-primary text-white p-1.5 rounded-md"> <Shield className="h-5 w-5" /> </div> <span className="text-lg font-bold">MCP Admin</span> </div> <button onClick={() => setIsOpen(!isOpen)} className="text-gray-400 hover:text-white focus:outline-none" > {isOpen ? <X className="h-6 w-6" /> : <Menu className="h-6 w-6" />} </button> </div> </div> {/* Mobile sidebar */} {isOpen && ( <div className="md:hidden fixed inset-0 z-20 bg-gray-800 bg-opacity-50"> <div className="absolute top-0 right-0 bottom-0 w-64 bg-gray-900"> <div className="flex justify-end p-4"> <button onClick={() => setIsOpen(false)} className="text-gray-400 hover:text-white focus:outline-none" > <X className="h-6 w-6" /> </button> </div> <nav className="px-4 py-2 space-y-1"> {navItems.map((item) => ( <NavLink key={item.path} to={item.path} className={({ isActive }) => `flex items-center px-4 py-3 text-sm rounded-md transition-colors ${ isActive ? "bg-primary text-white font-medium" : "text-gray-300 hover:bg-gray-800" }` } onClick={() => setIsOpen(false)} > {item.icon} <span className="ml-3">{item.name}</span> </NavLink> ))} </nav> <div className="absolute bottom-0 left-0 right-0 p-4 border-t border-gray-800"> <div className="flex items-center space-x-3"> <Avatar> <AvatarImage src={user?.avatar} alt={user?.name} /> <AvatarFallback className="bg-primary/20">{user ? getInitials(user.name) : 'A'}</AvatarFallback> </Avatar> <div className="flex-1 min-w-0"> <p className="text-sm font-medium text-white truncate">{user?.name}</p> <p className="text-xs text-gray-400 truncate">{user?.email}</p> </div> <button onClick={handleLogout} className="text-gray-400 hover:text-white" aria-label="Logout" > <LogOut className="w-5 h-5" /> </button> </div> </div> </div> </div> )} {/* Main content */} <main className="flex-1 overflow-auto"> <div className="pt-16 md:pt-0 px-4 md:px-8 py-6 max-w-7xl mx-auto"> {children} </div> </main> </div> ); }; export default AdminLayout;

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/ChiragPatankar/MCP'

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