1664e1b3d5
Extend /explore (ExploreHub) into the 365-day never-dark hub. Two new self-hiding sections feed REAL always-available data into the offseason: - NewsWire (components/vyndr/NewsWire.tsx): real ESPN headlines from /api/news/:sport (newest-first, mono timestamps, type chips, player/team links) + real injuries from /api/schedule/:sport/injuries (OUT/GTD chips, token colors). Reuses the retired TerminalTemplates INJURY_WIRE layout but never routes its sample constants. Self-hides when both feeds are empty. - FuturesBoard (components/vyndr/FuturesBoard.tsx): real futures from /api/futures/:sport — championship/win-total/award markets, mono tabular prices + movement colored by the contract (shortening=green / drifting=amber / flat=dim, NEVER red; move shown ONLY when the backend supplies one). Carries the honest "TRACKED · NOT GRADED" label — no fabricated grades on futures. Self-hides when markets:[]. - ExploreHub is offseason-aware (via emptyState OFF_SEASON month check): the hub LEADS with futures + wire when the board is dark, COMPLEMENTS the live board in-season. Sport selector kept; each section self-hides independently. - Testable pure helpers: lib/futuresMove.js (move→color, never red) + lib/newsFormat.js (timeAgo mono-stamp, ESPN type labels). Contracts consumed (Wave 2A owns the proxy/service files); code self-hides on fetch failure if a proxy isn't present yet. Tests: tests/unit/newsWire.test.js + futuresBoard.test.js (26 new). Full suite 259 suites / 3144 green; web build exit 0. vyndrParityQA stays green (mono data, no glitch on data surfaces). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
41 lines
1.8 KiB
JavaScript
41 lines
1.8 KiB
JavaScript
/* ============================================================
|
|
VYNDR — FUTURES MOVEMENT color/label (Wave 2B, Offseason Hub).
|
|
|
|
The color contract for a futures selection's price movement. HONESTY RULE:
|
|
futures are TRACKED, not model-graded — a movement is only ever shown when
|
|
the backend actually supplies a `move` (never fabricated). The color space
|
|
is deliberately narrow and NEVER red:
|
|
• shortening → the market moved TOWARD the selection → green (value/steam)
|
|
• drifting → the market moved AWAY → amber (caution)
|
|
• flat / absent → no movement to report → dim (say less)
|
|
Red is reserved system-wide for settled-negative outcomes; a futures drift
|
|
is NOT a miss, so it must never render red.
|
|
|
|
CommonJS so the .tsx surface imports it (allowJs) AND Jest exercises it.
|
|
============================================================ */
|
|
|
|
// Canonical move → CSS custom-property token. No branch returns the red
|
|
// (--miss) token — a normal drift is caution (amber), never a miss.
|
|
const MOVE_COLOR = {
|
|
shortening: 'var(--g-a)', // green — toward the selection (value)
|
|
drifting: 'var(--amber)', // amber — away from the selection (caution)
|
|
flat: 'var(--text-2)', // dim — no movement
|
|
};
|
|
|
|
/** moveColor(move) — the token for a move, defaulting to dim for flat/absent. */
|
|
function moveColor(move) {
|
|
const m = String(move || '').toLowerCase();
|
|
return MOVE_COLOR[m] || MOVE_COLOR.flat;
|
|
}
|
|
|
|
/** moveLabel(move) — a short mono glyph+word, or '' when there is no move. */
|
|
function moveLabel(move) {
|
|
const m = String(move || '').toLowerCase();
|
|
if (m === 'shortening') return '▼ SHORTENING';
|
|
if (m === 'drifting') return '▲ DRIFTING';
|
|
if (m === 'flat') return '— FLAT';
|
|
return '';
|
|
}
|
|
|
|
module.exports = { MOVE_COLOR, moveColor, moveLabel };
|