Fix UI
This commit is contained in:
434
auth-pages-backup.tsx
Normal file
434
auth-pages-backup.tsx
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
// ============================================
|
||||||
|
// AUTH PAGES BACKUP - Bento Style
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// LOGIN PAGE (LoginPage.tsx)
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { useAuthStore } from '@/store/auth'
|
||||||
|
import { marathonsApi } from '@/api'
|
||||||
|
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 символов'),
|
||||||
|
password: z.string().min(6, 'Пароль должен быть не менее 6 символов'),
|
||||||
|
})
|
||||||
|
|
||||||
|
type LoginForm = z.infer<typeof loginSchema>
|
||||||
|
|
||||||
|
export function LoginPage() {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { login, isLoading, error, clearError, consumePendingInviteCode } = useAuthStore()
|
||||||
|
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<LoginForm>({
|
||||||
|
resolver: zodResolver(loginSchema),
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSubmit = async (data: LoginForm) => {
|
||||||
|
setSubmitError(null)
|
||||||
|
clearError()
|
||||||
|
try {
|
||||||
|
await login(data)
|
||||||
|
|
||||||
|
// Check for pending invite code
|
||||||
|
const pendingCode = consumePendingInviteCode()
|
||||||
|
if (pendingCode) {
|
||||||
|
try {
|
||||||
|
const marathon = await marathonsApi.join(pendingCode)
|
||||||
|
navigate(`/marathons/${marathon.id}`)
|
||||||
|
return
|
||||||
|
} catch {
|
||||||
|
// If join fails (already member, etc), just go to marathons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate('/marathons')
|
||||||
|
} catch {
|
||||||
|
setSubmitError(error || 'Ошибка входа')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */}
|
||||||
|
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||||
|
<div className="absolute top-1/4 -left-32 w-96 h-96 bg-neon-500/10 rounded-full blur-[100px]" />
|
||||||
|
<div className="absolute bottom-1/4 -right-32 w-96 h-96 bg-accent-500/10 rounded-full blur-[100px]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Bento Grid */}
|
||||||
|
<div className="relative w-full max-w-4xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
{/* 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_40px_rgba(0,240,255,0.3)]">
|
||||||
|
<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>
|
||||||
|
</GlassCard>
|
||||||
|
|
||||||
|
{/* 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>
|
||||||
|
|
||||||
|
{/* 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="Логин"
|
||||||
|
placeholder="Введите логин"
|
||||||
|
error={errors.login?.message}
|
||||||
|
autoComplete="username"
|
||||||
|
{...register('login')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Пароль"
|
||||||
|
type="password"
|
||||||
|
placeholder="Введите пароль"
|
||||||
|
error={errors.password?.message}
|
||||||
|
autoComplete="current-password"
|
||||||
|
{...register('password')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NeonButton
|
||||||
|
type="submit"
|
||||||
|
className="w-full"
|
||||||
|
size="lg"
|
||||||
|
isLoading={isLoading}
|
||||||
|
icon={<LogIn className="w-5 h-5" />}
|
||||||
|
>
|
||||||
|
Войти
|
||||||
|
</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 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// REGISTER PAGE (RegisterPage.tsx)
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Link, useNavigate } from 'react-router-dom'
|
||||||
|
import { useForm } from 'react-hook-form'
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { useAuthStore } from '@/store/auth'
|
||||||
|
import { marathonsApi } from '@/api'
|
||||||
|
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
|
||||||
|
.string()
|
||||||
|
.min(3, 'Логин должен быть не менее 3 символов')
|
||||||
|
.max(50, 'Логин должен быть не более 50 символов')
|
||||||
|
.regex(/^[a-zA-Z0-9_]+$/, 'Логин может содержать только буквы, цифры и подчёркивания'),
|
||||||
|
nickname: z
|
||||||
|
.string()
|
||||||
|
.min(2, 'Никнейм должен быть не менее 2 символов')
|
||||||
|
.max(50, 'Никнейм должен быть не более 50 символов'),
|
||||||
|
password: z.string().min(6, 'Пароль должен быть не менее 6 символов'),
|
||||||
|
confirmPassword: z.string(),
|
||||||
|
}).refine((data) => data.password === data.confirmPassword, {
|
||||||
|
message: 'Пароли не совпадают',
|
||||||
|
path: ['confirmPassword'],
|
||||||
|
})
|
||||||
|
|
||||||
|
type RegisterForm = z.infer<typeof registerSchema>
|
||||||
|
|
||||||
|
export function RegisterPage() {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const { register: registerUser, isLoading, error, clearError, consumePendingInviteCode } = useAuthStore()
|
||||||
|
const [submitError, setSubmitError] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
handleSubmit,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<RegisterForm>({
|
||||||
|
resolver: zodResolver(registerSchema),
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSubmit = async (data: RegisterForm) => {
|
||||||
|
setSubmitError(null)
|
||||||
|
clearError()
|
||||||
|
try {
|
||||||
|
await registerUser({
|
||||||
|
login: data.login,
|
||||||
|
password: data.password,
|
||||||
|
nickname: data.nickname,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Check for pending invite code
|
||||||
|
const pendingCode = consumePendingInviteCode()
|
||||||
|
if (pendingCode) {
|
||||||
|
try {
|
||||||
|
const marathon = await marathonsApi.join(pendingCode)
|
||||||
|
navigate(`/marathons/${marathon.id}`)
|
||||||
|
return
|
||||||
|
} catch {
|
||||||
|
// If join fails, just go to marathons
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate('/marathons')
|
||||||
|
} catch {
|
||||||
|
setSubmitError(error || 'Ошибка регистрации')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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>
|
||||||
|
|
||||||
|
{/* Bento Grid */}
|
||||||
|
<div className="relative w-full max-w-4xl">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
{/* 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>
|
||||||
|
</GlassCard>
|
||||||
|
|
||||||
|
{/* 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>
|
||||||
|
|
||||||
|
{/* 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.login?.message}
|
||||||
|
autoComplete="username"
|
||||||
|
{...register('login')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Никнейм"
|
||||||
|
placeholder="Как вас называть?"
|
||||||
|
error={errors.nickname?.message}
|
||||||
|
{...register('nickname')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Пароль"
|
||||||
|
type="password"
|
||||||
|
placeholder="Придумайте пароль"
|
||||||
|
error={errors.password?.message}
|
||||||
|
autoComplete="new-password"
|
||||||
|
{...register('password')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="Подтвердите пароль"
|
||||||
|
type="password"
|
||||||
|
placeholder="Повторите пароль"
|
||||||
|
error={errors.confirmPassword?.message}
|
||||||
|
autoComplete="new-password"
|
||||||
|
{...register('confirmPassword')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NeonButton
|
||||||
|
type="submit"
|
||||||
|
className="w-full"
|
||||||
|
size="lg"
|
||||||
|
color="purple"
|
||||||
|
isLoading={isLoading}
|
||||||
|
icon={<UserPlus className="w-5 h-5" />}
|
||||||
|
>
|
||||||
|
Зарегистрироваться
|
||||||
|
</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 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>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -42,7 +42,7 @@ const EVENT_COLORS: Record<EventType, {
|
|||||||
gradient: 'from-purple-500/20 via-purple-500/10 to-transparent',
|
gradient: 'from-purple-500/20 via-purple-500/10 to-transparent',
|
||||||
border: 'border-purple-500/50',
|
border: 'border-purple-500/50',
|
||||||
text: 'text-purple-400',
|
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',
|
iconBg: 'bg-purple-500/20',
|
||||||
},
|
},
|
||||||
jackpot: {
|
jackpot: {
|
||||||
@@ -56,7 +56,7 @@ const EVENT_COLORS: Record<EventType, {
|
|||||||
gradient: 'from-neon-500/20 via-neon-500/10 to-transparent',
|
gradient: 'from-neon-500/20 via-neon-500/10 to-transparent',
|
||||||
border: 'border-neon-500/50',
|
border: 'border-neon-500/50',
|
||||||
text: 'text-neon-400',
|
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',
|
iconBg: 'bg-neon-500/20',
|
||||||
},
|
},
|
||||||
game_choice: {
|
game_choice: {
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ export function SpinWheel({ games, onSpin, onSpinComplete, disabled }: SpinWheel
|
|||||||
{/* Neon border glow */}
|
{/* Neon border glow */}
|
||||||
<div className={`absolute inset-0 border-2 rounded-lg transition-all duration-300 ${
|
<div className={`absolute inset-0 border-2 rounded-lg transition-all duration-300 ${
|
||||||
isSpinning
|
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-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_10px_rgba(0,240,255,0.2)]'
|
: 'border-neon-500/50 shadow-[0_0_8px_rgba(34,211,238,0.15)]'
|
||||||
}`} />
|
}`} />
|
||||||
|
|
||||||
{/* Side arrows */}
|
{/* 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
|
w-16 h-16 rounded-xl overflow-hidden flex-shrink-0
|
||||||
border transition-all duration-300
|
border transition-all duration-300
|
||||||
${isSelected
|
${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'
|
: 'border-dark-600'
|
||||||
}
|
}
|
||||||
`}>
|
`}>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function Layout() {
|
|||||||
className="flex items-center gap-3 group"
|
className="flex items-center gap-3 group"
|
||||||
>
|
>
|
||||||
<div className="relative">
|
<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>
|
</div>
|
||||||
<span className="text-xl font-bold text-white font-display tracking-wider glitch-hover">
|
<span className="text-xl font-bold text-white font-display tracking-wider glitch-hover">
|
||||||
МАРАФОН
|
МАРАФОН
|
||||||
@@ -109,7 +109,7 @@ export function Layout() {
|
|||||||
</Link>
|
</Link>
|
||||||
<Link
|
<Link
|
||||||
to="/register"
|
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>
|
</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',
|
'inline-flex items-center justify-center font-medium rounded-lg transition-all duration-200',
|
||||||
'disabled:opacity-50 disabled:cursor-not-allowed',
|
'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-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-red-600 hover:bg-red-700 text-white': variant === 'danger',
|
||||||
'bg-transparent hover:bg-dark-700 text-gray-300 hover:text-white': variant === 'ghost',
|
'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
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'bg-dark-800 rounded-xl p-6 border border-dark-600',
|
'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
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -91,10 +91,10 @@ export function StatsCard({
|
|||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div>
|
<div className="min-w-0 flex-1">
|
||||||
<p className="text-sm text-gray-400 mb-1">{label}</p>
|
<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}
|
{value}
|
||||||
</p>
|
</p>
|
||||||
{trend && (
|
{trend && (
|
||||||
@@ -111,7 +111,7 @@ export function StatsCard({
|
|||||||
{icon && (
|
{icon && (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
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]
|
iconColorClasses[color]
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -143,17 +143,17 @@ export function FeatureCard({
|
|||||||
neon: {
|
neon: {
|
||||||
icon: 'text-neon-500 bg-neon-500/10 group-hover:bg-neon-500/20',
|
icon: 'text-neon-500 bg-neon-500/10 group-hover:bg-neon-500/20',
|
||||||
border: 'group-hover:border-neon-500/50',
|
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: {
|
purple: {
|
||||||
icon: 'text-accent-500 bg-accent-500/10 group-hover:bg-accent-500/20',
|
icon: 'text-accent-500 bg-accent-500/10 group-hover:bg-accent-500/20',
|
||||||
border: 'group-hover:border-accent-500/50',
|
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: {
|
pink: {
|
||||||
icon: 'text-pink-500 bg-pink-500/10 group-hover:bg-pink-500/20',
|
icon: 'text-pink-500 bg-pink-500/10 group-hover:bg-pink-500/20',
|
||||||
border: 'group-hover:border-pink-500/50',
|
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 = {
|
const glowClasses = {
|
||||||
neon: 'neon-text',
|
neon: 'neon-text',
|
||||||
purple: 'neon-text-purple',
|
purple: 'neon-text-purple',
|
||||||
pink: '[text-shadow:0_0_10px_#ec4899,0_0_20px_#ec4899,0_0_30px_#ec4899]',
|
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_10px_rgba(255,255,255,0.5),0_0_20px_rgba(255,255,255,0.3)]',
|
white: '[text-shadow:0_0_8px_rgba(255,255,255,0.4),0_0_16px_rgba(255,255,255,0.2)]',
|
||||||
}
|
}
|
||||||
|
|
||||||
const intensityClasses = {
|
const intensityClasses = {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(
|
|||||||
className={clsx(
|
className={clsx(
|
||||||
'w-full px-4 py-3 bg-dark-800 border rounded-lg text-white placeholder-gray-500',
|
'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: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',
|
'transition-all duration-200',
|
||||||
error ? 'border-red-500' : 'border-dark-600',
|
error ? 'border-red-500' : 'border-dark-600',
|
||||||
className
|
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',
|
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',
|
ghost: 'bg-transparent hover:bg-neon-500/10 text-neon-400',
|
||||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||||
glow: '0 0 20px rgba(0, 240, 255, 0.5)',
|
glow: '0 0 12px rgba(34, 211, 238, 0.4)',
|
||||||
glowHover: '0 0 30px rgba(0, 240, 255, 0.7)',
|
glowHover: '0 0 18px rgba(34, 211, 238, 0.55)',
|
||||||
},
|
},
|
||||||
purple: {
|
purple: {
|
||||||
primary: 'bg-accent-500 hover:bg-accent-400 text-white',
|
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',
|
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',
|
ghost: 'bg-transparent hover:bg-accent-500/10 text-accent-400',
|
||||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||||
glow: '0 0 20px rgba(168, 85, 247, 0.5)',
|
glow: '0 0 12px rgba(139, 92, 246, 0.4)',
|
||||||
glowHover: '0 0 30px rgba(168, 85, 247, 0.7)',
|
glowHover: '0 0 18px rgba(139, 92, 246, 0.55)',
|
||||||
},
|
},
|
||||||
pink: {
|
pink: {
|
||||||
primary: 'bg-pink-500 hover:bg-pink-400 text-white',
|
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',
|
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',
|
ghost: 'bg-transparent hover:bg-pink-500/10 text-pink-400',
|
||||||
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
danger: 'bg-red-600 hover:bg-red-700 text-white',
|
||||||
glow: '0 0 20px rgba(236, 72, 153, 0.5)',
|
glow: '0 0 12px rgba(244, 114, 182, 0.4)',
|
||||||
glowHover: '0 0 30px rgba(236, 72, 153, 0.7)',
|
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',
|
'relative inline-flex items-center justify-center font-semibold rounded-lg',
|
||||||
'bg-gradient-to-r from-neon-500 via-accent-500 to-pink-500',
|
'bg-gradient-to-r from-neon-500 via-accent-500 to-pink-500',
|
||||||
'text-white transition-all duration-300',
|
'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',
|
'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',
|
'focus:outline-none focus:ring-2 focus:ring-accent-500 focus:ring-offset-2 focus:ring-offset-dark-900',
|
||||||
sizeClasses[size],
|
sizeClasses[size],
|
||||||
|
|||||||
@@ -6,36 +6,36 @@
|
|||||||
CSS Variables
|
CSS Variables
|
||||||
======================================== */
|
======================================== */
|
||||||
:root {
|
:root {
|
||||||
/* Base colors */
|
/* Base colors - slightly warmer dark tones */
|
||||||
--color-dark-950: #050508;
|
--color-dark-950: #08090d;
|
||||||
--color-dark-900: #0a0a0f;
|
--color-dark-900: #0d0e14;
|
||||||
--color-dark-800: #12121a;
|
--color-dark-800: #14161e;
|
||||||
--color-dark-700: #1a1a24;
|
--color-dark-700: #1c1e28;
|
||||||
--color-dark-600: #1e1e2e;
|
--color-dark-600: #252732;
|
||||||
--color-dark-500: #2a2a3a;
|
--color-dark-500: #2e313d;
|
||||||
|
|
||||||
/* Neon cyan (primary) */
|
/* Soft cyan (primary) - gentler on eyes */
|
||||||
--color-neon-500: #00f0ff;
|
--color-neon-500: #22d3ee;
|
||||||
--color-neon-400: #22d3ee;
|
--color-neon-400: #67e8f9;
|
||||||
--color-neon-600: #00d4e4;
|
--color-neon-600: #06b6d4;
|
||||||
|
|
||||||
/* Purple accent */
|
/* Soft violet accent */
|
||||||
--color-accent-500: #a855f7;
|
--color-accent-500: #8b5cf6;
|
||||||
--color-accent-600: #9333ea;
|
--color-accent-600: #7c3aed;
|
||||||
--color-accent-700: #7c3aed;
|
--color-accent-700: #6d28d9;
|
||||||
|
|
||||||
/* Pink highlight */
|
/* Soft pink highlight - used sparingly */
|
||||||
--color-pink-500: #ec4899;
|
--color-pink-500: #f472b6;
|
||||||
|
|
||||||
/* Glow colors */
|
/* Glow colors - reduced intensity */
|
||||||
--glow-neon: 0 0 5px #00f0ff, 0 0 10px #00f0ff, 0 0 20px #00f0ff;
|
--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 10px #00f0ff, 0 0 20px #00f0ff, 0 0 40px #00f0ff, 0 0 60px #00f0ff;
|
--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 5px #a855f7, 0 0 10px #a855f7, 0 0 20px #a855f7;
|
--glow-purple: 0 0 8px rgba(139, 92, 246, 0.4), 0 0 16px rgba(139, 92, 246, 0.2);
|
||||||
--glow-pink: 0 0 5px #ec4899, 0 0 10px #ec4899, 0 0 20px #ec4899;
|
--glow-pink: 0 0 8px rgba(244, 114, 182, 0.4), 0 0 16px rgba(244, 114, 182, 0.2);
|
||||||
|
|
||||||
/* Text glow */
|
/* Text glow - subtle */
|
||||||
--text-glow-neon: 0 0 10px #00f0ff, 0 0 20px #00f0ff, 0 0 30px #00f0ff;
|
--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 10px #a855f7, 0 0 20px #a855f7, 0 0 30px #a855f7;
|
--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;
|
@apply bg-dark-900 text-gray-100 min-h-screen antialiased;
|
||||||
font-family: 'Inter', system-ui, sans-serif;
|
font-family: 'Inter', system-ui, sans-serif;
|
||||||
background-image:
|
background-image:
|
||||||
linear-gradient(rgba(0, 240, 255, 0.02) 1px, transparent 1px),
|
linear-gradient(rgba(34, 211, 238, 0.015) 1px, transparent 1px),
|
||||||
linear-gradient(90deg, rgba(0, 240, 255, 0.02) 1px, transparent 1px);
|
linear-gradient(90deg, rgba(34, 211, 238, 0.015) 1px, transparent 1px);
|
||||||
background-size: 50px 50px;
|
background-size: 50px 50px;
|
||||||
background-attachment: fixed;
|
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");
|
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 Styles
|
||||||
======================================== */
|
======================================== */
|
||||||
::selection {
|
::selection {
|
||||||
background: rgba(0, 240, 255, 0.3);
|
background: rgba(34, 211, 238, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-moz-selection {
|
::-moz-selection {
|
||||||
background: rgba(0, 240, 255, 0.3);
|
background: rgba(34, 211, 238, 0.25);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,14 +162,14 @@ body {
|
|||||||
|
|
||||||
.glitch::before {
|
.glitch::before {
|
||||||
left: 2px;
|
left: 2px;
|
||||||
text-shadow: -2px 0 #ff00ff;
|
text-shadow: -2px 0 rgba(139, 92, 246, 0.7);
|
||||||
clip: rect(44px, 450px, 56px, 0);
|
clip: rect(44px, 450px, 56px, 0);
|
||||||
animation: glitch-anim 5s infinite linear alternate-reverse;
|
animation: glitch-anim 5s infinite linear alternate-reverse;
|
||||||
}
|
}
|
||||||
|
|
||||||
.glitch::after {
|
.glitch::after {
|
||||||
left: -2px;
|
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);
|
clip: rect(44px, 450px, 56px, 0);
|
||||||
animation: glitch-anim2 5s infinite linear alternate-reverse;
|
animation: glitch-anim2 5s infinite linear alternate-reverse;
|
||||||
}
|
}
|
||||||
@@ -272,10 +283,10 @@ body {
|
|||||||
|
|
||||||
@keyframes neon-pulse {
|
@keyframes neon-pulse {
|
||||||
0%, 100% {
|
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% {
|
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 {
|
.glass-neon {
|
||||||
background: rgba(18, 18, 26, 0.6);
|
background: rgba(20, 22, 30, 0.6);
|
||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
-webkit-backdrop-filter: blur(12px);
|
-webkit-backdrop-filter: blur(12px);
|
||||||
border: 1px solid rgba(0, 240, 255, 0.2);
|
border: 1px solid rgba(34, 211, 238, 0.15);
|
||||||
box-shadow: inset 0 0 20px rgba(0, 240, 255, 0.05);
|
box-shadow: inset 0 0 20px rgba(34, 211, 238, 0.03);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
Gradient Utilities
|
Gradient Utilities
|
||||||
======================================== */
|
======================================== */
|
||||||
.gradient-neon {
|
.gradient-neon {
|
||||||
background: linear-gradient(135deg, #00f0ff, #a855f7);
|
background: linear-gradient(135deg, #22d3ee, #8b5cf6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gradient-neon-text {
|
.gradient-neon-text {
|
||||||
background: linear-gradient(135deg, #00f0ff, #a855f7);
|
background: linear-gradient(135deg, #22d3ee, #8b5cf6);
|
||||||
-webkit-background-clip: text;
|
-webkit-background-clip: text;
|
||||||
-webkit-text-fill-color: transparent;
|
-webkit-text-fill-color: transparent;
|
||||||
background-clip: text;
|
background-clip: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gradient-pink-purple {
|
.gradient-pink-purple {
|
||||||
background: linear-gradient(135deg, #ec4899, #a855f7);
|
background: linear-gradient(135deg, #f472b6, #8b5cf6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gradient-dark {
|
.gradient-dark {
|
||||||
@@ -337,7 +348,7 @@ body {
|
|||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: -2px;
|
inset: -2px;
|
||||||
background: linear-gradient(90deg, #00f0ff, #a855f7, #ec4899, #00f0ff);
|
background: linear-gradient(90deg, #22d3ee, #8b5cf6, #f472b6, #22d3ee);
|
||||||
background-size: 300% 300%;
|
background-size: 300% 300%;
|
||||||
border-radius: 14px;
|
border-radius: 14px;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
@@ -389,11 +400,11 @@ body {
|
|||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
@apply bg-neon-500 hover:bg-neon-400 text-dark-900 font-semibold;
|
@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 {
|
.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 {
|
.btn-secondary {
|
||||||
@@ -416,7 +427,7 @@ body {
|
|||||||
.btn-neon:hover {
|
.btn-neon:hover {
|
||||||
@apply text-dark-900;
|
@apply text-dark-900;
|
||||||
background: var(--color-neon-500);
|
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 */
|
/* Inputs */
|
||||||
@@ -426,7 +437,7 @@ body {
|
|||||||
|
|
||||||
.input:focus {
|
.input:focus {
|
||||||
@apply outline-none border-neon-500;
|
@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 */
|
/* Cards */
|
||||||
@@ -436,7 +447,7 @@ body {
|
|||||||
|
|
||||||
.card-glass {
|
.card-glass {
|
||||||
@apply rounded-xl p-6;
|
@apply rounded-xl p-6;
|
||||||
background: rgba(18, 18, 26, 0.7);
|
background: rgba(20, 22, 30, 0.7);
|
||||||
backdrop-filter: blur(12px);
|
backdrop-filter: blur(12px);
|
||||||
-webkit-backdrop-filter: blur(12px);
|
-webkit-backdrop-filter: blur(12px);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
@@ -448,8 +459,8 @@ body {
|
|||||||
|
|
||||||
.card-hover:hover {
|
.card-hover:hover {
|
||||||
@apply -translate-y-1;
|
@apply -translate-y-1;
|
||||||
box-shadow: 0 10px 40px rgba(0, 240, 255, 0.1);
|
box-shadow: 0 10px 40px rgba(34, 211, 238, 0.08);
|
||||||
border-color: rgba(0, 240, 255, 0.3);
|
border-color: rgba(34, 211, 238, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Links */
|
/* Links */
|
||||||
@@ -481,7 +492,7 @@ body {
|
|||||||
|
|
||||||
.divider-glow {
|
.divider-glow {
|
||||||
@apply border-t border-neon-500/30;
|
@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 {
|
.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 {
|
.hover-border-glow {
|
||||||
@@ -509,8 +520,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hover-border-glow:hover {
|
.hover-border-glow:hover {
|
||||||
border-color: rgba(0, 240, 255, 0.5);
|
border-color: rgba(34, 211, 238, 0.4);
|
||||||
box-shadow: 0 0 15px rgba(0, 240, 255, 0.2);
|
box-shadow: 0 0 12px rgba(34, 211, 238, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stagger children animations */
|
/* Stagger children animations */
|
||||||
|
|||||||
@@ -344,14 +344,13 @@ export function AssignmentDetailPage() {
|
|||||||
|
|
||||||
{/* Dispute button */}
|
{/* Dispute button */}
|
||||||
{assignment.can_dispute && !dispute && !showDisputeForm && (
|
{assignment.can_dispute && !dispute && !showDisputeForm && (
|
||||||
<NeonButton
|
<button
|
||||||
variant="outline"
|
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"
|
||||||
className="w-full border-red-500/50 text-red-400 hover:bg-red-500/10"
|
|
||||||
onClick={() => setShowDisputeForm(true)}
|
onClick={() => setShowDisputeForm(true)}
|
||||||
icon={<Flag className="w-4 h-4" />}
|
|
||||||
>
|
>
|
||||||
|
<Flag className="w-4 h-4" />
|
||||||
Оспорить выполнение
|
Оспорить выполнение
|
||||||
</NeonButton>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Dispute creation form */}
|
{/* Dispute creation form */}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export function CreateMarathonPage() {
|
|||||||
className={`
|
className={`
|
||||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
||||||
${!isPublic
|
${!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'
|
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
@@ -192,7 +192,7 @@ export function CreateMarathonPage() {
|
|||||||
className={`
|
className={`
|
||||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
relative p-4 rounded-xl border-2 transition-all duration-300 text-left group
|
||||||
${isPublic
|
${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'
|
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
@@ -230,7 +230,7 @@ export function CreateMarathonPage() {
|
|||||||
className={`
|
className={`
|
||||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
||||||
${gameProposalMode === 'all_participants'
|
${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'
|
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
@@ -260,7 +260,7 @@ export function CreateMarathonPage() {
|
|||||||
className={`
|
className={`
|
||||||
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
relative p-4 rounded-xl border-2 transition-all duration-300 text-left
|
||||||
${gameProposalMode === 'organizer_only'
|
${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'
|
: 'border-dark-600 bg-dark-700/50 hover:border-dark-500'
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|||||||
@@ -7,26 +7,25 @@ export function HomePage() {
|
|||||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="-mt-8">
|
<div className="-mt-8 relative">
|
||||||
{/* Hero Section */}
|
{/* Global animated background - covers entire page */}
|
||||||
<section className="relative min-h-[80vh] flex items-center justify-center overflow-hidden">
|
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
||||||
{/* Animated background */}
|
|
||||||
<div className="absolute inset-0 overflow-hidden">
|
|
||||||
{/* Gradient orbs */}
|
{/* 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 top-[10%] left-[10%] w-[500px] h-[500px] bg-neon-500/20 rounded-full blur-[120px] 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-[40%] right-[10%] w-[600px] h-[600px] bg-accent-500/20 rounded-full blur-[120px] 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]" />
|
<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' }} />
|
||||||
{/* Grid lines */}
|
<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 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>
|
</div>
|
||||||
|
|
||||||
|
{/* Hero Section */}
|
||||||
|
<section className="relative min-h-[80vh] flex items-center justify-center overflow-hidden">
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div className="relative z-10 max-w-5xl mx-auto text-center px-4">
|
<div className="relative z-10 max-w-5xl mx-auto text-center px-4">
|
||||||
{/* Logo */}
|
{/* Logo */}
|
||||||
<div className="flex justify-center mb-8">
|
<div className="flex justify-center mb-8">
|
||||||
<div className="relative">
|
<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 className="absolute inset-0 bg-neon-500/20 blur-2xl rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -77,21 +76,6 @@ export function HomePage() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
|
|
||||||
{/* Scroll indicator */}
|
{/* Scroll indicator */}
|
||||||
@@ -139,8 +123,6 @@ export function HomePage() {
|
|||||||
|
|
||||||
{/* How it works */}
|
{/* How it works */}
|
||||||
<section className="py-24 relative">
|
<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="max-w-6xl mx-auto px-4 relative z-10">
|
||||||
<div className="text-center mb-16">
|
<div className="text-center mb-16">
|
||||||
<h2 className="text-3xl md:text-4xl font-bold text-white mb-4">
|
<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
|
bg-dark-800 border-2 transition-all duration-300
|
||||||
flex items-center justify-center
|
flex items-center justify-center
|
||||||
group-hover:-translate-y-2
|
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 === '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_30px_rgba(168,85,247,0.3)]' : ''}
|
${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_30px_rgba(236,72,153,0.3)]' : ''}
|
${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` }}
|
style={{ animationDelay: `${index * 100}ms` }}
|
||||||
>
|
>
|
||||||
@@ -244,7 +226,7 @@ export function HomePage() {
|
|||||||
Готовы к соревнованиям?
|
Готовы к соревнованиям?
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-gray-300 mb-8 max-w-xl mx-auto">
|
<p className="text-gray-300 mb-8 max-w-xl mx-auto">
|
||||||
Присоединяйтесь к сотням игроков, которые уже соревнуются в игровых челленджах
|
Создавайте марафоны, приглашайте друзей и соревнуйтесь в игровых челленджах
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{isAuthenticated ? (
|
{isAuthenticated ? (
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export function LeaderboardPage() {
|
|||||||
relative flex items-center gap-4 p-4 rounded-xl
|
relative flex items-center gap-4 p-4 rounded-xl
|
||||||
transition-all duration-300 group
|
transition-all duration-300 group
|
||||||
${isCurrentUser
|
${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`
|
: `${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 { z } from 'zod'
|
||||||
import { useAuthStore } from '@/store/auth'
|
import { useAuthStore } from '@/store/auth'
|
||||||
import { marathonsApi } from '@/api'
|
import { marathonsApi } from '@/api'
|
||||||
import { NeonButton, Input } from '@/components/ui'
|
import { NeonButton, Input, GlassCard } from '@/components/ui'
|
||||||
import { Gamepad2, LogIn, AlertCircle } from 'lucide-react'
|
import { Gamepad2, LogIn, AlertCircle, Trophy, Users, Zap, Target } from 'lucide-react'
|
||||||
|
|
||||||
const loginSchema = z.object({
|
const loginSchema = z.object({
|
||||||
login: z.string().min(3, 'Логин должен быть не менее 3 символов'),
|
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 (
|
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 -mt-8">
|
||||||
{/* Background effects */}
|
{/* Background effects */}
|
||||||
@@ -60,17 +67,55 @@ export function LoginPage() {
|
|||||||
<div className="absolute bottom-1/4 -right-32 w-96 h-96 bg-accent-500/10 rounded-full blur-[100px]" />
|
<div className="absolute bottom-1/4 -right-32 w-96 h-96 bg-accent-500/10 rounded-full blur-[100px]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative w-full max-w-md">
|
{/* Bento Grid */}
|
||||||
{/* Card */}
|
<div className="relative w-full max-w-4xl">
|
||||||
<div className="glass-neon rounded-2xl p-8 animate-scale-in">
|
<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>
|
||||||
|
</GlassCard>
|
||||||
|
|
||||||
|
{/* Form Block (right) */}
|
||||||
|
<GlassCard className="p-8">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-8">
|
<div className="text-center mb-8">
|
||||||
<div className="flex justify-center mb-4">
|
<h2 className="text-2xl font-bold text-white mb-2">Добро пожаловать!</h2>
|
||||||
<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" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<h1 className="text-2xl font-bold text-white mb-2">Добро пожаловать!</h1>
|
|
||||||
<p className="text-gray-400">Войдите, чтобы продолжить</p>
|
<p className="text-gray-400">Войдите, чтобы продолжить</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -123,11 +168,12 @@ export function LoginPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</GlassCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Decorative elements */}
|
{/* 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 -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" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ export function MarathonPage() {
|
|||||||
<div className="relative rounded-2xl overflow-hidden mb-8">
|
<div className="relative rounded-2xl overflow-hidden mb-8">
|
||||||
{/* Background */}
|
{/* 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-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="relative p-8">
|
||||||
<div className="flex flex-col md:flex-row justify-between items-start gap-6">
|
<div className="flex flex-col md:flex-row justify-between items-start gap-6">
|
||||||
@@ -254,15 +254,14 @@ export function MarathonPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{marathon.status === 'active' && isOrganizer && (
|
{marathon.status === 'active' && isOrganizer && (
|
||||||
<NeonButton
|
<button
|
||||||
variant="secondary"
|
|
||||||
onClick={handleFinish}
|
onClick={handleFinish}
|
||||||
isLoading={isFinishing}
|
disabled={isFinishing}
|
||||||
icon={<Flag className="w-4 h-4" />}
|
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"
|
||||||
className="!text-yellow-400 !border-yellow-500/30 hover:!bg-yellow-500/10"
|
|
||||||
>
|
>
|
||||||
|
{isFinishing ? <Loader2 className="w-4 h-4 animate-spin" /> : <Flag className="w-4 h-4" />}
|
||||||
Завершить
|
Завершить
|
||||||
</NeonButton>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{canDelete && (
|
{canDelete && (
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export function MarathonsPage() {
|
|||||||
return (
|
return (
|
||||||
<Link key={marathon.id} to={`/marathons/${marathon.id}`}>
|
<Link key={marathon.id} to={`/marathons/${marathon.id}`}>
|
||||||
<div
|
<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` }}
|
style={{ animationDelay: `${index * 50}ms` }}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ export function ProfilePage() {
|
|||||||
<button
|
<button
|
||||||
onClick={handleAvatarClick}
|
onClick={handleAvatarClick}
|
||||||
disabled={isUploadingAvatar}
|
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 ? (
|
{displayAvatar ? (
|
||||||
<img
|
<img
|
||||||
@@ -452,7 +452,6 @@ export function ProfilePage() {
|
|||||||
|
|
||||||
{!showPasswordForm ? (
|
{!showPasswordForm ? (
|
||||||
<NeonButton
|
<NeonButton
|
||||||
variant="secondary"
|
|
||||||
onClick={() => setShowPasswordForm(true)}
|
onClick={() => setShowPasswordForm(true)}
|
||||||
icon={<KeyRound className="w-4 h-4" />}
|
icon={<KeyRound className="w-4 h-4" />}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { zodResolver } from '@hookform/resolvers/zod'
|
|||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
import { useAuthStore } from '@/store/auth'
|
import { useAuthStore } from '@/store/auth'
|
||||||
import { marathonsApi } from '@/api'
|
import { marathonsApi } from '@/api'
|
||||||
import { NeonButton, Input } from '@/components/ui'
|
import { NeonButton, Input, GlassCard } from '@/components/ui'
|
||||||
import { Gamepad2, UserPlus, AlertCircle } from 'lucide-react'
|
import { Gamepad2, UserPlus, AlertCircle, Trophy, Users, Zap, Target, Sparkles } from 'lucide-react'
|
||||||
|
|
||||||
const registerSchema = z.object({
|
const registerSchema = z.object({
|
||||||
login: z
|
login: z
|
||||||
@@ -68,26 +68,98 @@ 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 (
|
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 */}
|
{/* Background effects */}
|
||||||
<div className="fixed inset-0 overflow-hidden pointer-events-none">
|
<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 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 className="absolute bottom-1/3 -left-32 w-96 h-96 bg-neon-500/10 rounded-full blur-[100px]" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="relative w-full max-w-md">
|
{/* Bento Grid */}
|
||||||
{/* Card */}
|
<div className="relative w-full max-w-4xl">
|
||||||
<div className="glass-neon rounded-2xl p-8 animate-scale-in">
|
<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>
|
||||||
|
</GlassCard>
|
||||||
|
|
||||||
|
{/* Form Block (right) */}
|
||||||
|
<GlassCard className="p-8 order-1 md:order-2">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="text-center mb-8">
|
<div className="text-center mb-6">
|
||||||
<div className="flex justify-center mb-4">
|
<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">
|
<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" />
|
<Gamepad2 className="w-8 h-8 text-accent-500" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl font-bold text-white mb-2">Создать аккаунт</h1>
|
<h2 className="text-2xl font-bold text-white mb-2">Создать аккаунт</h2>
|
||||||
<p className="text-gray-400">Присоединяйтесь к игровому марафону</p>
|
<p className="text-gray-400">Начните играть уже сегодня</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Form */}
|
{/* Form */}
|
||||||
@@ -156,11 +228,12 @@ export function RegisterPage() {
|
|||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</GlassCard>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Decorative elements */}
|
{/* 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 -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" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export function UserProfilePage() {
|
|||||||
<div className="flex items-center gap-6">
|
<div className="flex items-center gap-6">
|
||||||
{/* Аватар */}
|
{/* Аватар */}
|
||||||
<div className="relative">
|
<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 ? (
|
{avatarBlobUrl ? (
|
||||||
<img
|
<img
|
||||||
src={avatarBlobUrl}
|
src={avatarBlobUrl}
|
||||||
|
|||||||
@@ -7,42 +7,42 @@ export default {
|
|||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
// Base dark colors
|
// Base dark colors - slightly warmer tones
|
||||||
dark: {
|
dark: {
|
||||||
950: '#050508',
|
950: '#08090d',
|
||||||
900: '#0a0a0f',
|
900: '#0d0e14',
|
||||||
800: '#12121a',
|
800: '#14161e',
|
||||||
700: '#1a1a24',
|
700: '#1c1e28',
|
||||||
600: '#1e1e2e',
|
600: '#252732',
|
||||||
500: '#2a2a3a',
|
500: '#2e313d',
|
||||||
},
|
},
|
||||||
// Neon cyan (primary)
|
// Soft cyan (primary) - gentler on eyes
|
||||||
neon: {
|
neon: {
|
||||||
50: '#ecfeff',
|
50: '#ecfeff',
|
||||||
100: '#cffafe',
|
100: '#cffafe',
|
||||||
200: '#a5f3fc',
|
200: '#a5f3fc',
|
||||||
300: '#67e8f9',
|
300: '#67e8f9',
|
||||||
400: '#22d3ee',
|
400: '#67e8f9',
|
||||||
500: '#00f0ff',
|
500: '#22d3ee',
|
||||||
600: '#00d4e4',
|
600: '#06b6d4',
|
||||||
700: '#00a8b8',
|
700: '#0891b2',
|
||||||
800: '#007c8a',
|
800: '#155e75',
|
||||||
900: '#005a64',
|
900: '#164e63',
|
||||||
},
|
},
|
||||||
// Purple accent
|
// Soft violet accent
|
||||||
accent: {
|
accent: {
|
||||||
50: '#faf5ff',
|
50: '#f5f3ff',
|
||||||
100: '#f3e8ff',
|
100: '#ede9fe',
|
||||||
200: '#e9d5ff',
|
200: '#ddd6fe',
|
||||||
300: '#d8b4fe',
|
300: '#c4b5fd',
|
||||||
400: '#c084fc',
|
400: '#a78bfa',
|
||||||
500: '#a855f7',
|
500: '#8b5cf6',
|
||||||
600: '#9333ea',
|
600: '#7c3aed',
|
||||||
700: '#7c3aed',
|
700: '#6d28d9',
|
||||||
800: '#6b21a8',
|
800: '#5b21b6',
|
||||||
900: '#581c87',
|
900: '#4c1d95',
|
||||||
},
|
},
|
||||||
// Pink highlight
|
// Soft pink highlight - used sparingly
|
||||||
pink: {
|
pink: {
|
||||||
400: '#f472b6',
|
400: '#f472b6',
|
||||||
500: '#ec4899',
|
500: '#ec4899',
|
||||||
@@ -54,12 +54,12 @@ export default {
|
|||||||
100: '#cffafe',
|
100: '#cffafe',
|
||||||
200: '#a5f3fc',
|
200: '#a5f3fc',
|
||||||
300: '#67e8f9',
|
300: '#67e8f9',
|
||||||
400: '#22d3ee',
|
400: '#67e8f9',
|
||||||
500: '#00f0ff',
|
500: '#22d3ee',
|
||||||
600: '#00d4e4',
|
600: '#06b6d4',
|
||||||
700: '#00a8b8',
|
700: '#0891b2',
|
||||||
800: '#007c8a',
|
800: '#155e75',
|
||||||
900: '#005a64',
|
900: '#164e63',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
@@ -123,10 +123,10 @@ export default {
|
|||||||
},
|
},
|
||||||
'glow-pulse': {
|
'glow-pulse': {
|
||||||
'0%, 100%': {
|
'0%, 100%': {
|
||||||
boxShadow: '0 0 5px var(--glow-color, #00f0ff), 0 0 10px var(--glow-color, #00f0ff), 0 0 20px var(--glow-color, #00f0ff)'
|
boxShadow: '0 0 6px rgba(34, 211, 238, 0.4), 0 0 12px rgba(34, 211, 238, 0.2)'
|
||||||
},
|
},
|
||||||
'50%': {
|
'50%': {
|
||||||
boxShadow: '0 0 10px var(--glow-color, #00f0ff), 0 0 20px var(--glow-color, #00f0ff), 0 0 40px var(--glow-color, #00f0ff)'
|
boxShadow: '0 0 10px rgba(34, 211, 238, 0.5), 0 0 20px rgba(34, 211, 238, 0.3)'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'float': {
|
'float': {
|
||||||
@@ -165,10 +165,10 @@ export default {
|
|||||||
},
|
},
|
||||||
'pulse-neon': {
|
'pulse-neon': {
|
||||||
'0%, 100%': {
|
'0%, 100%': {
|
||||||
textShadow: '0 0 5px var(--neon-color, #00f0ff), 0 0 10px var(--neon-color, #00f0ff)'
|
textShadow: '0 0 6px rgba(34, 211, 238, 0.5), 0 0 12px rgba(34, 211, 238, 0.25)'
|
||||||
},
|
},
|
||||||
'50%': {
|
'50%': {
|
||||||
textShadow: '0 0 10px var(--neon-color, #00f0ff), 0 0 20px var(--neon-color, #00f0ff), 0 0 30px var(--neon-color, #00f0ff)'
|
textShadow: '0 0 10px rgba(34, 211, 238, 0.6), 0 0 18px rgba(34, 211, 238, 0.35)'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'border-flow': {
|
'border-flow': {
|
||||||
@@ -182,7 +182,7 @@ export default {
|
|||||||
},
|
},
|
||||||
'blink-caret': {
|
'blink-caret': {
|
||||||
'from, to': { borderColor: 'transparent' },
|
'from, to': { borderColor: 'transparent' },
|
||||||
'50%': { borderColor: '#00f0ff' },
|
'50%': { borderColor: '#22d3ee' },
|
||||||
},
|
},
|
||||||
'shake': {
|
'shake': {
|
||||||
'0%, 100%': { transform: 'translateX(0)' },
|
'0%, 100%': { transform: 'translateX(0)' },
|
||||||
@@ -197,21 +197,21 @@ export default {
|
|||||||
backgroundImage: {
|
backgroundImage: {
|
||||||
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
|
||||||
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
|
||||||
'neon-glow': 'linear-gradient(90deg, #00f0ff, #a855f7, #00f0ff)',
|
'neon-glow': 'linear-gradient(90deg, #22d3ee, #8b5cf6, #22d3ee)',
|
||||||
'cyber-grid': `
|
'cyber-grid': `
|
||||||
linear-gradient(rgba(0, 240, 255, 0.03) 1px, transparent 1px),
|
linear-gradient(rgba(34, 211, 238, 0.02) 1px, transparent 1px),
|
||||||
linear-gradient(90deg, rgba(0, 240, 255, 0.03) 1px, transparent 1px)
|
linear-gradient(90deg, rgba(34, 211, 238, 0.02) 1px, transparent 1px)
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
backgroundSize: {
|
backgroundSize: {
|
||||||
'grid': '50px 50px',
|
'grid': '50px 50px',
|
||||||
},
|
},
|
||||||
boxShadow: {
|
boxShadow: {
|
||||||
'neon': '0 0 5px #00f0ff, 0 0 10px #00f0ff, 0 0 20px #00f0ff',
|
'neon': '0 0 8px rgba(34, 211, 238, 0.4), 0 0 16px rgba(34, 211, 238, 0.2)',
|
||||||
'neon-lg': '0 0 10px #00f0ff, 0 0 20px #00f0ff, 0 0 40px #00f0ff, 0 0 60px #00f0ff',
|
'neon-lg': '0 0 12px rgba(34, 211, 238, 0.5), 0 0 24px rgba(34, 211, 238, 0.3)',
|
||||||
'neon-purple': '0 0 5px #a855f7, 0 0 10px #a855f7, 0 0 20px #a855f7',
|
'neon-purple': '0 0 8px rgba(139, 92, 246, 0.4), 0 0 16px rgba(139, 92, 246, 0.2)',
|
||||||
'neon-pink': '0 0 5px #ec4899, 0 0 10px #ec4899, 0 0 20px #ec4899',
|
'neon-pink': '0 0 8px rgba(244, 114, 182, 0.4), 0 0 16px rgba(244, 114, 182, 0.2)',
|
||||||
'inner-glow': 'inset 0 0 20px rgba(0, 240, 255, 0.1)',
|
'inner-glow': 'inset 0 0 20px rgba(34, 211, 238, 0.06)',
|
||||||
'glass': '0 8px 32px 0 rgba(0, 0, 0, 0.37)',
|
'glass': '0 8px 32px 0 rgba(0, 0, 0, 0.37)',
|
||||||
},
|
},
|
||||||
backdropBlur: {
|
backdropBlur: {
|
||||||
|
|||||||
Reference in New Issue
Block a user