mnoga che sdelal

This commit is contained in:
aurinex
2025-12-13 22:17:17 +05:00
parent abb45c3838
commit ca8ac8e880
9 changed files with 302 additions and 190 deletions

View File

@ -1,4 +1,4 @@
import { Box, Button, Tab, Tabs, Typography } from '@mui/material';
import { Box, Button, Tab, Tabs, Typography, Menu, MenuItem, Divider } from '@mui/material';
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
import { useLocation, useNavigate } from 'react-router-dom';
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
@ -7,6 +7,11 @@ import { Tooltip } from '@mui/material';
import { fetchCoins } from '../api';
import CustomTooltip from './Notifications/CustomTooltip';
import CoinsDisplay from './CoinsDisplay';
import { HeadAvatar } from './HeadAvatar';
import { fetchPlayer } from './../api'
import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
import EmojiEventsIcon from '@mui/icons-material/EmojiEvents';
import PersonIcon from '@mui/icons-material/Person';
declare global {
interface Window {
electron: {
@ -29,14 +34,38 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
// Получаем текущий путь
const location = useLocation();
const isLoginPage = location.pathname === '/login';
const [isAuthed, setIsAuthed] = useState(false);
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 [skinUrl, setSkinUrl] = useState<string>('');
const [avatarAnchorEl, setAvatarAnchorEl] =
useState<null | HTMLElement>(null);
const [menuOpen, setMenuOpen] = useState<boolean>(false);
useEffect(() => {
const saved = localStorage.getItem('launcher_config');
try {
const cfg = saved ? JSON.parse(saved) : null;
setIsAuthed(Boolean(cfg?.accessToken)); // или cfg?.uuid/username — как у тебя принято
} catch {
setIsAuthed(false);
}
}, [location.pathname]); // можно и без dependency, но так надёжнее при logout/login
const avatarMenuOpen = Boolean(avatarAnchorEl);
const handleAvatarClick = (event: React.MouseEvent<HTMLElement>) => {
setAvatarAnchorEl(event.currentTarget);
};
const handleAvatarMenuClose = () => {
setAvatarAnchorEl(null);
};
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
@ -147,6 +176,19 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
navigate('/login');
};
useEffect(() => {
const savedConfig = localStorage.getItem('launcher_config');
if (!savedConfig) return;
const config = JSON.parse(savedConfig);
const uuid = config.uuid;
if (!uuid) return;
fetchPlayer(uuid)
.then((player) => setSkinUrl(player.skin_url))
.catch((e) => console.error('Не удалось получить скин:', e));
}, []);
return (
<Box
sx={{
@ -197,7 +239,7 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
<ArrowBackRoundedIcon />
</Button>
)}
{!isLaunchPage && !isRegistrationPage && !isLoginPage && (
{isAuthed && !isLaunchPage && (
<Box
ref={tabsWrapperRef}
onWheel={handleTabsWheel}
@ -264,25 +306,6 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
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}
@ -357,32 +380,17 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
}}
>
{!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.01)',
boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)',
},
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
<Box sx={{ display: 'flex', alignItems: 'center', gap: '1vw' }}>
<HeadAvatar
skinUrl={skinUrl}
size={44}
style={{
borderRadius: '3vw',
cursor: 'pointer',
}}
>
Выйти
</Button>
onClick={handleAvatarClick}
/>
</Box>
)}
{/* Кнопка регистрации, если на странице логина */}
{!isLoginPage && !isRegistrationPage && username && (
@ -393,37 +401,6 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
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: 'all 0.3s ease',
'&:hover': {
background:
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
transform: 'scale(1.01)',
boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)',
},
'&:active': {
color: 'transparent',
},
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
userSelect: 'none',
}}
>
<Typography sx={{ fontSize: '1em', color: 'white' }}>Регистрация</Typography>
</Button>
)}
{/* Кнопки управления окном */}
<Button
@ -465,6 +442,165 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
<CloseRoundedIcon sx={{ color: 'white' }} />
</Button>
</Box>
<Menu
anchorEl={avatarAnchorEl}
open={avatarMenuOpen}
onClose={handleAvatarMenuClose}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
PaperProps={{
sx: {
mt: '0.5vw',
borderRadius: '1vw',
minWidth: '16vw',
bgcolor: 'rgba(0,0,0,0.92)',
color: 'white',
boxShadow: '0 0 20px rgba(0,0,0,0.6)',
border: '1px solid rgba(255,77,77,0.35)',
},
}}
>
{/* ===== 1 строка: аватар + ник + валюта ===== */}
<Box
sx={{
display: 'grid',
gridTemplateColumns: 'auto 1fr',
gap: '1.5vw',
alignItems: 'center',
px: '2vw',
py: '0.8vw',
}}
>
<HeadAvatar
skinUrl={skinUrl}
size={40}
style={{ borderRadius: '3vw' }}
/>
<Box sx={{ display: 'flex', flexDirection: 'column' }}>
<Typography
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '2vw',
}}
>
{username || 'Игрок'}
</Typography>
<CoinsDisplay
username={username}
size="medium"
autoUpdate={true}
showTooltip={true}
sx={{
border: 'none',
padding: '0vw',
}}
backgroundColor={'rgba(0, 0, 0, 0)'}
/>
</Box>
</Box>
<Divider sx={{ my: '0.4vw', borderColor: 'rgba(255,255,255,0.08)' }} />
<MenuItem
onClick={() => {
handleAvatarMenuClose();
navigate('/profile');
}}
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1.5vw',
gap: '0.5vw',
py: '0.7vw',
'&:hover': {
bgcolor: 'rgba(255,77,77,0.15)',
},
}}
>
<PersonIcon sx={{ fontSize: '2vw' }}/> Профиль
</MenuItem>
{/* ===== 2 строка: ежедневные задания ===== */}
<MenuItem
onClick={() => {
handleAvatarMenuClose();
navigate('/dailyquests');
}}
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1.5vw',
gap: '0.5vw',
py: '0.7vw',
'&:hover': {
bgcolor: 'rgba(255,77,77,0.15)',
},
}}
>
<CalendarMonthIcon sx={{ fontSize: '2vw' }} /> Ежедневные задания
</MenuItem>
{/* ===== 3 строка: ежедневная награда ===== */}
<MenuItem
onClick={() => {
handleAvatarMenuClose();
navigate('/daily');
}}
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1.5vw',
gap: '0.5vw',
py: '0.7vw',
'&:hover': {
bgcolor: 'rgba(255,77,77,0.15)',
},
}}
>
<EmojiEventsIcon sx={{ fontSize: '2vw' }} /> Ежедневная награда
</MenuItem>
<Divider sx={{ my: '0.4vw', borderColor: 'rgba(255,255,255,0.08)' }} />
{!isLoginPage && !isRegistrationPage && username && (
<Button
variant="outlined"
color="primary"
onClick={() => {
logout();
setMenuOpen(false);
}}
sx={{
width: '8vw',
height: '3vw',
borderRadius: '2.5vw',
fontFamily: 'Benzin-Bold',
fontSize: '1.2vw',
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.01)',
boxShadow: '0 4px 15px rgba(242, 113, 33, 0.4)',
},
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.3)',
m: '0 0 0 18vw'
}}
>
Выйти
</Button>
)}
{/* ↓↓↓ дальше ты сам добавишь пункты ↓↓↓ */}
</Menu>
</Box>
);
}