Files
popa-launcher/src/renderer/components/TopBar.tsx

465 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}