Files
k 4c3c8c6f87 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>
2026-06-09 22:55:27 +08:00

49 lines
1.5 KiB
TypeScript

'use client'
/**
* AnimatedNumber — flashes green/red when its value changes, the way a live
* trading terminal ticks. Pure presentational: it renders `display` (already
* formatted) but watches `value` (the raw number) to decide flash direction.
*
* The flash is a CSS class toggled for ~600ms via a keyframe (`tick-flash-up` /
* `tick-flash-down` in globals.css). Respects prefers-reduced-motion (the CSS
* keyframes are disabled there, so this degrades to a plain number).
*/
import { useEffect, useRef, useState } from 'react'
interface Props {
/** Raw numeric value — drives the flash direction when it changes. */
value: number | null | undefined
/** Pre-formatted string to actually show (e.g. "$72,140"). */
display: string
/** Extra className(s) for the wrapper. */
className?: string
style?: React.CSSProperties
}
export default function AnimatedNumber({ value, display, className = '', style }: Props) {
const prev = useRef<number | null | undefined>(value)
const [dir, setDir] = useState<'up' | 'down' | null>(null)
useEffect(() => {
const p = prev.current
if (value != null && p != null && value !== p) {
setDir(value > p ? 'up' : 'down')
const id = setTimeout(() => setDir(null), 600)
prev.current = value
return () => clearTimeout(id)
}
prev.current = value
}, [value])
return (
<span
className={`tick-num ${dir ? `tick-flash-${dir}` : ''} ${className}`}
style={style}
>
{display}
</span>
)
}