diff --git a/src/renderer/components/CoinsDisplay.tsx b/src/renderer/components/CoinsDisplay.tsx new file mode 100644 index 0000000..83847af --- /dev/null +++ b/src/renderer/components/CoinsDisplay.tsx @@ -0,0 +1,233 @@ +// CoinsDisplay.tsx +import { Box, Typography } from '@mui/material'; +import CustomTooltip from './CustomTooltip'; +import { useEffect, useState } from 'react'; +import { fetchCoins } from '../api'; + +interface CoinsDisplayProps { + // Основные пропсы + value?: number; // Передаем значение напрямую + username?: string; // Или получаем по username из API + + // Опции отображения + size?: 'small' | 'medium' | 'large'; + showTooltip?: boolean; + tooltipText?: string; + showIcon?: boolean; + iconColor?: string; + + // Опции обновления + autoUpdate?: boolean; // Автоматическое обновление из API + updateInterval?: number; // Интервал обновления в миллисекундах + + // Стилизация + backgroundColor?: string; + textColor?: string; +} + +export default function CoinsDisplay({ + // Основные пропсы + value: externalValue, + username, + + // Опции отображения + size = 'medium', + showTooltip = true, + tooltipText = 'Попы — внутриигровая валюта, начисляемая за время игры на серверах.', + showIcon = true, + iconColor = '#2bff00ff', + + // Опции обновления + autoUpdate = false, + updateInterval = 60000, + + // Стилизация + backgroundColor = 'rgba(0, 0, 0, 0.2)', + textColor = 'white', +}: CoinsDisplayProps) { + const [coins, setCoins] = useState(externalValue || 0); + const [isLoading, setIsLoading] = useState(false); + + // Определяем размеры в зависимости от параметра size + const getSizes = () => { + switch (size) { + case 'small': + return { + containerPadding: '4px 8px', + iconSize: '16px', + fontSize: '12px', + borderRadius: '12px', + gap: '6px', + }; + case 'large': + return { + containerPadding: '8px 16px', + iconSize: '28px', + fontSize: '18px', + borderRadius: '20px', + gap: '10px', + }; + case 'medium': + default: + return { + containerPadding: '6px 12px', + iconSize: '24px', + fontSize: '16px', + borderRadius: '16px', + gap: '8px', + }; + } + }; + + const sizes = getSizes(); + + // Функция для получения количества монет из API + const fetchCoinsData = async () => { + if (!username) return; + + setIsLoading(true); + try { + const coinsData = await fetchCoins(username); + setCoins(coinsData.coins); + } catch (error) { + console.error('Ошибка при получении количества монет:', error); + } finally { + setIsLoading(false); + } + }; + + // Эффект для внешнего значения + useEffect(() => { + if (externalValue !== undefined) { + setCoins(externalValue); + } + }, [externalValue]); + + // Эффект для API обновлений + useEffect(() => { + if (username && autoUpdate) { + fetchCoinsData(); + + // Создаем интервалы для периодического обновления данных + const coinsInterval = setInterval(fetchCoinsData, updateInterval); + + return () => { + clearInterval(coinsInterval); + }; + } + }, [username, autoUpdate, updateInterval]); + + // Ручное обновление данных + const handleRefresh = () => { + if (username) { + fetchCoinsData(); + } + }; + + // Форматирование числа с разделителями тысяч + const formatNumber = (num: number): string => { + return num.toLocaleString('ru-RU'); + }; + + const coinsDisplay = ( + + {showIcon && ( + + + P + + + )} + + + {isLoading ? '...' : formatNumber(coins)} + + + ); + + if (showTooltip) { + return ( + + {coinsDisplay} + + ); + } + + return coinsDisplay; +} + +// Примеры использования в комментариях для разработчика: +/* +// Пример 1: Простое отображение числа + + +// Пример 2: Получение данных по username с автообновлением + + +// Пример 3: Кастомная стилизация без иконки + + +// Пример 4: Большой отображение для профиля + +*/ diff --git a/src/renderer/components/CustomTooltip.tsx b/src/renderer/components/CustomTooltip.tsx index 5e0e070..cf6415c 100644 --- a/src/renderer/components/CustomTooltip.tsx +++ b/src/renderer/components/CustomTooltip.tsx @@ -8,16 +8,28 @@ const CustomTooltip = styled(({ className, ...props }: TooltipProps) => ( ))(({ theme }) => ({ [`& .${tooltipClasses.tooltip}`]: { - backgroundColor: 'rgba(0, 0, 0, 1)', - color: 'white', + backgroundColor: 'rgba(0, 0, 0, 0.9)', + color: '#fff', maxWidth: 300, fontSize: '0.9vw', - border: '1px solid rgba(255, 77, 77, 0.5)', + border: '1px solid rgba(242, 113, 33, 0.5)', borderRadius: '1vw', padding: '1vw', - boxShadow: - '0 0 1vw rgba(255, 77, 77, 0.3), inset 0.8vw -0.8vw 2vw rgba(255, 77, 77, 0.15)', + boxShadow: ` + 0 0 1.5vw rgba(242, 113, 33, 0.4), + 0 0 0.5vw rgba(233, 64, 87, 0.3), + inset 0 0 0.5vw rgba(138, 35, 135, 0.2) + `, fontFamily: 'Benzin-Bold', + background: ` + linear-gradient( + 135deg, + rgba(0, 0, 0, 0.95) 0%, + rgba(20, 20, 20, 0.95) 100% + ) + `, + position: 'relative', + zIndex: 1, '&::before': { content: '""', position: 'absolute', @@ -26,12 +38,37 @@ const CustomTooltip = styled(({ className, ...props }: TooltipProps) => ( right: 0, bottom: 0, borderRadius: '1vw', - // background: 'linear-gradient(45deg, rgba(255, 77, 77, 0.1), transparent)', + padding: '2px', + background: ` + linear-gradient( + 135deg, + rgba(242, 113, 33, 0.8) 0%, + rgba(233, 64, 87, 0.6) 50%, + rgba(138, 35, 135, 0.4) 100% + ) + `, + WebkitMask: ` + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0) + `, + WebkitMaskComposite: 'xor', + maskComposite: 'exclude', zIndex: -1, }, }, [`& .${tooltipClasses.arrow}`]: { - color: 'rgba(255, 77, 77, 0.5)', + color: 'rgba(242, 113, 33, 0.9)', + '&::before': { + background: ` + linear-gradient( + 135deg, + rgba(242, 113, 33, 0.9) 0%, + rgba(233, 64, 87, 0.7) 50%, + rgba(138, 35, 135, 0.5) 100% + ) + `, + border: '1px solid rgba(242, 113, 33, 0.5)', + }, }, })); diff --git a/src/renderer/components/TopBar.tsx b/src/renderer/components/TopBar.tsx index 0370838..58df107 100644 --- a/src/renderer/components/TopBar.tsx +++ b/src/renderer/components/TopBar.tsx @@ -6,6 +6,7 @@ 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: { @@ -208,111 +209,118 @@ export default function TopBar({ onRegister, username }: TopBarProps) { }, }} > - - { - 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', - }} - /> - { - 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', - }} - /> - { - 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', - }} - /> - { - 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', - }} - /> - { - 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', - }} - /> - + sx={{ maxWidth: '42vw' }} + > + { + 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', + }} + /> + { + 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', + }} + /> + { + 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', + }} + /> + { + 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', + }} + /> + { + 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', + }} + /> + + )} @@ -376,46 +384,12 @@ export default function TopBar({ onRegister, username }: TopBarProps) { )} {/* Кнопка регистрации, если на странице логина */} {!isLoginPage && !isRegistrationPage && username && ( - - - - P - - - {coins} - - - + )} {isLoginPage && (