Files
madbase/control-plane-ui/src/components/Layout.tsx
Vlad Durnea a66d908eff
Some checks failed
CI / podman-build (push) Has been cancelled
CI / rust (push) Has been cancelled
chore: full stack stability and migration fixes, plus react UI progress
2026-03-18 09:01:38 +02:00

165 lines
4.5 KiB
TypeScript

import React, { useState } from 'react'
import {
AppBar,
Box,
Toolbar,
Typography,
Drawer,
List,
ListItem,
ListItemIcon,
ListItemText,
ListItemButton,
IconButton,
Divider,
Chip,
} from '@mui/material'
import {
Menu as MenuIcon,
Dashboard as DashboardIcon,
Dns as ServerIcon,
Description as TemplateIcon,
Cloud as ProviderIcon,
TrendingUp as ScalingIcon,
Favorite as HealthIcon,
Settings as SettingsIcon,
People as UsersIcon,
Folder as StorageIcon,
TableChart as DatabaseIcon,
Functions as FunctionsIcon,
Bolt as RealtimeIcon,
Article as LogsIcon,
} from '@mui/icons-material'
import { useNavigate, useLocation } from 'react-router-dom'
const drawerWidth = 240
const menuItems = [
{ text: 'Dashboard', icon: <DashboardIcon />, path: '/' },
{ text: 'Users', icon: <UsersIcon />, path: '/auth' },
{ text: 'Storage', icon: <StorageIcon />, path: '/storage' },
{ text: 'Database', icon: <DatabaseIcon />, path: '/database' },
{ text: 'Functions', icon: <FunctionsIcon />, path: '/functions' },
{ text: 'Realtime', icon: <RealtimeIcon />, path: '/realtime' },
{ text: 'Logs', icon: <LogsIcon />, path: '/logs' },
{ text: 'Servers', icon: <ServerIcon />, path: '/servers' },
{ text: 'Templates', icon: <TemplateIcon />, path: '/templates' },
{ text: 'Providers', icon: <ProviderIcon />, path: '/providers' },
{ text: 'Scaling', icon: <ScalingIcon />, path: '/scaling' },
{ text: 'Cluster Health', icon: <HealthIcon />, path: '/cluster' },
{ text: 'Settings', icon: <SettingsIcon />, path: '/settings' },
]
interface LayoutProps {
children: React.ReactNode
}
export default function Layout({ children }: LayoutProps) {
const [mobileOpen, setMobileOpen] = useState(false)
const navigate = useNavigate()
const location = useLocation()
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen)
}
const drawer = (
<div>
<Toolbar>
<Typography variant="h6" noWrap component="div" sx={{ fontWeight: 'bold' }}>
MadBase
</Typography>
<Chip label="Control Plane" size="small" sx={{ ml: 1 }} />
</Toolbar>
<Divider />
<List>
{menuItems.map((item) => (
<ListItem key={item.text} disablePadding>
<ListItemButton
selected={location.pathname === item.path}
onClick={() => navigate(item.path)}
>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<Box sx={{ p: 2 }}>
<Typography variant="caption" color="text.secondary">
v0.1.0
</Typography>
</Box>
</div>
)
return (
<Box sx={{ display: 'flex' }}>
<AppBar
position="fixed"
sx={{
width: { sm: `calc(100% - ${drawerWidth}px)` },
ml: { sm: `${drawerWidth}px` },
}}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
sx={{ mr: 2, display: { sm: 'none' } }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
{menuItems.find((item) => item.path === location.pathname)?.text || 'MadBase Control Plane'}
</Typography>
<Chip label="API Online" color="success" size="small" variant="outlined" />
</Toolbar>
</AppBar>
<Box
component="nav"
sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}
>
<Drawer
variant="temporary"
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{
keepMounted: true,
}}
sx={{
display: { xs: 'block', sm: 'none' },
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
}}
>
{drawer}
</Drawer>
<Drawer
variant="permanent"
sx={{
display: { xs: 'none', sm: 'block' },
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: drawerWidth },
}}
open
>
{drawer}
</Drawer>
</Box>
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: { sm: `calc(100% - ${drawerWidth}px)` },
}}
>
<Toolbar />
{children}
</Box>
</Box>
)
}