add gradient to topbar, alert quests, restyle onlineplayerspanel

This commit is contained in:
aurinex
2025-12-14 13:12:01 +05:00
parent 41c1ae3357
commit d1e64382a4
3 changed files with 398 additions and 198 deletions

View File

@ -5,7 +5,6 @@ import {
Typography,
Paper,
Chip,
TextField,
MenuItem,
Select,
FormControl,
@ -20,6 +19,7 @@ import {
import { FullScreenLoader } from './FullScreenLoader';
import { HeadAvatar } from './HeadAvatar';
import { translateServer } from '../utils/serverTranslator';
import GradientTextField from './GradientTextField'; // <-- используем ваш градиентный инпут
type OnlinePlayerFlat = {
username: string;
@ -33,6 +33,9 @@ interface OnlinePlayersPanelProps {
currentUsername: string;
}
const GRADIENT =
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)';
export const OnlinePlayersPanel: React.FC<OnlinePlayersPanelProps> = ({
currentUsername,
}) => {
@ -42,7 +45,6 @@ export const OnlinePlayersPanel: React.FC<OnlinePlayersPanelProps> = ({
const [error, setError] = useState<string | null>(null);
const [serverFilter, setServerFilter] = useState<string>('all');
const [search, setSearch] = useState('');
const [skinMap, setSkinMap] = useState<Record<string, string>>({});
useEffect(() => {
@ -85,64 +87,46 @@ export const OnlinePlayersPanel: React.FC<OnlinePlayersPanelProps> = ({
// Догружаем скины по uuid
useEffect(() => {
const loadSkins = async () => {
// Берём всех видимых игроков (чтобы не грузить для тысяч, если их много)
const uuids = Array.from(new Set(onlinePlayers.map((p) => p.uuid)));
const toLoad = uuids.filter((uuid) => !skinMap[uuid]);
if (!toLoad.length) return;
try {
// Просто по очереди, чтобы не DDOS'ить API
for (const uuid of toLoad) {
try {
const player = await fetchPlayer(uuid);
if (player.skin_url) {
setSkinMap((prev) => ({
...prev,
[uuid]: player.skin_url,
}));
}
} catch (e) {
console.warn('Не удалось получить скин для', uuid, e);
for (const uuid of toLoad) {
try {
const player = await fetchPlayer(uuid);
if (player.skin_url) {
setSkinMap((prev) => ({ ...prev, [uuid]: player.skin_url }));
}
} catch (e) {
console.warn('Не удалось получить скин для', uuid, e);
}
} catch (e) {
console.error('Ошибка при загрузке скинов:', e);
}
};
loadSkins();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [onlinePlayers]);
const filteredPlayers = useMemo(() => {
return (
onlinePlayers
.filter((p) =>
serverFilter === 'all' ? true : p.serverId === serverFilter,
)
.filter((p) =>
search.trim()
? p.username.toLowerCase().includes(search.toLowerCase())
: true,
)
// свой ник наверх
.sort((a, b) => {
if (a.username === currentUsername && b.username !== currentUsername)
return -1;
if (b.username === currentUsername && a.username !== currentUsername)
return 1;
return a.username.localeCompare(b.username);
})
);
return onlinePlayers
.filter((p) => (serverFilter === 'all' ? true : p.serverId === serverFilter))
.filter((p) =>
search.trim()
? p.username.toLowerCase().includes(search.toLowerCase())
: true,
)
.sort((a, b) => {
if (a.username === currentUsername && b.username !== currentUsername) return -1;
if (b.username === currentUsername && a.username !== currentUsername) return 1;
return a.username.localeCompare(b.username);
});
}, [onlinePlayers, serverFilter, search, currentUsername]);
if (loading) {
return <FullScreenLoader message="Загружаем игроков онлайн..." />;
}
if (loading) return <FullScreenLoader message="Загружаем игроков онлайн..." />;
if (error) {
return (
<Typography color="error" sx={{ mt: 2 }}>
<Typography sx={{ mt: 2, color: '#ff8080', fontFamily: 'Benzin-Bold' }}>
{error}
</Typography>
);
@ -150,7 +134,7 @@ export const OnlinePlayersPanel: React.FC<OnlinePlayersPanelProps> = ({
if (!onlinePlayers.length) {
return (
<Typography sx={{ mt: 2, opacity: 0.8 }}>
<Typography sx={{ mt: 2, color: 'rgba(255,255,255,0.75)', fontWeight: 700 }}>
Сейчас на серверах никого нет.
</Typography>
);
@ -160,121 +144,258 @@ export const OnlinePlayersPanel: React.FC<OnlinePlayersPanelProps> = ({
return (
<Paper
elevation={0}
sx={{
mt: 3,
p: 2,
borderRadius: '1vw',
background: 'rgba(255,255,255,0.03)',
border: '1px solid rgba(255,255,255,0.06)',
borderRadius: '1.2vw',
overflow: 'hidden',
background:
'radial-gradient(circle at 10% 10%, rgba(242,113,33,0.16), transparent 55%), radial-gradient(circle at 90% 20%, rgba(233,64,205,0.12), transparent 55%), rgba(10,10,20,0.92)',
border: '1px solid rgba(255,255,255,0.08)',
boxShadow: '0 1.2vw 3.2vw rgba(0,0,0,0.55)',
backdropFilter: 'blur(14px)',
color: 'white',
}}
elevation={0}
>
{/* header */}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
mb: 2,
gap: 2,
px: '1.8vw',
pt: '1.2vw',
pb: '1.1vw',
position: 'sticky',
top: 0,
zIndex: 2,
background:
'radial-gradient(circle at 10% 10%, rgba(242,113,33,0.16), transparent 55%), radial-gradient(circle at 90% 20%, rgba(233,64,205,0.12), transparent 55%), rgba(10,10,20,0.92)',
backdropFilter: 'blur(14px)',
borderBottom: '1px solid rgba(255,255,255,0.08)',
}}
>
<Box>
<Typography
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1.2vw',
mb: 0.5,
}}
>
Игроки онлайн
</Typography>
<Typography sx={{ fontSize: '0.9vw', opacity: 0.7 }}>
Сейчас на серверах: {totalOnline}
</Typography>
</Box>
<Box sx={{ display: 'flex', gap: 2, alignItems: 'center' }}>
<FormControl size="small" sx={{ minWidth: 160 }}>
<InputLabel sx={{ color: 'white' }}>Сервер</InputLabel>
<Select
label="Сервер"
value={serverFilter}
onChange={(e) => setServerFilter(e.target.value)}
sx={{ color: 'white' }}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'flex-end',
gap: '1.6vw',
flexWrap: 'wrap',
}}
>
<Box sx={{ minWidth: 240 }}>
<Typography
sx={{
fontFamily: 'Benzin-Bold',
fontSize: '1.35vw',
lineHeight: 1.1,
backgroundImage: GRADIENT,
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
<MenuItem value="all" sx={{ color: 'black' }}>
Все сервера
</MenuItem>
{servers.map((s) => (
<MenuItem key={s.id} value={s.id} sx={{ color: 'black' }}>
{s.name}
</MenuItem>
))}
</Select>
</FormControl>
Игроки онлайн
</Typography>
<Typography sx={{ fontSize: '0.9vw', color: 'rgba(255,255,255,0.70)', fontWeight: 700 }}>
Сейчас на серверах: {totalOnline}
</Typography>
</Box>
<TextField
size="small"
label="Поиск по нику"
value={search}
onChange={(e) => setSearch(e.target.value)}
sx={{ color: 'white' }}
/>
<Box sx={{ display: 'flex', gap: '1vw', alignItems: 'center', flexWrap: 'wrap' }}>
{/* Select в “нашем” стиле */}
<FormControl
size="small"
sx={{
minWidth: '12vw',
'& .MuiInputLabel-root': {
color: 'rgba(255,255,255,0.75)',
fontFamily: 'Benzin-Bold',
},
'& .MuiInputLabel-root.Mui-focused': {
color: 'rgba(242,113,33,0.95)',
},
}}
>
<InputLabel>Сервер</InputLabel>
<Select
label="Сервер"
value={serverFilter}
onChange={(e) => setServerFilter(e.target.value)}
MenuProps={{
PaperProps: {
sx: {
bgcolor: 'rgba(10,10,20,0.96)',
border: '1px solid rgba(255,255,255,0.10)',
borderRadius: '1vw',
backdropFilter: 'blur(14px)',
'& .MuiMenuItem-root': {
color: 'rgba(255,255,255,0.9)',
fontFamily: 'Benzin-Bold',
},
'& .MuiMenuItem-root.Mui-selected': {
backgroundColor: 'rgba(242,113,33,0.16)',
},
'& .MuiMenuItem-root:hover': {
backgroundColor: 'rgba(233,64,205,0.14)',
},
},
},
}}
sx={{
color: 'white',
fontFamily: 'Benzin-Bold',
borderRadius: '999px',
bgcolor: 'rgba(255,255,255,0.04)',
'& .MuiSelect-select': {
py: '0.7vw',
px: '1.2vw',
},
'& .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(255,255,255,0.14)',
},
'&:hover .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(242,113,33,0.55)',
},
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderColor: 'rgba(233,64,205,0.65)',
borderWidth: '2px',
},
'& .MuiSelect-icon': {
color: 'rgba(255,255,255,0.75)',
},
}}
>
<MenuItem value="all">Все сервера</MenuItem>
{servers.map((s) => (
<MenuItem key={s.id} value={s.id}>
{s.name}
</MenuItem>
))}
</Select>
</FormControl>
{/* Поиск через ваш GradientTextField */}
<Box sx={{ minWidth: '16vw' }}>
<GradientTextField
size="small"
label="Поиск по нику"
value={search}
onChange={(e) => setSearch(e.target.value)}
sx={{
mt: 0,
mb: 0,
'& .MuiOutlinedInput-root': { borderRadius: '999px' },
'& .MuiOutlinedInput-root::before': { borderRadius: '999px' },
'& .MuiInputBase-input': {
padding: '0.85vw 1.2vw',
fontSize: '0.9vw',
},
'& .MuiInputLabel-root': {
// background: 'rgba(10,10,20,0.92)',
},
}}
/>
</Box>
</Box>
</Box>
</Box>
{/* list */}
<Box
sx={{
px: '1.8vw',
py: '1.3vw',
maxHeight: '35vh',
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
gap: 1,
gap: '0.65vw',
// аккуратный скроллбар (webkit)
'&::-webkit-scrollbar': { width: '0.55vw' },
'&::-webkit-scrollbar-thumb': {
borderRadius: '999px',
background: 'rgba(255,255,255,0.12)',
},
'&::-webkit-scrollbar-thumb:hover': {
background: 'rgba(242,113,33,0.25)',
},
}}
>
{filteredPlayers.map((p) => (
<Box
key={p.uuid}
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
py: 0.6,
px: 1.5,
borderRadius: '999px',
background: 'rgba(0,0,0,0.35)',
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<HeadAvatar skinUrl={skinMap[p.uuid]} size={24} />
<Typography sx={{ fontFamily: 'Benzin-Bold' }}>
{p.username}
</Typography>
{p.username === currentUsername && (
{filteredPlayers.map((p) => {
const isMe = p.username === currentUsername;
return (
<Paper
key={p.uuid}
elevation={0}
sx={{
px: '1.1vw',
py: '0.75vw',
borderRadius: '1.1vw',
background: 'rgba(255,255,255,0.04)',
border: '1px solid rgba(255,255,255,0.08)',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
gap: '1vw',
transition: 'transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease',
'&:hover': {
transform: 'scale(1.01)',
borderColor: 'rgba(242,113,33,0.35)',
boxShadow: '0 0.8vw 2.4vw rgba(0,0,0,0.45)',
},
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', gap: '0.8vw', minWidth: 0 }}>
<HeadAvatar skinUrl={skinMap[p.uuid]} size={26} />
<Typography
sx={{
fontFamily: 'Benzin-Bold',
color: 'rgba(255,255,255,0.92)',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
}}
>
{p.username}
</Typography>
{isMe && (
<Chip
label="Вы"
size="small"
sx={{
height: '1.55rem',
fontSize: '0.72rem',
fontWeight: 900,
color: 'white',
borderRadius: '999px',
backgroundImage: GRADIENT,
boxShadow: '0 10px 22px rgba(0,0,0,0.45)',
}}
/>
)}
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: '0.6vw', flexShrink: 0 }}>
<Chip
label="Вы"
label={translateServer({ name: p.serverName })}
size="small"
sx={{
height: '1.4rem',
fontSize: '0.7rem',
bgcolor: 'rgb(255,77,77)',
color: 'white',
fontFamily: 'Benzin-Bold',
fontSize: '0.72rem',
borderRadius: '999px',
color: 'rgba(255,255,255,0.88)',
background:
'linear-gradient(120deg, rgba(242,113,33,0.18), rgba(233,64,205,0.12), rgba(138,35,135,0.16))',
border: '1px solid rgba(255,255,255,0.10)',
backdropFilter: 'blur(12px)',
}}
/>
)}
</Box>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
<Chip
label={translateServer({ name: p.serverName })}
size="small"
sx={{ bgcolor: 'rgba(255,255,255,0.08)', color: 'white' }}
/>
{/* Можно позже красиво форматировать onlineSince */}
</Box>
</Box>
))}
{/* onlineSince можно потом красиво форматировать */}
</Box>
</Paper>
);
})}
</Box>
</Paper>
);

View File

@ -11,7 +11,7 @@ import {
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 { useEffect, useRef, useState, useCallback } from 'react';
import CustomTooltip from './Notifications/CustomTooltip';
import CoinsDisplay from './CoinsDisplay';
import { HeadAvatar } from './HeadAvatar';
@ -46,6 +46,23 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
const isRegistrationPage = location.pathname === '/registration';
const navigate = useNavigate();
const tabsWrapperRef = useRef<HTMLDivElement | null>(null);
const tabsRootRef = useRef<HTMLDivElement | null>(null);
const updateGradientVars = useCallback(() => {
const root = tabsRootRef.current;
if (!root) return;
const tabsRect = root.getBoundingClientRect();
const active = root.querySelector<HTMLElement>('.MuiTab-root.Mui-selected');
if (!active) return;
const activeRect = active.getBoundingClientRect();
const x = activeRect.left - tabsRect.left;
root.style.setProperty('--tabs-w', `${tabsRect.width}px`);
root.style.setProperty('--active-x', `${x}px`);
}, []);
const [skinUrl, setSkinUrl] = useState<string>('');
const [avatarAnchorEl, setAvatarAnchorEl] = useState<null | HTMLElement>(
null,
@ -81,6 +98,12 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
const selectedTab =
TAB_ROUTES.find((r) => r.match(location.pathname))?.value ?? false;
useEffect(() => {
updateGradientVars();
window.addEventListener('resize', updateGradientVars);
return () => window.removeEventListener('resize', updateGradientVars);
}, [updateGradientVars, selectedTab, location.pathname]);
useEffect(() => {
const saved = localStorage.getItem('launcher_config');
try {
@ -140,6 +163,8 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
// Прокручиваем горизонтально, используя вертикальный скролл мыши
scroller.scrollLeft += event.deltaY * 0.3;
requestAnimationFrame(updateGradientVars);
};
// const getPageTitle = () => {
@ -168,6 +193,27 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
// Функция для получения количества монет
const tabBaseSx = {
color: 'white',
fontFamily: 'Benzin-Bold',
fontSize: '0.7em',
transition: 'all 0.3s ease',
'&:hover': {
color: 'rgb(170, 170, 170)',
},
};
const activeTabSx = {
color: 'transparent',
WebkitTextFillColor: 'transparent',
backgroundImage: 'var(--tabs-grad)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'var(--tabs-w) 100%',
backgroundPosition: 'calc(-1 * var(--active-x)) 0',
WebkitBackgroundClip: 'text',
backgroundClip: 'text',
};
const logout = () => {
localStorage.removeItem('launcher_config');
navigate('/login');
@ -208,7 +254,6 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
background:
'linear-gradient(71deg, rgba(242,113,33,0.18) 0%, rgba(233,64,205,0.14) 70%, rgba(138,35,135,0.16) 100%)',
backdropFilter: 'blur(10px)',
borderBottom: '1px solid rgba(255,255,255,0.08)',
boxShadow: '0 8px 30px rgba(0,0,0,0.35)',
}}
>
@ -248,29 +293,29 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
ref={tabsWrapperRef}
onWheel={handleTabsWheel}
// старый вариант
sx={{
borderBottom: 1,
borderColor: 'transparent',
// '& .MuiTabs-indicator': {
// backgroundColor: 'rgba(255, 77, 77, 1)',
// },
}}
// sx={{
// borderBottom: 1,
// borderColor: 'transparent',
// borderBottom: 'none',
// borderRadius: '2vw',
// px: '0.6vw',
// py: '0.4vw',
// background: 'rgba(0,0,0,0.35)',
// border: '1px solid rgba(255,255,255,0.08)',
// boxShadow: '0 8px 20px rgba(0,0,0,0.25)',
// '& .MuiTabs-indicator': {
// backgroundColor: 'rgba(255, 77, 77, 1)',
// height: '100%',
// borderRadius: '1.6vw',
// background:
// 'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
// opacity: 0.18,
// },
// }}
sx={{
borderBottom: 'none',
borderRadius: '2vw',
px: '0.6vw',
py: '0.4vw',
background: 'rgba(0,0,0,0.35)',
border: '1px solid rgba(255,255,255,0.08)',
boxShadow: '0 8px 20px rgba(0,0,0,0.25)',
'& .MuiTabs-indicator': {
height: '100%',
borderRadius: '1.6vw',
background:
'linear-gradient(71deg, #F27121 0%, #E940CD 70%, #8A2387 100%)',
opacity: 0.18,
},
}}
>
<CustomTooltip
title={
@ -281,81 +326,71 @@ export default function TopBar({ onRegister, username }: TopBarProps) {
TransitionProps={{ timeout: 100 }}
>
<Tabs
ref={tabsRootRef}
value={selectedTab}
onChange={(_, newValue) => {
const route = TAB_ROUTES.find((r) => r.value === newValue);
if (route) {
navigate(route.to);
}
if (route) navigate(route.to);
}}
aria-label="basic tabs example"
variant="scrollable"
scrollButtons={false}
disableRipple={true}
sx={{ maxWidth: '42vw' }}
sx={{
// один градиент на весь Tabs
'--tabs-grad': 'linear-gradient(90deg, #F27121 0%, #E940CD 50%, #8A2387 100%)',
// активный текст показывает “срез” общего градиента
'& .MuiTab-root.Mui-selected': {
color: 'transparent',
backgroundImage: 'var(--tabs-grad)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'var(--tabs-w) 100%',
backgroundPosition: 'calc(-1 * var(--active-x)) 0',
WebkitBackgroundClip: 'text',
backgroundClip: 'text',
},
// подчёркивание тоже из того же “единого” градиента
'& .MuiTabs-indicator': {
height: '2px',
backgroundImage: 'var(--tabs-grad)',
backgroundRepeat: 'no-repeat',
backgroundSize: 'var(--tabs-w) 100%',
backgroundPosition: 'calc(-1 * var(--active-x)) 0',
},
}}
>
<Tab
label="Новости"
disableRipple={true}
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',
...tabBaseSx,
...(selectedTab === 0 ? activeTabSx : null),
}}
/>
<Tab
label="Версии"
disableRipple={true}
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',
...tabBaseSx,
...(selectedTab === 1 ? activeTabSx : null),
}}
/>
<Tab
label="Магазин"
disableRipple={true}
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',
...tabBaseSx,
...(selectedTab === 2 ? activeTabSx : null),
}}
/>
<Tab
label="Рынок"
disableRipple={true}
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',
...tabBaseSx,
...(selectedTab === 3 ? activeTabSx : null),
}}
/>
</Tabs>

View File

@ -210,6 +210,8 @@ export default function DailyQuests() {
variant="outlined"
sx={{
borderRadius: '2.5vw',
fontSize: '1vw',
px: '3vw',
fontFamily: 'Benzin-Bold',
borderColor: 'rgba(255,255,255,0.25)',
color: '#fff',
@ -231,8 +233,50 @@ export default function DailyQuests() {
{/* content */}
<Box sx={{ px: '2vw', py: '2vh', overflowY: 'auto', flex: 1 }}>
{!wasOnlineToday && (
<Alert severity="warning" sx={{ mb: 2 }}>
Зайдите на сервер сегодня, чтобы открыть получение наград за квесты.
<Alert
severity="warning"
icon={false}
sx={{
mb: 2,
borderRadius: '1.1vw',
px: '1.4vw',
py: '1.1vw',
color: 'rgba(255,255,255,0.90)',
fontWeight: 800,
bgcolor: 'rgba(255,255,255,0.04)',
border: '1px solid rgba(255,255,255,0.10)',
position: 'relative',
overflow: 'hidden',
backdropFilter: 'blur(10px)',
boxShadow: '0 1.0vw 2.8vw rgba(0,0,0,0.45)',
'& .MuiAlert-message': {
padding: 0,
width: '100%',
},
'&:before': {
content: '""',
position: 'absolute',
inset: 0,
background:
'radial-gradient(circle at 12% 30%, rgba(242,113,33,0.22), transparent 60%), radial-gradient(circle at 85% 0%, rgba(233,64,205,0.14), transparent 55%)',
pointerEvents: 'none',
},
'&:after': {
content: '""',
position: 'absolute',
left: 0,
top: 0,
bottom: 0,
width: '0.35vw',
background: 'linear-gradient(180deg, #F27121 0%, #E940CD 65%, #8A2387 100%)',
opacity: 0.95,
pointerEvents: 'none',
},
}}
>
<Typography sx={{ position: 'relative', zIndex: 1, color: 'rgba(255,255,255,0.90)', fontWeight: 800 }}>
Зайдите на сервер сегодня, чтобы открыть получение наград за квесты.
</Typography>
</Alert>
)}