From 332491454d14982572a718de6dd5fa511d086519 Mon Sep 17 00:00:00 2001 From: Oronemu Date: Wed, 17 Dec 2025 02:03:33 +0700 Subject: [PATCH] Redesign p1 --- REDESIGN_PLAN.md | 389 ++++++ frontend/src/components/ActivityFeed.tsx | 148 +- frontend/src/components/EventBanner.tsx | 109 +- frontend/src/components/EventControl.tsx | 132 +- frontend/src/components/SpinWheel.tsx | 240 ++-- frontend/src/components/layout/Layout.tsx | 165 ++- frontend/src/components/ui/Button.tsx | 8 +- frontend/src/components/ui/Card.tsx | 11 +- frontend/src/components/ui/GlassCard.tsx | 211 +++ frontend/src/components/ui/GlitchText.tsx | 116 ++ frontend/src/components/ui/Input.tsx | 13 +- frontend/src/components/ui/NeonButton.tsx | 166 +++ frontend/src/components/ui/index.ts | 5 + frontend/src/index.css | 541 +++++++- frontend/src/pages/AssignmentDetailPage.tsx | 635 +++++---- frontend/src/pages/CreateMarathonPage.tsx | 336 +++-- frontend/src/pages/HomePage.tsx | 322 +++-- frontend/src/pages/InvitePage.tsx | 188 ++- frontend/src/pages/LeaderboardPage.tsx | 290 +++- frontend/src/pages/LobbyPage.tsx | 660 ++++----- frontend/src/pages/LoginPage.tsx | 70 +- frontend/src/pages/MarathonPage.tsx | 349 +++-- frontend/src/pages/MarathonsPage.tsx | 252 +++- frontend/src/pages/NotFoundPage.tsx | 61 +- frontend/src/pages/PlayPage.tsx | 1350 +++++++++---------- frontend/src/pages/ProfilePage.tsx | 529 ++++---- frontend/src/pages/RegisterPage.tsx | 72 +- frontend/src/pages/UserProfilePage.tsx | 151 ++- frontend/tailwind.config.js | 205 ++- 29 files changed, 5137 insertions(+), 2587 deletions(-) create mode 100644 REDESIGN_PLAN.md create mode 100644 frontend/src/components/ui/GlassCard.tsx create mode 100644 frontend/src/components/ui/GlitchText.tsx create mode 100644 frontend/src/components/ui/NeonButton.tsx diff --git a/REDESIGN_PLAN.md b/REDESIGN_PLAN.md new file mode 100644 index 0000000..1080c2e --- /dev/null +++ b/REDESIGN_PLAN.md @@ -0,0 +1,389 @@ +# План редизайна фронтенда Game Marathon + +## Концепция дизайна + +**Стиль:** Минималистичный геймерский дизайн +- Темная база с неоновыми акцентами (cyan/purple/pink градиенты) +- Glitch эффекты на заголовках и при hover +- Glassmorphism для карточек (blur + transparency) +- Subtle grain/noise текстура на фоне +- Геометрические паттерны и линии +- Микро-анимации везде + +**Цветовая палитра:** +``` +Background: #0a0a0f (почти черный с синим оттенком) +Surface: #12121a (карточки) +Border: #1e1e2e (границы) +Primary: #00f0ff (cyan неон) +Secondary: #a855f7 (purple) +Accent: #f0abfc (pink) +Success: #22c55e +Error: #ef4444 +Text: #e2e8f0 +Text Muted: #64748b +``` + +--- + +## Фаза 1: Базовая инфраструктура + +### 1.1 Обновление Tailwind Config +- [ ] Новая цветовая палитра (neon colors) +- [ ] Кастомные анимации: + - `glitch` - glitch эффект для текста + - `glow-pulse` - пульсация свечения + - `float` - плавное парение + - `slide-in-left/right/up/down` - слайды + - `scale-in` - появление с масштабом + - `shimmer` - блик на элементах +- [ ] Кастомные backdrop-blur классы +- [ ] Градиентные утилиты + +### 1.2 Глобальные стили (index.css) +- [ ] CSS переменные для цветов +- [ ] Glitch keyframes анимация +- [ ] Noise/grain overlay +- [ ] Glow эффекты (box-shadow неон) +- [ ] Custom scrollbar (неоновый) +- [ ] Selection стили (выделение текста) + +### 1.3 Новые UI компоненты +- [ ] `GlitchText` - текст с glitch эффектом +- [ ] `NeonButton` - кнопка с неоновым свечением +- [ ] `GlassCard` - карточка с glassmorphism +- [ ] `AnimatedCounter` - анимированные числа +- [ ] `ProgressBar` - неоновый прогресс бар +- [ ] `Badge` - бейджи со свечением +- [ ] `Skeleton` - скелетоны загрузки +- [ ] `Tooltip` - тултипы +- [ ] `Tabs` - табы с анимацией +- [ ] `Modal` - переработанная модалка + +--- + +## Фаза 2: Layout и навигация + +### 2.1 Новый Header +- [ ] Sticky header с blur при скролле +- [ ] Логотип с glitch эффектом при hover +- [ ] Анимированная навигация (underline slide) +- [ ] Notification bell с badge +- [ ] User dropdown с аватаром +- [ ] Mobile hamburger menu с slide-in + +### 2.2 Sidebar (новый компонент) +- [ ] Collapsible sidebar для desktop +- [ ] Иконки с tooltip +- [ ] Active state с неоновой подсветкой +- [ ] Quick stats внизу + +### 2.3 Footer +- [ ] Минималистичный footer +- [ ] Social links +- [ ] Version info + +--- + +## Фаза 3: Страницы + +### 3.1 HomePage (полный редизайн) +``` +┌─────────────────────────────────────────────┐ +│ HERO SECTION │ +│ ┌─────────────────────────────────────┐ │ +│ │ Animated background (particles/ │ │ +│ │ geometric shapes) │ │ +│ │ │ │ +│ │ GAME MARATHON │ │ +│ │ │ │ +│ │ Tagline with typing effect │ │ +│ │ │ │ +│ │ [Start Playing] [Watch Demo] │ │ +│ └─────────────────────────────────────┘ │ +├─────────────────────────────────────────────┤ +│ FEATURES SECTION (3 glass cards) │ +│ ┌───────┐ ┌───────┐ ┌───────┐ │ +│ │ Icon │ │ Icon │ │ Icon │ hover: │ +│ │ Title │ │ Title │ │ Title │ lift + │ +│ │ Desc │ │ Desc │ │ Desc │ glow │ +│ └───────┘ └───────┘ └───────┘ │ +├─────────────────────────────────────────────┤ +│ HOW IT WORKS (timeline style) │ +│ ○───────○───────○───────○ │ +│ 1 2 3 4 │ +│ Create Add Spin Win │ +├─────────────────────────────────────────────┤ +│ LIVE STATS (animated counters) │ +│ [ 1,234 Marathons ] [ 5,678 Challenges ] │ +├─────────────────────────────────────────────┤ +│ CTA SECTION │ +│ Ready to compete? [Join Now] │ +└─────────────────────────────────────────────┘ +``` + +### 3.2 Login/Register Pages +- [ ] Centered card с glassmorphism +- [ ] Animated background (subtle) +- [ ] Form inputs с glow при focus +- [ ] Password strength indicator +- [ ] Social login buttons (future) +- [ ] Smooth transitions между login/register + +### 3.3 MarathonsPage (Dashboard) +``` +┌─────────────────────────────────────────────┐ +│ Header: "My Marathons" + Create button │ +├─────────────────────────────────────────────┤ +│ Quick Stats Bar │ +│ [Active: 2] [Completed: 5] [Total Wins: 3]│ +├─────────────────────────────────────────────┤ +│ Filters/Tabs: All | Active | Completed │ +├─────────────────────────────────────────────┤ +│ Marathon Cards Grid (2-3 columns) │ +│ ┌──────────────────┐ ┌──────────────────┐ │ +│ │ Cover image/ │ │ │ │ +│ │ gradient │ │ │ │ +│ │ ──────────── │ │ │ │ +│ │ Title │ │ │ │ +│ │ Status badge │ │ │ │ +│ │ Participants │ │ │ │ +│ │ Progress bar │ │ │ │ +│ └──────────────────┘ └──────────────────┘ │ +├─────────────────────────────────────────────┤ +│ Join by Code (expandable section) │ +└─────────────────────────────────────────────┘ +``` + +### 3.4 MarathonPage (Detail) +``` +┌─────────────────────────────────────────────┐ +│ Hero Banner │ +│ ┌─────────────────────────────────────┐ │ +│ │ Background gradient + pattern │ │ +│ │ Marathon Title (large) │ │ +│ │ Status | Dates | Participants │ │ +│ │ [Play] [Leaderboard] [Settings] │ │ +│ └─────────────────────────────────────┘ │ +├─────────────────────────────────────────────┤ +│ Event Banner (if active) - animated │ +├────────────────────┬────────────────────────┤ +│ Main Content │ Sidebar │ +│ ┌──────────────┐ │ ┌──────────────────┐ │ +│ │ Your Stats │ │ │ Activity Feed │ │ +│ │ Points/Streak│ │ │ (scrollable) │ │ +│ └──────────────┘ │ │ │ │ +│ ┌──────────────┐ │ │ │ │ +│ │ Quick Actions│ │ │ │ │ +│ └──────────────┘ │ │ │ │ +│ ┌──────────────┐ │ │ │ │ +│ │ Games List │ │ │ │ │ +│ │ (collapsible)│ │ │ │ │ +│ └──────────────┘ │ └──────────────────┘ │ +└────────────────────┴────────────────────────┘ +``` + +### 3.5 PlayPage (Game Screen) - ГЛАВНАЯ СТРАНИЦА +``` +┌─────────────────────────────────────────────┐ +│ Top Bar: Points | Streak | Event Timer │ +├─────────────────────────────────────────────┤ +│ ┌─────────────────────────────────────┐ │ +│ │ SPIN WHEEL │ │ +│ │ (redesigned, neon style) │ │ +│ │ ┌─────────┐ │ │ +│ │ │ WHEEL │ │ │ +│ │ │ │ │ │ +│ │ └─────────┘ │ │ +│ │ [SPIN BUTTON] │ │ +│ └─────────────────────────────────────┘ │ +├─────────────────────────────────────────────┤ +│ Active Challenge Card (если есть) │ +│ ┌─────────────────────────────────────┐ │ +│ │ Game: [Title] | Difficulty: [★★★] │ │ +│ │ ─────────────────────────────────── │ │ +│ │ Challenge Title │ │ +│ │ Description... │ │ +│ │ ─────────────────────────────────── │ │ +│ │ Points: 100 | Time: ~2h │ │ +│ │ ─────────────────────────────────── │ │ +│ │ Proof Upload Area │ │ +│ │ [File] [URL] [Comment] │ │ +│ │ ─────────────────────────────────── │ │ +│ │ [Complete ✓] [Skip ✗] │ │ +│ └─────────────────────────────────────┘ │ +├─────────────────────────────────────────────┤ +│ Mini Leaderboard (top 3 + you) │ +└─────────────────────────────────────────────┘ +``` + +### 3.6 LeaderboardPage +- [ ] Animated podium для top 3 +- [ ] Table с hover эффектами +- [ ] Highlight для текущего пользователя +- [ ] Streak fire animation +- [ ] Sorting/filtering + +### 3.7 ProfilePage +``` +┌─────────────────────────────────────────────┐ +│ Profile Header │ +│ ┌─────────────────────────────────────┐ │ +│ │ Avatar (large, glow border) │ │ +│ │ Nickname [Edit] │ │ +│ │ Member since: Date │ │ +│ └─────────────────────────────────────┘ │ +├─────────────────────────────────────────────┤ +│ Stats Cards (animated counters) │ +│ [Marathons] [Wins] [Challenges] [Points] │ +├─────────────────────────────────────────────┤ +│ Achievements Section (future) │ +├─────────────────────────────────────────────┤ +│ Telegram Connection Card │ +├─────────────────────────────────────────────┤ +│ Security Section (password change) │ +└─────────────────────────────────────────────┘ +``` + +### 3.8 LobbyPage +- [ ] Step-by-step wizard UI +- [ ] Game cards grid с preview +- [ ] Challenge preview с difficulty badges +- [ ] AI generation progress animation +- [ ] Launch countdown + +--- + +## Фаза 4: Специальные компоненты + +### 4.1 SpinWheel (полный редизайн) +- [ ] 3D perspective эффект +- [ ] Неоновые сегменты с названиями игр +- [ ] Particle effects при кручении +- [ ] Glow trail за указателем +- [ ] Sound effects (optional) +- [ ] Confetti при выигрыше + +### 4.2 EventBanner (переработка) +- [ ] Pulsating glow border +- [ ] Countdown timer с flip animation +- [ ] Event-specific icons/colors +- [ ] Dismiss animation + +### 4.3 ActivityFeed (переработка) +- [ ] Timeline style +- [ ] Avatar circles +- [ ] Type-specific icons +- [ ] Hover для деталей +- [ ] New items animation (slide-in) + +### 4.4 Challenge Cards +- [ ] Difficulty stars/badges +- [ ] Progress indicator +- [ ] Expandable details +- [ ] Proof preview thumbnail + +--- + +## Фаза 5: Анимации и эффекты + +### 5.1 Page Transitions +- [ ] Framer Motion page transitions +- [ ] Fade + slide between routes +- [ ] Loading skeleton screens + +### 5.2 Micro-interactions +- [ ] Button press effects +- [ ] Input focus glow +- [ ] Success checkmark animation +- [ ] Error shake animation +- [ ] Loading spinners (custom) + +### 5.3 Background Effects +- [ ] Animated gradient mesh +- [ ] Floating particles (optional) +- [ ] Grid pattern overlay +- [ ] Noise texture + +### 5.4 Special Effects +- [ ] Glitch text на заголовках +- [ ] Neon glow на важных элементах +- [ ] Shimmer effect на loading +- [ ] Confetti на achievements + +--- + +## Фаза 6: Responsive и Polish + +### 6.1 Mobile Optimization +- [ ] Touch-friendly targets +- [ ] Swipe gestures +- [ ] Bottom navigation (mobile) +- [ ] Collapsible sections + +### 6.2 Accessibility +- [ ] Keyboard navigation +- [ ] Focus indicators +- [ ] Screen reader support +- [ ] Reduced motion option + +### 6.3 Performance +- [ ] Lazy loading images +- [ ] Code splitting +- [ ] Animation optimization +- [ ] Bundle size check + +--- + +## Порядок реализации + +### Sprint 1: Фундамент (2-3 дня) +1. Tailwind config + colors +2. Global CSS + animations +3. Base UI components (Button, Card, Input) +4. GlitchText component +5. Updated Layout/Header + +### Sprint 2: Core Pages (3-4 дня) +1. HomePage с hero +2. Login/Register +3. MarathonsPage dashboard +4. Profile page + +### Sprint 3: Game Flow (3-4 дня) +1. MarathonPage detail +2. SpinWheel redesign +3. PlayPage +4. LeaderboardPage + +### Sprint 4: Polish (2-3 дня) +1. LobbyPage +2. Event components +3. Activity feed +4. Animations & transitions + +### Sprint 5: Finalization (1-2 дня) +1. Mobile testing +2. Performance optimization +3. Bug fixes +4. Final polish + +--- + +## Референсы для вдохновления + +- Cyberpunk 2077 UI +- Discord dark theme +- Valorant game UI +- Steam profile pages +- Twitch streaming UI +- Epic Games Store + +--- + +## Технические заметки + +**Framer Motion:** Использовать для page transitions и сложных анимаций +**CSS:** Использовать для простых transitions и hover эффектов +**Tailwind:** Основной инструмент для стилей +**Custom Hooks:** useAnimation, useGlitch для переиспользования логики diff --git a/frontend/src/components/ActivityFeed.tsx b/frontend/src/components/ActivityFeed.tsx index ddc4ee1..a89f843 100644 --- a/frontend/src/components/ActivityFeed.tsx +++ b/frontend/src/components/ActivityFeed.tsx @@ -2,13 +2,12 @@ import { useState, useEffect, useCallback, useRef, useImperativeHandle, forwardR import { useNavigate } from 'react-router-dom' import { feedApi } from '@/api' import type { Activity, ActivityType } from '@/types' -import { Loader2, ChevronDown, Bell, ExternalLink, AlertTriangle } from 'lucide-react' +import { Loader2, ChevronDown, Activity as ActivityIcon, ExternalLink, AlertTriangle, Sparkles, Zap } from 'lucide-react' import { UserAvatar } from '@/components/ui' import { formatRelativeTime, getActivityIcon, getActivityColor, - getActivityBgClass, isEventActivity, formatActivityMessage, } from '@/utils/activity' @@ -100,52 +99,66 @@ export const ActivityFeed = forwardRef( if (isLoading) { return ( -
-
- -

Активность

+
+
+
+ +
+

Активность

-
- +
+
) } return ( -
+
{/* Header */} -
-
- -

Активность

+
+
+
+ +
+
+

Активность

+ {total > 0 && ( +

{total} событий

+ )} +
- {total > 0 && ( - {total} - )} +
{/* Activity list */}
{activities.length === 0 ? ( -
- Пока нет активности +
+
+ +
+

Пока нет активности

) : ( -
- {activities.map((activity) => ( - +
+ {activities.map((activity, index) => ( + ))}
)} {/* Load more button */} {hasMore && ( -
+
{disputeStatus === 'open' && ( - + Оспаривается )} {disputeStatus === 'valid' && ( - + Отклонено diff --git a/frontend/src/components/EventBanner.tsx b/frontend/src/components/EventBanner.tsx index 8b023cf..4c920eb 100644 --- a/frontend/src/components/EventBanner.tsx +++ b/frontend/src/components/EventBanner.tsx @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react' -import { Zap, Users, Shield, Gift, ArrowLeftRight, Gamepad2, Clock } from 'lucide-react' +import { Zap, Users, Shield, Gift, ArrowLeftRight, Gamepad2, Clock, Sparkles } from 'lucide-react' import type { ActiveEvent, EventType } from '@/types' import { EVENT_INFO } from '@/types' @@ -17,13 +17,55 @@ const EVENT_ICONS: Record = { game_choice: , } -const EVENT_COLORS: Record = { - golden_hour: 'from-yellow-500/20 to-yellow-600/20 border-yellow-500/50 text-yellow-400', - common_enemy: 'from-red-500/20 to-red-600/20 border-red-500/50 text-red-400', - double_risk: 'from-purple-500/20 to-purple-600/20 border-purple-500/50 text-purple-400', - jackpot: 'from-green-500/20 to-green-600/20 border-green-500/50 text-green-400', - swap: 'from-blue-500/20 to-blue-600/20 border-blue-500/50 text-blue-400', - game_choice: 'from-orange-500/20 to-orange-600/20 border-orange-500/50 text-orange-400', +const EVENT_COLORS: Record = { + golden_hour: { + gradient: 'from-yellow-500/20 via-yellow-500/10 to-transparent', + border: 'border-yellow-500/50', + text: 'text-yellow-400', + glow: 'shadow-[0_0_30px_rgba(234,179,8,0.3)]', + iconBg: 'bg-yellow-500/20', + }, + common_enemy: { + gradient: 'from-red-500/20 via-red-500/10 to-transparent', + border: 'border-red-500/50', + text: 'text-red-400', + glow: 'shadow-[0_0_30px_rgba(239,68,68,0.3)]', + iconBg: 'bg-red-500/20', + }, + double_risk: { + gradient: 'from-purple-500/20 via-purple-500/10 to-transparent', + border: 'border-purple-500/50', + text: 'text-purple-400', + glow: 'shadow-[0_0_30px_rgba(168,85,247,0.3)]', + iconBg: 'bg-purple-500/20', + }, + jackpot: { + gradient: 'from-green-500/20 via-green-500/10 to-transparent', + border: 'border-green-500/50', + text: 'text-green-400', + glow: 'shadow-[0_0_30px_rgba(34,197,94,0.3)]', + iconBg: 'bg-green-500/20', + }, + swap: { + gradient: 'from-neon-500/20 via-neon-500/10 to-transparent', + border: 'border-neon-500/50', + text: 'text-neon-400', + glow: 'shadow-[0_0_30px_rgba(0,240,255,0.3)]', + iconBg: 'bg-neon-500/20', + }, + game_choice: { + gradient: 'from-orange-500/20 via-orange-500/10 to-transparent', + border: 'border-orange-500/50', + text: 'text-orange-400', + glow: 'shadow-[0_0_30px_rgba(249,115,22,0.3)]', + iconBg: 'bg-orange-500/20', + }, } function formatTime(seconds: number): string { @@ -68,42 +110,53 @@ export function EventBanner({ activeEvent, onRefresh }: EventBannerProps) { const event = activeEvent.event const info = EVENT_INFO[event.type] const icon = EVENT_ICONS[event.type] - const colorClass = EVENT_COLORS[event.type] + const colors = EVENT_COLORS[event.type] return (
- {/* Animated background effect */} + {/* Background gradient */} +
+ + {/* Animated shimmer effect */}
-
-
-
+ {/* Grid pattern */} +
+ +
+
+
{icon}
-

{info.name}

-

{info.description}

+
+

{info.name}

+ +
+

{info.description}

- {timeRemaining !== null && timeRemaining > 0 && ( -
- - {formatTime(timeRemaining)} -
- )} +
+ {activeEvent.effects.points_multiplier !== 1.0 && ( +
+ x{activeEvent.effects.points_multiplier} +
+ )} - {activeEvent.effects.points_multiplier !== 1.0 && ( -
- x{activeEvent.effects.points_multiplier} -
- )} + {timeRemaining !== null && timeRemaining > 0 && ( +
+ + {formatTime(timeRemaining)} +
+ )} +
) diff --git a/frontend/src/components/EventControl.tsx b/frontend/src/components/EventControl.tsx index 33e4b36..f7dddb9 100644 --- a/frontend/src/components/EventControl.tsx +++ b/frontend/src/components/EventControl.tsx @@ -1,6 +1,6 @@ import { useState } from 'react' -import { Zap, Users, Shield, Gift, ArrowLeftRight, Gamepad2, Play, Square } from 'lucide-react' -import { Button } from '@/components/ui' +import { Zap, Users, Shield, Gift, ArrowLeftRight, Gamepad2, Play, Square, Sparkles } from 'lucide-react' +import { NeonButton } from '@/components/ui' import { eventsApi } from '@/api' import type { ActiveEvent, EventType, Challenge } from '@/types' import { EVENT_INFO } from '@/types' @@ -24,12 +24,21 @@ const EVENT_TYPES: EventType[] = [ ] const EVENT_ICONS: Record = { - golden_hour: , - common_enemy: , - double_risk: , - jackpot: , - swap: , - game_choice: , + golden_hour: , + common_enemy: , + double_risk: , + jackpot: , + swap: , + game_choice: , +} + +const EVENT_COLORS: Record = { + golden_hour: { selected: 'border-yellow-500/50 bg-yellow-500/10', icon: 'text-yellow-400' }, + common_enemy: { selected: 'border-red-500/50 bg-red-500/10', icon: 'text-red-400' }, + double_risk: { selected: 'border-purple-500/50 bg-purple-500/10', icon: 'text-purple-400' }, + jackpot: { selected: 'border-green-500/50 bg-green-500/10', icon: 'text-green-400' }, + swap: { selected: 'border-neon-500/50 bg-neon-500/10', icon: 'text-neon-400' }, + game_choice: { selected: 'border-orange-500/50 bg-orange-500/10', icon: 'text-orange-400' }, } // Default durations for events (in minutes) @@ -107,54 +116,81 @@ export function EventControl({ } if (activeEvent.event) { + const colors = EVENT_COLORS[activeEvent.event.type] return ( -
-
-
- {EVENT_ICONS[activeEvent.event.type]} - - Активно: {EVENT_INFO[activeEvent.event.type].name} - +
+
+
+
+ {EVENT_ICONS[activeEvent.event.type]} +
+
+ + {EVENT_INFO[activeEvent.event.type].name} + + активно +
- +
) } return ( -
-

Запустить событие

+
+
+
+ +
+
+

Запустить событие

+

Выберите тип и настройте параметры

+
+
-
- {EVENT_TYPES.map((type) => ( - - ))} +
+ {EVENT_TYPES.map((type) => { + const colors = EVENT_COLORS[type] + const isSelected = selectedType === type + return ( + + ) + })}
{/* Duration setting */} @@ -170,9 +206,9 @@ export function EventControl({ min={1} max={480} placeholder={`По умолчанию: ${DEFAULT_DURATIONS[selectedType]}`} - className="w-full p-2 bg-gray-700 border border-gray-600 rounded-lg text-white" + className="input w-full" /> -

+

Оставьте пустым для значения по умолчанию ({DEFAULT_DURATIONS[selectedType]} мин)

@@ -186,7 +222,7 @@ export function EventControl({