Files
trumpsignal-frontend/app/opengraph-image.tsx
T
k be151edf6e fix(seo/geo): canonical URLs, OG KOL count, FAQ key-storage copy, expand llms.txt
SEO fixes:
- canonical on trump/macro/kol pages now hardcodes /en/ instead of
  /${locale}/ — prevents /zh/* routes (i18n shelved, routes still resolve)
  from generating duplicate-content signals pointing to /zh/ canonicals
- OG image: "15 KOL feeds" → "19" (matches kol_substack.py KOL_FEEDS count)
- FAQ JSON-LD: corrected API key storage description ("stored encrypted in
  your browser's local settings" was wrong — key is server-side encrypted,
  not stored in the browser)

GEO (Generative Engine Optimization):
- llms.txt fully rewritten: +full KOL list (all 19 named), +explicit
  differentiation section, +who-this-is-for, +technology stack detail
  (model names, price sources, DB), +Hyperliquid and isolated-margin
  definitions. AI crawlers (Perplexity, ChatGPT, Claude) use this file
  directly when answering questions about the product.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 16:56:53 +08:00

172 lines
4.6 KiB
TypeScript

import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export const alt = 'Trump Alpha — Four crypto alpha feeds, one dashboard'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export default function OGImage() {
return new ImageResponse(
(
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
justifyContent: 'flex-end',
padding: '64px 72px',
background: '#0a0907',
position: 'relative',
overflow: 'hidden',
fontFamily: 'system-ui, sans-serif',
}}
>
{/* Background grid */}
<div
style={{
position: 'absolute',
inset: 0,
backgroundImage:
'linear-gradient(rgba(245,165,36,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(245,165,36,0.04) 1px, transparent 1px)',
backgroundSize: '48px 48px',
}}
/>
{/* Ambient glow */}
<div
style={{
position: 'absolute',
top: -200,
left: -200,
width: 800,
height: 800,
borderRadius: '50%',
background: 'radial-gradient(circle, rgba(245,165,36,0.12) 0%, transparent 70%)',
}}
/>
{/* Top-right corner badge */}
<div
style={{
position: 'absolute',
top: 48,
right: 72,
display: 'flex',
alignItems: 'center',
gap: 8,
padding: '6px 14px',
borderRadius: 999,
background: 'rgba(245,165,36,0.12)',
border: '1px solid rgba(245,165,36,0.3)',
}}
>
<div
style={{
width: 8,
height: 8,
borderRadius: '50%',
background: '#22c55e',
}}
/>
<span style={{ fontSize: 14, color: '#f5a524', fontWeight: 700, letterSpacing: '0.06em' }}>
LIVE
</span>
</div>
{/* Four signal pills */}
<div
style={{
display: 'flex',
gap: 12,
marginBottom: 40,
flexWrap: 'wrap',
}}
>
{[
{ label: 'Trump · Truth Social', color: '#f5a524' },
{ label: 'Macro Vibes', color: '#a78bfa' },
{ label: 'KOL Signal', color: '#22c55e' },
{ label: 'Talks vs Trades', color: '#ef4444' },
].map((p) => (
<div
key={p.label}
style={{
display: 'flex',
padding: '7px 16px',
borderRadius: 6,
background: 'rgba(255,255,255,0.05)',
border: `1px solid ${p.color}40`,
fontSize: 13,
fontWeight: 600,
color: p.color,
letterSpacing: '0.02em',
}}
>
{p.label}
</div>
))}
</div>
{/* Main title */}
<div
style={{
fontSize: 72,
fontWeight: 800,
lineHeight: 1.05,
color: '#f5f2ea',
marginBottom: 24,
letterSpacing: '-0.03em',
}}
>
Trump Alpha
</div>
{/* Sub */}
<div
style={{
fontSize: 24,
color: '#8a8578',
fontWeight: 400,
lineHeight: 1.5,
maxWidth: 700,
marginBottom: 0,
}}
>
Four crypto alpha feeds. AI-scored in real time.
<br />
One dashboard zero noise.
</div>
{/* Bottom right stat strip */}
<div
style={{
position: 'absolute',
bottom: 52,
right: 72,
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-end',
gap: 6,
}}
>
{[
{ v: '<3s', l: 'post → position' },
{ v: '19', l: 'KOL feeds' },
{ v: '$0', l: 'platform fee' },
].map((s) => (
<div key={s.l} style={{ display: 'flex', gap: 10, alignItems: 'baseline' }}>
<span style={{ fontSize: 22, fontWeight: 700, color: '#f5a524', fontFamily: 'monospace' }}>
{s.v}
</span>
<span style={{ fontSize: 13, color: '#5c584e' }}>{s.l}</span>
</div>
))}
</div>
</div>
),
{ ...size },
)
}