feat: update UI components and add new assets

- Update App, CompetitionPage, CryptoFeatureCard components with improvements
- Enhance Header and LoginPage components
- Update styling in index.css and API configurations
- Add new hand background and hand image assets
- Remove old logo.png file
- Update server configuration
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: tinkle-community <tinklefund@gmail.com>
This commit is contained in:
icy
2025-11-02 06:23:06 +08:00
parent 2c0bb26154
commit c24807ff18
11 changed files with 274 additions and 201 deletions

View File

@@ -31,6 +31,8 @@ export function CompetitionPage() {
setIsModalOpen(true);
} catch (error) {
console.error('Failed to fetch trader config:', error);
// 对于未登录用户,不显示详细配置,这是正常行为
// 竞赛页面主要用于查看排行榜和基本信息
}
};

View File

@@ -30,8 +30,8 @@ export const CryptoFeatureCard = React.forwardRef<HTMLDivElement, CryptoFeatureC
<div
className={cn(
"relative h-full overflow-hidden border-2 transition-all duration-300 rounded-xl",
"bg-gradient-to-br from-[#0C0E12] to-[#1E2329]",
"border-[#2B3139] hover:border-[#F0B90B]/50",
"bg-gradient-to-br from-[#000000] to-[#0A0A0A]",
"border-[#1A1A1A] hover:border-[#F0B90B]/50",
isHovered && "shadow-[0_0_20px_rgba(240,185,11,0.2)]",
className
)}
@@ -61,11 +61,11 @@ export const CryptoFeatureCard = React.forwardRef<HTMLDivElement, CryptoFeatureC
<div className="relative z-10 p-8 flex flex-col h-full">
{/* Icon container */}
<motion.div
className={cn(
"mb-6 inline-flex items-center justify-center w-16 h-16 rounded-xl",
"bg-gradient-to-br from-[#F0B90B]/20 to-[#F0B90B]/5",
"border border-[#F0B90B]/30"
)}
className="mb-6 inline-flex items-center justify-center w-16 h-16 rounded-xl"
style={{
background: 'linear-gradient(135deg, rgba(240, 185, 11, 0.2) 0%, rgba(240, 185, 11, 0.05) 100%)',
border: '1px solid rgba(240, 185, 11, 0.3)'
}}
animate={{
scale: isHovered ? 1.1 : 1,
boxShadow: isHovered
@@ -74,14 +74,14 @@ export const CryptoFeatureCard = React.forwardRef<HTMLDivElement, CryptoFeatureC
}}
transition={{ duration: 0.3 }}
>
<div className="text-[#F0B90B]">{icon}</div>
<div style={{ color: 'var(--brand-yellow)' }}>{icon}</div>
</motion.div>
{/* Title */}
<h3 className="text-2xl font-bold text-[#EAECEF] mb-3">{title}</h3>
<h3 className="text-2xl font-bold mb-3" style={{ color: 'var(--brand-light-gray)' }}>{title}</h3>
{/* Description */}
<p className="text-[#848E9C] mb-6 flex-grow leading-relaxed">{description}</p>
<p className="mb-6 flex-grow leading-relaxed" style={{ color: 'var(--text-secondary)' }}>{description}</p>
{/* Features list */}
<div className="space-y-3 mb-6">
@@ -95,11 +95,11 @@ export const CryptoFeatureCard = React.forwardRef<HTMLDivElement, CryptoFeatureC
className="flex items-start gap-3"
>
<div className="mt-0.5 flex-shrink-0">
<div className="w-5 h-5 rounded-full bg-[#F0B90B]/20 flex items-center justify-center">
<Check className="w-3 h-3 text-[#F0B90B]" />
<div className="w-5 h-5 rounded-full flex items-center justify-center" style={{ background: 'rgba(240, 185, 11, 0.2)' }}>
<Check className="w-3 h-3" style={{ color: 'var(--brand-yellow)' }} />
</div>
</div>
<span className="text-sm text-[#EAECEF]">{feature}</span>
<span className="text-sm" style={{ color: 'var(--brand-light-gray)' }}>{feature}</span>
</motion.div>
))}
</div>

View File

@@ -15,7 +15,7 @@ export function Header({ simple = false }: HeaderProps) {
{/* Left - Logo and Title */}
<div className="flex items-center gap-3">
<div className="flex items-center justify-center">
<img src="/images/logo.png" alt="NoFx Logo" className="w-8 h-8" />
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-8 h-8" />
</div>
<div>
<h1 className="text-xl font-bold" style={{ color: '#EAECEF' }}>

View File

@@ -2,8 +2,7 @@ import React, { useState } from 'react';
import { useAuth } from '../contexts/AuthContext';
import { useLanguage } from '../contexts/LanguageContext';
import { t } from '../i18n/translations';
import { Header } from './Header';
import { ArrowLeft } from 'lucide-react';
import HeaderBar from './landing/HeaderBar';
export function LoginPage() {
const { language } = useLanguage();
@@ -51,43 +50,44 @@ export function LoginPage() {
};
return (
<div className="min-h-screen" style={{ background: '#0B0E11' }}>
<Header simple />
<div className="min-h-screen" style={{ background: 'var(--brand-black)' }}>
<HeaderBar
onLoginClick={() => {}}
isLoggedIn={false}
isHomePage={false}
currentPage="login"
language={language}
onLanguageChange={(lang) => {}}
onPageChange={(page) => {
console.log('LoginPage onPageChange called with:', page);
if (page === 'competition') {
window.location.href = '/competition';
}
}}
/>
<div className="flex items-center justify-center" style={{ minHeight: 'calc(100vh - 80px)' }}>
<div className="flex items-center justify-center pt-20" style={{ minHeight: 'calc(100vh - 80px)' }}>
<div className="w-full max-w-md">
{/* Back to Home */}
<button
onClick={() => {
window.history.pushState({}, '', '/');
window.dispatchEvent(new PopStateEvent('popstate'));
}}
className="flex items-center gap-2 mb-6 text-sm hover:text-[#F0B90B] transition-colors"
style={{ color: '#848E9C' }}
>
<ArrowLeft className="w-4 h-4" />
</button>
{/* Logo */}
<div className="text-center mb-8">
<div className="w-16 h-16 mx-auto mb-4 flex items-center justify-center">
<img src="/images/logo.png" alt="NoFx Logo" className="w-16 h-16 object-contain" />
<img src="/icons/nofx.svg" alt="NoFx Logo" className="w-16 h-16 object-contain" />
</div>
<h1 className="text-2xl font-bold" style={{ color: '#EAECEF' }}>
{t('loginTitle', language)}
<h1 className="text-2xl font-bold" style={{ color: 'var(--brand-light-gray)' }}>
NOFX
</h1>
<p className="text-sm mt-2" style={{ color: '#848E9C' }}>
{step === 'login' ? t('loginTitle', language) : t('enterOTPCode', language)}
<p className="text-sm mt-2" style={{ color: 'var(--text-secondary)' }}>
{step === 'login' ? '请输入您的邮箱和密码' : '请输入两步验证码'}
</p>
</div>
{/* Login Form */}
<div className="rounded-lg p-6" style={{ background: '#1E2329', border: '1px solid #2B3139' }}>
<div className="rounded-lg p-6" style={{ background: 'var(--panel-bg)', border: '1px solid var(--panel-border)' }}>
{step === 'login' ? (
<form onSubmit={handleLogin} className="space-y-4">
<div>
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
{t('email', language)}
</label>
<input
@@ -95,14 +95,14 @@ export function LoginPage() {
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 py-2 rounded"
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
placeholder={t('emailPlaceholder', language)}
required
/>
</div>
<div>
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
{t('password', language)}
</label>
<input
@@ -110,14 +110,14 @@ export function LoginPage() {
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full px-3 py-2 rounded"
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
placeholder={t('passwordPlaceholder', language)}
required
/>
</div>
{error && (
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
{error}
</div>
)}
@@ -126,7 +126,7 @@ export function LoginPage() {
type="submit"
disabled={loading}
className="w-full px-4 py-2 rounded text-sm font-semibold transition-all hover:scale-105 disabled:opacity-50"
style={{ background: '#F0B90B', color: '#000' }}
style={{ background: 'var(--brand-yellow)', color: 'var(--brand-black)' }}
>
{loading ? t('loading', language) : t('loginButton', language)}
</button>
@@ -142,7 +142,7 @@ export function LoginPage() {
</div>
<div>
<label className="block text-sm font-semibold mb-2" style={{ color: '#EAECEF' }}>
<label className="block text-sm font-semibold mb-2" style={{ color: 'var(--brand-light-gray)' }}>
{t('otpCode', language)}
</label>
<input
@@ -150,7 +150,7 @@ export function LoginPage() {
value={otpCode}
onChange={(e) => setOtpCode(e.target.value.replace(/\D/g, '').slice(0, 6))}
className="w-full px-3 py-2 rounded text-center text-2xl font-mono"
style={{ background: '#0B0E11', border: '1px solid #2B3139', color: '#EAECEF' }}
style={{ background: 'var(--brand-black)', border: '1px solid var(--panel-border)', color: 'var(--brand-light-gray)' }}
placeholder={t('otpPlaceholder', language)}
maxLength={6}
required
@@ -158,7 +158,7 @@ export function LoginPage() {
</div>
{error && (
<div className="text-sm px-3 py-2 rounded" style={{ background: 'rgba(246, 70, 93, 0.1)', color: '#F6465D' }}>
<div className="text-sm px-3 py-2 rounded" style={{ background: 'var(--binance-red-bg)', color: 'var(--binance-red)' }}>
{error}
</div>
)}
@@ -168,7 +168,7 @@ export function LoginPage() {
type="button"
onClick={() => setStep('login')}
className="flex-1 px-4 py-2 rounded text-sm font-semibold"
style={{ background: '#2B3139', color: '#848E9C' }}
style={{ background: 'var(--panel-bg-hover)', color: 'var(--text-secondary)' }}
>
{t('back', language)}
</button>
@@ -187,17 +187,17 @@ export function LoginPage() {
{/* Register Link */}
<div className="text-center mt-6">
<p className="text-sm" style={{ color: '#848E9C' }}>
{t('noAccount', language)}{' '}
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
{' '}
<button
onClick={() => {
window.history.pushState({}, '', '/register');
window.dispatchEvent(new PopStateEvent('popstate'));
}}
className="font-semibold hover:underline"
style={{ color: '#F0B90B' }}
className="font-semibold hover:underline transition-colors"
style={{ color: 'var(--brand-yellow)' }}
>
{t('registerNow', language)}
</button>
</p>
</div>