KOL count: 29 → 25 across marketing/SEO copy
Backend KOL_FEEDS trimmed from 29 to 25 (dead feeds removed).
Sync all hardcoded count mentions:
- layout.tsx JSON-LD, page.tsx (metric + comparison + copy)
- kol/page.tsx, KolPageClient.tsx ("and 26 more" → "and 22 more")
- glossary/page.tsx, opengraph-image.tsx
- public/llms.txt, llms-full.txt
- drop removed KOLs (Dragonfly Capital, Nic Carter) from named lists
Bundles other in-flight frontend work already in the working tree.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { useLocale } from 'next-intl'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useWsSubscribe } from '@/lib/wsContext'
|
||||
|
||||
const API_BASE = '/api/proxy/api'
|
||||
@@ -30,82 +29,22 @@ function timeAgo(iso: string) {
|
||||
return `${Math.round(diff / 3600)}h ago`
|
||||
}
|
||||
|
||||
// ── iOS-style toggle switch ───────────────────────────────────────────────────
|
||||
function ToggleSwitch({ on, loading, onToggle }: {
|
||||
on: boolean
|
||||
loading: boolean
|
||||
onToggle: () => void
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
onClick={onToggle}
|
||||
disabled={loading}
|
||||
title={on ? 'Click to disable' : 'Click to enable'}
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
cursor: loading ? 'not-allowed' : 'pointer',
|
||||
padding: 0,
|
||||
opacity: loading ? 0.5 : 1,
|
||||
}}
|
||||
>
|
||||
{/* Switch track */}
|
||||
<div style={{
|
||||
width: 44,
|
||||
height: 26,
|
||||
borderRadius: 13,
|
||||
background: on ? '#22c55e' : 'var(--ink-4)',
|
||||
position: 'relative',
|
||||
transition: 'background 0.2s',
|
||||
flexShrink: 0,
|
||||
opacity: on ? 1 : 0.5,
|
||||
}}>
|
||||
{/* Thumb */}
|
||||
<div style={{
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: '50%',
|
||||
background: '#fff',
|
||||
position: 'absolute',
|
||||
top: 2,
|
||||
left: on ? 20 : 2,
|
||||
transition: 'left 0.2s',
|
||||
boxShadow: '0 1px 3px rgba(0,0,0,0.3)',
|
||||
}} />
|
||||
</div>
|
||||
<span style={{
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
color: on ? '#22c55e' : 'var(--ink-3)',
|
||||
letterSpacing: '0.05em',
|
||||
minWidth: 24,
|
||||
}}>
|
||||
{on ? 'ON' : 'OFF'}
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
// ── Main component ────────────────────────────────────────────────────────────
|
||||
// Display-only: toggle is operator-only (requires X-Ingest-Key) so the
|
||||
// on/off switch is intentionally absent from the user-facing UI.
|
||||
export default function SignalMonitor() {
|
||||
const locale = useLocale()
|
||||
const isZh = false // i18n shelved — Chinese branches kept as dead code for future revival; see messages/zh.json
|
||||
const [enabled, setEnabledState] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [backendOk, setBackendOk] = useState<boolean | null>(null)
|
||||
const [signals, setSignals] = useState<SignalAlert[]>([])
|
||||
const [btcTrend, setBtcTrend] = useState<string | null>(null)
|
||||
const [lastScan, setLastScan] = useState<Date | null>(null)
|
||||
const [signals, setSignals] = useState<SignalAlert[]>([])
|
||||
const [btcTrend, setBtcTrend] = useState<string | null>(null)
|
||||
const [lastScan, setLastScan] = useState<Date | null>(null)
|
||||
|
||||
// ── Load initial state ───────────────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
fetch(`${API_BASE}/signal/status`)
|
||||
.then(r => { if (!r.ok) throw new Error(); return r.json() })
|
||||
.then(d => { setEnabledState(d.enabled); setBackendOk(true) })
|
||||
.catch(() => setBackendOk(false))
|
||||
.then(d => { setEnabledState(d.enabled) })
|
||||
.catch(() => {})
|
||||
|
||||
fetch(`${API_BASE}/signal/history?limit=20`)
|
||||
.then(r => r.json())
|
||||
@@ -128,22 +67,6 @@ export default function SignalMonitor() {
|
||||
setSignals(prev => [alert, ...prev].slice(0, 50))
|
||||
})
|
||||
|
||||
// ── Toggle ───────────────────────────────────────────────────────────────
|
||||
const toggle = useCallback(async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const next = !enabled
|
||||
const r = await fetch(`${API_BASE}/signal/toggle?enabled=${next}`, { method: 'POST' })
|
||||
if (!r.ok) throw new Error()
|
||||
const d = await r.json()
|
||||
setEnabledState(d.enabled)
|
||||
setBackendOk(true)
|
||||
} catch {
|
||||
setBackendOk(false)
|
||||
}
|
||||
setLoading(false)
|
||||
}, [enabled])
|
||||
|
||||
// ── Render ───────────────────────────────────────────────────────────────
|
||||
const btcUp = btcTrend?.includes('↑')
|
||||
|
||||
@@ -160,20 +83,16 @@ export default function SignalMonitor() {
|
||||
{isZh ? 'ETH · LINK · 5 分钟扫描' : 'ETH · LINK · 5m scan'}
|
||||
</div>
|
||||
</div>
|
||||
<ToggleSwitch on={enabled} loading={loading} onToggle={toggle} />
|
||||
</div>
|
||||
|
||||
{/* Backend offline warning */}
|
||||
{backendOk === false && (
|
||||
<div style={{
|
||||
fontSize: 11, color: '#f59e0b',
|
||||
padding: '6px 10px', borderRadius: 6,
|
||||
background: 'rgba(245,158,11,0.1)',
|
||||
marginBottom: 12,
|
||||
}}>
|
||||
⚠️ {isZh ? '后端离线,开关暂时不可用' : "Backend offline — toggle won't work"}
|
||||
{/* Enabled status dot — display-only; toggle is operator-only (X-Ingest-Key) */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: enabled ? '#22c55e' : 'var(--ink-3)' }}>
|
||||
<div style={{
|
||||
width: 7, height: 7, borderRadius: '50%',
|
||||
background: enabled ? '#22c55e' : 'var(--ink-4)',
|
||||
boxShadow: enabled ? '0 0 0 2px rgba(34,197,94,0.25)' : 'none',
|
||||
}} />
|
||||
{enabled ? (isZh ? '监控中' : 'Active') : (isZh ? '已暂停' : 'Paused')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Status row: BTC trend + last scan */}
|
||||
<div style={{
|
||||
@@ -208,7 +127,7 @@ export default function SignalMonitor() {
|
||||
}}>
|
||||
{enabled
|
||||
? (isZh ? '· 正在等待信号…' : '· Watching for signals…')
|
||||
: (isZh ? '· 打开开关后开始监控' : '· Enable the toggle to start watching')}
|
||||
: (isZh ? '· 暂无历史信号' : '· No signals yet')}
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
|
||||
|
||||
Reference in New Issue
Block a user