Initial commit: StreamFlow IPTV platform
This commit is contained in:
commit
73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions
165
frontend/src/components/Sidebar.jsx
Normal file
165
frontend/src/components/Sidebar.jsx
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
import React from 'react';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
Drawer,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Box,
|
||||
Typography,
|
||||
Avatar
|
||||
} from '@mui/material';
|
||||
import {
|
||||
LiveTv,
|
||||
Movie,
|
||||
Theaters,
|
||||
Favorite,
|
||||
Settings,
|
||||
Radio as RadioIcon,
|
||||
BarChart,
|
||||
Security
|
||||
} from '@mui/icons-material';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAuthStore } from '../store/authStore';
|
||||
import Logo from './Logo';
|
||||
|
||||
const drawerWidth = 200;
|
||||
|
||||
function Sidebar({ open, onClose }) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { user } = useAuthStore();
|
||||
|
||||
const menuItems = [
|
||||
{ text: 'live_tv', icon: <LiveTv fontSize="small" />, path: '/live-tv' },
|
||||
{ text: 'radio', icon: <RadioIcon fontSize="small" />, path: '/radio' },
|
||||
{ text: 'favorite_tv', icon: <Favorite fontSize="small" />, path: '/favorites/tv' },
|
||||
{ text: 'favorite_radio', icon: <Favorite fontSize="small" />, path: '/favorites/radio' },
|
||||
...(user?.role === 'admin' ? [
|
||||
{ text: 'Analytics', icon: <BarChart fontSize="small" />, path: '/stats' },
|
||||
{ text: 'security.title', icon: <Security fontSize="small" />, path: '/security' }
|
||||
] : []),
|
||||
{ text: 'settings.title', icon: <Settings fontSize="small" />, path: '/settings' }
|
||||
];
|
||||
|
||||
const handleNavigate = (path) => {
|
||||
navigate(path);
|
||||
onClose();
|
||||
};
|
||||
|
||||
const drawerContent = (
|
||||
<>
|
||||
<Box sx={{ p: 2, textAlign: 'center' }}>
|
||||
<Logo size={36} />
|
||||
<Typography variant="h6" fontSize="0.95rem" fontWeight="bold" sx={{ mt: 0.5 }}>
|
||||
{t('app_name')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ px: 1.5, mb: 1.5 }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 1,
|
||||
p: 1,
|
||||
borderRadius: 1.5,
|
||||
bgcolor: 'action.hover'
|
||||
}}
|
||||
>
|
||||
<Avatar sx={{ width: 28, height: 28, bgcolor: 'primary.main', fontSize: '0.875rem' }}>
|
||||
{user?.username?.[0]?.toUpperCase()}
|
||||
</Avatar>
|
||||
<Typography variant="body2" fontSize="0.8rem" fontWeight="600" noWrap>
|
||||
{user?.username}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<List sx={{ px: 1.5 }}>
|
||||
{menuItems.map((item) => {
|
||||
const isActive = location.pathname === item.path ||
|
||||
(item.path === '/live-tv' && location.pathname === '/') ||
|
||||
(item.path === '/favorites/tv' && location.pathname === '/favorites');
|
||||
return (
|
||||
<ListItem key={item.text} disablePadding sx={{ mb: 0.5 }}>
|
||||
<ListItemButton
|
||||
selected={isActive}
|
||||
onClick={() => handleNavigate(item.path)}
|
||||
sx={{
|
||||
borderRadius: 1.5,
|
||||
minHeight: 36,
|
||||
py: 0.75,
|
||||
'&.Mui-selected': {
|
||||
bgcolor: 'primary.main',
|
||||
color: 'white',
|
||||
'&:hover': {
|
||||
bgcolor: 'primary.dark'
|
||||
},
|
||||
'& .MuiListItemIcon-root': {
|
||||
color: 'white'
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemIcon sx={{ minWidth: 32, color: isActive ? 'white' : 'inherit' }}>
|
||||
{item.icon}
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={t(item.text)}
|
||||
primaryTypographyProps={{ fontSize: '0.8125rem' }}
|
||||
/>
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
);
|
||||
})}
|
||||
</List>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Mobile drawer - temporary */}
|
||||
<Drawer
|
||||
variant="temporary"
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
sx={{
|
||||
display: { xs: 'block', md: 'none' },
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: drawerWidth,
|
||||
boxSizing: 'border-box',
|
||||
borderRight: 'none'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{drawerContent}
|
||||
</Drawer>
|
||||
|
||||
{/* Desktop drawer - permanent, always visible */}
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
display: { xs: 'none', md: 'block' },
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: drawerWidth,
|
||||
boxSizing: 'border-box',
|
||||
borderRight: 'none',
|
||||
position: 'relative'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{drawerContent}
|
||||
</Drawer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Sidebar;
|
||||
Loading…
Add table
Add a link
Reference in a new issue