diff --git a/src/renderer/components/BonusShopItem.tsx b/src/renderer/components/BonusShopItem.tsx index 6d2466b..8e47cfd 100644 --- a/src/renderer/components/BonusShopItem.tsx +++ b/src/renderer/components/BonusShopItem.tsx @@ -1,3 +1,4 @@ +// src/renderer/components/BonusShopItem.tsx import React from 'react'; import { Card, @@ -80,53 +81,45 @@ export const BonusShopItem: React.FC = ({ sx={{ position: 'relative', width: '100%', - maxWidth: 280, - height: 420, + maxWidth: 300, + height: 440, display: 'flex', flexDirection: 'column', - bgcolor: 'rgba(5, 5, 15, 0.96)', - borderRadius: '20px', - border: '1px solid rgba(255, 255, 255, 0.08)', - boxShadow: '0 18px 45px rgba(0, 0, 0, 0.8)', + background: 'rgba(20,20,20,0.9)', + borderRadius: '2.5vw', + border: '1px solid rgba(255,255,255,0.08)', + boxShadow: '0 10px 40px rgba(0,0,0,0.8)', overflow: 'hidden', - transition: - 'transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease', + + transition: 'transform 0.35s ease, box-shadow 0.35s ease', '&:hover': { - transform: 'translateY(-6px)', - boxShadow: '0 26px 60px rgba(0, 0, 0, 0.95)', - borderColor: 'rgba(255, 255, 255, 0.18)', + transform: 'scale(1.05)', + boxShadow: '0 20px 60px rgba(242,113,33,0.45)', }, }} > - {/* верхний “свет” */} + {/* Градиентный свет сверху — как в ShopItem */} {imageUrl && ( - + = ({ alt={name} sx={{ width: '100%', - height: '11vw', - minHeight: '140px', + height: 160, objectFit: 'cover', - filter: 'saturate(1.1)', }} /> @@ -147,91 +138,95 @@ export const BonusShopItem: React.FC = ({ + {/* Имя бонуса — градиентом как у ShopItem */} {name} Уровень: {level} + {isPermanent && ' • Постоянный'} {description && ( {description} )} - + - Текущий эффект: {effectValue.toLocaleString('ru-RU')} + Текущий эффект:{' '} + + {effectValue.toLocaleString('ru-RU')} + {typeof nextEffectValue === 'number' && !isBuyMode && canUpgrade && ( Следующий уровень:{' '} - {nextEffectValue.toLocaleString('ru-RU')} + + {nextEffectValue.toLocaleString('ru-RU')} + )} - - - {isActive ? 'Бонус активен' : 'Бонус не активен'} - - + + {isActive ? 'Бонус активен' : 'Бонус не активен'} + = ({ }} > {isBuyMode ? 'Цена покупки' : 'Цена улучшения'} @@ -262,43 +255,48 @@ export const BonusShopItem: React.FC = ({ )} + {/* Кнопка в стиле Registration / ShopItem */} diff --git a/src/renderer/components/CaseRoulette.tsx b/src/renderer/components/CaseRoulette.tsx index 45509de..98bd3a8 100644 --- a/src/renderer/components/CaseRoulette.tsx +++ b/src/renderer/components/CaseRoulette.tsx @@ -81,17 +81,14 @@ export default function CaseRoulette({ useEffect(() => { if (!open || !reward || !items || items.length === 0) return; - // Очистка предыдущих таймеров if (animationTimeoutRef.current) clearTimeout(animationTimeoutRef.current); if (finishTimeoutRef.current) clearTimeout(finishTimeoutRef.current); - // Сброс состояний setAnimating(false); setAnimationFinished(false); setOffset(0); itemRefs.current = []; - // 1. Генерируем последовательность const totalItems = VISIBLE_ITEMS * 3; const seq: CaseItem[] = []; @@ -108,7 +105,7 @@ export default function CaseRoulette({ setSequence(seq); }, [open, reward, items]); - // Эффект для запуска анимации после рендера элементов + // Эффект запуска анимации useEffect(() => { if (sequence.length === 0 || !open) return; @@ -116,12 +113,10 @@ export default function CaseRoulette({ const widths = measureItemWidths(); const winPosition = Math.floor(sequence.length / 2); - // Сколько "оборотов" хотим сделать до остановки const EXTRA_SPINS = 3; const averageItemWidth = ITEM_WIDTH + ITEM_GAP; const extraDistance = EXTRA_SPINS * VISIBLE_ITEMS * averageItemWidth; - // fallback, если не смогли корректно измерить ширины if (widths.length === 0 || widths.length !== sequence.length) { const centerItemCenter = winPosition * (ITEM_WIDTH + ITEM_GAP) + ITEM_WIDTH / 2; @@ -143,7 +138,6 @@ export default function CaseRoulette({ return; } - // вариант с реальными ширинами let cumulativeOffset = 0; for (let i = 0; i < winPosition; i++) { cumulativeOffset += widths[i] + ITEM_GAP; @@ -196,51 +190,64 @@ export default function CaseRoulette({ fullWidth PaperProps={{ sx: { - bgcolor: 'rgba(5, 5, 10, 0.96)', - borderRadius: '24px', - border: '1px solid rgba(255,255,255,0.12)', - boxShadow: '0 25px 80px rgba(0,0,0,0.8)', + bgcolor: 'transparent', + borderRadius: '2.5vw', overflow: 'hidden', + boxShadow: '0 30px 80px rgba(0,0,0,0.9)', }, }} > + {/* лёгкий "бордер" по контуру */} + + + {/* заголовок с градиентом как в Registration */} Открытие кейса {caseName} + {/* контейнер рулетки */} {/* затемнённые края */} @@ -250,12 +257,12 @@ export default function CaseRoulette({ inset: 0, pointerEvents: 'none', background: - 'linear-gradient(90deg, rgba(0,0,0,0.7) 0%, transparent 20%, transparent 80%, rgba(0,0,0,0.7) 100%)', + 'linear-gradient(90deg, rgba(0,0,0,0.85) 0%, transparent 20%, transparent 80%, rgba(0,0,0,0.85) 100%)', zIndex: 1, }} /> - {/* Линия центра */} + {/* центральная линия (прицел) */} - {/* Лента с предметами */} + {/* Лента предметов */} (itemRefs.current[index] = el)} sx={{ minWidth: `${ITEM_WIDTH}px`, - width: 'auto', - height: '130px', - borderRadius: '14px', - bgcolor: 'rgba(255, 255, 255, 0.03)', + height: 130, + borderRadius: '1.4vw', + background: 'rgba(255,255,255,0.03)', display: 'flex', flexDirection: 'column', alignItems: 'center', @@ -317,10 +324,10 @@ export default function CaseRoulette({ ? `2px solid ${color}` : `1px solid ${color}`, boxShadow: isWinningItem - ? `0 0 22px ${color}` - : '0 0 8px rgba(0,0,0,0.6)', + ? `0 0 24px ${color}` + : '0 0 10px rgba(0,0,0,0.6)', transition: 'all 0.3s ease', - padding: '0 10px', + px: 1, transform: isWinningItem ? 'scale(1.08)' : 'scale(1)', }} > @@ -329,8 +336,8 @@ export default function CaseRoulette({ src={`https://cdn.minecraft.popa-popa.ru/textures/${item.material.toLowerCase()}.png`} alt={item.material} sx={{ - width: '52px', - height: '52px', + width: 52, + height: 52, objectFit: 'contain', imageRendering: 'pixelated', mb: 1, @@ -342,7 +349,7 @@ export default function CaseRoulette({ color: 'white', textAlign: 'center', fontSize: '0.72rem', - maxWidth: '100px', + maxWidth: 100, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', @@ -359,46 +366,50 @@ export default function CaseRoulette({ {animationFinished && winningName && ( Вам выпало:{' '} - + {winningName} - + )} - + {/* кнопка как в Registration */} + diff --git a/src/renderer/pages/Shop.tsx b/src/renderer/pages/Shop.tsx index 5276830..7622c8e 100644 --- a/src/renderer/pages/Shop.tsx +++ b/src/renderer/pages/Shop.tsx @@ -422,7 +422,7 @@ export default function Shop() { height: '80%', gap: '2vw', overflow: 'auto', - paddingBottom: '7vh', + paddingBottom: '10vh', paddingLeft: '5vw', paddingRight: '5vw', }} @@ -560,6 +560,10 @@ export default function Shop() { transform: 'scale(1.1)', }, }} + onClick={() => { + checkPlayerStatus(); // обновляем онлайн-статус + loadCases(); // обновляем ТОЛЬКО кейсы + }} > Обновить @@ -658,12 +662,9 @@ export default function Shop() { onClose={handleCloseNotification} > {notification.message}