gui version
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import { Box, Container, Grid, Typography, IconButton, Link, Stack, useTheme } from '@mui/material';
|
||||
import { GitHub, YouTube, Telegram, Article } from '@mui/icons-material';
|
||||
|
||||
export default function Footer() {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Box
|
||||
component="footer"
|
||||
sx={{
|
||||
py: 3,
|
||||
px: 2,
|
||||
mt: 'auto', // Ключевой стиль для прижатия к низу
|
||||
backgroundColor: (theme) =>
|
||||
theme.palette.mode === 'light'
|
||||
? theme.palette.grey[200]
|
||||
: theme.palette.grey[900],
|
||||
}}
|
||||
>
|
||||
<Container maxWidth={false}>
|
||||
<Grid container spacing={4} justifyContent="space-between" alignItems="center">
|
||||
|
||||
{/* Логотип и копирайт */}
|
||||
<Grid size={{ xs: 12, sm: 4 }}>
|
||||
<Stack direction="row" alignItems="center" spacing={1}>
|
||||
<img src="/img/logo.png" alt="Logo" width={32} height={32} style={{ marginRight: 14 }} />
|
||||
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
{/* Ссылка на документацию */}
|
||||
<Grid size={{ xs: 12, sm: 4 }} sx={{ textAlign: { xs: 'left', sm: 'center' } }}>
|
||||
<Link
|
||||
href="https://3dp-manager.com/docs/intro" // Ссылка на ваш репо или доку
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
color="text.primary"
|
||||
underline="hover"
|
||||
sx={{ display: 'inline-flex', alignItems: 'center', gap: 1, fontWeight: 500 }}
|
||||
>
|
||||
Документация
|
||||
</Link>
|
||||
</Grid>
|
||||
|
||||
{/* Социальные иконки */}
|
||||
<Grid size={{ xs: 12, sm: 4 }} sx={{ textAlign: { xs: 'left', sm: 'right' } }}>
|
||||
<Stack direction="row" spacing={1} justifyContent={{ xs: 'flex-start', sm: 'flex-end' }}>
|
||||
|
||||
<IconButton
|
||||
component="a"
|
||||
href="https://github.com/denpiligrim"
|
||||
target="_blank"
|
||||
aria-label="GitHub"
|
||||
color="inherit"
|
||||
>
|
||||
<GitHub />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
component="a"
|
||||
href="https://youtube.com/@denpiligrim"
|
||||
target="_blank"
|
||||
aria-label="YouTube"
|
||||
color="inherit"
|
||||
>
|
||||
<YouTube />
|
||||
</IconButton>
|
||||
|
||||
<IconButton
|
||||
component="a"
|
||||
href="https://t.me/denpiligrim_web"
|
||||
target="_blank"
|
||||
aria-label="Telegram"
|
||||
color="inherit"
|
||||
>
|
||||
<Telegram />
|
||||
</IconButton>
|
||||
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
AppBar, Toolbar, Typography, IconButton, Tooltip, Box,
|
||||
Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Button, List, ListItem, ListItemText
|
||||
} from '@mui/material';
|
||||
import {
|
||||
Brightness7, Brightness4, BrightnessAuto,
|
||||
Logout, HelpOutline
|
||||
} from '@mui/icons-material';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useThemeContext } from '../ThemeContext';
|
||||
import { useAuth } from '../auth/AuthContext';
|
||||
|
||||
export default function Header() {
|
||||
const { mode, toggleColorMode } = useThemeContext();
|
||||
const { logout } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
// Состояние для модального окна справки
|
||||
const [helpOpen, setHelpOpen] = useState(false);
|
||||
|
||||
// Логика выхода
|
||||
const handleLogout = () => {
|
||||
if (confirm('Вы действительно хотите выйти?')) {
|
||||
logout();
|
||||
navigate('/login');
|
||||
}
|
||||
};
|
||||
|
||||
const getThemeIcon = () => {
|
||||
switch (mode) {
|
||||
case 'light': return <Brightness7 />;
|
||||
case 'dark': return <Brightness4 />;
|
||||
case 'system': return <BrightnessAuto />;
|
||||
}
|
||||
};
|
||||
|
||||
const getThemeLabel = () => {
|
||||
switch (mode) {
|
||||
case 'light': return 'Светлая тема';
|
||||
case 'dark': return 'Темная тема';
|
||||
case 'system': return 'Системная тема';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppBar
|
||||
position="fixed"
|
||||
sx={{ zIndex: (theme) => theme.zIndex.drawer + 1 }}
|
||||
>
|
||||
<Toolbar>
|
||||
<img src="/img/logo.png" alt="Logo" width={32} height={32} style={{ marginRight: 14 }} />
|
||||
<Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1, fontWeight: 'bold', color: '#1395de' }}>
|
||||
3DP-MANAGER
|
||||
</Typography>
|
||||
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
|
||||
{/* Кнопка Справки */}
|
||||
<Tooltip title="Справка о программе">
|
||||
<IconButton color="inherit" onClick={() => setHelpOpen(true)}>
|
||||
<HelpOutline />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{/* Кнопка Темы */}
|
||||
<Tooltip title={`Режим: ${getThemeLabel()}`}>
|
||||
<IconButton color="inherit" onClick={toggleColorMode}>
|
||||
{getThemeIcon()}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
{/* Кнопка Выхода */}
|
||||
<Tooltip title="Выйти из системы">
|
||||
<IconButton color="inherit" onClick={handleLogout}>
|
||||
<Logout />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
</Box>
|
||||
</Toolbar>
|
||||
</AppBar>
|
||||
|
||||
{/* Модальное окно справки */}
|
||||
<Dialog
|
||||
open={helpOpen}
|
||||
onClose={() => setHelpOpen(false)}
|
||||
maxWidth="sm"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle>Об утилите 3DP-MANAGER</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<DialogContentText paragraph>
|
||||
Утилита для автогенерации инбаундов к панели 3x-ui, формирования единой подписки и настройки перенаправления трафика с промежуточного сервера на основной.
|
||||
</DialogContentText>
|
||||
|
||||
<Typography variant="subtitle1" gutterBottom sx={{ fontWeight: 'bold' }}>
|
||||
Основные возможности:
|
||||
</Typography>
|
||||
|
||||
<List dense>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="Автоматическая генерация"
|
||||
secondary="Система создает новые инбаунды в заданном интервале."
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="Управление подписками"
|
||||
secondary="Создание пользователей с уникальными UUID. Одна подписка генерирует множество подключений."
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="Белый список доменов"
|
||||
secondary="Для работы инбаундов необходим список доменов, под которые маскируется трафик."
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemText
|
||||
primary="Перенаправление"
|
||||
secondary="Если вы используете Каскадную схему подключения, то вы сможете добавить свои промежуточные сервера."
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mt: 2 }}>
|
||||
Версия: 2.0.0<br />
|
||||
Разработчик: DenPiligrim
|
||||
</Typography>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setHelpOpen(false)}>Понятно</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Toolbar, Drawer, List, ListItem,
|
||||
ListItemButton, ListItemIcon, ListItemText, Box
|
||||
} from '@mui/material';
|
||||
import { People, Settings, Dns, SwapHoriz } from '@mui/icons-material';
|
||||
import { useNavigate, useLocation, Outlet } from 'react-router-dom';
|
||||
|
||||
import Header from './Header'; // <--- Новый компонент
|
||||
import Footer from './Footer';
|
||||
|
||||
const drawerWidth = 240;
|
||||
|
||||
export default function Layout() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const menuItems = [
|
||||
{ text: 'Подписки', icon: <People />, path: '/' },
|
||||
{ text: 'Домены', icon: <Dns />, path: '/domains' },
|
||||
{ text: 'Перенаправление', icon: <SwapHoriz />, path: '/tunnels' },
|
||||
{ text: 'Настройки', icon: <Settings />, path: '/settings' },
|
||||
];
|
||||
|
||||
return (
|
||||
<Box sx={{ display: 'flex', minHeight: '100vh', width: '100%' }}>
|
||||
|
||||
{/* Шапка */}
|
||||
<Header />
|
||||
|
||||
{/* Боковое меню */}
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
[`& .MuiDrawer-paper`]: { width: drawerWidth, boxSizing: 'border-box' },
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
<Box sx={{ overflow: 'auto' }}>
|
||||
<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>
|
||||
</Box>
|
||||
</Drawer>
|
||||
|
||||
{/* Основной контейнер контента */}
|
||||
<Box
|
||||
component="main"
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: '100vh',
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<Toolbar />
|
||||
|
||||
{/* Контент страницы */}
|
||||
<Box sx={{ flexGrow: 1, p: 3 }}>
|
||||
<Outlet />
|
||||
</Box>
|
||||
|
||||
{/* Футер */}
|
||||
<Footer />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user