feat: improve landing page responsiveness and styling

This commit is contained in:
tinkle-community
2026-01-03 13:12:25 +08:00
parent 7f7c4ea2a7
commit 04141642a5
7 changed files with 206 additions and 49 deletions

View File

@@ -1,6 +1,6 @@
import { useEffect, useState, useRef } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
// Force HMR Update
// Force HMR Update - Reliability Fix v3 (Emergency Recovery)
import useSWR, { mutate } from 'swr'
import { api } from './lib/api'
import { ChartTabs } from './components/ChartTabs'

View File

@@ -42,9 +42,9 @@ export default function FooterSection({ language }: FooterSectionProps) {
return (
<footer style={{ background: '#0B0E11', borderTop: '1px solid rgba(255, 255, 255, 0.06)' }}>
<div className="max-w-6xl mx-auto px-4 py-12">
<div className="max-w-6xl mx-auto px-4 py-8 md:py-12">
{/* Top Section */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-10 mb-12">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8 md:gap-10 mb-8 md:mb-12">
{/* Brand */}
<div className="md:col-span-1">
<div className="flex items-center gap-3 mb-4">

View File

@@ -19,19 +19,27 @@ export default function BrandStats() {
}}
/>
<div className="max-w-[1920px] mx-auto px-6 lg:px-16 relative z-10">
<div className="grid grid-cols-2 md:grid-cols-4 gap-12 text-center md:text-left">
<div className="max-w-[1920px] mx-auto px-4 lg:px-16 relative z-10">
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 md:gap-12 md:text-left">
{stats.map((stat, i) => (
<motion.div
key={i}
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
transition={{ delay: i * 0.1 }}
className="relative overflow-hidden group bg-black/40 backdrop-blur-md border border-white/10 p-6 rounded-lg md:bg-transparent md:border-0 md:p-0 md:backdrop-blur-none"
>
<div className="text-5xl md:text-6xl font-black text-white tracking-tighter mb-2">
{/* Mobile Neon Corners */}
<div className="absolute top-0 right-0 w-3 h-3 border-t-2 border-r-2 border-nofx-gold md:hidden opacity-80 shadow-[0_0_10px_rgba(234,179,8,0.5)]"></div>
<div className="absolute bottom-0 left-0 w-3 h-3 border-b-2 border-l-2 border-nofx-gold md:hidden opacity-80 shadow-[0_0_10px_rgba(234,179,8,0.5)]"></div>
{/* Mobile Inner Glow */}
<div className="absolute inset-0 bg-nofx-gold/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300 pointer-events-none md:hidden"></div>
<div className="text-3xl md:text-6xl font-black text-white tracking-tighter mb-2 group-hover:scale-110 transition-transform duration-300 origin-left relative z-10">
{stat.value}
</div>
<div className="text-sm md:text-base font-bold text-black/60 uppercase tracking-widest bg-white/20 inline-block px-2 py-1">
<div className="text-[10px] md:text-base font-bold text-zinc-400 md:text-black/60 uppercase tracking-widest bg-white/5 md:bg-white/20 inline-block px-2 py-1 rounded relative z-10">
{stat.label}
</div>
</motion.div>

View File

@@ -4,6 +4,8 @@ import { TrendingUp, Layers, Zap, Hexagon, Crosshair } from 'lucide-react'
const agents = [
{
name: "ALPHA-1",
// ... (rest of agents array remains, but I can't skip lines in replacement content easily without context. Wait, let's just replace the top section)
// Actually, I'll use multi_replace for targeted cleanup.
class: "SCALPER",
desc: "High-frequency microstructure exploitation.",
apy: "142%",
@@ -41,8 +43,10 @@ const agents = [
]
export default function AgentGrid() {
// Simplified State to prevent crash
return (
<section id="market-scanner" className="py-24 bg-nofx-bg relative overflow-hidden">
<section id="market-scanner" className="py-16 md:py-24 bg-nofx-bg relative overflow-hidden">
{/* Background Details */}
<div className="absolute top-0 right-0 p-10 opacity-20 pointer-events-none">
@@ -51,7 +55,7 @@ export default function AgentGrid() {
<div className="max-w-7xl mx-auto px-6 relative z-10">
<div className="flex flex-col md:flex-row justify-between items-end mb-16 gap-6">
<div className="flex flex-col md:flex-row justify-between items-end mb-10 md:mb-16 gap-6">
<div>
<div className="flex items-center gap-2 text-nofx-gold font-mono text-xs mb-2 tracking-widest uppercase">
<Crosshair className="w-4 h-4" /> MARKET SELECT
@@ -65,17 +69,18 @@ export default function AgentGrid() {
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* Grid Container - Removing scroll tracking for stability test */}
<div className="flex flex-row md:grid md:grid-cols-3 gap-4 md:gap-8 overflow-x-auto md:overflow-visible pb-12 md:pb-0 snap-x snap-mandatory -mx-6 px-6 md:mx-0 md:px-0 scrollbar-hide">
{agents.map((agent, i) => {
const Icon = agent.icon
return (
<motion.div
key={i}
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: i * 0.1 }}
className={`group relative bg-black/40 backdrop-blur-sm border ${agent.border} overflow-hidden hover:bg-zinc-900/40 transition-all duration-300 ${agent.bg_glow}`}
style={{ clipPath: 'polygon(0 0, 100% 0, 100% 85%, 85% 100%, 0 100%)' }}
className={`group relative bg-black/40 backdrop-blur-xl border ${agent.border} overflow-hidden transition-all duration-300 min-w-[85vw] md:min-w-0 snap-center shrink-0 rounded-xl md:rounded-none`}
>
{/* Top "Hinge" decoration */}
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-transparent via-white/10 to-transparent"></div>

View File

@@ -65,7 +65,7 @@ export default function LiveFeed() {
<section className="w-full bg-[#020304] border-y border-zinc-800 py-1 overflow-hidden relative">
<div className="absolute inset-0 bg-scanlines opacity-10 pointer-events-none"></div>
<div className="max-w-[1920px] mx-auto px-4 flex flex-col md:flex-row gap-0 md:gap-8 items-stretch h-[320px] md:h-12 text-xs font-mono">
<div className="max-w-[1920px] mx-auto px-4 flex flex-col md:flex-row gap-0 md:gap-8 items-stretch h-[240px] md:h-12 text-xs font-mono">
{/* Left Status Bar (Static) */}
<div className="hidden md:flex items-center gap-6 text-zinc-600 border-r border-zinc-900 pr-6 shrink-0">
@@ -92,8 +92,8 @@ export default function LiveFeed() {
>
<span className="text-zinc-600">[{log.time}]</span>
<span className={`font-bold w-10 ${log.type === 'LIQ' ? 'text-red-500 bg-red-500/10 px-1 rounded' :
log.type === 'ARB' ? 'text-nofx-gold bg-nofx-gold/10 px-1 rounded' :
log.type === 'EXE' ? 'text-green-500' : 'text-zinc-500'
log.type === 'ARB' ? 'text-nofx-gold bg-nofx-gold/10 px-1 rounded' :
log.type === 'EXE' ? 'text-green-500' : 'text-zinc-500'
}`}>{log.type}</span>
<span className={`${log.color}`}>{log.msg}</span>
</motion.div>
@@ -106,8 +106,8 @@ export default function LiveFeed() {
<div key={log.id} className="flex gap-2 w-full truncate border-b border-zinc-900/50 pb-1 last:border-0">
<span className="text-zinc-700 w-16 shrink-0">{log.time.split('.')[0]}</span>
<span className={`font-bold w-8 shrink-0 ${log.type === 'LIQ' ? 'text-red-500' :
log.type === 'ARB' ? 'text-nofx-gold' :
'text-zinc-500'
log.type === 'ARB' ? 'text-nofx-gold' :
'text-zinc-500'
}`}>{log.type}</span>
<span className={`${log.color} truncate`}>{log.msg}</span>
</div>

View File

@@ -1,7 +1,6 @@
import { motion } from 'framer-motion'
import { ArrowRight, Shield, Activity, CircuitBoard, Cpu, Wifi, Globe, Lock, Zap, Star, GitFork, Users, MessageCircle } from 'lucide-react'
import { useState, useEffect } from 'react'
import { httpClient } from '../../../lib/httpClient'
import { useGitHubStats } from '../../../hooks/useGitHubStats'
export default function TerminalHero() {
@@ -27,9 +26,18 @@ export default function TerminalHero() {
try {
const results = await Promise.all(symbols.map(async (sym) => {
try {
const res = await httpClient.get(`/api/klines?symbol=${sym}USDT&interval=1m&limit=1`)
if (res.success && res.data?.length > 0) {
const closePrice = parseFloat(res.data[0].close)
// Use native fetch to bypass global error handlers (toasts) in httpClient
const response = await fetch(`/api/klines?symbol=${sym}USDT&interval=1m&limit=1`)
if (!response.ok) return null
const res = await response.json()
// Check for standard API response structure or direct array
const klineData = res.data || res
if (Array.isArray(klineData) && klineData.length > 0) {
const closePrice = parseFloat(klineData[0].close || klineData[0][4]) // Handle object or array format
if (isNaN(closePrice)) return null
// Format price: < 1 use 4 decimals, > 1 use 2
const formatted = closePrice < 1
? closePrice.toFixed(4)
@@ -37,7 +45,7 @@ export default function TerminalHero() {
return { symbol: sym, price: formatted }
}
} catch (err) {
// ignore individual failures
// Silent failure for background polling
}
return null
}))
@@ -64,6 +72,7 @@ export default function TerminalHero() {
{/* BACKGROUND LAYERS */}
{/* 1. Grid */}
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-20 mix-blend-soft-light pointer-events-none"></div>
<div className="absolute inset-x-0 bottom-0 h-[50vh] bg-[linear-gradient(to_right,#80808012_1px,transparent_1px),linear-gradient(to_bottom,#80808012_1px,transparent_1px)] bg-[size:40px_40px] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,#000_70%,transparent_100%)] pointer-events-none md:hidden" style={{ transform: 'perspective(500px) rotateX(60deg) translateY(100px) scale(2)' }}></div>
<div className="absolute inset-0 bg-grid-pattern opacity-[0.03] pointer-events-none"></div>
{/* 2. World Map / Data Viz Background (Abstract) */}
@@ -72,9 +81,19 @@ export default function TerminalHero() {
<div className="absolute w-[60vw] h-[60vw] rounded-full border border-dashed border-nofx-accent/20 animate-[spin_60s_linear_infinite]"></div>
</div>
{/* 3. Gradient Spots */}
<div className="absolute top-[-10%] left-[-10%] w-[40vw] h-[40vw] bg-nofx-gold/10 rounded-full blur-[120px] pointer-events-none"></div>
<div className="absolute bottom-[-10%] right-[-10%] w-[40vw] h-[40vw] bg-nofx-accent/5 rounded-full blur-[120px] pointer-events-none"></div>
{/* 3. Gradient Spots - Intensified for Mobile */}
<div className="absolute top-[-10%] left-[-10%] w-[40vw] h-[40vw] bg-nofx-gold/20 rounded-full blur-[120px] pointer-events-none mix-blend-screen"></div>
<div className="absolute bottom-[-10%] right-[-10%] w-[40vw] h-[40vw] bg-nofx-accent/10 rounded-full blur-[120px] pointer-events-none mix-blend-screen"></div>
{/* Mobile Bottom Fade */}
<div className="absolute bottom-0 left-0 w-full h-32 bg-gradient-to-t from-nofx-bg to-transparent z-20 pointer-events-none md:hidden" />
{/* Mobile Floating HUD - Moved to Left to avoid covering face */}
<div className="md:hidden absolute top-24 left-4 z-0 opacity-40 pointer-events-none">
<div className="w-24 h-24 border border-dashed border-nofx-gold/30 rounded-full animate-spin-slow flex items-center justify-center">
<div className="w-16 h-16 border border-nofx-accent/30 rounded-full"></div>
</div>
</div>
{/* CONTENT GRID */}
<div className="relative z-10 flex-1 grid grid-cols-1 lg:grid-cols-12 gap-0 lg:gap-8 max-w-[1800px] mx-auto w-full px-6 h-full pb-20 pt-10 pointer-events-none">
@@ -153,15 +172,18 @@ export default function TerminalHero() {
</motion.div>
{/* Main Title - Massive & Impactful */}
<h1 className="text-6xl md:text-8xl lg:text-9xl font-black tracking-tighter leading-[0.8] mb-6 select-none bg-clip-text text-transparent bg-gradient-to-b from-white via-white to-zinc-600">
AGENTIC<br />
<span className="text-stroke-1 text-transparent bg-clip-text bg-gradient-to-r from-nofx-gold via-white to-nofx-gold animate-shimmer bg-[length:200%_auto]">TRADING</span>
</h1>
{/* Main Title - Massive & Impactful */}
<div className="relative z-20 mix-blend-hard-light md:mix-blend-normal">
<h1 className="text-6xl sm:text-6xl md:text-8xl lg:text-9xl font-black tracking-tighter leading-[0.9] md:leading-[0.8] mb-6 select-none bg-clip-text text-transparent bg-gradient-to-b from-white via-white to-zinc-600 drop-shadow-2xl">
AGENTIC<br />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-nofx-gold via-white to-nofx-gold animate-shimmer bg-[length:200%_auto] tracking-tight filter drop-shadow-[0_0_15px_rgba(234,179,8,0.3)]">TRADING</span>
</h1>
<p className="max-w-xl text-zinc-400 text-lg mb-6 font-light leading-relaxed">
The World's First Open-Source Agentic Trading OS.
Deploy autonomous high-frequency trading agents powered by advanced LLMs.
</p>
<p className="max-w-xl text-zinc-200 md:text-zinc-400 text-lg mb-6 font-light leading-relaxed drop-shadow-md">
The World's First Open-Source Agentic Trading OS.
Deploy autonomous high-frequency trading agents powered by advanced LLMs.
</p>
</div>
{/* Market Access Strip - Prominent Display */}
{/* Market Access Strip - Prominent Display */}
@@ -214,26 +236,52 @@ export default function TerminalHero() {
</div>
</div>
{/* RIGHT COLUMN: HOLOGRAPHIC DISPLAY - Absolute Overlay for "Far Right" Effect */}
<div className="absolute top-0 right-0 h-full w-[45vw] hidden lg:flex pointer-events-none items-center justify-center z-0">
{/* RIGHT COLUMN: HOLOGRAPHIC DISPLAY - Absolute Overlay for "Far Right" Effect on Desktop, Background on Mobile */}
<div className="absolute top-20 md:top-0 right-0 h-[50vh] md:h-full w-full lg:w-[45vw] flex pointer-events-none items-center justify-center z-0 opacity-80 lg:opacity-100 mix-blend-normal">
<div className="relative w-full h-full flex items-center justify-center perspective-1000">
{/* 3D Hologram Effect Container */}
<div className="relative w-full h-[90%] flex items-center justify-center transform-style-3d rotate-y-[-12deg]">
{/* Scanning Grid behind Mascot */}
<div className="absolute inset-x-0 top-[10%] bottom-[10%] bg-[linear-gradient(rgba(0,240,255,0.05)_1px,transparent_1px),linear-gradient(90deg,rgba(0,240,255,0.05)_1px,transparent_1px)] bg-[size:20px_20px] [mask-image:radial-gradient(ellipse_at_center,black_40%,transparent_80%)]"></div>
{/* Scanning Grid behind Mascot - Mobile Optimized */}
<div className="absolute inset-x-0 top-[10%] bottom-[10%] bg-[linear-gradient(rgba(0,240,255,0.05)_1px,transparent_1px),linear-gradient(90deg,rgba(0,240,255,0.05)_1px,transparent_1px)] bg-[size:20px_20px] [mask-image:radial-gradient(ellipse_at_center,black_40%,transparent_80%)] mobile-grid-pulse"></div>
{/* The Mascot Image with Glitch/Holo Effects */}
<div className="relative z-10 w-full h-full opacity-90 transition-all duration-500 hover:opacity-100 group flex flex-col justify-end pointer-events-auto">
<div className="absolute inset-0 bg-nofx-accent/10 blur-[80px] rounded-full animate-pulse-slow transition-colors duration-500 group-hover:bg-nofx-gold/40"></div>
<img
src="/images/nofx_mascot.png"
alt="Agent NoFX"
className="w-full h-full object-contain object-bottom filter drop-shadow-[0_0_25px_rgba(0,240,255,0.2)] contrast-110 saturate-0 group-hover:saturate-100 group-hover:drop-shadow-[0_0_35px_rgba(234,179,8,0.5)] transition-all duration-500"
style={{ maskImage: 'linear-gradient(to bottom, black 90%, transparent 100%)' }}
/>
{/* Holo Scan Line */}
<div className="absolute w-full h-2 bg-nofx-accent/30 drop-shadow-[0_0_10px_rgba(0,240,255,0.8)] top-0 animate-scan-fast pointer-events-none"></div>
<div className="relative z-10 w-full h-full opacity-100 transition-all duration-500 group flex flex-col justify-end pointer-events-auto">
<div className="absolute inset-x-0 bottom-0 top-1/2 bg-nofx-accent/5 blur-[60px] rounded-full animate-pulse-slow transition-colors duration-500 group-hover:bg-nofx-gold/20"></div>
{/* Mobile Holo-Portrait Style - Full Color & Optimized & Premium Desktop */}
<div className="relative w-full h-full flex items-end justify-center">
<img
src="/images/nofx_mascot.png"
alt="Agent NoFX"
className="w-full h-full object-contain object-bottom char-premium-effects animate-breath-mobile transition-all duration-500"
style={{
maskImage: 'radial-gradient(ellipse at center, black 60%, transparent 100%), linear-gradient(to bottom, black 0%, black 85%, transparent 100%)',
WebkitMaskImage: 'radial-gradient(ellipse at center, black 60%, transparent 100%), linear-gradient(to bottom, black 0%, black 85%, transparent 100%)',
maskComposite: 'intersect',
WebkitMaskComposite: 'source-in'
}}
/>
{/* Dynamic Holographic Overlay - Premium Noise & Gradient */}
<div className="absolute inset-0 w-full h-full holo-overlay animate-holo opacity-80 pointer-events-none"
style={{
maskImage: 'url(/images/nofx_mascot.png)',
WebkitMaskImage: 'url(/images/nofx_mascot.png)',
maskSize: 'contain',
WebkitMaskSize: 'contain',
maskPosition: 'bottom center',
WebkitMaskPosition: 'bottom center',
maskRepeat: 'no-repeat',
WebkitMaskRepeat: 'no-repeat'
}}
/>
</div>
{/* Holo Scan Line - Subtle on Mobile */}
<div className="absolute w-full h-1 bg-nofx-accent/30 drop-shadow-[0_0_10px_rgba(0,240,255,0.8)] top-0 animate-scan-fast pointer-events-none mix-blend-overlay"></div>
{/* Mobile Glitch Overlay - Reduced Intensity */}
<div className="absolute inset-0 bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-10 mix-blend-overlay md:hidden animate-pulse-fast"></div>
</div>
</div>
@@ -241,7 +289,7 @@ export default function TerminalHero() {
<motion.div
animate={{ y: [0, -10, 0] }}
transition={{ duration: 4, repeat: Infinity, ease: "easeInOut" }}
className="absolute top-[30%] left-[10%] bg-black/80 border border-nofx-accent/30 p-2 rounded backdrop-blur-md shadow-neon-blue"
className="absolute top-[30%] left-[10%] bg-black/80 border border-nofx-accent/30 p-2 rounded backdrop-blur-md shadow-neon-blue hidden md:block"
>
<Cpu className="w-5 h-5 text-nofx-accent" />
</motion.div>
@@ -249,7 +297,7 @@ export default function TerminalHero() {
<motion.div
animate={{ y: [0, 10, 0] }}
transition={{ duration: 5, repeat: Infinity, ease: "easeInOut", delay: 1 }}
className="absolute bottom-[20%] right-[20%] bg-black/80 border border-nofx-gold/30 p-2 rounded backdrop-blur-md shadow-neon"
className="absolute bottom-[20%] right-[20%] bg-black/80 border border-nofx-gold/30 p-2 rounded backdrop-blur-md shadow-neon hidden md:block"
>
<Lock className="w-5 h-5 text-nofx-gold" />
</motion.div>

View File

@@ -846,4 +846,100 @@ tr:hover {
.stat-card {
padding: 1rem;
}
}
/* Holographic Character Effects - Premium Polish */
@keyframes holo-shift {
0% {
background-position: 0% 50%;
filter: hue-rotate(0deg) contrast(1);
}
50% {
background-position: 100% 50%;
filter: hue-rotate(15deg) contrast(1.1);
}
100% {
background-position: 0% 50%;
filter: hue-rotate(0deg) contrast(1);
}
}
@keyframes holo-flicker {
0%,
100% {
opacity: 0.7;
}
5% {
opacity: 0.8;
}
10% {
opacity: 0.7;
}
}
.animate-holo {
background-size: 200% 200%;
animation: holo-shift 8s ease infinite, holo-flicker 4s infinite;
}
/* Mobile Breathing Animation */
@keyframes holo-breath {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.02);
}
}
.animate-breath-mobile {
animation: none;
}
@media (max-width: 768px) {
.animate-breath-mobile {
animation: holo-breath 4s ease-in-out infinite;
}
/* Optimize premium effects for mobile */
.char-premium-effects {
filter:
drop-shadow(0 0 1px rgba(240, 185, 11, 0.6)) drop-shadow(0 0 1px rgba(0, 240, 255, 0.5));
}
}
.holo-overlay {
/* Complex gradient + noise for texture */
background:
url('https://grainy-gradients.vercel.app/noise.svg'),
conic-gradient(from 0deg at 50% 50%,
rgba(240, 185, 11, 0.1) 0deg,
rgba(0, 240, 255, 0.1) 120deg,
rgba(240, 185, 11, 0.1) 240deg,
rgba(240, 185, 11, 0.1) 360deg);
mix-blend-mode: overlay;
background-blend-mode: overlay, normal;
}
/* Chromatic Aberration & Rim Light */
.char-premium-effects {
filter:
/* Rim Light (Gold/Cyan) */
drop-shadow(0 0 1px rgba(240, 185, 11, 0.8)) drop-shadow(0 0 2px rgba(0, 240, 255, 0.6))
/* Chromatic Aberration */
drop-shadow(-2px 0 0 rgba(255, 0, 0, 0.3)) drop-shadow(2px 0 0 rgba(0, 255, 255, 0.3));
transition: filter 0.3s ease;
}
.char-premium-effects:hover {
filter:
drop-shadow(0 0 2px rgba(240, 185, 11, 1)) drop-shadow(0 0 5px rgba(0, 240, 255, 0.8)) drop-shadow(-3px 0 0 rgba(255, 0, 0, 0.4)) drop-shadow(3px 0 0 rgba(0, 255, 255, 0.4));
}