S6 (a1): display — the full picture under the grammar
- specs/ROW-GRAMMAR.md: the row grammar law (slot order, color law, mark
law, mobile stacking, no-truncation), locked by tests/unit/rowGrammar.
StatStrip violations fixed: MovementChip before the grade (market
context before model output); ViabilityChips after the archetype
(identity is one contiguous run).
- Line-movement sparklines: intradayRefreshService.trackHistory captures
real {t,line} points per grade (seeded with the lock, deduped when
flat, capped 24) inside the snapshot write-back; StatStrip.LineSparkline
renders at >=3 points (green toward / amber against / dim flat).
- Last-10 dot strips: services/last10Dots (streaksService accessors) ->
/api/snapshot/:sport attaches last10_dots from rosterlogs:{sport};
StatStrip.DotStrip renders vs the LOCKED line, newest first.
- CLV distribution: getModelAggregate emits clv_distribution (7 signed
buckets, outliers clamped) only past the centralized n>=20 gate;
ledger MODEL header renders the bar strip.
- Global search: SearchModal (cmd-K via GlobalHosts + window.__search),
players via /api/players/search per sport + static lib/teams.js
(soccer deliberately absent); Nav search icon + Search first in the
mobile More sheet. Explore tab untouched.
- Landing LCP: fade-up floored at opacity .6 (hero h1 contentful on
first frame, S33 visible-floor rule) + IBM Plex Mono preload:false
(4 decorative font files off the slow-4G critical path).
2654 -> 2698 tests (226 suites) green; web build exit 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -384,6 +384,10 @@ function buildPlayerStripsFromProps(gameProps, gradeIndex, deltaIndex, now = Dat
|
||||
// + the ORIGINAL grade when a public revision happened.
|
||||
movement: rec.movement || null,
|
||||
revisedFrom: rec.revised_from_grade || null,
|
||||
// S6 (A1 board, ROW-GRAMMAR sub-line) — real captured line history
|
||||
// (sparkline, ≥3 points) + last-10 ●/○ vs tonight's locked line.
|
||||
history: Array.isArray(rec.history) && rec.history.length > 0 ? rec.history : null,
|
||||
last10Dots: Array.isArray(rec.last10_dots) && rec.last10_dots.length > 0 ? rec.last10_dots : null,
|
||||
});
|
||||
} else {
|
||||
byPlayer[pk].props.push({
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/* ============================================================
|
||||
S6 (A1 board) — static team registry for global search.
|
||||
League membership is a stable public fact (not market data), so a
|
||||
static list is honest. CommonJS so the Jest suite requires it and
|
||||
the .tsx SearchModal imports it (allowJs).
|
||||
|
||||
Soccer is deliberately ABSENT: the product has no canonical soccer
|
||||
team registry (no soccer team-hub branch, no fixed competition set)
|
||||
— absent beats wrong. Add it when the soccer hub lands.
|
||||
|
||||
Team links go to /team/:abbr?sport= (the S51 Team Hub). MLB abbrs
|
||||
match statsapi (AZ, CWS, ATH); NBA/WNBA hubs render the partial
|
||||
graded-roster view until a free roster feed exists.
|
||||
============================================================ */
|
||||
|
||||
const TEAMS = [
|
||||
// ── MLB (30) ──────────────────────────────────────────────
|
||||
{ sport: 'mlb', abbr: 'AZ', name: 'Arizona Diamondbacks' },
|
||||
{ sport: 'mlb', abbr: 'ATL', name: 'Atlanta Braves' },
|
||||
{ sport: 'mlb', abbr: 'BAL', name: 'Baltimore Orioles' },
|
||||
{ sport: 'mlb', abbr: 'BOS', name: 'Boston Red Sox' },
|
||||
{ sport: 'mlb', abbr: 'CHC', name: 'Chicago Cubs' },
|
||||
{ sport: 'mlb', abbr: 'CWS', name: 'Chicago White Sox' },
|
||||
{ sport: 'mlb', abbr: 'CIN', name: 'Cincinnati Reds' },
|
||||
{ sport: 'mlb', abbr: 'CLE', name: 'Cleveland Guardians' },
|
||||
{ sport: 'mlb', abbr: 'COL', name: 'Colorado Rockies' },
|
||||
{ sport: 'mlb', abbr: 'DET', name: 'Detroit Tigers' },
|
||||
{ sport: 'mlb', abbr: 'HOU', name: 'Houston Astros' },
|
||||
{ sport: 'mlb', abbr: 'KC', name: 'Kansas City Royals' },
|
||||
{ sport: 'mlb', abbr: 'LAA', name: 'Los Angeles Angels' },
|
||||
{ sport: 'mlb', abbr: 'LAD', name: 'Los Angeles Dodgers' },
|
||||
{ sport: 'mlb', abbr: 'MIA', name: 'Miami Marlins' },
|
||||
{ sport: 'mlb', abbr: 'MIL', name: 'Milwaukee Brewers' },
|
||||
{ sport: 'mlb', abbr: 'MIN', name: 'Minnesota Twins' },
|
||||
{ sport: 'mlb', abbr: 'NYM', name: 'New York Mets' },
|
||||
{ sport: 'mlb', abbr: 'NYY', name: 'New York Yankees' },
|
||||
{ sport: 'mlb', abbr: 'ATH', name: 'Athletics' },
|
||||
{ sport: 'mlb', abbr: 'PHI', name: 'Philadelphia Phillies' },
|
||||
{ sport: 'mlb', abbr: 'PIT', name: 'Pittsburgh Pirates' },
|
||||
{ sport: 'mlb', abbr: 'SD', name: 'San Diego Padres' },
|
||||
{ sport: 'mlb', abbr: 'SF', name: 'San Francisco Giants' },
|
||||
{ sport: 'mlb', abbr: 'SEA', name: 'Seattle Mariners' },
|
||||
{ sport: 'mlb', abbr: 'STL', name: 'St. Louis Cardinals' },
|
||||
{ sport: 'mlb', abbr: 'TB', name: 'Tampa Bay Rays' },
|
||||
{ sport: 'mlb', abbr: 'TEX', name: 'Texas Rangers' },
|
||||
{ sport: 'mlb', abbr: 'TOR', name: 'Toronto Blue Jays' },
|
||||
{ sport: 'mlb', abbr: 'WSH', name: 'Washington Nationals' },
|
||||
// ── NBA (30) ──────────────────────────────────────────────
|
||||
{ sport: 'nba', abbr: 'ATL', name: 'Atlanta Hawks' },
|
||||
{ sport: 'nba', abbr: 'BOS', name: 'Boston Celtics' },
|
||||
{ sport: 'nba', abbr: 'BKN', name: 'Brooklyn Nets' },
|
||||
{ sport: 'nba', abbr: 'CHA', name: 'Charlotte Hornets' },
|
||||
{ sport: 'nba', abbr: 'CHI', name: 'Chicago Bulls' },
|
||||
{ sport: 'nba', abbr: 'CLE', name: 'Cleveland Cavaliers' },
|
||||
{ sport: 'nba', abbr: 'DAL', name: 'Dallas Mavericks' },
|
||||
{ sport: 'nba', abbr: 'DEN', name: 'Denver Nuggets' },
|
||||
{ sport: 'nba', abbr: 'DET', name: 'Detroit Pistons' },
|
||||
{ sport: 'nba', abbr: 'GSW', name: 'Golden State Warriors' },
|
||||
{ sport: 'nba', abbr: 'HOU', name: 'Houston Rockets' },
|
||||
{ sport: 'nba', abbr: 'IND', name: 'Indiana Pacers' },
|
||||
{ sport: 'nba', abbr: 'LAC', name: 'LA Clippers' },
|
||||
{ sport: 'nba', abbr: 'LAL', name: 'Los Angeles Lakers' },
|
||||
{ sport: 'nba', abbr: 'MEM', name: 'Memphis Grizzlies' },
|
||||
{ sport: 'nba', abbr: 'MIA', name: 'Miami Heat' },
|
||||
{ sport: 'nba', abbr: 'MIL', name: 'Milwaukee Bucks' },
|
||||
{ sport: 'nba', abbr: 'MIN', name: 'Minnesota Timberwolves' },
|
||||
{ sport: 'nba', abbr: 'NOP', name: 'New Orleans Pelicans' },
|
||||
{ sport: 'nba', abbr: 'NYK', name: 'New York Knicks' },
|
||||
{ sport: 'nba', abbr: 'OKC', name: 'Oklahoma City Thunder' },
|
||||
{ sport: 'nba', abbr: 'ORL', name: 'Orlando Magic' },
|
||||
{ sport: 'nba', abbr: 'PHI', name: 'Philadelphia 76ers' },
|
||||
{ sport: 'nba', abbr: 'PHX', name: 'Phoenix Suns' },
|
||||
{ sport: 'nba', abbr: 'POR', name: 'Portland Trail Blazers' },
|
||||
{ sport: 'nba', abbr: 'SAC', name: 'Sacramento Kings' },
|
||||
{ sport: 'nba', abbr: 'SAS', name: 'San Antonio Spurs' },
|
||||
{ sport: 'nba', abbr: 'TOR', name: 'Toronto Raptors' },
|
||||
{ sport: 'nba', abbr: 'UTA', name: 'Utah Jazz' },
|
||||
{ sport: 'nba', abbr: 'WAS', name: 'Washington Wizards' },
|
||||
// ── WNBA (13) ─────────────────────────────────────────────
|
||||
{ sport: 'wnba', abbr: 'ATL', name: 'Atlanta Dream' },
|
||||
{ sport: 'wnba', abbr: 'CHI', name: 'Chicago Sky' },
|
||||
{ sport: 'wnba', abbr: 'CON', name: 'Connecticut Sun' },
|
||||
{ sport: 'wnba', abbr: 'DAL', name: 'Dallas Wings' },
|
||||
{ sport: 'wnba', abbr: 'GSV', name: 'Golden State Valkyries' },
|
||||
{ sport: 'wnba', abbr: 'IND', name: 'Indiana Fever' },
|
||||
{ sport: 'wnba', abbr: 'LVA', name: 'Las Vegas Aces' },
|
||||
{ sport: 'wnba', abbr: 'LAS', name: 'Los Angeles Sparks' },
|
||||
{ sport: 'wnba', abbr: 'MIN', name: 'Minnesota Lynx' },
|
||||
{ sport: 'wnba', abbr: 'NYL', name: 'New York Liberty' },
|
||||
{ sport: 'wnba', abbr: 'PHX', name: 'Phoenix Mercury' },
|
||||
{ sport: 'wnba', abbr: 'SEA', name: 'Seattle Storm' },
|
||||
{ sport: 'wnba', abbr: 'WAS', name: 'Washington Mystics' },
|
||||
];
|
||||
|
||||
/** /team/:abbr?sport= — the canonical Team Hub link (S51). */
|
||||
function teamHref(team) {
|
||||
return `/team/${encodeURIComponent(team.abbr)}?sport=${encodeURIComponent(team.sport)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Case-insensitive team match: full name substring, mascot (last word)
|
||||
* prefix, or abbreviation prefix. Returns [] under 2 chars.
|
||||
*/
|
||||
function searchTeams(q, limit = 6) {
|
||||
const s = String(q || '').trim().toLowerCase();
|
||||
if (s.length < 2) return [];
|
||||
const out = [];
|
||||
for (const t of TEAMS) {
|
||||
const name = t.name.toLowerCase();
|
||||
const mascot = name.split(' ').pop() || '';
|
||||
if (name.includes(s) || mascot.startsWith(s) || t.abbr.toLowerCase().startsWith(s)) {
|
||||
out.push(t);
|
||||
if (out.length >= limit) break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
module.exports = { TEAMS, searchTeams, teamHref };
|
||||
Reference in New Issue
Block a user