UpNext / Activity Feed
Activity Feed
<ActivityFeed />StableThe athlete activity thread — one component for every place the app narrates history: the manage-athlete panel, board side sheets, list detail. A Badge states, a Chip acts, an activity event narrates. Pure presentation over an events array — no fetching, no ordering, no state. Each event kind wears one outfit (a soft tone tile — the tone at ~20% + the ink-colored registry glyph, a couple notches deeper than the standard soft so the small glyph grounds; scoped to the feed) via the ACTIVITY_KIND map — yellow for lists, gold for smart lists — both wearing the ListCard's own drawn list glyph, the corner sparkle marking smart, purple for boards, and semantic tones for milestones — actor events lead with the Avatar primitive, and every entity reference — a list, a board, a school, a coach — is a REAL Link control with its underline visible at rest, never a hover-revealed affordance. University mentions carry a small crest via the base Avatar. Every color resolves through tokens; dark mode ships free.
Manage-athlete thread — live replica
The shipped Activity view, 1:1: status changes, portal entry, board/list adds, custom tags, transfers, and coach notes + assignments in one thread. Every bold mention is a Link control — click one and the readout below names it. The page owns the events array, timestamp formatting, and what each mention does; the feed just narrates.
Status changed to
May 31, 2026
Entered the
May 30, 2026
- CV
May 28, 2026
OV scheduled 6/14. Bringing both parents.
- SH
assigned to evaluate player
May 28, 2026
Added to the
May 25, 2026
Auto-added to smart list — matched its criteria
May 24, 2026
Added to list
May 23, 2026
- CD
May 20, 2026
Spoke with his QB coach — confirmed he wants a place he can start Week 1. Tape vs ranked opponents is legit.
Custom tagged
May 20, 2026
- CD
May 18, 2026
Family prioritizes academics + NIL. Set up a visit for the first week of June.
- CD
started a conversation
May 17, 2026
Transferred from to
May 15, 2026
Click any bold mention (list, board, school, coach) — they're Link controls.
Inspector
Edit one prop at a time and see the token chain resolve. The preview re-renders, the code panel updates, and the resolves-to column shows every Tailwind class → CSS variable → final value.
Preview
Committed to Penn State
May 31, 2026
- CD
Coach DanielsMay 20, 2026
Spoke with his QB coach — wants a place he can start Week 1.
Added to Top QB Players list
May 18, 2026
Code
import { ActivityFeed } from "@/components/upnext";<ActivityFeed />
Shapes
Three shapes cover the thread: an icon event (kind → tile + glyph), an actor line (assignments, 'started a conversation'), and an actor note (name and timestamp share the header, the body sits under it). Mentions are Link controls — href renders an anchor, onSelect a button, neither plain bold text; the underline is visible at rest so the affordance never hides.
Status changed to Offered
May 31, 2026
<ActivityFeed events={[{id: "s",kind: "status", // → violet tile + status glyphtimestamp: "May 31, 2026",parts: ["Status changed to ", { label: "Offered", href: "/status" }],}]} />
Composition
The kind taxonomy — 17 event kinds, each a fixed tone + glyph in ACTIVITY_KIND (the documented convention; every tile is a feed-scoped deeper-soft fill — the tone at ~20% — so all colors are token-driven). Two rules hold at once. (1) Status / milestone events STICK TO OUR SEMANTIC CONVENTION — committed=success, decommitted=error, flagged=warning, offered=info — because they carry a judgement. (2) Categorical kinds are spread ACROSS the hue wheel so no two neighbours read alike, with stable pairings: yellow=list, gold+sparkle=smart list (its AI/dynamic sibling), purple=board, orange=tag, teal=transfer, cocoa=evaluation, magenta=film, pink=visit. A run of activity is a rainbow, and the valence still reads by color. And one kind covers a whole LIFECYCLE — created, added, auto-added are narration verbs on the same outfit (see List lifecycle): the tile names the object family, the words name the moment, and creation stays a kind-tile event so the standard vs smart tell never hides.
Status changed to Offered
Status change
Committed to Penn State
Committed
Decommitted from Alabama
Decommitted
Flagged for follow-up
Flagged
Offer extended by Ohio State
Offer extended
Signed with Georgia
Signed
Entered the transfer portal
Entered portal
Transferred to Villanova
Transferred
Added to Top QB Players list
Added to list
Auto-added to Rising Juniors smart list
Smart list
Added to the Recruiting board
Added to board
Custom tagged Elite production
Tagged
Graded Elite on production
Evaluated
Film added — vs. ranked opponents
Film
Official visit scheduled 6/14
Visit
Phone call logged with Coach Vega
Call
Messaged the family
Message
// 17 kinds → 17 tones + glyphs, one map (ACTIVITY_KIND).ACTIVITY_KINDS.map((kind) => ({ id: kind, kind, timestamp, parts }))// milestone: status·committed·offered·signed·decommitted·flagged// movement: portal·transfer · organization: list·smartList·board·tag// scouting: evaluation·film·visit · communication: call·message
Source
A domain component composed from atoms: Avatar (actor identity + university crests), the Icon registry (one glyph per kind via ACTIVITY_KIND; the list pair wears the ListCard's drawn ListTypeGlyph so lists look identical everywhere), and Link (interactive mentions). No fetching or state — the page supplies the events and wires each mention.