Fix UI
This commit is contained in:
@@ -42,7 +42,7 @@ const EVENT_COLORS: Record<EventType, {
|
||||
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)]',
|
||||
glow: 'shadow-[0_0_20px_rgba(139,92,246,0.25)]',
|
||||
iconBg: 'bg-purple-500/20',
|
||||
},
|
||||
jackpot: {
|
||||
@@ -56,7 +56,7 @@ const EVENT_COLORS: Record<EventType, {
|
||||
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)]',
|
||||
glow: 'shadow-[0_0_20px_rgba(34,211,238,0.25)]',
|
||||
iconBg: 'bg-neon-500/20',
|
||||
},
|
||||
game_choice: {
|
||||
|
||||
@@ -128,8 +128,8 @@ export function SpinWheel({ games, onSpin, onSpinComplete, disabled }: SpinWheel
|
||||
{/* Neon border glow */}
|
||||
<div className={`absolute inset-0 border-2 rounded-lg transition-all duration-300 ${
|
||||
isSpinning
|
||||
? 'border-neon-400 shadow-[0_0_20px_rgba(0,240,255,0.5),inset_0_0_20px_rgba(0,240,255,0.1)]'
|
||||
: 'border-neon-500/50 shadow-[0_0_10px_rgba(0,240,255,0.2)]'
|
||||
? 'border-neon-400 shadow-[0_0_14px_rgba(34,211,238,0.4),inset_0_0_14px_rgba(34,211,238,0.08)]'
|
||||
: 'border-neon-500/50 shadow-[0_0_8px_rgba(34,211,238,0.15)]'
|
||||
}`} />
|
||||
|
||||
{/* Side arrows */}
|
||||
@@ -198,7 +198,7 @@ export function SpinWheel({ games, onSpin, onSpinComplete, disabled }: SpinWheel
|
||||
w-16 h-16 rounded-xl overflow-hidden flex-shrink-0
|
||||
border transition-all duration-300
|
||||
${isSelected
|
||||
? 'border-neon-500/50 shadow-[0_0_15px_rgba(0,240,255,0.3)]'
|
||||
? 'border-neon-500/50 shadow-[0_0_12px_rgba(34,211,238,0.25)]'
|
||||
: 'border-dark-600'
|
||||
}
|
||||
`}>
|
||||
|
||||
@@ -50,7 +50,7 @@ export function Layout() {
|
||||
className="flex items-center gap-3 group"
|
||||
>
|
||||
<div className="relative">
|
||||
<Gamepad2 className="w-8 h-8 text-neon-500 transition-all duration-300 group-hover:text-neon-400 group-hover:drop-shadow-[0_0_8px_rgba(0,240,255,0.8)]" />
|
||||
<Gamepad2 className="w-8 h-8 text-neon-500 transition-all duration-300 group-hover:text-neon-400 group-hover:drop-shadow-[0_0_8px_rgba(34,211,238,0.6)]" />
|
||||
</div>
|
||||
<span className="text-xl font-bold text-white font-display tracking-wider glitch-hover">
|
||||
МАРАФОН
|
||||
@@ -109,7 +109,7 @@ export function Layout() {
|
||||
</Link>
|
||||
<Link
|
||||
to="/register"
|
||||
className="px-4 py-2 bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold rounded-lg transition-all duration-200 shadow-[0_0_15px_rgba(0,240,255,0.3)] hover:shadow-[0_0_25px_rgba(0,240,255,0.5)]"
|
||||
className="px-4 py-2 bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold rounded-lg transition-all duration-200 shadow-[0_0_10px_rgba(34,211,238,0.25)] hover:shadow-[0_0_16px_rgba(34,211,238,0.4)]"
|
||||
>
|
||||
Регистрация
|
||||
</Link>
|
||||
|
||||
@@ -18,7 +18,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
'inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||
{
|
||||
'bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold shadow-[0_0_10px_rgba(0,240,255,0.3)] hover:shadow-[0_0_20px_rgba(0,240,255,0.5)]': variant === 'primary',
|
||||
'bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold shadow-[0_0_8px_rgba(34,211,238,0.25)] hover:shadow-[0_0_14px_rgba(34,211,238,0.4)]': variant === 'primary',
|
||||
'bg-dark-600 hover:bg-dark-500 text-white border border-dark-500': variant === 'secondary',
|
||||
'bg-red-600 hover:bg-red-700 text-white': variant === 'danger',
|
||||
'bg-transparent hover:bg-dark-700 text-gray-300 hover:text-white': variant === 'ghost',
|
||||
|
||||
@@ -12,7 +12,7 @@ export function Card({ children, className, hover = false }: CardProps) {
|
||||
<div
|
||||
className={clsx(
|
||||
'bg-dark-800 rounded-xl p-6 border border-dark-600',
|
||||
hover && 'transition-all duration-300 hover:-translate-y-1 hover:border-neon-500/30 hover:shadow-[0_10px_40px_rgba(0,240,255,0.1)]',
|
||||
hover && 'transition-all duration-300 hover:-translate-y-1 hover:border-neon-500/30 hover:shadow-[0_10px_40px_rgba(34,211,238,0.08)]',
|
||||
className
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -91,10 +91,10 @@ export function StatsCard({
|
||||
className
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<p className="text-sm text-gray-400 mb-1">{label}</p>
|
||||
<p className={clsx('text-2xl font-bold', valueColorClasses[color])}>
|
||||
<p className={clsx('text-2xl font-bold truncate', valueColorClasses[color])}>
|
||||
{value}
|
||||
</p>
|
||||
{trend && (
|
||||
@@ -111,7 +111,7 @@ export function StatsCard({
|
||||
{icon && (
|
||||
<div
|
||||
className={clsx(
|
||||
'w-12 h-12 rounded-lg flex items-center justify-center',
|
||||
'w-12 h-12 rounded-lg flex items-center justify-center flex-shrink-0',
|
||||
iconColorClasses[color]
|
||||
)}
|
||||
>
|
||||
@@ -143,17 +143,17 @@ export function FeatureCard({
|
||||
neon: {
|
||||
icon: 'text-neon-500 bg-neon-500/10 group-hover:bg-neon-500/20',
|
||||
border: 'group-hover:border-neon-500/50',
|
||||
glow: 'group-hover:shadow-[0_0_30px_rgba(0,240,255,0.15)]',
|
||||
glow: 'group-hover:shadow-[0_0_20px_rgba(34,211,238,0.12)]',
|
||||
},
|
||||
purple: {
|
||||
icon: 'text-accent-500 bg-accent-500/10 group-hover:bg-accent-500/20',
|
||||
border: 'group-hover:border-accent-500/50',
|
||||
glow: 'group-hover:shadow-[0_0_30px_rgba(168,85,247,0.15)]',
|
||||
glow: 'group-hover:shadow-[0_0_20px_rgba(139,92,246,0.12)]',
|
||||
},
|
||||
pink: {
|
||||
icon: 'text-pink-500 bg-pink-500/10 group-hover:bg-pink-500/20',
|
||||
border: 'group-hover:border-pink-500/50',
|
||||
glow: 'group-hover:shadow-[0_0_30px_rgba(236,72,153,0.15)]',
|
||||
glow: 'group-hover:shadow-[0_0_20px_rgba(244,114,182,0.12)]',
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ export function GlitchText({
|
||||
const glowClasses = {
|
||||
neon: 'neon-text',
|
||||
purple: 'neon-text-purple',
|
||||
pink: '[text-shadow:0_0_10px_#ec4899,0_0_20px_#ec4899,0_0_30px_#ec4899]',
|
||||
white: '[text-shadow:0_0_10px_rgba(255,255,255,0.5),0_0_20px_rgba(255,255,255,0.3)]',
|
||||
pink: '[text-shadow:0_0_8px_rgba(244,114,182,0.5),0_0_16px_rgba(244,114,182,0.25)]',
|
||||
white: '[text-shadow:0_0_8px_rgba(255,255,255,0.4),0_0_16px_rgba(255,255,255,0.2)]',
|
||||
}
|
||||
|
||||
const intensityClasses = {
|
||||
|
||||
@@ -21,7 +21,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
||||
className={clsx(
|
||||
'w-full px-4 py-3 bg-dark-800 border rounded-lg text-white placeholder-gray-500',
|
||||
'focus:outline-none focus:border-neon-500',
|
||||
'focus:shadow-[0_0_0_3px_rgba(0,240,255,0.1),0_0_10px_rgba(0,240,255,0.2)]',
|
||||
'focus:shadow-[0_0_0_3px_rgba(34,211,238,0.1),0_0_8px_rgba(34,211,238,0.15)]',
|
||||
'transition-all duration-200',
|
||||
error ? 'border-red-500' : 'border-dark-600',
|
||||
className
|
||||
|
||||
@@ -38,8 +38,8 @@ export const NeonButton = forwardRef<HTMLButtonElement, NeonButtonProps>(
|
||||
outline: 'bg-transparent border-2 border-neon-500 text-neon-500 hover:bg-neon-500 hover:text-dark-900',
|
||||
ghost: 'bg-transparent hover:bg-neon-500/10 text-neon-400',
|
||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||
glow: '0 0 20px rgba(0, 240, 255, 0.5)',
|
||||
glowHover: '0 0 30px rgba(0, 240, 255, 0.7)',
|
||||
glow: '0 0 12px rgba(34, 211, 238, 0.4)',
|
||||
glowHover: '0 0 18px rgba(34, 211, 238, 0.55)',
|
||||
},
|
||||
purple: {
|
||||
primary: 'bg-accent-500 hover:bg-accent-400 text-white',
|
||||
@@ -47,8 +47,8 @@ export const NeonButton = forwardRef<HTMLButtonElement, NeonButtonProps>(
|
||||
outline: 'bg-transparent border-2 border-accent-500 text-accent-500 hover:bg-accent-500 hover:text-white',
|
||||
ghost: 'bg-transparent hover:bg-accent-500/10 text-accent-400',
|
||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||
glow: '0 0 20px rgba(168, 85, 247, 0.5)',
|
||||
glowHover: '0 0 30px rgba(168, 85, 247, 0.7)',
|
||||
glow: '0 0 12px rgba(139, 92, 246, 0.4)',
|
||||
glowHover: '0 0 18px rgba(139, 92, 246, 0.55)',
|
||||
},
|
||||
pink: {
|
||||
primary: 'bg-pink-500 hover:bg-pink-400 text-white',
|
||||
@@ -56,8 +56,8 @@ export const NeonButton = forwardRef<HTMLButtonElement, NeonButtonProps>(
|
||||
outline: 'bg-transparent border-2 border-pink-500 text-pink-500 hover:bg-pink-500 hover:text-white',
|
||||
ghost: 'bg-transparent hover:bg-pink-500/10 text-pink-400',
|
||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||
glow: '0 0 20px rgba(236, 72, 153, 0.5)',
|
||||
glowHover: '0 0 30px rgba(236, 72, 153, 0.7)',
|
||||
glow: '0 0 12px rgba(244, 114, 182, 0.4)',
|
||||
glowHover: '0 0 18px rgba(244, 114, 182, 0.55)',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ export const GradientButton = forwardRef<HTMLButtonElement, GradientButtonProps>
|
||||
'relative inline-flex items-center justify-center font-semibold rounded-lg',
|
||||
'bg-gradient-to-r from-neon-500 via-accent-500 to-pink-500',
|
||||
'text-white transition-all duration-300',
|
||||
'hover:shadow-[0_0_30px_rgba(168,85,247,0.5)]',
|
||||
'hover:shadow-[0_0_20px_rgba(139,92,246,0.35)]',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
||||
'focus:outline-none focus:ring-2 focus:ring-accent-500 focus:ring-offset-2 focus:ring-offset-dark-900',
|
||||
sizeClasses[size],
|
||||
|
||||
@@ -6,36 +6,36 @@
|
||||
CSS Variables
|
||||
======================================== */
|
||||
:root {
|
||||
/* Base colors */
|
||||
--color-dark-950: #050508;
|
||||
--color-dark-900: #0a0a0f;
|
||||
--color-dark-800: #12121a;
|
||||
--color-dark-700: #1a1a24;
|
||||
--color-dark-600: #1e1e2e;
|
||||
--color-dark-500: #2a2a3a;
|
||||
/* Base colors - slightly warmer dark tones */
|
||||
--color-dark-950: #08090d;
|
||||
--color-dark-900: #0d0e14;
|
||||
--color-dark-800: #14161e;
|
||||
--color-dark-700: #1c1e28;
|
||||
--color-dark-600: #252732;
|
||||
--color-dark-500: #2e313d;
|
||||
|
||||
/* Neon cyan (primary) */
|
||||
--color-neon-500: #00f0ff;
|
||||
--color-neon-400: #22d3ee;
|
||||
--color-neon-600: #00d4e4;
|
||||
/* Soft cyan (primary) - gentler on eyes */
|
||||
--color-neon-500: #22d3ee;
|
||||
--color-neon-400: #67e8f9;
|
||||
--color-neon-600: #06b6d4;
|
||||
|
||||
/* Purple accent */
|
||||
--color-accent-500: #a855f7;
|
||||
--color-accent-600: #9333ea;
|
||||
--color-accent-700: #7c3aed;
|
||||
/* Soft violet accent */
|
||||
--color-accent-500: #8b5cf6;
|
||||
--color-accent-600: #7c3aed;
|
||||
--color-accent-700: #6d28d9;
|
||||
|
||||
/* Pink highlight */
|
||||
--color-pink-500: #ec4899;
|
||||
/* Soft pink highlight - used sparingly */
|
||||
--color-pink-500: #f472b6;
|
||||
|
||||
/* Glow colors */
|
||||
--glow-neon: 0 0 5px #00f0ff, 0 0 10px #00f0ff, 0 0 20px #00f0ff;
|
||||
--glow-neon-lg: 0 0 10px #00f0ff, 0 0 20px #00f0ff, 0 0 40px #00f0ff, 0 0 60px #00f0ff;
|
||||
--glow-purple: 0 0 5px #a855f7, 0 0 10px #a855f7, 0 0 20px #a855f7;
|
||||
--glow-pink: 0 0 5px #ec4899, 0 0 10px #ec4899, 0 0 20px #ec4899;
|
||||
/* Glow colors - reduced intensity */
|
||||
--glow-neon: 0 0 8px rgba(34, 211, 238, 0.4), 0 0 16px rgba(34, 211, 238, 0.2);
|
||||
--glow-neon-lg: 0 0 12px rgba(34, 211, 238, 0.5), 0 0 24px rgba(34, 211, 238, 0.3);
|
||||
--glow-purple: 0 0 8px rgba(139, 92, 246, 0.4), 0 0 16px rgba(139, 92, 246, 0.2);
|
||||
--glow-pink: 0 0 8px rgba(244, 114, 182, 0.4), 0 0 16px rgba(244, 114, 182, 0.2);
|
||||
|
||||
/* Text glow */
|
||||
--text-glow-neon: 0 0 10px #00f0ff, 0 0 20px #00f0ff, 0 0 30px #00f0ff;
|
||||
--text-glow-purple: 0 0 10px #a855f7, 0 0 20px #a855f7, 0 0 30px #a855f7;
|
||||
/* Text glow - subtle */
|
||||
--text-glow-neon: 0 0 8px rgba(34, 211, 238, 0.5), 0 0 16px rgba(34, 211, 238, 0.25);
|
||||
--text-glow-purple: 0 0 8px rgba(139, 92, 246, 0.5), 0 0 16px rgba(139, 92, 246, 0.25);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -49,8 +49,8 @@ body {
|
||||
@apply bg-dark-900 text-gray-100 min-h-screen antialiased;
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
background-image:
|
||||
linear-gradient(rgba(0, 240, 255, 0.02) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0, 240, 255, 0.02) 1px, transparent 1px);
|
||||
linear-gradient(rgba(34, 211, 238, 0.015) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(34, 211, 238, 0.015) 1px, transparent 1px);
|
||||
background-size: 50px 50px;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
@@ -69,16 +69,27 @@ body {
|
||||
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* Autofill styles - override browser defaults */
|
||||
input:-webkit-autofill,
|
||||
input:-webkit-autofill:hover,
|
||||
input:-webkit-autofill:focus,
|
||||
input:-webkit-autofill:active {
|
||||
-webkit-box-shadow: 0 0 0 30px #14161e inset !important;
|
||||
-webkit-text-fill-color: #fff !important;
|
||||
caret-color: #fff;
|
||||
transition: background-color 5000s ease-in-out 0s;
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Selection Styles
|
||||
======================================== */
|
||||
::selection {
|
||||
background: rgba(0, 240, 255, 0.3);
|
||||
background: rgba(34, 211, 238, 0.25);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: rgba(0, 240, 255, 0.3);
|
||||
background: rgba(34, 211, 238, 0.25);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -151,14 +162,14 @@ body {
|
||||
|
||||
.glitch::before {
|
||||
left: 2px;
|
||||
text-shadow: -2px 0 #ff00ff;
|
||||
text-shadow: -2px 0 rgba(139, 92, 246, 0.7);
|
||||
clip: rect(44px, 450px, 56px, 0);
|
||||
animation: glitch-anim 5s infinite linear alternate-reverse;
|
||||
}
|
||||
|
||||
.glitch::after {
|
||||
left: -2px;
|
||||
text-shadow: -2px 0 #00ffff, 2px 2px #ff00ff;
|
||||
text-shadow: -2px 0 rgba(34, 211, 238, 0.7), 2px 2px rgba(139, 92, 246, 0.7);
|
||||
clip: rect(44px, 450px, 56px, 0);
|
||||
animation: glitch-anim2 5s infinite linear alternate-reverse;
|
||||
}
|
||||
@@ -272,10 +283,10 @@ body {
|
||||
|
||||
@keyframes neon-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 5px #00f0ff, 0 0 10px #00f0ff, 0 0 20px #00f0ff;
|
||||
box-shadow: 0 0 6px rgba(34, 211, 238, 0.4), 0 0 12px rgba(34, 211, 238, 0.2);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 10px #00f0ff, 0 0 20px #00f0ff, 0 0 40px #00f0ff, 0 0 60px #00f0ff;
|
||||
box-shadow: 0 0 10px rgba(34, 211, 238, 0.5), 0 0 20px rgba(34, 211, 238, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,29 +308,29 @@ body {
|
||||
}
|
||||
|
||||
.glass-neon {
|
||||
background: rgba(18, 18, 26, 0.6);
|
||||
background: rgba(20, 22, 30, 0.6);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(0, 240, 255, 0.2);
|
||||
box-shadow: inset 0 0 20px rgba(0, 240, 255, 0.05);
|
||||
border: 1px solid rgba(34, 211, 238, 0.15);
|
||||
box-shadow: inset 0 0 20px rgba(34, 211, 238, 0.03);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Gradient Utilities
|
||||
======================================== */
|
||||
.gradient-neon {
|
||||
background: linear-gradient(135deg, #00f0ff, #a855f7);
|
||||
background: linear-gradient(135deg, #22d3ee, #8b5cf6);
|
||||
}
|
||||
|
||||
.gradient-neon-text {
|
||||
background: linear-gradient(135deg, #00f0ff, #a855f7);
|
||||
background: linear-gradient(135deg, #22d3ee, #8b5cf6);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.gradient-pink-purple {
|
||||
background: linear-gradient(135deg, #ec4899, #a855f7);
|
||||
background: linear-gradient(135deg, #f472b6, #8b5cf6);
|
||||
}
|
||||
|
||||
.gradient-dark {
|
||||
@@ -337,7 +348,7 @@ body {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -2px;
|
||||
background: linear-gradient(90deg, #00f0ff, #a855f7, #ec4899, #00f0ff);
|
||||
background: linear-gradient(90deg, #22d3ee, #8b5cf6, #f472b6, #22d3ee);
|
||||
background-size: 300% 300%;
|
||||
border-radius: 14px;
|
||||
z-index: -1;
|
||||
@@ -389,11 +400,11 @@ body {
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold;
|
||||
box-shadow: 0 0 10px rgba(0, 240, 255, 0.3);
|
||||
box-shadow: 0 0 8px rgba(34, 211, 238, 0.25);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
box-shadow: 0 0 20px rgba(0, 240, 255, 0.5);
|
||||
box-shadow: 0 0 14px rgba(34, 211, 238, 0.4);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@@ -416,7 +427,7 @@ body {
|
||||
.btn-neon:hover {
|
||||
@apply text-dark-900;
|
||||
background: var(--color-neon-500);
|
||||
box-shadow: 0 0 20px rgba(0, 240, 255, 0.5);
|
||||
box-shadow: 0 0 14px rgba(34, 211, 238, 0.4);
|
||||
}
|
||||
|
||||
/* Inputs */
|
||||
@@ -426,7 +437,7 @@ body {
|
||||
|
||||
.input:focus {
|
||||
@apply outline-none border-neon-500;
|
||||
box-shadow: 0 0 0 3px rgba(0, 240, 255, 0.1), 0 0 10px rgba(0, 240, 255, 0.2);
|
||||
box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.1), 0 0 8px rgba(34, 211, 238, 0.15);
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
@@ -436,7 +447,7 @@ body {
|
||||
|
||||
.card-glass {
|
||||
@apply rounded-xl p-6;
|
||||
background: rgba(18, 18, 26, 0.7);
|
||||
background: rgba(20, 22, 30, 0.7);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
@@ -448,8 +459,8 @@ body {
|
||||
|
||||
.card-hover:hover {
|
||||
@apply -translate-y-1;
|
||||
box-shadow: 0 10px 40px rgba(0, 240, 255, 0.1);
|
||||
border-color: rgba(0, 240, 255, 0.3);
|
||||
box-shadow: 0 10px 40px rgba(34, 211, 238, 0.08);
|
||||
border-color: rgba(34, 211, 238, 0.25);
|
||||
}
|
||||
|
||||
/* Links */
|
||||
@@ -481,7 +492,7 @@ body {
|
||||
|
||||
.divider-glow {
|
||||
@apply border-t border-neon-500/30;
|
||||
box-shadow: 0 0 10px rgba(0, 240, 255, 0.2);
|
||||
box-shadow: 0 0 8px rgba(34, 211, 238, 0.15);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +512,7 @@ body {
|
||||
}
|
||||
|
||||
.hover-glow:hover {
|
||||
box-shadow: 0 0 20px rgba(0, 240, 255, 0.3);
|
||||
box-shadow: 0 0 14px rgba(34, 211, 238, 0.25);
|
||||
}
|
||||
|
||||
.hover-border-glow {
|
||||
@@ -509,8 +520,8 @@ body {
|
||||
}
|
||||
|
||||
.hover-border-glow:hover {
|
||||
border-color: rgba(0, 240, 255, 0.5);
|
||||
box-shadow: 0 0 15px rgba(0, 240, 255, 0.2);
|
||||
border-color: rgba(34, 211, 238, 0.4);
|
||||
box-shadow: 0 0 12px rgba(34, 211, 238, 0.15);
|
||||
}
|
||||
|
||||
/* Stagger children animations */
|
||||
|
||||
@@ -344,14 +344,13 @@ export function AssignmentDetailPage() {
|
||||
|
||||
{/* Dispute button */}
|
||||
{assignment.can_dispute && !dispute && !showDisputeForm && (
|
||||
<NeonButton
|
||||
variant="outline"
|
||||
className="w-full border-red-500/50 text-red-400 hover:bg-red-500/10"
|
||||
<button
|
||||
className="w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg font-semibold transition-all duration-200 border-2 border-red-500/50 text-red-400 bg-transparent hover:bg-red-500/10 hover:border-red-500"
|
||||
onClick={() => setShowDisputeForm(true)}
|
||||
icon={<Flag className="w-4 h-4" />}
|
||||
>
|
||||
<Flag className="w-4 h-4" />
|
||||
Оспорить выполнение
|
||||
</NeonButton>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Dispute creation form */}
|
||||
|
||||
@@ -162,7 +162,7 @@ export function CreateMarathonPage() {
|
||||
className={`
|
||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
||||
${!isPublic
|
||||
? 'border-neon-500/50 bg-neon-500/10 shadow-[0_0_20px_rgba(0,240,255,0.1)]'
|
||||
? 'border-neon-500/50 bg-neon-500/10 shadow-[0_0_14px_rgba(34,211,238,0.08)]'
|
||||
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||
}
|
||||
`}
|
||||
@@ -192,7 +192,7 @@ export function CreateMarathonPage() {
|
||||
className={`
|
||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
||||
${isPublic
|
||||
? 'border-accent-500/50 bg-accent-500/10 shadow-[0_0_20px_rgba(168,85,247,0.1)]'
|
||||
? 'border-accent-500/50 bg-accent-500/10 shadow-[0_0_14px_rgba(139,92,246,0.08)]'
|
||||
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||
}
|
||||
`}
|
||||
@@ -230,7 +230,7 @@ export function CreateMarathonPage() {
|
||||
className={`
|
||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
||||
${gameProposalMode === 'all_participants'
|
||||
? 'border-neon-500/50 bg-neon-500/10 shadow-[0_0_20px_rgba(0,240,255,0.1)]'
|
||||
? 'border-neon-500/50 bg-neon-500/10 shadow-[0_0_14px_rgba(34,211,238,0.08)]'
|
||||
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||
}
|
||||
`}
|
||||
@@ -260,7 +260,7 @@ export function CreateMarathonPage() {
|
||||
className={`
|
||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
||||
${gameProposalMode === 'organizer_only'
|
||||
? 'border-accent-500/50 bg-accent-500/10 shadow-[0_0_20px_rgba(168,85,247,0.1)]'
|
||||
? 'border-accent-500/50 bg-accent-500/10 shadow-[0_0_14px_rgba(139,92,246,0.08)]'
|
||||
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||
}
|
||||
`}
|
||||
|
||||
@@ -7,26 +7,25 @@ export function HomePage() {
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
|
||||
|
||||
return (
|
||||
<div className="-mt-8">
|
||||
<div className="-mt-8 relative">
|
||||
{/* Global animated background - covers entire page */}
|
||||
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||
{/* Gradient orbs */}
|
||||
<div className="absolute top-[10%] left-[10%] w-[500px] h-[500px] bg-neon-500/20 rounded-full blur-[120px] animate-float" />
|
||||
<div className="absolute top-[40%] right-[10%] w-[600px] h-[600px] bg-accent-500/20 rounded-full blur-[120px] animate-float" style={{ animationDelay: '-3s' }} />
|
||||
<div className="absolute top-[60%] left-[30%] w-[700px] h-[700px] bg-pink-500/10 rounded-full blur-[150px]" />
|
||||
<div className="absolute bottom-[10%] right-[30%] w-[400px] h-[400px] bg-neon-500/15 rounded-full blur-[100px] animate-float" style={{ animationDelay: '-1.5s' }} />
|
||||
<div className="absolute bottom-[30%] left-[5%] w-[450px] h-[450px] bg-accent-500/15 rounded-full blur-[100px] animate-float" style={{ animationDelay: '-4.5s' }} />
|
||||
</div>
|
||||
|
||||
{/* Hero Section */}
|
||||
<section className="relative min-h-[80vh] flex items-center justify-center overflow-hidden">
|
||||
{/* Animated background */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
{/* Gradient orbs */}
|
||||
<div className="absolute top-1/4 -left-20 w-96 h-96 bg-neon-500/20 rounded-full blur-[100px] animate-float" />
|
||||
<div className="absolute bottom-1/4 -right-20 w-96 h-96 bg-accent-500/20 rounded-full blur-[100px] animate-float" style={{ animationDelay: '-3s' }} />
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[600px] h-[600px] bg-pink-500/10 rounded-full blur-[120px]" />
|
||||
|
||||
{/* Grid lines */}
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(0,240,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(0,240,255,0.03)_1px,transparent_1px)] bg-[size:100px_100px] [mask-image:radial-gradient(ellipse_50%_50%_at_50%_50%,black_40%,transparent_100%)]" />
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="relative z-10 max-w-5xl mx-auto text-center px-4">
|
||||
{/* Logo */}
|
||||
<div className="flex justify-center mb-8">
|
||||
<div className="relative">
|
||||
<Gamepad2 className="w-24 h-24 text-neon-500 animate-float drop-shadow-[0_0_30px_rgba(0,240,255,0.5)]" />
|
||||
<Gamepad2 className="w-24 h-24 text-neon-500 animate-float drop-shadow-[0_0_20px_rgba(34,211,238,0.4)]" />
|
||||
<div className="absolute inset-0 bg-neon-500/20 blur-2xl rounded-full" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -77,22 +76,7 @@ export function HomePage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="flex flex-wrap justify-center gap-8 mt-16">
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-neon-400">100+</div>
|
||||
<div className="text-sm text-gray-500">Марафонов</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-accent-400">500+</div>
|
||||
<div className="text-sm text-gray-500">Игроков</div>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold text-pink-400">2000+</div>
|
||||
<div className="text-sm text-gray-500">Челленджей</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll indicator */}
|
||||
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 animate-bounce">
|
||||
@@ -139,8 +123,6 @@ export function HomePage() {
|
||||
|
||||
{/* How it works */}
|
||||
<section className="py-24 relative">
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-dark-800/50 to-transparent" />
|
||||
|
||||
<div className="max-w-6xl mx-auto px-4 relative z-10">
|
||||
<div className="text-center mb-16">
|
||||
<h2 className="text-3xl md:text-4xl font-bold text-white mb-4">
|
||||
@@ -195,9 +177,9 @@ export function HomePage() {
|
||||
bg-dark-800 border-2 transition-all duration-300
|
||||
flex items-center justify-center
|
||||
group-hover:-translate-y-2
|
||||
${item.color === 'neon' ? 'border-neon-500/50 group-hover:border-neon-500 group-hover:shadow-[0_0_30px_rgba(0,240,255,0.3)]' : ''}
|
||||
${item.color === 'accent' ? 'border-accent-500/50 group-hover:border-accent-500 group-hover:shadow-[0_0_30px_rgba(168,85,247,0.3)]' : ''}
|
||||
${item.color === 'pink' ? 'border-pink-500/50 group-hover:border-pink-500 group-hover:shadow-[0_0_30px_rgba(236,72,153,0.3)]' : ''}
|
||||
${item.color === 'neon' ? 'border-neon-500/50 group-hover:border-neon-500 group-hover:shadow-[0_0_20px_rgba(34,211,238,0.25)]' : ''}
|
||||
${item.color === 'accent' ? 'border-accent-500/50 group-hover:border-accent-500 group-hover:shadow-[0_0_20px_rgba(139,92,246,0.25)]' : ''}
|
||||
${item.color === 'pink' ? 'border-pink-500/50 group-hover:border-pink-500 group-hover:shadow-[0_0_20px_rgba(244,114,182,0.25)]' : ''}
|
||||
`}
|
||||
style={{ animationDelay: `${index * 100}ms` }}
|
||||
>
|
||||
@@ -244,7 +226,7 @@ export function HomePage() {
|
||||
Готовы к соревнованиям?
|
||||
</h2>
|
||||
<p className="text-gray-300 mb-8 max-w-xl mx-auto">
|
||||
Присоединяйтесь к сотням игроков, которые уже соревнуются в игровых челленджах
|
||||
Создавайте марафоны, приглашайте друзей и соревнуйтесь в игровых челленджах
|
||||
</p>
|
||||
|
||||
{isAuthenticated ? (
|
||||
|
||||
@@ -209,7 +209,7 @@ export function LeaderboardPage() {
|
||||
relative flex items-center gap-4 p-4 rounded-xl
|
||||
transition-all duration-300 group
|
||||
${isCurrentUser
|
||||
? 'bg-neon-500/10 border border-neon-500/30 shadow-[0_0_20px_rgba(0,240,255,0.1)]'
|
||||
? 'bg-neon-500/10 border border-neon-500/30 shadow-[0_0_14px_rgba(34,211,238,0.08)]'
|
||||
: `${rankConfig.bg} border ${rankConfig.border} hover:border-neon-500/20`
|
||||
}
|
||||
`}
|
||||
|
||||
@@ -5,8 +5,8 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { marathonsApi } from '@/api'
|
||||
import { NeonButton, Input } from '@/components/ui'
|
||||
import { Gamepad2, LogIn, AlertCircle } from 'lucide-react'
|
||||
import { NeonButton, Input, GlassCard } from '@/components/ui'
|
||||
import { Gamepad2, LogIn, AlertCircle, Trophy, Users, Zap, Target } from 'lucide-react'
|
||||
|
||||
const loginSchema = z.object({
|
||||
login: z.string().min(3, 'Логин должен быть не менее 3 символов'),
|
||||
@@ -52,6 +52,13 @@ export function LoginPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const features = [
|
||||
{ icon: <Trophy className="w-5 h-5" />, text: 'Соревнуйтесь с друзьями' },
|
||||
{ icon: <Target className="w-5 h-5" />, text: 'Выполняйте челленджи' },
|
||||
{ icon: <Zap className="w-5 h-5" />, text: 'Зарабатывайте очки' },
|
||||
{ icon: <Users className="w-5 h-5" />, text: 'Создавайте марафоны' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-[80vh] flex items-center justify-center px-4 -mt-8">
|
||||
{/* Background effects */}
|
||||
@@ -60,74 +67,113 @@ export function LoginPage() {
|
||||
<div className="absolute bottom-1/4 -right-32 w-96 h-96 bg-accent-500/10 rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative w-full max-w-md">
|
||||
{/* Card */}
|
||||
<div className="glass-neon rounded-2xl p-8 animate-scale-in">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="flex justify-center mb-4">
|
||||
<div className="w-16 h-16 rounded-2xl bg-neon-500/10 border border-neon-500/30 flex items-center justify-center">
|
||||
<Gamepad2 className="w-8 h-8 text-neon-500" />
|
||||
{/* Bento Grid */}
|
||||
<div className="relative w-full max-w-4xl">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 animate-scale-in">
|
||||
{/* Branding Block (left) */}
|
||||
<GlassCard className="p-8 flex flex-col justify-center relative overflow-hidden" variant="neon">
|
||||
{/* Background decoration */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute -top-20 -left-20 w-48 h-48 bg-neon-500/20 rounded-full blur-[60px]" />
|
||||
<div className="absolute -bottom-20 -right-20 w-48 h-48 bg-accent-500/20 rounded-full blur-[60px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
{/* Logo */}
|
||||
<div className="flex justify-center md:justify-start mb-6">
|
||||
<div className="w-20 h-20 rounded-2xl bg-neon-500/10 border border-neon-500/30 flex items-center justify-center shadow-[0_0_24px_rgba(34,211,238,0.25)]">
|
||||
<Gamepad2 className="w-10 h-10 text-neon-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="text-3xl md:text-4xl font-bold text-white mb-2 text-center md:text-left">
|
||||
Game Marathon
|
||||
</h1>
|
||||
<p className="text-gray-400 mb-8 text-center md:text-left">
|
||||
Платформа для игровых соревнований
|
||||
</p>
|
||||
|
||||
{/* Features */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-2 p-3 rounded-xl bg-dark-700/50 border border-dark-600"
|
||||
>
|
||||
<div className="w-8 h-8 rounded-lg bg-neon-500/20 flex items-center justify-center text-neon-400">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<span className="text-sm text-gray-300">{feature.text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white mb-2">Добро пожаловать!</h1>
|
||||
<p className="text-gray-400">Войдите, чтобы продолжить</p>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
|
||||
{(submitError || error) && (
|
||||
<div className="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/30 rounded-xl text-red-400 text-sm animate-shake">
|
||||
<AlertCircle className="w-5 h-5 flex-shrink-0" />
|
||||
<span>{submitError || error}</span>
|
||||
</div>
|
||||
)}
|
||||
{/* Form Block (right) */}
|
||||
<GlassCard className="p-8">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-8">
|
||||
<h2 className="text-2xl font-bold text-white mb-2">Добро пожаловать!</h2>
|
||||
<p className="text-gray-400">Войдите, чтобы продолжить</p>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Логин"
|
||||
placeholder="Введите логин"
|
||||
error={errors.login?.message}
|
||||
autoComplete="username"
|
||||
{...register('login')}
|
||||
/>
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
|
||||
{(submitError || error) && (
|
||||
<div className="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/30 rounded-xl text-red-400 text-sm animate-shake">
|
||||
<AlertCircle className="w-5 h-5 flex-shrink-0" />
|
||||
<span>{submitError || error}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Input
|
||||
label="Пароль"
|
||||
type="password"
|
||||
placeholder="Введите пароль"
|
||||
error={errors.password?.message}
|
||||
autoComplete="current-password"
|
||||
{...register('password')}
|
||||
/>
|
||||
<Input
|
||||
label="Логин"
|
||||
placeholder="Введите логин"
|
||||
error={errors.login?.message}
|
||||
autoComplete="username"
|
||||
{...register('login')}
|
||||
/>
|
||||
|
||||
<NeonButton
|
||||
type="submit"
|
||||
className="w-full"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
icon={<LogIn className="w-5 h-5" />}
|
||||
>
|
||||
Войти
|
||||
</NeonButton>
|
||||
</form>
|
||||
<Input
|
||||
label="Пароль"
|
||||
type="password"
|
||||
placeholder="Введите пароль"
|
||||
error={errors.password?.message}
|
||||
autoComplete="current-password"
|
||||
{...register('password')}
|
||||
/>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-6 pt-6 border-t border-dark-600 text-center">
|
||||
<p className="text-gray-400 text-sm">
|
||||
Нет аккаунта?{' '}
|
||||
<Link
|
||||
to="/register"
|
||||
className="text-neon-400 hover:text-neon-300 transition-colors font-medium"
|
||||
<NeonButton
|
||||
type="submit"
|
||||
className="w-full"
|
||||
size="lg"
|
||||
isLoading={isLoading}
|
||||
icon={<LogIn className="w-5 h-5" />}
|
||||
>
|
||||
Зарегистрироваться
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
Войти
|
||||
</NeonButton>
|
||||
</form>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-6 pt-6 border-t border-dark-600 text-center">
|
||||
<p className="text-gray-400 text-sm">
|
||||
Нет аккаунта?{' '}
|
||||
<Link
|
||||
to="/register"
|
||||
className="text-neon-400 hover:text-neon-300 transition-colors font-medium"
|
||||
>
|
||||
Зарегистрироваться
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute -top-4 -right-4 w-24 h-24 border border-neon-500/20 rounded-2xl -z-10" />
|
||||
<div className="absolute -bottom-4 -left-4 w-32 h-32 border border-accent-500/20 rounded-2xl -z-10" />
|
||||
<div className="absolute -top-4 -right-4 w-24 h-24 border border-neon-500/20 rounded-2xl -z-10 hidden md:block" />
|
||||
<div className="absolute -bottom-4 -left-4 w-32 h-32 border border-accent-500/20 rounded-2xl -z-10 hidden md:block" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -189,7 +189,7 @@ export function MarathonPage() {
|
||||
<div className="relative rounded-2xl overflow-hidden mb-8">
|
||||
{/* Background */}
|
||||
<div className="absolute inset-0 bg-gradient-to-br from-neon-500/10 via-dark-800 to-accent-500/10" />
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(0,240,255,0.03)_1px,transparent_1px),linear-gradient(90deg,rgba(0,240,255,0.03)_1px,transparent_1px)] bg-[size:50px_50px]" />
|
||||
<div className="absolute inset-0 bg-[linear-gradient(rgba(34,211,238,0.02)_1px,transparent_1px),linear-gradient(90deg,rgba(34,211,238,0.02)_1px,transparent_1px)] bg-[size:50px_50px]" />
|
||||
|
||||
<div className="relative p-8">
|
||||
<div className="flex flex-col md:flex-row justify-between items-start gap-6">
|
||||
@@ -254,15 +254,14 @@ export function MarathonPage() {
|
||||
</Link>
|
||||
|
||||
{marathon.status === 'active' && isOrganizer && (
|
||||
<NeonButton
|
||||
variant="secondary"
|
||||
<button
|
||||
onClick={handleFinish}
|
||||
isLoading={isFinishing}
|
||||
icon={<Flag className="w-4 h-4" />}
|
||||
className="!text-yellow-400 !border-yellow-500/30 hover:!bg-yellow-500/10"
|
||||
disabled={isFinishing}
|
||||
className="inline-flex items-center justify-center gap-2 px-4 py-2.5 rounded-lg font-semibold transition-all duration-200 border border-yellow-500/30 bg-dark-600 text-yellow-400 hover:bg-yellow-500/10 hover:border-yellow-500/50 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{isFinishing ? <Loader2 className="w-4 h-4 animate-spin" /> : <Flag className="w-4 h-4" />}
|
||||
Завершить
|
||||
</NeonButton>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{canDelete && (
|
||||
|
||||
@@ -216,7 +216,7 @@ export function MarathonsPage() {
|
||||
return (
|
||||
<Link key={marathon.id} to={`/marathons/${marathon.id}`}>
|
||||
<div
|
||||
className="group glass rounded-xl p-5 border border-dark-600 transition-all duration-300 hover:border-neon-500/30 hover:-translate-y-0.5 hover:shadow-[0_10px_40px_rgba(0,240,255,0.1)]"
|
||||
className="group glass rounded-xl p-5 border border-dark-600 transition-all duration-300 hover:border-neon-500/30 hover:-translate-y-0.5 hover:shadow-[0_10px_40px_rgba(34,211,238,0.08)]"
|
||||
style={{ animationDelay: `${index * 50}ms` }}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
|
||||
@@ -263,7 +263,7 @@ export function ProfilePage() {
|
||||
<button
|
||||
onClick={handleAvatarClick}
|
||||
disabled={isUploadingAvatar}
|
||||
className="relative w-28 h-28 rounded-2xl overflow-hidden bg-dark-700 border-2 border-neon-500/30 hover:border-neon-500 transition-all group-hover:shadow-[0_0_30px_rgba(0,240,255,0.3)]"
|
||||
className="relative w-28 h-28 rounded-2xl overflow-hidden bg-dark-700 border-2 border-neon-500/30 hover:border-neon-500 transition-all group-hover:shadow-[0_0_20px_rgba(34,211,238,0.25)]"
|
||||
>
|
||||
{displayAvatar ? (
|
||||
<img
|
||||
@@ -452,7 +452,6 @@ export function ProfilePage() {
|
||||
|
||||
{!showPasswordForm ? (
|
||||
<NeonButton
|
||||
variant="secondary"
|
||||
onClick={() => setShowPasswordForm(true)}
|
||||
icon={<KeyRound className="w-4 h-4" />}
|
||||
>
|
||||
|
||||
@@ -5,8 +5,8 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { z } from 'zod'
|
||||
import { useAuthStore } from '@/store/auth'
|
||||
import { marathonsApi } from '@/api'
|
||||
import { NeonButton, Input } from '@/components/ui'
|
||||
import { Gamepad2, UserPlus, AlertCircle } from 'lucide-react'
|
||||
import { NeonButton, Input, GlassCard } from '@/components/ui'
|
||||
import { Gamepad2, UserPlus, AlertCircle, Trophy, Users, Zap, Target, Sparkles } from 'lucide-react'
|
||||
|
||||
const registerSchema = z.object({
|
||||
login: z
|
||||
@@ -68,99 +68,172 @@ export function RegisterPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const features = [
|
||||
{ icon: <Trophy className="w-5 h-5" />, text: 'Соревнуйтесь с друзьями' },
|
||||
{ icon: <Target className="w-5 h-5" />, text: 'Выполняйте челленджи' },
|
||||
{ icon: <Zap className="w-5 h-5" />, text: 'Зарабатывайте очки' },
|
||||
{ icon: <Users className="w-5 h-5" />, text: 'Создавайте марафоны' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="min-h-[80vh] flex items-center justify-center px-4 -mt-8">
|
||||
<div className="min-h-[80vh] flex items-center justify-center px-4 py-8">
|
||||
{/* Background effects */}
|
||||
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute top-1/3 -right-32 w-96 h-96 bg-accent-500/10 rounded-full blur-[100px]" />
|
||||
<div className="absolute bottom-1/3 -left-32 w-96 h-96 bg-neon-500/10 rounded-full blur-[100px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative w-full max-w-md">
|
||||
{/* Card */}
|
||||
<div className="glass-neon rounded-2xl p-8 animate-scale-in">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="flex justify-center mb-4">
|
||||
<div className="w-16 h-16 rounded-2xl bg-accent-500/10 border border-accent-500/30 flex items-center justify-center">
|
||||
<Gamepad2 className="w-8 h-8 text-accent-500" />
|
||||
{/* Bento Grid */}
|
||||
<div className="relative w-full max-w-4xl">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 animate-scale-in">
|
||||
{/* Branding Block (left) */}
|
||||
<GlassCard className="p-8 flex flex-col justify-center relative overflow-hidden order-2 md:order-1" variant="neon">
|
||||
{/* Background decoration */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
<div className="absolute -top-20 -left-20 w-48 h-48 bg-accent-500/20 rounded-full blur-[60px]" />
|
||||
<div className="absolute -bottom-20 -right-20 w-48 h-48 bg-neon-500/20 rounded-full blur-[60px]" />
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
{/* Logo */}
|
||||
<div className="flex justify-center md:justify-start mb-6">
|
||||
<div className="w-20 h-20 rounded-2xl bg-accent-500/10 border border-accent-500/30 flex items-center justify-center shadow-[0_0_40px_rgba(147,51,234,0.3)]">
|
||||
<Gamepad2 className="w-10 h-10 text-accent-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<h1 className="text-3xl md:text-4xl font-bold text-white mb-2 text-center md:text-left">
|
||||
Game Marathon
|
||||
</h1>
|
||||
<p className="text-gray-400 mb-6 text-center md:text-left">
|
||||
Присоединяйтесь к игровому сообществу
|
||||
</p>
|
||||
|
||||
{/* Benefits */}
|
||||
<div className="p-4 rounded-xl bg-dark-700/50 border border-dark-600 mb-6">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Sparkles className="w-5 h-5 text-accent-400" />
|
||||
<span className="text-white font-semibold">Что вас ждет:</span>
|
||||
</div>
|
||||
<ul className="space-y-2 text-sm text-gray-400">
|
||||
<li className="flex items-center gap-2">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-neon-500" />
|
||||
Создавайте игровые марафоны
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-accent-500" />
|
||||
Выполняйте уникальные челленджи
|
||||
</li>
|
||||
<li className="flex items-center gap-2">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-pink-500" />
|
||||
Соревнуйтесь за первое место
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{/* Features */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{features.map((feature, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex items-center gap-2 p-3 rounded-xl bg-dark-700/50 border border-dark-600"
|
||||
>
|
||||
<div className="w-8 h-8 rounded-lg bg-accent-500/20 flex items-center justify-center text-accent-400">
|
||||
{feature.icon}
|
||||
</div>
|
||||
<span className="text-sm text-gray-300">{feature.text}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white mb-2">Создать аккаунт</h1>
|
||||
<p className="text-gray-400">Присоединяйтесь к игровому марафону</p>
|
||||
</div>
|
||||
</GlassCard>
|
||||
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
{(submitError || error) && (
|
||||
<div className="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/30 rounded-xl text-red-400 text-sm animate-shake">
|
||||
<AlertCircle className="w-5 h-5 flex-shrink-0" />
|
||||
<span>{submitError || error}</span>
|
||||
{/* Form Block (right) */}
|
||||
<GlassCard className="p-8 order-1 md:order-2">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-6">
|
||||
<div className="flex justify-center mb-4 md:hidden">
|
||||
<div className="w-16 h-16 rounded-2xl bg-accent-500/10 border border-accent-500/30 flex items-center justify-center">
|
||||
<Gamepad2 className="w-8 h-8 text-accent-500" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<h2 className="text-2xl font-bold text-white mb-2">Создать аккаунт</h2>
|
||||
<p className="text-gray-400">Начните играть уже сегодня</p>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="Логин"
|
||||
placeholder="Придумайте логин"
|
||||
error={errors.login?.message}
|
||||
autoComplete="username"
|
||||
{...register('login')}
|
||||
/>
|
||||
{/* Form */}
|
||||
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
|
||||
{(submitError || error) && (
|
||||
<div className="flex items-center gap-3 p-4 bg-red-500/10 border border-red-500/30 rounded-xl text-red-400 text-sm animate-shake">
|
||||
<AlertCircle className="w-5 h-5 flex-shrink-0" />
|
||||
<span>{submitError || error}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Input
|
||||
label="Никнейм"
|
||||
placeholder="Как вас называть?"
|
||||
error={errors.nickname?.message}
|
||||
{...register('nickname')}
|
||||
/>
|
||||
<Input
|
||||
label="Логин"
|
||||
placeholder="Придумайте логин"
|
||||
error={errors.login?.message}
|
||||
autoComplete="username"
|
||||
{...register('login')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Пароль"
|
||||
type="password"
|
||||
placeholder="Придумайте пароль"
|
||||
error={errors.password?.message}
|
||||
autoComplete="new-password"
|
||||
{...register('password')}
|
||||
/>
|
||||
<Input
|
||||
label="Никнейм"
|
||||
placeholder="Как вас называть?"
|
||||
error={errors.nickname?.message}
|
||||
{...register('nickname')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="Подтвердите пароль"
|
||||
type="password"
|
||||
placeholder="Повторите пароль"
|
||||
error={errors.confirmPassword?.message}
|
||||
autoComplete="new-password"
|
||||
{...register('confirmPassword')}
|
||||
/>
|
||||
<Input
|
||||
label="Пароль"
|
||||
type="password"
|
||||
placeholder="Придумайте пароль"
|
||||
error={errors.password?.message}
|
||||
autoComplete="new-password"
|
||||
{...register('password')}
|
||||
/>
|
||||
|
||||
<NeonButton
|
||||
type="submit"
|
||||
className="w-full"
|
||||
size="lg"
|
||||
color="purple"
|
||||
isLoading={isLoading}
|
||||
icon={<UserPlus className="w-5 h-5" />}
|
||||
>
|
||||
Зарегистрироваться
|
||||
</NeonButton>
|
||||
</form>
|
||||
<Input
|
||||
label="Подтвердите пароль"
|
||||
type="password"
|
||||
placeholder="Повторите пароль"
|
||||
error={errors.confirmPassword?.message}
|
||||
autoComplete="new-password"
|
||||
{...register('confirmPassword')}
|
||||
/>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-6 pt-6 border-t border-dark-600 text-center">
|
||||
<p className="text-gray-400 text-sm">
|
||||
Уже есть аккаунт?{' '}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-accent-400 hover:text-accent-300 transition-colors font-medium"
|
||||
<NeonButton
|
||||
type="submit"
|
||||
className="w-full"
|
||||
size="lg"
|
||||
color="purple"
|
||||
isLoading={isLoading}
|
||||
icon={<UserPlus className="w-5 h-5" />}
|
||||
>
|
||||
Войти
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
Зарегистрироваться
|
||||
</NeonButton>
|
||||
</form>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="mt-6 pt-6 border-t border-dark-600 text-center">
|
||||
<p className="text-gray-400 text-sm">
|
||||
Уже есть аккаунт?{' '}
|
||||
<Link
|
||||
to="/login"
|
||||
className="text-accent-400 hover:text-accent-300 transition-colors font-medium"
|
||||
>
|
||||
Войти
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</GlassCard>
|
||||
</div>
|
||||
|
||||
{/* Decorative elements */}
|
||||
<div className="absolute -top-4 -left-4 w-24 h-24 border border-accent-500/20 rounded-2xl -z-10" />
|
||||
<div className="absolute -bottom-4 -right-4 w-32 h-32 border border-neon-500/20 rounded-2xl -z-10" />
|
||||
<div className="absolute -top-4 -left-4 w-24 h-24 border border-accent-500/20 rounded-2xl -z-10 hidden md:block" />
|
||||
<div className="absolute -bottom-4 -right-4 w-32 h-32 border border-neon-500/20 rounded-2xl -z-10 hidden md:block" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -123,7 +123,7 @@ export function UserProfilePage() {
|
||||
<div className="flex items-center gap-6">
|
||||
{/* Аватар */}
|
||||
<div className="relative">
|
||||
<div className="w-24 h-24 rounded-2xl overflow-hidden bg-dark-700 border-2 border-neon-500/30 shadow-[0_0_20px_rgba(0,240,255,0.2)]">
|
||||
<div className="w-24 h-24 rounded-2xl overflow-hidden bg-dark-700 border-2 border-neon-500/30 shadow-[0_0_14px_rgba(34,211,238,0.15)]">
|
||||
{avatarBlobUrl ? (
|
||||
<img
|
||||
src={avatarBlobUrl}
|
||||
|
||||
Reference in New Issue
Block a user