This commit is contained in:
2025-12-17 14:53:56 +07:00
parent 332491454d
commit debdd66458
22 changed files with 853 additions and 310 deletions

View File

@@ -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: {

View File

@@ -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'
}
`}>

View File

@@ -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>

View File

@@ -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',

View File

@@ -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
)}
>

View File

@@ -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)]',
},
}

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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],

View File

@@ -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 */

View File

@@ -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 */}

View File

@@ -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'
}
`}

View File

@@ -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 ? (

View File

@@ -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`
}
`}

View File

@@ -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>
)

View File

@@ -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 && (

View File

@@ -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">

View File

@@ -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" />}
>

View File

@@ -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>
)

View File

@@ -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}