fix: pre-launch UI hardening + KOL reduce-action type, proxy IP relay, settings redesign
Frontend half of the pre-launch audit campaign: - types/index.ts + kol/KolPageClient.tsx: add missing 'reduce' KolAction (backend emits it; frontend lacked the type + color/label maps → undefined styling). Adds ACTION_COLOR/actionLabel/postActionLabel entries. - proxy/[...path]/route.ts: relay real client IP (x-forwarded-for / x-real-ip) so the backend rate limiter buckets per-user instead of per-Next-server (BUG-02). - Settings/BotConfigPanel redesign, paper-mode clarity, copy cleanup. - Assorted page/display fixes, loading states, Pagination component. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+140
-51
@@ -224,8 +224,9 @@ export default function LandingPage() {
|
||||
useCursorVars(rootRef as React.RefObject<HTMLElement>)
|
||||
|
||||
// Decoded hero text — assembles from random glyphs on mount.
|
||||
const heroLine1 = useScramble('Where crypto alpha actually lives —', 1100)
|
||||
const heroLine2 = useScramble('all in one tab.', 1500)
|
||||
const heroLine1 = useScramble('Trump. KOL. Macro.', 900)
|
||||
const heroLine2 = useScramble('Six engines.', 1200)
|
||||
const heroLine3 = useScramble('Always first.', 1500)
|
||||
// primaryRef / useMagnetic intentionally removed — the hero CTA is now a
|
||||
// static button. The hook is still defined above in case the effect is
|
||||
// reinstated on another element later.
|
||||
@@ -254,56 +255,74 @@ export default function LandingPage() {
|
||||
<div className="lp-wrap">
|
||||
{/* ---------- HERO ---------- */}
|
||||
<section className="lp-hero">
|
||||
<div className="lp-live-badge">
|
||||
<span className="lp-live-dot" />
|
||||
Six signal engines running · right now
|
||||
</div>
|
||||
|
||||
<h1 className="lp-h1 lp-decode">
|
||||
<span className="lp-decode-line">{heroLine1}</span>
|
||||
<br />
|
||||
<span className="grad lp-decode-line">{heroLine2}</span>
|
||||
</h1>
|
||||
|
||||
<p className="lp-sub">
|
||||
Trump posts. On-chain bottoms. KOL essays. Wallets that move before
|
||||
they tweet. We scrape every edge, score it with AI, and surface only
|
||||
what’s tradeable. You sleep. It doesn’t.
|
||||
</p>
|
||||
|
||||
<div className="lp-ctas">
|
||||
<Link href="/en" className="lp-btn lp-btn-primary">
|
||||
Launch Dashboard
|
||||
<span className="lp-arrow">→</span>
|
||||
</Link>
|
||||
<a href="#pillars" className="lp-btn lp-btn-secondary">
|
||||
See all six signals
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Live counter strip — animates in when hero is visible */}
|
||||
<HeroStats />
|
||||
|
||||
|
||||
{/* Ticker strip */}
|
||||
<div className="lp-ticker" aria-hidden>
|
||||
<div className="lp-ticker-track">
|
||||
{[0, 1].map((k) => (
|
||||
<div key={k} style={{ display: 'flex', gap: 48 }}>
|
||||
<TickerItem asset="BTC" kind="buy" text="Post scored 82 · AUTO-LONG fired" />
|
||||
<TickerItem asset="ETH" kind="hold" text="Below user confidence floor · skipped" />
|
||||
<TickerItem asset="BTC" kind="sell" text="Signal SHORT · TP/SL armed" />
|
||||
<TickerItem asset="ETH" kind="buy" text="Post scored 74 · AUTO-LONG fired" />
|
||||
<TickerItem asset="BTC" kind="hold" text="Outside active window · standing by" />
|
||||
<TickerItem asset="ETH" kind="sell" text="Signal SHORT · position opened" />
|
||||
</div>
|
||||
))}
|
||||
{/* LEFT column */}
|
||||
<div className="lp-hero-left">
|
||||
<div className="lp-live-badge">
|
||||
<span className="lp-live-dot" />
|
||||
6 signal engines · live right now
|
||||
</div>
|
||||
|
||||
<h1 className="lp-h1 lp-decode">
|
||||
<span className="lp-decode-line">{heroLine1}</span>
|
||||
<br />
|
||||
<span className="grad lp-decode-line">{heroLine2}</span>
|
||||
<br />
|
||||
<span className="lp-decode-line">{heroLine3}</span>
|
||||
</h1>
|
||||
|
||||
<p className="lp-sub">
|
||||
AI reads every signal in under 3 seconds.
|
||||
You’re in the position before the headline hits.
|
||||
</p>
|
||||
|
||||
<div className="lp-ctas">
|
||||
<Link href="/en" className="lp-btn lp-btn-primary">
|
||||
Launch Dashboard
|
||||
<span className="lp-arrow">→</span>
|
||||
</Link>
|
||||
<a href="#pillars" className="lp-btn lp-btn-secondary">
|
||||
See all six signals
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Engine chips — show breadth at a glance */}
|
||||
<div className="lp-engine-chips">
|
||||
<span className="lp-engine-chip trump">Trump Signal</span>
|
||||
<span className="lp-engine-chip macro">Macro Vibes</span>
|
||||
<span className="lp-engine-chip kol">KOL Signal</span>
|
||||
<span className="lp-engine-chip tvt">Talks vs Trades</span>
|
||||
<span className="lp-engine-chip fund">Funding Reversal</span>
|
||||
<span className="lp-engine-chip auto">Auto-Trader</span>
|
||||
</div>
|
||||
|
||||
{/* Live counter strip */}
|
||||
<HeroStats />
|
||||
</div>
|
||||
|
||||
{/* RIGHT column — X-style live signal feed */}
|
||||
<div className="lp-hero-right">
|
||||
<LiveFeed />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Ticker strip — below the 2-col hero */}
|
||||
<div className="lp-ticker" aria-hidden>
|
||||
<div className="lp-ticker-track">
|
||||
{[0, 1].map((k) => (
|
||||
<div key={k} style={{ display: 'flex', gap: 48 }}>
|
||||
<TickerItem asset="BTC" kind="buy" text="Post scored 82 · AUTO-LONG fired" />
|
||||
<TickerItem asset="ETH" kind="hold" text="Below user confidence floor · skipped" />
|
||||
<TickerItem asset="BTC" kind="sell" text="Signal SHORT · TP/SL armed" />
|
||||
<TickerItem asset="ETH" kind="buy" text="Post scored 74 · AUTO-LONG fired" />
|
||||
<TickerItem asset="BTC" kind="hold" text="Outside active window · standing by" />
|
||||
<TickerItem asset="ETH" kind="sell" text="Signal SHORT · position opened" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ---------- FOUR PILLARS ---------- */}
|
||||
<section id="pillars" className="lp-section" style={{ paddingTop: 60 }}>
|
||||
<section id="pillars" className="lp-section" style={{ paddingTop: 48 }}>
|
||||
<div className="lp-reveal" style={{ maxWidth: 680 }}>
|
||||
<div className="lp-eyebrow">What runs inside</div>
|
||||
<h2 className="lp-h2">
|
||||
@@ -369,7 +388,7 @@ export default function LandingPage() {
|
||||
</section>
|
||||
|
||||
{/* ---------- THE ENGINE (terminal block) — Pillar 1 deep-dive ---------- */}
|
||||
<section id="engine" className="lp-section" style={{ paddingTop: 60 }}>
|
||||
<section id="engine" className="lp-section" style={{ paddingTop: 48 }}>
|
||||
<div className="lp-reveal" style={{ maxWidth: 640 }}>
|
||||
<div className="lp-eyebrow">Pillar 1 · live engine</div>
|
||||
<h2 className="lp-h2">
|
||||
@@ -439,7 +458,7 @@ export default function LandingPage() {
|
||||
</section>
|
||||
|
||||
{/* ---------- PRESS / HEADLINES ---------- */}
|
||||
<section className="lp-section" style={{ paddingTop: 60 }}>
|
||||
<section className="lp-section" style={{ paddingTop: 48 }}>
|
||||
<div className="lp-reveal" style={{ maxWidth: 680 }}>
|
||||
<div className="lp-eyebrow">Headlines you can Google</div>
|
||||
<h2 className="lp-h2">
|
||||
@@ -598,7 +617,7 @@ export default function LandingPage() {
|
||||
</section>
|
||||
|
||||
{/* ---------- COMPARISON TABLE ---------- */}
|
||||
<section id="compare" className="lp-section" style={{ paddingTop: 60 }}>
|
||||
<section id="compare" className="lp-section" style={{ paddingTop: 48 }}>
|
||||
<div className="lp-reveal" style={{ maxWidth: 680 }}>
|
||||
<div className="lp-eyebrow">How it compares</div>
|
||||
<h2 className="lp-h2">
|
||||
@@ -631,7 +650,7 @@ export default function LandingPage() {
|
||||
</section>
|
||||
|
||||
{/* ---------- WHAT IS TRUMP ALPHA (canonical definition for GEO) ---------- */}
|
||||
<section id="about" className="lp-section" style={{ paddingTop: 80 }}>
|
||||
<section id="about" className="lp-section" style={{ paddingTop: 56 }}>
|
||||
<div className="lp-reveal" style={{ maxWidth: 720 }}>
|
||||
<div className="lp-eyebrow">What is Trump Alpha</div>
|
||||
<h2 className="lp-h2">
|
||||
@@ -730,6 +749,76 @@ export default function LandingPage() {
|
||||
)
|
||||
}
|
||||
|
||||
/* ---------- Live feed (hero right column) ---------- */
|
||||
function LiveFeed() {
|
||||
return (
|
||||
<div className="lp-livefeed">
|
||||
<div className="lp-livefeed-head">
|
||||
<span className="lp-livefeed-dot" />
|
||||
Live signal feed
|
||||
<span className="lp-livefeed-count">3 today</span>
|
||||
</div>
|
||||
<LiveSignalPost
|
||||
isNew
|
||||
ts="2m ago"
|
||||
text="BITCOIN is the FUTURE of money. America will LEAD the world in crypto. BIG things coming very soon. ENJOY!"
|
||||
signal={{ type: 'LONG', asset: 'BTC', conf: 82, action: 'AUTO-LONG fired' }}
|
||||
/>
|
||||
<LiveSignalPost
|
||||
ts="14m ago"
|
||||
text="Massive new TARIFFS on China coming — they have RIPPED OFF the USA for decades. No more!"
|
||||
signal={{ type: 'SHORT', asset: 'BTC', conf: 71, action: 'AUTO-SHORT fired' }}
|
||||
/>
|
||||
<LiveSignalPost
|
||||
ts="38m ago"
|
||||
text="Crooked Joe and the Radical Left Lunatics are destroying our beautiful country. SAD!"
|
||||
signal={{ type: 'NOISE', skip: 'off-topic · skipped' }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function LiveSignalPost({
|
||||
isNew, ts, text, signal,
|
||||
}: {
|
||||
isNew?: boolean
|
||||
ts: string
|
||||
text: string
|
||||
signal:
|
||||
| { type: 'LONG' | 'SHORT'; asset: string; conf: number; action: string }
|
||||
| { type: 'NOISE'; skip: string }
|
||||
}) {
|
||||
const t = signal.type
|
||||
return (
|
||||
<div className={`lp-signal-post${isNew ? ' is-new' : ''}`}>
|
||||
<div className="lp-signal-post-head">
|
||||
<span className="lp-signal-handle">Donald Trump</span>
|
||||
<span className="lp-signal-at">@realDonaldTrump</span>
|
||||
{isNew && <span className="lp-signal-new-badge">new</span>}
|
||||
<span className="lp-signal-ts">{ts}</span>
|
||||
</div>
|
||||
<p className="lp-signal-text">{text}</p>
|
||||
<div className="lp-signal-chips">
|
||||
<span className={`lp-signal-chip ${t === 'LONG' ? 'long' : t === 'SHORT' ? 'short' : 'noise'}`}>
|
||||
{t}
|
||||
</span>
|
||||
{'asset' in signal && (
|
||||
<>
|
||||
<span className="lp-signal-chip asset">{signal.asset}</span>
|
||||
<span className="lp-signal-chip conf">CONF {signal.conf}</span>
|
||||
<span className={`lp-signal-chip ${signal.action.includes('fired') ? 'action-ok' : 'action-skip'}`}>
|
||||
· {signal.action}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{'skip' in signal && (
|
||||
<span className="lp-signal-chip action-skip">· {signal.skip}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/* ---------- Terminal row ---------- */
|
||||
function TermRow({
|
||||
isNew,
|
||||
|
||||
Reference in New Issue
Block a user