Files
creator-hub/web/src/layout.jsx
T
2026-08-27 22:34:36 +08:00

75 lines
4.2 KiB
React

import { useState } from 'react'
import { NavLink } from 'react-router-dom'
import {
AppBar,
Box,
Drawer,
IconButton,
ListItemButton,
ListItemIcon,
ListItemText,
Toolbar,
Typography,
useMediaQuery,
} from '@mui/material'
import ChevronLeft from '@mui/icons-material/ChevronLeft'
import ChevronRight from '@mui/icons-material/ChevronRight'
import DnsOutlined from '@mui/icons-material/DnsOutlined'
import HistoryOutlined from '@mui/icons-material/HistoryOutlined'
import MenuIcon from '@mui/icons-material/Menu'
import WidgetsOutlined from '@mui/icons-material/WidgetsOutlined'
import { useTheme } from '@mui/material/styles'
const expandedWidth = 240
const collapsedWidth = 76
export function CreatorHubMenu({ collapsed, onNavigate }) {
return (
<>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.4, height: 70, px: collapsed ? 2.5 : 2.75 }}>
<WidgetsOutlined sx={{ color: '#1680ff', fontSize: 30 }} />
{collapsed ? null : <Typography variant="h6" sx={{ color: '#fff', fontWeight: 760 }}>CreatorHub</Typography>}
</Box>
<Box component="nav" aria-label="主导航" sx={{ px: 1.5, pt: 4 }}>
<ListItemButton component={NavLink} to="/browsers" aria-label="运行环境" onClick={onNavigate} sx={{ minHeight: 52, mb: 1.25, borderRadius: 1, color: '#a9b7cc', justifyContent: collapsed ? 'center' : 'flex-start', '&.active': { color: '#fff', bgcolor: '#0866ef' }, '&:hover': { bgcolor: '#0b2a54' }, '&.active:hover': { bgcolor: '#0866ef' } }}>
<ListItemIcon sx={{ minWidth: collapsed ? 0 : 42, color: 'inherit' }}><DnsOutlined /></ListItemIcon>
{collapsed ? null : <ListItemText primary="运行环境" />}
</ListItemButton>
<ListItemButton disabled aria-label="审计记录" sx={{ minHeight: 52, borderRadius: 1, color: '#a9b7cc', justifyContent: collapsed ? 'center' : 'flex-start', '&.Mui-disabled': { opacity: 0.58 } }}>
<ListItemIcon sx={{ minWidth: collapsed ? 0 : 42, color: 'inherit' }}><HistoryOutlined /></ListItemIcon>
{collapsed ? null : <ListItemText primary="审计记录" />}
</ListItemButton>
</Box>
</>
)
}
export function CreatorHubLayout({ children }) {
const theme = useTheme()
const desktop = useMediaQuery(theme.breakpoints.up('md'))
const [collapsed, setCollapsed] = useState(false)
const [mobileOpen, setMobileOpen] = useState(false)
const width = collapsed ? collapsedWidth : expandedWidth
return (
<Box sx={{ display: 'flex', minHeight: '100vh', bgcolor: 'background.default' }}>
<AppBar position="fixed" color="inherit" elevation={0} sx={{ width: desktop ? `calc(100% - ${width}px)` : '100%', ml: desktop ? `${width}px` : 0, borderBottom: '1px solid', borderColor: 'divider', transition: theme.transitions.create(['width', 'margin']) }}>
<Toolbar sx={{ minHeight: '70px !important' }}>
<IconButton aria-label={desktop ? (collapsed ? '展开导航' : '收起导航') : '打开导航'} onClick={() => desktop ? setCollapsed(value => !value) : setMobileOpen(true)} edge="start">
<MenuIcon />
</IconButton>
</Toolbar>
</AppBar>
<Drawer variant={desktop ? 'permanent' : 'temporary'} open={desktop || mobileOpen} onClose={() => setMobileOpen(false)} ModalProps={{ keepMounted: true }} sx={{ width: desktop ? width : expandedWidth, flexShrink: 0, '& .MuiDrawer-paper': { width: desktop ? width : expandedWidth, border: 0, bgcolor: '#061a38', color: '#fff', transition: theme.transitions.create('width'), overflowX: 'hidden' } }}>
<CreatorHubMenu collapsed={desktop && collapsed} onNavigate={() => setMobileOpen(false)} />
{desktop ? <IconButton aria-label={collapsed ? '展开导航' : '收起导航'} onClick={() => setCollapsed(value => !value)} sx={{ position: 'absolute', right: 16, bottom: 24, color: '#a9b7cc', border: '1px solid #35506f' }}>{collapsed ? <ChevronRight /> : <ChevronLeft />}</IconButton> : null}
</Drawer>
<Box component="main" sx={{ width: desktop ? `calc(100% - ${width}px)` : '100%', mt: '70px', px: { xs: 2, sm: 3, lg: 4.5 }, py: { xs: 3, lg: 4.5 }, transition: theme.transitions.create('width') }}>
<Box sx={{ width: '100%', maxWidth: 1280 }}>{children}</Box>
</Box>
</Box>
)
}