465 lines
14 KiB
TypeScript
465 lines
14 KiB
TypeScript
import { Box, Button, Tab, Tabs, Typography } from '@mui/material';
|
||
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
|
||
import { useLocation, useNavigate } from 'react-router-dom';
|
||
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
|
||
import { useEffect, useRef, useState } from 'react';
|
||
import { Tooltip } from '@mui/material';
|
||
import { fetchCoins } from '../api';
|
||
import CustomTooltip from './CustomTooltip';
|
||
import CoinsDisplay from './CoinsDisplay';
|
||
declare global {
|
||
interface Window {
|
||
electron: {
|
||
ipcRenderer: {
|
||
invoke(channel: string, ...args: unknown[]): Promise<any>;
|
||
on(channel: string, func: (...args: unknown[]) => void): void;
|
||
removeAllListeners(channel: string): void;
|
||
};
|
||
};
|
||
}
|
||
}
|
||
|
||
// Определяем пропсы
|
||
interface TopBarProps {
|
||
onRegister?: () => void; // Опционально, если нужен обработчик регистрации
|
||
username?: string;
|
||
}
|
||
|
||
export default function TopBar({ onRegister, username }: TopBarProps) {
|
||
// Получаем текущий путь
|
||
const location = useLocation();
|
||
const isLoginPage = location.pathname === '/login';
|
||
const isLaunchPage = location.pathname.startsWith('/launch');
|
||
const isVersionsExplorerPage = location.pathname.startsWith('/');
|
||
const isRegistrationPage = location.pathname === '/registration';
|
||
const navigate = useNavigate();
|
||
const [coins, setCoins] = useState<number>(0);
|
||
const [value, setValue] = useState(1);
|
||
const [activePage, setActivePage] = useState('versions');
|
||
const tabsWrapperRef = useRef<HTMLDivElement | null>(null);
|
||
|
||
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
|
||
setValue(newValue);
|
||
if (newValue === 0) {
|
||
navigate('/news');
|
||
} else if (newValue === 1) {
|
||
navigate('/');
|
||
} else if (newValue === 2) {
|
||
navigate('/profile');
|
||
} else if (newValue === 3) {
|
||
navigate('/shop');
|
||
} else if (newValue === 4) {
|
||
navigate('/marketplace');
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (location.pathname === '/news') {
|
||
setValue(0);
|
||
setActivePage('news');
|
||
} else if (location.pathname === '/') {
|
||
setValue(1);
|
||
setActivePage('versions');
|
||
} else if (location.pathname.startsWith('/profile')) {
|
||
setValue(2);
|
||
setActivePage('profile');
|
||
} else if (location.pathname.startsWith('/shop')) {
|
||
setValue(3);
|
||
setActivePage('shop');
|
||
} else if (location.pathname.startsWith('/marketplace')) {
|
||
setValue(4);
|
||
setActivePage('marketplace');
|
||
}
|
||
}, [location.pathname]);
|
||
|
||
const handleLaunchPage = () => {
|
||
navigate('/');
|
||
};
|
||
|
||
const handleTabsWheel = (event: React.WheelEvent<HTMLDivElement>) => {
|
||
// чтобы страница не скроллилась вертикально
|
||
event.preventDefault();
|
||
|
||
if (!tabsWrapperRef.current) return;
|
||
|
||
// Находим внутренний скроллер MUI Tabs
|
||
const scroller = tabsWrapperRef.current.querySelector(
|
||
'.MuiTabs-scroller',
|
||
) as HTMLDivElement | null;
|
||
|
||
if (!scroller) return;
|
||
|
||
// Прокручиваем горизонтально, используя вертикальный скролл мыши
|
||
scroller.scrollLeft += event.deltaY * 0.3;
|
||
};
|
||
|
||
// const getPageTitle = () => {
|
||
// if (isLoginPage) {
|
||
// return 'Вход';
|
||
// }
|
||
// if (isLaunchPage) {
|
||
// return 'Запуск';
|
||
// }
|
||
// if (isVersionsExplorerPage) {
|
||
// if (activePage === 'versions') {
|
||
// return 'Версии';
|
||
// }
|
||
// if (activePage === 'profile') {
|
||
// return 'Профиль';
|
||
// }
|
||
// if (activePage === 'shop') {
|
||
// return 'Магазин';
|
||
// }
|
||
// if (activePage === 'marketplace') {
|
||
// return 'Рынок';
|
||
// }
|
||
// }
|
||
// return 'Неизвестная страница';
|
||
// };
|
||
|
||
// Функция для получения количества монет
|
||
const fetchCoinsData = async () => {
|
||
if (!username) return;
|
||
|
||
try {
|
||
const coinsData = await fetchCoins(username);
|
||
setCoins(coinsData.coins);
|
||
} catch (error) {
|
||
console.error('Ошибка при получении количества монет:', error);
|
||
}
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (username) {
|
||
fetchCoinsData();
|
||
|
||
// Создаем интервалы для периодического обновления данных
|
||
const coinsInterval = setInterval(fetchCoinsData, 60000);
|
||
|
||
return () => {
|
||
clearInterval(coinsInterval);
|
||
};
|
||
}
|
||
}, [username]);
|
||
|
||
const logout = () => {
|
||
localStorage.removeItem('launcher_config');
|
||
navigate('/login');
|
||
};
|
||
|
||
return (
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
position: 'absolute',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
height: '7vh',
|
||
zIndex: 1000,
|
||
width: '100%',
|
||
WebkitAppRegion: 'drag',
|
||
overflow: 'hidden',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
// marginLeft: '1em',
|
||
// marginRight: '1em',
|
||
}}
|
||
>
|
||
{/* Левая часть */}
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
WebkitAppRegion: 'no-drag',
|
||
gap: '2vw',
|
||
alignItems: 'center',
|
||
marginLeft: '1vw',
|
||
}}
|
||
>
|
||
{(isLaunchPage || isRegistrationPage) && (
|
||
<Button
|
||
variant="outlined"
|
||
onClick={() => handleLaunchPage()}
|
||
sx={{
|
||
width: '3em',
|
||
height: '3em',
|
||
borderRadius: '50%',
|
||
border: 'unset',
|
||
color: 'white',
|
||
minWidth: 'unset',
|
||
minHeight: 'unset',
|
||
transition: 'transform 0.3s ease',
|
||
'&:hover': {
|
||
transform: 'scale(1.2)',
|
||
},
|
||
}}
|
||
>
|
||
<ArrowBackRoundedIcon />
|
||
</Button>
|
||
)}
|
||
{!isLaunchPage && !isRegistrationPage && !isLoginPage && (
|
||
<Box
|
||
ref={tabsWrapperRef}
|
||
onWheel={handleTabsWheel}
|
||
sx={{
|
||
borderBottom: 1,
|
||
borderColor: 'transparent',
|
||
'& .MuiTabs-indicator': {
|
||
backgroundColor: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
}}
|
||
>
|
||
<CustomTooltip
|
||
title={'Покрути колесиком мыши чтобы увидеть больше кнопок'}
|
||
arrow
|
||
placement="bottom"
|
||
TransitionProps={{ timeout: 100 }}
|
||
>
|
||
<Tabs
|
||
value={value}
|
||
onChange={handleChange}
|
||
aria-label="basic tabs example"
|
||
variant="scrollable"
|
||
scrollButtons={false}
|
||
disableRipple={true}
|
||
sx={{ maxWidth: '42vw' }}
|
||
>
|
||
<Tab
|
||
label="Новости"
|
||
disableRipple={true}
|
||
onClick={() => {
|
||
setActivePage('news');
|
||
}}
|
||
sx={{
|
||
color: 'white',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.7em',
|
||
'&.Mui-selected': {
|
||
color: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
'&:hover': {
|
||
color: 'rgb(177, 52, 52)',
|
||
},
|
||
transition: 'all 0.3s ease',
|
||
}}
|
||
/>
|
||
<Tab
|
||
label="Версии"
|
||
disableRipple={true}
|
||
onClick={() => {
|
||
setActivePage('versions');
|
||
}}
|
||
sx={{
|
||
color: 'white',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.7em',
|
||
'&.Mui-selected': {
|
||
color: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
'&:hover': {
|
||
color: 'rgb(177, 52, 52)',
|
||
},
|
||
transition: 'all 0.3s ease',
|
||
}}
|
||
/>
|
||
<Tab
|
||
label="Профиль"
|
||
disableRipple={true}
|
||
onClick={() => {
|
||
setActivePage('profile');
|
||
}}
|
||
sx={{
|
||
color: 'white',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.7em',
|
||
'&.Mui-selected': {
|
||
color: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
'&:hover': {
|
||
color: 'rgb(177, 52, 52)',
|
||
},
|
||
transition: 'all 0.3s ease',
|
||
}}
|
||
/>
|
||
<Tab
|
||
label="Магазин"
|
||
disableRipple={true}
|
||
onClick={() => {
|
||
setActivePage('shop');
|
||
}}
|
||
sx={{
|
||
color: 'white',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.7em',
|
||
'&.Mui-selected': {
|
||
color: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
'&:hover': {
|
||
color: 'rgb(177, 52, 52)',
|
||
},
|
||
transition: 'all 0.3s ease',
|
||
}}
|
||
/>
|
||
<Tab
|
||
label="Рынок"
|
||
disableRipple={true}
|
||
onClick={() => {
|
||
setActivePage('marketplace');
|
||
}}
|
||
sx={{
|
||
color: 'white',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.7em',
|
||
'&.Mui-selected': {
|
||
color: 'rgba(255, 77, 77, 1)',
|
||
},
|
||
'&:hover': {
|
||
color: 'rgb(177, 52, 52)',
|
||
},
|
||
transition: 'all 0.3s ease',
|
||
}}
|
||
/>
|
||
</Tabs>
|
||
</CustomTooltip>
|
||
</Box>
|
||
)}
|
||
</Box>
|
||
{/* Центр */}
|
||
<Box
|
||
sx={{
|
||
position: 'absolute',
|
||
left: '50%',
|
||
transform: 'translateX(-50%)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
flexGrow: 1,
|
||
WebkitAppRegion: 'drag',
|
||
}}
|
||
>
|
||
{/* <Typography
|
||
variant="h6"
|
||
sx={{ color: 'white', fontFamily: 'Benzin-Bold' }}
|
||
>
|
||
{getPageTitle()}
|
||
</Typography> */}
|
||
</Box>
|
||
{/* Правая часть со всеми кнопками */}
|
||
<Box
|
||
sx={{
|
||
display: 'flex',
|
||
WebkitAppRegion: 'no-drag',
|
||
gap: '1vw',
|
||
alignItems: 'center',
|
||
marginRight: '1vw',
|
||
}}
|
||
>
|
||
{!isLoginPage && !isRegistrationPage && username && (
|
||
<Button
|
||
variant="outlined"
|
||
color="primary"
|
||
onClick={() => logout()}
|
||
sx={{
|
||
width: '8em',
|
||
height: '3em',
|
||
borderRadius: '2.5vw',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.9em',
|
||
background:
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
|
||
color: 'white',
|
||
border: 'none',
|
||
transition: 'transform 0.3s ease',
|
||
'&:hover': {
|
||
background:
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
|
||
transform: 'scale(1.05)',
|
||
boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)',
|
||
},
|
||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
|
||
}}
|
||
>
|
||
Выйти
|
||
</Button>
|
||
)}
|
||
{/* Кнопка регистрации, если на странице логина */}
|
||
{!isLoginPage && !isRegistrationPage && username && (
|
||
<CoinsDisplay
|
||
username={username}
|
||
size="medium"
|
||
autoUpdate={true}
|
||
showTooltip={true}
|
||
/>
|
||
)}
|
||
{isLoginPage && (
|
||
<Button
|
||
variant="contained"
|
||
onClick={() => navigate('/registration')}
|
||
sx={{
|
||
width: '13em',
|
||
height: '3em',
|
||
borderRadius: '2.5vw',
|
||
fontFamily: 'Benzin-Bold',
|
||
fontSize: '0.9em',
|
||
background:
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
|
||
color: 'white',
|
||
border: 'none',
|
||
transition: 'transform 0.3s ease',
|
||
'&:hover': {
|
||
background:
|
||
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
|
||
transform: 'scale(1.05)',
|
||
boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)',
|
||
},
|
||
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
|
||
}}
|
||
>
|
||
Регистрация
|
||
</Button>
|
||
)}
|
||
|
||
{/* Кнопки управления окном */}
|
||
<Button
|
||
onClick={() => {
|
||
window.electron.ipcRenderer.invoke('minimize-app');
|
||
}}
|
||
sx={{
|
||
minWidth: 'unset',
|
||
minHeight: 'unset',
|
||
width: '3em',
|
||
height: '3em',
|
||
borderRadius: '50%',
|
||
}}
|
||
>
|
||
<svg
|
||
className="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium"
|
||
focusable="false"
|
||
aria-hidden="true"
|
||
viewBox="0 0 24 24"
|
||
>
|
||
<path
|
||
d="M 7 19 h 10 c 0.55 0 1 0.45 1 1 s -0.45 1 -1 1 H 7 c -0.55 0 -1 -0.45 -1 -1 s 0.45 -1 1 -1"
|
||
fill="white"
|
||
></path>
|
||
</svg>
|
||
</Button>
|
||
<Button
|
||
onClick={() => {
|
||
window.electron.ipcRenderer.invoke('close-app');
|
||
}}
|
||
sx={{
|
||
minWidth: 'unset',
|
||
minHeight: 'unset',
|
||
width: '3em',
|
||
height: '3em',
|
||
borderRadius: '50%',
|
||
}}
|
||
>
|
||
<CloseRoundedIcon sx={{ color: 'white' }} />
|
||
</Button>
|
||
</Box>
|
||
</Box>
|
||
);
|
||
}
|