feat: redesign landing page UI and improve header

This commit is contained in:
tinkle-community
2025-12-09 13:59:14 +08:00
parent 4291b80273
commit 48792907b3
12 changed files with 1204 additions and 738 deletions

View File

@@ -1,7 +1,5 @@
import { motion } from 'framer-motion'
import { Shield, Target } from 'lucide-react'
import AnimatedSection from './AnimatedSection'
import Typewriter from '../Typewriter'
import { Terminal, Shield, Cpu, BarChart3 } from 'lucide-react'
import { t, Language } from '../../i18n/translations'
interface AboutSectionProps {
@@ -9,119 +7,151 @@ interface AboutSectionProps {
}
export default function AboutSection({ language }: AboutSectionProps) {
const features = [
{
icon: Shield,
title: language === 'zh' ? '完全自主控制' : 'Full Control',
desc: language === 'zh' ? '自托管,数据安全' : 'Self-hosted, data secure',
},
{
icon: Cpu,
title: language === 'zh' ? '多 AI 支持' : 'Multi-AI Support',
desc: language === 'zh' ? 'DeepSeek, GPT, Claude...' : 'DeepSeek, GPT, Claude...',
},
{
icon: BarChart3,
title: language === 'zh' ? '实时监控' : 'Real-time Monitor',
desc: language === 'zh' ? '可视化交易看板' : 'Visual trading dashboard',
},
]
return (
<AnimatedSection id="about" backgroundColor="var(--brand-dark-gray)">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 items-center">
<section className="py-24 relative overflow-hidden" style={{ background: '#0B0E11' }}>
{/* Background Decoration */}
<div
className="absolute top-0 right-0 w-96 h-96 rounded-full blur-3xl opacity-30"
style={{ background: 'radial-gradient(circle, rgba(240, 185, 11, 0.1) 0%, transparent 70%)' }}
/>
<div className="max-w-6xl mx-auto px-4">
<div className="grid lg:grid-cols-2 gap-16 items-center">
{/* Left Content */}
<motion.div
className="space-y-6"
initial={{ opacity: 0, x: -50 }}
initial={{ opacity: 0, x: -30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6 }}
>
<motion.div
className="inline-flex items-center gap-2 px-4 py-2 rounded-full"
className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full mb-6"
style={{
background: 'rgba(240, 185, 11, 0.1)',
border: '1px solid rgba(240, 185, 11, 0.2)',
}}
whileHover={{ scale: 1.05 }}
>
<Target
className="w-4 h-4"
style={{ color: 'var(--brand-yellow)' }}
/>
<span
className="text-sm font-semibold"
style={{ color: 'var(--brand-yellow)' }}
>
<Terminal className="w-4 h-4" style={{ color: '#F0B90B' }} />
<span className="text-xs font-medium" style={{ color: '#F0B90B' }}>
{t('aboutNofx', language)}
</span>
</motion.div>
<h2
className="text-4xl font-bold"
style={{ color: 'var(--brand-light-gray)' }}
>
<h2 className="text-4xl lg:text-5xl font-bold mb-6" style={{ color: '#EAECEF' }}>
{t('whatIsNofx', language)}
</h2>
<p
className="text-lg leading-relaxed"
style={{ color: 'var(--text-secondary)' }}
>
{t('nofxNotAnotherBot', language)}{' '}
{t('nofxDescription1', language)}{' '}
{t('nofxDescription2', language)}
<p className="text-lg mb-8 leading-relaxed" style={{ color: '#848E9C' }}>
{t('nofxNotAnotherBot', language)} {t('nofxDescription1', language)}
</p>
<p
className="text-lg leading-relaxed"
style={{ color: 'var(--text-secondary)' }}
>
{t('nofxDescription3', language)}{' '}
{t('nofxDescription4', language)}{' '}
{t('nofxDescription5', language)}
</p>
<motion.div
className="flex items-center gap-3 pt-4"
whileHover={{ x: 5 }}
>
<div
className="w-12 h-12 rounded-full flex items-center justify-center"
style={{ background: 'rgba(240, 185, 11, 0.1)' }}
>
<Shield
className="w-6 h-6"
style={{ color: 'var(--brand-yellow)' }}
/>
</div>
<div>
<div
className="font-semibold"
style={{ color: 'var(--brand-light-gray)' }}
{/* Feature Pills */}
<div className="flex flex-wrap gap-3">
{features.map((feature, index) => (
<motion.div
key={feature.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1 }}
className="flex items-center gap-3 px-4 py-3 rounded-xl"
style={{
background: 'rgba(255, 255, 255, 0.03)',
border: '1px solid rgba(255, 255, 255, 0.06)',
}}
>
{t('youFullControl', language)}
</div>
<div
className="text-sm"
style={{ color: 'var(--text-secondary)' }}
>
{t('fullControlDesc', language)}
</div>
</div>
</motion.div>
<div
className="w-10 h-10 rounded-lg flex items-center justify-center"
style={{ background: 'rgba(240, 185, 11, 0.1)' }}
>
<feature.icon className="w-5 h-5" style={{ color: '#F0B90B' }} />
</div>
<div>
<div className="text-sm font-semibold" style={{ color: '#EAECEF' }}>
{feature.title}
</div>
<div className="text-xs" style={{ color: '#5E6673' }}>
{feature.desc}
</div>
</div>
</motion.div>
))}
</div>
</motion.div>
<div className="relative">
{/* Right - Terminal */}
<motion.div
initial={{ opacity: 0, x: 30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2 }}
>
<div
className="rounded-2xl p-8"
className="rounded-2xl overflow-hidden"
style={{
background: 'var(--brand-black)',
border: '1px solid var(--panel-border)',
background: '#0D1117',
border: '1px solid rgba(255, 255, 255, 0.1)',
boxShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.5)',
}}
>
<Typewriter
lines={[
'$ git clone https://github.com/tinkle-community/nofx.git',
'$ cd nofx',
'$ chmod +x start.sh',
'$ ./start.sh start --build',
t('startupMessages1', language),
t('startupMessages2', language),
t('startupMessages3', language),
]}
typingSpeed={70}
lineDelay={900}
className="text-sm font-mono"
style={{
color: '#00FF88',
textShadow: '0 0 8px rgba(0,255,136,0.4)',
}}
/>
{/* Terminal Header */}
<div
className="flex items-center gap-2 px-4 py-3"
style={{ background: 'rgba(255, 255, 255, 0.03)', borderBottom: '1px solid rgba(255, 255, 255, 0.06)' }}
>
<div className="flex gap-2">
<div className="w-3 h-3 rounded-full" style={{ background: '#FF5F56' }} />
<div className="w-3 h-3 rounded-full" style={{ background: '#FFBD2E' }} />
<div className="w-3 h-3 rounded-full" style={{ background: '#27C93F' }} />
</div>
<span className="text-xs ml-2" style={{ color: '#5E6673' }}>terminal</span>
</div>
{/* Terminal Content */}
<div className="p-6 font-mono text-sm space-y-2">
<div style={{ color: '#5E6673' }}>$ git clone https://github.com/NoFxAiOS/nofx.git</div>
<div style={{ color: '#5E6673' }}>$ cd nofx && chmod +x start.sh</div>
<div style={{ color: '#5E6673' }}>$ ./start.sh start --build</div>
<div className="pt-2" style={{ color: '#F0B90B' }}>
{t('startupMessages1', language)}
</div>
<div style={{ color: '#0ECB81' }}>
{t('startupMessages2', language)}
</div>
<div style={{ color: '#0ECB81' }}>
{t('startupMessages3', language)}
</div>
<motion.div
className="flex items-center gap-2 pt-2"
animate={{ opacity: [1, 0.5, 1] }}
transition={{ duration: 1.5, repeat: Infinity }}
>
<span style={{ color: '#F0B90B' }}></span>
<span style={{ color: '#EAECEF' }}>_</span>
</motion.div>
</div>
</div>
</div>
</motion.div>
</div>
</div>
</AnimatedSection>
</section>
)
}

View File

@@ -1,7 +1,8 @@
import { motion } from 'framer-motion'
import AnimatedSection from './AnimatedSection'
import { MessageCircle, Heart, Repeat2, ExternalLink } from 'lucide-react'
import { Language } from '../../i18n/translations'
interface CardProps {
interface TweetProps {
quote: string
authorName: string
handle: string
@@ -10,49 +11,94 @@ interface CardProps {
delay: number
}
function TestimonialCard({ quote, authorName, delay }: CardProps) {
function TweetCard({ quote, authorName, handle, avatarUrl, tweetUrl, delay }: TweetProps) {
return (
<motion.div
className="p-6 rounded-xl"
<motion.a
href={tweetUrl}
target="_blank"
rel="noopener noreferrer"
className="block p-5 rounded-2xl transition-all duration-300 group"
style={{
background: 'var(--brand-dark-gray)',
border: '1px solid rgba(240, 185, 11, 0.1)',
background: '#12161C',
border: '1px solid rgba(255, 255, 255, 0.06)',
}}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay }}
whileHover={{ scale: 1.05 }}
whileHover={{
y: -4,
borderColor: 'rgba(240, 185, 11, 0.3)',
}}
>
<p className="text-lg mb-4" style={{ color: 'var(--brand-light-gray)' }}>
"{quote}"
</p>
<div className="flex items-center gap-2">
{/* Header */}
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-3">
<img
src={avatarUrl}
alt={authorName}
className="w-10 h-10 rounded-full object-cover"
style={{ border: '2px solid rgba(255, 255, 255, 0.1)' }}
/>
<div>
<div className="font-semibold text-sm" style={{ color: '#EAECEF' }}>
{authorName}
</div>
<div className="text-xs" style={{ color: '#5E6673' }}>
{handle}
</div>
</div>
</div>
{/* X Logo */}
<div
className="w-8 h-8 rounded-full"
style={{ background: 'var(--binance-yellow)' }}
/>
<span
className="text-sm font-semibold"
style={{ color: 'var(--text-secondary)' }}
className="w-6 h-6 flex items-center justify-center opacity-50 group-hover:opacity-100 transition-opacity"
style={{ color: '#EAECEF' }}
>
{authorName}
</span>
<svg viewBox="0 0 24 24" className="w-4 h-4" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
</div>
</div>
</motion.div>
{/* Content */}
<p
className="text-sm leading-relaxed mb-4 line-clamp-4"
style={{ color: '#B7BDC6' }}
>
{quote}
</p>
{/* Footer */}
<div className="flex items-center gap-6 pt-3" style={{ borderTop: '1px solid rgba(255, 255, 255, 0.05)' }}>
<div className="flex items-center gap-1.5 text-xs" style={{ color: '#5E6673' }}>
<MessageCircle className="w-3.5 h-3.5" />
<span>Reply</span>
</div>
<div className="flex items-center gap-1.5 text-xs" style={{ color: '#5E6673' }}>
<Repeat2 className="w-3.5 h-3.5" />
<span>Repost</span>
</div>
<div className="flex items-center gap-1.5 text-xs" style={{ color: '#5E6673' }}>
<Heart className="w-3.5 h-3.5" />
<span>Like</span>
</div>
<div className="ml-auto opacity-0 group-hover:opacity-100 transition-opacity">
<ExternalLink className="w-3.5 h-3.5" style={{ color: '#F0B90B' }} />
</div>
</div>
</motion.a>
)
}
export default function CommunitySection() {
const staggerContainer = {
animate: { transition: { staggerChildren: 0.1 } },
}
interface CommunitySectionProps {
language?: Language
}
// 推特内容整合(保持原三列布局,超出自动换行)
const items: CardProps[] = [
export default function CommunitySection({ language }: CommunitySectionProps) {
const tweets: TweetProps[] = [
{
quote:
'前不久非常火的 AI 量化交易系统 NOF1在 GitHub 上有人将其复刻并开源,这就是 NOFX 项目。基于 DeepSeek、Qwen 等大语言模型,打造的通用架构 AI 交易操作系统,完成了从决策、到交易、再到复盘的闭环。GitHub: https://github.com/NoFxAiOS/nofx',
'前不久非常火的 AI 量化交易系统 NOF1在 GitHub 上有人将其复刻并开源,这就是 NOFX 项目。基于 DeepSeek、Qwen 等大语言模型,打造的通用架构 AI 交易操作系统,完成了从决策、到交易、再到复盘的闭环。',
authorName: 'Michael Williams',
handle: '@MichaelWil93725',
avatarUrl:
@@ -84,20 +130,61 @@ export default function CommunitySection() {
]
return (
<AnimatedSection>
<div className="max-w-7xl mx-auto">
<section className="py-24 relative" style={{ background: '#0B0E11' }}>
{/* Background Decoration */}
<div
className="absolute right-0 top-1/2 -translate-y-1/2 w-96 h-96 rounded-full blur-3xl opacity-20"
style={{ background: 'radial-gradient(circle, rgba(29, 161, 242, 0.1) 0%, transparent 70%)' }}
/>
<div className="max-w-6xl mx-auto px-4 relative z-10">
{/* Header */}
<motion.div
className="grid md:grid-cols-3 gap-6"
variants={staggerContainer}
initial="initial"
whileInView="animate"
className="text-center mb-12"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
{items.map((item, idx) => (
<TestimonialCard key={idx} {...item} />
<h2 className="text-4xl lg:text-5xl font-bold mb-4" style={{ color: '#EAECEF' }}>
{language === 'zh' ? '社区声音' : 'Community Voices'}
</h2>
<p className="text-lg" style={{ color: '#848E9C' }}>
{language === 'zh' ? '看看大家怎么说' : 'See what others are saying'}
</p>
</motion.div>
{/* Tweet Grid */}
<div className="grid md:grid-cols-3 gap-5">
{tweets.map((tweet, idx) => (
<TweetCard key={idx} {...tweet} />
))}
</div>
{/* CTA */}
<motion.div
className="text-center mt-12"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<a
href="https://twitter.com/nofx_official"
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-6 py-3 rounded-xl font-medium transition-all hover:scale-105"
style={{
background: 'rgba(29, 161, 242, 0.1)',
color: '#1DA1F2',
border: '1px solid rgba(29, 161, 242, 0.3)',
}}
>
<svg viewBox="0 0 24 24" className="w-5 h-5" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
{language === 'zh' ? '关注我们的 X' : 'Follow us on X'}
</a>
</motion.div>
</div>
</AnimatedSection>
</section>
)
}

View File

@@ -1,7 +1,5 @@
import { motion } from 'framer-motion'
import AnimatedSection from './AnimatedSection'
import { CryptoFeatureCard } from '../CryptoFeatureCard'
import { Code, Cpu, Lock, Rocket } from 'lucide-react'
import { Brain, Swords, BarChart3, Shield, Blocks, LineChart } from 'lucide-react'
import { t, Language } from '../../i18n/translations'
interface FeaturesSectionProps {
@@ -9,84 +7,199 @@ interface FeaturesSectionProps {
}
export default function FeaturesSection({ language }: FeaturesSectionProps) {
const features = [
{
icon: Brain,
title: language === 'zh' ? 'AI 策略编排引擎' : 'AI Strategy Orchestration',
desc: language === 'zh'
? '支持 DeepSeek、GPT、Claude、Qwen 等多种大模型,自定义 Prompt 策略AI 自主分析市场并做出交易决策'
: 'Support DeepSeek, GPT, Claude, Qwen and more. Custom prompts, AI autonomously analyzes markets and makes trading decisions',
highlight: true,
badge: language === 'zh' ? '核心能力' : 'Core',
},
{
icon: Swords,
title: language === 'zh' ? '多 AI 竞技场' : 'Multi-AI Arena',
desc: language === 'zh'
? '多个 AI 交易员同台竞技,实时 PnL 排行榜,自动优胜劣汰,让最强策略脱颖而出'
: 'Multiple AI traders compete in real-time, live PnL leaderboard, automatic survival of the fittest',
highlight: true,
badge: language === 'zh' ? '独创' : 'Unique',
},
{
icon: LineChart,
title: language === 'zh' ? '专业量化数据' : 'Pro Quant Data',
desc: language === 'zh'
? '集成 K线、技术指标、市场深度、资金费率、持仓量等专业量化数据为 AI 决策提供全面信息'
: 'Integrated candlesticks, indicators, order book, funding rates, open interest - comprehensive data for AI decisions',
highlight: true,
badge: language === 'zh' ? '专业' : 'Pro',
},
{
icon: Blocks,
title: language === 'zh' ? '多交易所支持' : 'Multi-Exchange Support',
desc: language === 'zh'
? 'Binance、OKX、Bybit、Hyperliquid、Aster DEX一套系统管理多个交易所'
: 'Binance, OKX, Bybit, Hyperliquid, Aster DEX - one system, multiple exchanges',
},
{
icon: BarChart3,
title: language === 'zh' ? '实时可视化看板' : 'Real-time Dashboard',
desc: language === 'zh'
? '交易监控、收益曲线、持仓分析、AI 决策日志,一目了然'
: 'Trade monitoring, PnL curves, position analysis, AI decision logs at a glance',
},
{
icon: Shield,
title: language === 'zh' ? '开源自托管' : 'Open Source & Self-Hosted',
desc: language === 'zh'
? '代码完全开源可审计数据存储在本地API 密钥不经过第三方'
: 'Fully open source, data stored locally, API keys never leave your server',
},
]
return (
<AnimatedSection id="features">
<div className="max-w-7xl mx-auto">
<section className="py-24 relative" style={{ background: '#0B0E11' }}>
{/* Background */}
<div
className="absolute inset-0 opacity-[0.02]"
style={{
backgroundImage: `linear-gradient(#F0B90B 1px, transparent 1px), linear-gradient(90deg, #F0B90B 1px, transparent 1px)`,
backgroundSize: '40px 40px',
}}
/>
<div className="max-w-6xl mx-auto px-4 relative z-10">
{/* Header */}
<motion.div
className="text-center mb-16"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<motion.div
className="inline-flex items-center gap-2 px-4 py-2 rounded-full mb-6"
style={{
background: 'rgba(240, 185, 11, 0.1)',
border: '1px solid rgba(240, 185, 11, 0.2)',
}}
whileHover={{ scale: 1.05 }}
>
<Rocket
className="w-4 h-4"
style={{ color: 'var(--brand-yellow)' }}
/>
<span
className="text-sm font-semibold"
style={{ color: 'var(--brand-yellow)' }}
>
{t('coreFeatures', language)}
</span>
</motion.div>
<h2
className="text-4xl font-bold mb-4"
style={{ color: 'var(--brand-light-gray)' }}
>
<h2 className="text-4xl lg:text-5xl font-bold mb-4" style={{ color: '#EAECEF' }}>
{t('whyChooseNofx', language)}
</h2>
<p className="text-lg" style={{ color: 'var(--text-secondary)' }}>
{t('openCommunityDriven', language)}
<p className="text-lg max-w-2xl mx-auto" style={{ color: '#848E9C' }}>
{language === 'zh'
? '不只是交易机器人,而是完整的 AI 交易操作系统'
: 'Not just a trading bot, but a complete AI trading operating system'}
</p>
</motion.div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-7xl mx-auto">
<CryptoFeatureCard
icon={<Code className="w-8 h-8" />}
title={t('openSourceSelfHosted', language)}
description={t('openSourceDesc', language)}
features={[
t('openSourceFeatures1', language),
t('openSourceFeatures2', language),
t('openSourceFeatures3', language),
t('openSourceFeatures4', language),
]}
delay={0}
/>
<CryptoFeatureCard
icon={<Cpu className="w-8 h-8" />}
title={t('multiAgentCompetition', language)}
description={t('multiAgentDesc', language)}
features={[
t('multiAgentFeatures1', language),
t('multiAgentFeatures2', language),
t('multiAgentFeatures3', language),
t('multiAgentFeatures4', language),
]}
delay={0.1}
/>
<CryptoFeatureCard
icon={<Lock className="w-8 h-8" />}
title={t('secureReliableTrading', language)}
description={t('secureDesc', language)}
features={[
t('secureFeatures1', language),
t('secureFeatures2', language),
t('secureFeatures3', language),
t('secureFeatures4', language),
]}
delay={0.2}
/>
{/* Features Grid */}
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-5">
{features.map((feature, index) => (
<motion.div
key={feature.title}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.1 }}
className={`
relative group rounded-2xl p-6 transition-all duration-300
${feature.highlight ? 'md:col-span-1 lg:col-span-1' : ''}
`}
style={{
background: feature.highlight
? 'linear-gradient(135deg, rgba(240, 185, 11, 0.08) 0%, rgba(240, 185, 11, 0.02) 100%)'
: '#12161C',
border: feature.highlight
? '1px solid rgba(240, 185, 11, 0.2)'
: '1px solid rgba(255, 255, 255, 0.06)',
}}
>
{/* Badge */}
{feature.badge && (
<div
className="absolute top-4 right-4 px-2 py-1 rounded text-xs font-medium"
style={{
background: 'rgba(240, 185, 11, 0.15)',
color: '#F0B90B',
}}
>
{feature.badge}
</div>
)}
{/* Icon */}
<motion.div
className="w-12 h-12 rounded-xl flex items-center justify-center mb-4"
style={{
background: feature.highlight
? 'rgba(240, 185, 11, 0.15)'
: 'rgba(240, 185, 11, 0.1)',
border: '1px solid rgba(240, 185, 11, 0.2)',
}}
whileHover={{ scale: 1.1, rotate: 5 }}
>
<feature.icon
className="w-6 h-6"
style={{ color: '#F0B90B' }}
/>
</motion.div>
{/* Text */}
<h3
className="text-xl font-bold mb-3"
style={{ color: '#EAECEF' }}
>
{feature.title}
</h3>
<p
className="text-sm leading-relaxed"
style={{ color: '#848E9C' }}
>
{feature.desc}
</p>
{/* Hover Glow */}
<div
className="absolute -bottom-10 -right-10 w-32 h-32 rounded-full blur-3xl opacity-0 group-hover:opacity-30 transition-opacity duration-500"
style={{ background: '#F0B90B' }}
/>
</motion.div>
))}
</div>
{/* Bottom Stats */}
<motion.div
className="mt-16 grid grid-cols-2 md:grid-cols-4 gap-6"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
{[
{ value: '10+', label: language === 'zh' ? 'AI 模型支持' : 'AI Models' },
{ value: '5+', label: language === 'zh' ? '交易所集成' : 'Exchanges' },
{ value: '24/7', label: language === 'zh' ? '自动交易' : 'Auto Trading' },
{ value: '100%', label: language === 'zh' ? '开源免费' : 'Open Source' },
].map((stat) => (
<div
key={stat.label}
className="text-center p-4 rounded-xl"
style={{
background: 'rgba(255, 255, 255, 0.02)',
border: '1px solid rgba(255, 255, 255, 0.05)',
}}
>
<div
className="text-2xl font-bold mb-1"
style={{
background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{stat.value}
</div>
<div className="text-xs" style={{ color: '#5E6673' }}>
{stat.label}
</div>
</div>
))}
</motion.div>
</div>
</AnimatedSection>
</section>
)
}

View File

@@ -1,180 +1,169 @@
import { Github, Send, ExternalLink } from 'lucide-react'
import { t, Language } from '../../i18n/translations'
import { OFFICIAL_LINKS } from '../../constants/branding'
interface FooterSectionProps {
language: Language
}
export default function FooterSection({ language }: FooterSectionProps) {
const links = {
social: [
{ name: 'GitHub', href: OFFICIAL_LINKS.github, icon: Github },
{
name: 'X (Twitter)',
href: OFFICIAL_LINKS.twitter,
icon: () => (
<svg viewBox="0 0 24 24" className="w-4 h-4" fill="currentColor">
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
</svg>
),
},
{ name: 'Telegram', href: OFFICIAL_LINKS.telegram, icon: Send },
],
resources: [
{
name: language === 'zh' ? '文档' : 'Documentation',
href: 'https://github.com/NoFxAiOS/nofx/blob/main/README.md',
},
{ name: 'Issues', href: 'https://github.com/NoFxAiOS/nofx/issues' },
{ name: 'Pull Requests', href: 'https://github.com/NoFxAiOS/nofx/pulls' },
],
supporters: [
{ name: 'Aster DEX', href: 'https://www.asterdex.com/en/referral/fdfc0e' },
{ name: 'Binance', href: 'https://www.maxweb.red/join?ref=NOFXAI' },
{ name: 'Hyperliquid', href: 'https://hyperliquid.xyz/' },
{
name: 'Amber.ac',
href: 'https://amber.ac/',
badge: language === 'zh' ? '战略投资' : 'Strategic',
},
],
}
return (
<footer
style={{
borderTop: '1px solid var(--panel-border)',
background: 'var(--brand-dark-gray)',
}}
>
<div className="max-w-[1200px] mx-auto px-6 py-10">
{/* Brand */}
<div className="flex items-center gap-3 mb-8">
<img src="/icons/nofx.svg" alt="NOFX Logo" className="w-8 h-8" />
<div>
<div className="text-lg font-bold" style={{ color: '#EAECEF' }}>
NOFX
<footer style={{ background: '#0B0E11', borderTop: '1px solid rgba(255, 255, 255, 0.06)' }}>
<div className="max-w-6xl mx-auto px-4 py-12">
{/* Top Section */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-10 mb-12">
{/* Brand */}
<div className="md:col-span-1">
<div className="flex items-center gap-3 mb-4">
<img src="/icons/nofx.svg" alt="NOFX Logo" className="w-8 h-8" />
<span className="text-xl font-bold" style={{ color: '#EAECEF' }}>
NOFX
</span>
</div>
<div className="text-xs" style={{ color: '#848E9C' }}>
<p className="text-sm mb-6" style={{ color: '#5E6673' }}>
{t('futureStandardAI', language)}
</p>
{/* Social Icons */}
<div className="flex items-center gap-3">
{links.social.map((link) => (
<a
key={link.name}
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="w-9 h-9 rounded-lg flex items-center justify-center transition-all hover:scale-110"
style={{
background: 'rgba(255, 255, 255, 0.05)',
color: '#848E9C',
}}
title={link.name}
>
<link.icon className="w-4 h-4" />
</a>
))}
</div>
</div>
</div>
{/* Multi-link columns */}
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-3 gap-8">
{/* Links */}
<div>
<h3
className="text-sm font-semibold mb-3"
style={{ color: '#EAECEF' }}
>
<h4 className="text-sm font-semibold mb-4" style={{ color: '#EAECEF' }}>
{t('links', language)}
</h3>
<ul className="space-y-2 text-sm" style={{ color: '#848E9C' }}>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://github.com/tinkle-community/nofx"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://t.me/nofx_dev_community"
target="_blank"
rel="noopener noreferrer"
>
Telegram
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://x.com/nofx_official"
target="_blank"
rel="noopener noreferrer"
>
X (Twitter)
</a>
</li>
</h4>
<ul className="space-y-3">
{links.social.map((link) => (
<li key={link.name}>
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="text-sm transition-colors hover:text-[#F0B90B]"
style={{ color: '#5E6673' }}
>
{link.name}
</a>
</li>
))}
</ul>
</div>
{/* Resources */}
<div>
<h3
className="text-sm font-semibold mb-3"
style={{ color: '#EAECEF' }}
>
<h4 className="text-sm font-semibold mb-4" style={{ color: '#EAECEF' }}>
{t('resources', language)}
</h3>
<ul className="space-y-2 text-sm" style={{ color: '#848E9C' }}>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://github.com/tinkle-community/nofx/blob/main/README.md"
target="_blank"
rel="noopener noreferrer"
>
{t('documentation', language)}
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://github.com/tinkle-community/nofx/issues"
target="_blank"
rel="noopener noreferrer"
>
Issues
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://github.com/tinkle-community/nofx/pulls"
target="_blank"
rel="noopener noreferrer"
>
Pull Requests
</a>
</li>
</h4>
<ul className="space-y-3">
{links.resources.map((link) => (
<li key={link.name}>
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="text-sm transition-colors hover:text-[#F0B90B] inline-flex items-center gap-1"
style={{ color: '#5E6673' }}
>
{link.name}
<ExternalLink className="w-3 h-3 opacity-50" />
</a>
</li>
))}
</ul>
</div>
{/* Supporters */}
<div>
<h3
className="text-sm font-semibold mb-3"
style={{ color: '#EAECEF' }}
>
<h4 className="text-sm font-semibold mb-4" style={{ color: '#EAECEF' }}>
{t('supporters', language)}
</h3>
<ul className="space-y-2 text-sm" style={{ color: '#848E9C' }}>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://www.asterdex.com/en/referral/fdfc0e"
target="_blank"
rel="noopener noreferrer"
>
Aster DEX
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://www.maxweb.red/join?ref=NOFXAI"
target="_blank"
rel="noopener noreferrer"
>
Binance
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://hyperliquid.xyz/"
target="_blank"
rel="noopener noreferrer"
>
Hyperliquid
</a>
</li>
<li>
<a
className="hover:text-[#F0B90B]"
href="https://amber.ac/"
target="_blank"
rel="noopener noreferrer"
>
Amber.ac{' '}
<span className="opacity-70">
{t('strategicInvestment', language)}
</span>
</a>
</li>
</h4>
<ul className="space-y-3">
{links.supporters.map((link) => (
<li key={link.name}>
<a
href={link.href}
target="_blank"
rel="noopener noreferrer"
className="text-sm transition-colors hover:text-[#F0B90B] inline-flex items-center gap-2"
style={{ color: '#5E6673' }}
>
{link.name}
{link.badge && (
<span
className="text-xs px-1.5 py-0.5 rounded"
style={{
background: 'rgba(240, 185, 11, 0.1)',
color: '#F0B90B',
}}
>
{link.badge}
</span>
)}
</a>
</li>
))}
</ul>
</div>
</div>
{/* Bottom note (kept subtle) */}
{/* Bottom Section */}
<div
className="pt-6 mt-8 text-center text-xs"
style={{
color: 'var(--text-tertiary)',
borderTop: '1px solid var(--panel-border)',
}}
className="pt-6 text-center text-xs"
style={{ color: '#5E6673', borderTop: '1px solid rgba(255, 255, 255, 0.06)' }}
>
<p>{t('footerTitle', language)}</p>
<p className="mt-1">{t('footerWarning', language)}</p>
<p className="mb-2">{t('footerTitle', language)}</p>
<p style={{ color: '#3C4249' }}>{t('footerWarning', language)}</p>
</div>
</div>
</footer>

View File

@@ -1,214 +1,252 @@
import { motion, useScroll, useTransform, useAnimation } from 'framer-motion'
import { Sparkles } from 'lucide-react'
import { motion } from 'framer-motion'
import { ArrowRight, Play, Github, Zap } from 'lucide-react'
import { t, Language } from '../../i18n/translations'
import { useGitHubStats } from '../../hooks/useGitHubStats'
import { useCounterAnimation } from '../../hooks/useCounterAnimation'
import { OFFICIAL_LINKS } from '../../constants/branding'
interface HeroSectionProps {
language: Language
}
export default function HeroSection({ language }: HeroSectionProps) {
const { scrollYProgress } = useScroll()
const opacity = useTransform(scrollYProgress, [0, 0.2], [1, 0])
const scale = useTransform(scrollYProgress, [0, 0.2], [1, 0.8])
const handControls = useAnimation()
const { stars, daysOld, isLoading } = useGitHubStats('NoFxAiOS', 'nofx')
// 动画数字 - 仅对 stars 添加动画
const animatedStars = useCounterAnimation({
start: 0,
end: stars,
duration: 2000,
})
const fadeInUp = {
initial: { opacity: 0, y: 60 },
animate: { opacity: 1, y: 0 },
transition: { duration: 0.6, ease: [0.6, -0.05, 0.01, 0.99] },
}
const staggerContainer = {
animate: { transition: { staggerChildren: 0.1 } },
}
return (
<section className="relative pt-32 pb-20 px-4">
<div className="max-w-7xl mx-auto">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Left Content */}
<motion.div
className="space-y-6 relative z-10"
style={{ opacity, scale }}
initial="initial"
animate="animate"
variants={staggerContainer}
>
<motion.div variants={fadeInUp}>
<motion.div
className="inline-flex items-center gap-2 px-4 py-2 rounded-full mb-6"
style={{
background: 'rgba(240, 185, 11, 0.1)',
border: '1px solid rgba(240, 185, 11, 0.2)',
}}
whileHover={{
scale: 1.05,
boxShadow: '0 0 20px rgba(240, 185, 11, 0.2)',
}}
>
<Sparkles
className="w-4 h-4"
style={{ color: 'var(--brand-yellow)' }}
/>
<span
className="text-sm font-semibold"
style={{ color: 'var(--brand-yellow)' }}
>
{isLoading ? (
t('githubStarsInDays', language)
) : language === 'zh' ? (
<>
{daysOld} {' '}
<span className="inline-block tabular-nums">
{(animatedStars / 1000).toFixed(1)}
</span>
K+ GitHub Stars
</>
) : (
<>
<span className="inline-block tabular-nums">
{(animatedStars / 1000).toFixed(1)}
</span>
K+ GitHub Stars in {daysOld} days
</>
)}
</span>
</motion.div>
</motion.div>
<h1
className="text-5xl lg:text-7xl font-bold leading-tight"
style={{ color: 'var(--brand-light-gray)' }}
>
{t('heroTitle1', language)}
<br />
<span style={{ color: 'var(--brand-yellow)' }}>
{t('heroTitle2', language)}
</span>
</h1>
<motion.p
className="text-xl leading-relaxed"
style={{ color: 'var(--text-secondary)' }}
variants={fadeInUp}
>
{t('heroDescription', language)}
</motion.p>
<div className="flex items-center gap-3 flex-wrap">
<motion.a
href="https://github.com/tinkle-community/nofx"
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.05 }}
transition={{ type: 'spring', stiffness: 400 }}
>
<img
src="https://img.shields.io/github/stars/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A"
alt="GitHub Stars"
className="h-7"
/>
</motion.a>
<motion.a
href="https://github.com/tinkle-community/nofx/network/members"
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.05 }}
transition={{ type: 'spring', stiffness: 400 }}
>
<img
src="https://img.shields.io/github/forks/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A"
alt="GitHub Forks"
className="h-7"
/>
</motion.a>
<motion.a
href="https://github.com/tinkle-community/nofx/graphs/contributors"
target="_blank"
rel="noopener noreferrer"
whileHover={{ scale: 1.05 }}
transition={{ type: 'spring', stiffness: 400 }}
>
<img
src="https://img.shields.io/github/contributors/tinkle-community/nofx?style=for-the-badge&logo=github&logoColor=white&color=F0B90B&labelColor=0A0A0A"
alt="GitHub Contributors"
className="h-7"
/>
</motion.a>
</div>
<motion.p
className="text-xs pt-4"
style={{ color: 'var(--text-tertiary)' }}
variants={fadeInUp}
>
{t('poweredBy', language)}
</motion.p>
</motion.div>
{/* Right Visual - Interactive Robot */}
<div
className="relative w-full cursor-pointer"
onMouseEnter={() => {
handControls.start({
y: [-8, 8, -8],
rotate: [-3, 3, -3],
x: [-2, 2, -2],
transition: {
duration: 2.5,
repeat: Infinity,
ease: 'easeInOut',
times: [0, 0.5, 1],
},
})
}}
onMouseLeave={() => {
handControls.start({
y: 0,
rotate: 0,
x: 0,
transition: {
duration: 0.6,
ease: 'easeOut',
},
})
}}
>
{/* Background Layer */}
<motion.img
src="/images/hand-bg.png"
alt="NOFX Platform Background"
className="w-full opacity-90"
style={{ opacity, scale }}
whileHover={{ scale: 1.02 }}
transition={{ type: 'spring', stiffness: 300 }}
/>
{/* Hand Layer - Animated */}
<motion.img
src="/images/hand.png"
alt="Robot Hand"
className="absolute top-0 left-0 w-full"
style={{ opacity }}
animate={handControls}
initial={{ y: 0, rotate: 0, x: 0 }}
whileHover={{
scale: 1.05,
transition: { type: 'spring', stiffness: 400 },
}}
/>
</div>
</div>
<section className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16">
{/* Animated Background */}
<div className="absolute inset-0 overflow-hidden">
{/* Grid Pattern */}
<div
className="absolute inset-0 opacity-[0.03]"
style={{
backgroundImage: `linear-gradient(#F0B90B 1px, transparent 1px), linear-gradient(90deg, #F0B90B 1px, transparent 1px)`,
backgroundSize: '60px 60px',
}}
/>
{/* Radial Gradient */}
<div
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] rounded-full"
style={{
background: 'radial-gradient(circle, rgba(240, 185, 11, 0.08) 0%, transparent 70%)',
}}
/>
{/* Floating Orbs */}
<motion.div
className="absolute top-20 right-20 w-32 h-32 rounded-full blur-3xl"
style={{ background: 'rgba(240, 185, 11, 0.15)' }}
animate={{
y: [0, 30, 0],
scale: [1, 1.1, 1],
}}
transition={{ duration: 8, repeat: Infinity, ease: 'easeInOut' }}
/>
<motion.div
className="absolute bottom-40 left-20 w-48 h-48 rounded-full blur-3xl"
style={{ background: 'rgba(240, 185, 11, 0.1)' }}
animate={{
y: [0, -40, 0],
scale: [1, 1.2, 1],
}}
transition={{ duration: 10, repeat: Infinity, ease: 'easeInOut' }}
/>
</div>
<div className="relative z-10 max-w-6xl mx-auto px-4 text-center">
{/* Badge */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
className="inline-flex items-center gap-2 px-4 py-2 rounded-full mb-8"
style={{
background: 'rgba(240, 185, 11, 0.1)',
border: '1px solid rgba(240, 185, 11, 0.3)',
}}
>
<Zap className="w-4 h-4" style={{ color: '#F0B90B' }} />
<span className="text-sm font-medium" style={{ color: '#F0B90B' }}>
{isLoading ? (
t('githubStarsInDays', language)
) : language === 'zh' ? (
<>
{daysOld} {' '}
<span className="font-bold tabular-nums">
{(animatedStars / 1000).toFixed(1)}K+
</span>{' '}
GitHub Stars
</>
) : (
<>
<span className="font-bold tabular-nums">
{(animatedStars / 1000).toFixed(1)}K+
</span>{' '}
GitHub Stars in {daysOld} days
</>
)}
</span>
</motion.div>
{/* Main Title */}
<motion.h1
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
className="text-5xl sm:text-6xl lg:text-7xl font-bold mb-6 leading-tight"
>
<span style={{ color: '#EAECEF' }}>{t('heroTitle1', language)}</span>
<br />
<span
className="relative inline-block"
style={{
background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{t('heroTitle2', language)}
<motion.span
className="absolute -bottom-2 left-0 h-1 rounded-full"
style={{ background: 'linear-gradient(90deg, #F0B90B, #FCD535)' }}
initial={{ width: 0 }}
animate={{ width: '100%' }}
transition={{ duration: 0.8, delay: 0.8 }}
/>
</span>
</motion.h1>
{/* Description */}
<motion.p
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.2 }}
className="text-lg sm:text-xl max-w-3xl mx-auto mb-10 leading-relaxed"
style={{ color: '#848E9C' }}
>
{t('heroDescription', language)}
</motion.p>
{/* CTA Buttons */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
className="flex flex-col sm:flex-row items-center justify-center gap-4 mb-12"
>
<motion.a
href="/competition"
className="group flex items-center gap-3 px-8 py-4 rounded-xl font-bold text-lg transition-all"
style={{
background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)',
color: '#0B0E11',
boxShadow: '0 4px 24px rgba(240, 185, 11, 0.3)',
}}
whileHover={{
scale: 1.02,
boxShadow: '0 8px 32px rgba(240, 185, 11, 0.4)',
}}
whileTap={{ scale: 0.98 }}
>
<Play className="w-5 h-5" />
{t('liveCompetition', language) || 'Live Competition'}
<ArrowRight className="w-5 h-5 transition-transform group-hover:translate-x-1" />
</motion.a>
<motion.a
href={OFFICIAL_LINKS.github}
target="_blank"
rel="noopener noreferrer"
className="group flex items-center gap-3 px-8 py-4 rounded-xl font-bold text-lg transition-all"
style={{
background: 'rgba(255, 255, 255, 0.05)',
color: '#EAECEF',
border: '1px solid rgba(255, 255, 255, 0.1)',
}}
whileHover={{
scale: 1.02,
background: 'rgba(255, 255, 255, 0.08)',
borderColor: 'rgba(240, 185, 11, 0.3)',
}}
whileTap={{ scale: 0.98 }}
>
<Github className="w-5 h-5" />
{t('viewSourceCode', language)}
</motion.a>
</motion.div>
{/* Stats Row */}
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
className="flex flex-wrap items-center justify-center gap-8 sm:gap-12"
>
{[
{ label: 'GitHub Stars', value: `${(stars / 1000).toFixed(1)}K+` },
{ label: language === 'zh' ? '支持交易所' : 'Exchanges', value: '5+' },
{ label: language === 'zh' ? 'AI 模型' : 'AI Models', value: '10+' },
{ label: language === 'zh' ? '开源免费' : 'Open Source', value: '100%' },
].map((stat, index) => (
<motion.div
key={stat.label}
className="text-center"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 + index * 0.1 }}
>
<div
className="text-3xl sm:text-4xl font-bold mb-1"
style={{
background: 'linear-gradient(135deg, #F0B90B 0%, #FCD535 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
}}
>
{stat.value}
</div>
<div className="text-sm" style={{ color: '#5E6673' }}>
{stat.label}
</div>
</motion.div>
))}
</motion.div>
{/* Powered By */}
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.6, delay: 0.8 }}
className="mt-16 text-xs"
style={{ color: '#5E6673' }}
>
{t('poweredBy', language)}
</motion.p>
</div>
{/* Scroll Indicator */}
<motion.div
className="absolute bottom-8 left-1/2 -translate-x-1/2"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 1 }}
>
<motion.div
className="w-6 h-10 rounded-full flex justify-center pt-2"
style={{ border: '2px solid rgba(240, 185, 11, 0.3)' }}
animate={{ y: [0, 8, 0] }}
transition={{ duration: 2, repeat: Infinity }}
>
<motion.div
className="w-1.5 h-3 rounded-full"
style={{ background: '#F0B90B' }}
/>
</motion.div>
</motion.div>
</section>
)
}

View File

@@ -1,140 +1,167 @@
import { motion } from 'framer-motion'
import AnimatedSection from './AnimatedSection'
import { Download, Rocket, TrendingUp, AlertTriangle } from 'lucide-react'
import { t, Language } from '../../i18n/translations'
function StepCard({ number, title, description, delay }: any) {
return (
<motion.div
className="flex gap-6 items-start"
initial={{ opacity: 0, x: -50 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ delay }}
whileHover={{ x: 10 }}
>
<motion.div
className="flex-shrink-0 w-14 h-14 rounded-full flex items-center justify-center font-bold text-2xl"
style={{
background: 'var(--binance-yellow)',
color: 'var(--brand-black)',
}}
whileHover={{ scale: 1.2, rotate: 360 }}
transition={{ type: 'spring', stiffness: 260, damping: 20 }}
>
{number}
</motion.div>
<div>
<h3
className="text-2xl font-semibold mb-2"
style={{ color: 'var(--brand-light-gray)' }}
>
{title}
</h3>
<p
className="text-lg leading-relaxed"
style={{ color: 'var(--text-secondary)' }}
>
{description}
</p>
</div>
</motion.div>
)
}
interface HowItWorksSectionProps {
language: Language
}
export default function HowItWorksSection({
language,
}: HowItWorksSectionProps) {
export default function HowItWorksSection({ language }: HowItWorksSectionProps) {
const steps = [
{
icon: Download,
number: '01',
title: language === 'zh' ? '克隆项目' : 'Clone Project',
desc: language === 'zh'
? 'git clone 项目到本地'
: 'git clone the project locally',
code: 'git clone https://github.com/NoFxAiOS/nofx.git',
},
{
icon: Rocket,
number: '02',
title: language === 'zh' ? '启动服务' : 'Start Service',
desc: language === 'zh'
? 'Docker 一键启动所有服务'
: 'Docker one-click start all services',
code: './start.sh start --build',
},
{
icon: TrendingUp,
number: '03',
title: language === 'zh' ? '开始交易' : 'Start Trading',
desc: language === 'zh'
? '创建交易员,让 AI 开始工作'
: 'Create trader, let AI do the work',
code: 'http://localhost:3000',
},
]
return (
<AnimatedSection id="how-it-works" backgroundColor="var(--brand-dark-gray)">
<div className="max-w-7xl mx-auto">
<section className="py-24 relative overflow-hidden" style={{ background: '#0D1117' }}>
{/* Background Decoration */}
<div
className="absolute left-0 top-1/2 -translate-y-1/2 w-96 h-96 rounded-full blur-3xl opacity-20"
style={{ background: 'radial-gradient(circle, rgba(240, 185, 11, 0.15) 0%, transparent 70%)' }}
/>
<div className="max-w-6xl mx-auto px-4 relative z-10">
{/* Header */}
<motion.div
className="text-center mb-16"
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
<h2
className="text-4xl font-bold mb-4"
style={{ color: 'var(--brand-light-gray)' }}
>
<h2 className="text-4xl lg:text-5xl font-bold mb-4" style={{ color: '#EAECEF' }}>
{t('howToStart', language)}
</h2>
<p className="text-lg" style={{ color: 'var(--text-secondary)' }}>
<p className="text-lg" style={{ color: '#848E9C' }}>
{t('fourSimpleSteps', language)}
</p>
</motion.div>
<div className="space-y-8">
{[
{
number: 1,
title: t('step1Title', language),
description: t('step1Desc', language),
},
{
number: 2,
title: t('step2Title', language),
description: t('step2Desc', language),
},
{
number: 3,
title: t('step3Title', language),
description: t('step3Desc', language),
},
{
number: 4,
title: t('step4Title', language),
description: t('step4Desc', language),
},
].map((step, index) => (
<StepCard key={step.number} {...step} delay={index * 0.1} />
))}
{/* Steps Timeline */}
<div className="relative">
{/* Connecting Line */}
<div
className="absolute left-[39px] top-0 bottom-0 w-px hidden lg:block"
style={{ background: 'linear-gradient(to bottom, transparent, rgba(240, 185, 11, 0.3), transparent)' }}
/>
<div className="space-y-6">
{steps.map((step, index) => (
<motion.div
key={step.number}
initial={{ opacity: 0, x: -30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true }}
transition={{ delay: index * 0.15 }}
className="relative"
>
<div
className="flex flex-col lg:flex-row items-start gap-6 p-6 rounded-2xl transition-all duration-300 hover:translate-x-2"
style={{
background: 'rgba(255, 255, 255, 0.02)',
border: '1px solid rgba(255, 255, 255, 0.05)',
}}
>
{/* Number Circle */}
<div className="flex-shrink-0 relative z-10">
<motion.div
className="w-20 h-20 rounded-2xl flex items-center justify-center"
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)',
}}
whileHover={{ scale: 1.1 }}
>
<step.icon className="w-8 h-8" style={{ color: '#F0B90B' }} />
</motion.div>
</div>
{/* Content */}
<div className="flex-grow">
<div className="flex items-center gap-3 mb-2">
<span
className="text-sm font-mono font-bold"
style={{ color: '#F0B90B' }}
>
{step.number}
</span>
<h3 className="text-xl font-bold" style={{ color: '#EAECEF' }}>
{step.title}
</h3>
</div>
<p className="mb-4" style={{ color: '#848E9C' }}>
{step.desc}
</p>
{/* Code Block */}
<div
className="inline-flex items-center gap-2 px-4 py-2 rounded-lg font-mono text-sm"
style={{
background: 'rgba(0, 0, 0, 0.3)',
border: '1px solid rgba(255, 255, 255, 0.06)',
}}
>
<span style={{ color: '#5E6673' }}>$</span>
<span style={{ color: '#EAECEF' }}>{step.code}</span>
</div>
</div>
</div>
</motion.div>
))}
</div>
</div>
{/* Risk Warning */}
<motion.div
className="mt-12 p-6 rounded-xl flex items-start gap-4"
className="mt-12 p-6 rounded-2xl flex items-start gap-4"
style={{
background: 'rgba(246, 70, 93, 0.1)',
border: '1px solid rgba(246, 70, 93, 0.3)',
background: 'rgba(240, 185, 11, 0.05)',
border: '1px solid rgba(240, 185, 11, 0.15)',
}}
initial={{ opacity: 0, scale: 0.9 }}
whileInView={{ opacity: 1, scale: 1 }}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
whileHover={{ scale: 1.02 }}
>
<div
className="w-10 h-10 rounded-full flex items-center justify-center flex-shrink-0"
style={{ background: 'rgba(246, 70, 93, 0.2)', color: '#F6465D' }}
className="w-12 h-12 rounded-xl flex items-center justify-center flex-shrink-0"
style={{ background: 'rgba(240, 185, 11, 0.1)' }}
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="w-6 h-6"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0Z" />
<line x1="12" x2="12" y1="9" y2="13" />
<line x1="12" x2="12.01" y1="17" y2="17" />
</svg>
<AlertTriangle className="w-6 h-6" style={{ color: '#F0B90B' }} />
</div>
<div>
<div className="font-semibold mb-2" style={{ color: '#F6465D' }}>
<div className="font-semibold mb-2" style={{ color: '#F0B90B' }}>
{t('importantRiskWarning', language)}
</div>
<p className="text-sm" style={{ color: 'var(--text-secondary)' }}>
<p className="text-sm leading-relaxed" style={{ color: '#5E6673' }}>
{t('riskWarningText', language)}
</p>
</div>
</motion.div>
</div>
</AnimatedSection>
</section>
)
}