feat(radar): replace the header ticker with a context-aware radar card - #146
Merged
Conversation
The old ticker rotated a seeded, priority-weighted pool every 9 s, so the one item that mattered was on screen a third of the time, countdowns went stale for up to 15 minutes, facts were buried inside jokes, and nothing could be acted on or dismissed. The radar replaces it end to end: - domain/radar: deterministic collectors turn the semester + clock into a ranked `live` queue (class now/soon/next/tomorrow, homework by urgency, the nearest exam with a study-pace hint from unwatched recordings, a recordings backlog, setup nudges) and a `calm` rotation (late night, weekend, morning, free day, classes done, all-clear with progress stats, a course roast, study tips). Facts live in a bidi-safe title/meta line; personality lives in a curated quip catalog, some quips conditional on context (free time before the next class, late night). - services/storage/radarSnooze: a device-local, per-day snooze map. - features/radar/RadarCard: the top-ranked signal stays pinned (only the quip rotates), the rest wait in an "up next" rail whose chips carry the one fact that matters and can be promoted; homework can be marked done and any signal snoozed until tomorrow, both with undo; the headline deep-links into the course dialog; a live class shows its progress. Rotation pauses when hidden, hovered, focused or under reduced motion; countdowns still tick every minute. - Removed domain/ticker, features/ticker and the tickerTarget mapper; shared Check / BellOff icons; README + comments updated. Tests: domain (ranking, every collector, formatting, quips, stats, snooze filtering), storage, hook, component, target mapping, and two Playwright flows (setup -> homework -> done -> snooze survives reload; deep-link). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… cases Review of #146 turned up six P2 issues and a handful of nits; all addressed: - Snoozing a capped pick (top homework / nearest exam / biggest backlog / first undated) now reveals the next candidate instead of hiding the whole category: candidates are snooze-filtered before each collector caps. - Class signal ids no longer embed the phase, so "until tomorrow" holds as a class moves next -> soon -> live; the headline re-enters on a kind change via a key that includes the kind. - Keyboard activation of a chip / Done / Snooze that unmounts the focused control no longer drops focus to <body> (which also left rotation paused): focus is restored to the headline, hover and focus are tracked separately, and blur only releases when focus actually leaves the card. - A zero-length slot (start === end, importer-only) is no longer a 24-hour LIVE class; it is not a class at all, matching the calendar's strict wrap. - Ranking: the constants comment now describes the deliberate interleaving of the long-horizon tiers, and a class within the hour gets a proximity bonus so it is not stuck behind tomorrow's homework as a chip until 15 min. - Snooze persistence moved to an effect with a try/catch (a throwing setItem keeps the snooze for the session), no ref written during render. - Hebrew-only quips render inside <bdi>; `stats` dropped from the snapshot and the never-produced 'calm' meta tone removed; `hhmmToMinutes` shared from lib/dates by the calendar and the radar; "exams behind you" wording. Tests added for each: snooze reveals the next candidate, class snooze across phases, cross-tier ordering and the near-class bonus, zero-length slots, Saturday-evening preview, day-rollover expiry through the card, keyboard focus restoration, a throwing storage write, and a fixed-clock e2e that seeds a running class and checks the progress bar and chip promotion. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Owner
Author
Review passA separate reviewer agent went through the diff line by line (verdict: merge after fixes, no P0/P1). Everything it raised is addressed in the follow-up commit:
Tests: 971 unit/component (was 959), coverage floors met (domain/radar 100 % lines), e2e 14/14 including a new fixed-clock flow ( |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The header ticker rotated a seeded, priority-weighted pool of one-liners every 9 seconds. That meant the single thing that actually mattered (an overdue assignment, a class starting in 8 minutes) was on screen about a third of the time, "class in 14 minutes" could be 14 minutes stale (items only rebuilt on 15-minute buckets), the facts were buried inside the jokes, and nothing could be acted on or dismissed.
What
Radar — a context-aware "what matters right now" card, built end to end.
Ideas weighed
Design
domain/radar(pure,nowinjected, hash-only "randomness"):livequeue, ranked by a tiered score: class now / soon / next / tomorrow, homework by urgency (two picks, second prefers another course), the nearest exam with a study-pace hint ("5 unwatched · 1 lecture every 2 days"), a recordings backlog, setup nudges. Snoozed ids are filtered out.calmrotation, only when nothing is live: late night (with the clock), weekend (Israeli week: Fri afternoon + Sat), morning, free day, "classes done for today", all-clear with semester progress stats, a daily course roast, study tips (the old NOTE tips).title+metaline (user text marked for<bdi>/isolate()); personality in a curated quip catalog (legacy lines kept, facts stripped, Hebrew flourishes kept), some quips conditional on context: free time before the next class, late-night.services/storage/radarSnooze: device-local per-day snooze map (not synced, on purpose).features/radar/RadarCard:HW!! Wet 2 · 2 days overdue) and promote on click.domain/ticker,features/ticker,features/courses/tickerTarget; sharedCheckIcon/BellOffIcon; README feature row + architecture text; aradar-inkeyframe.Tests
domain/radar.test.ts(53): every collector, ranking, snoozing, calm rotation, quips, hashing, formatting.services/storage/radarSnooze.test.ts,features/radar/useRadarSnooze.test.tsx,features/radar/target.test.ts.features/radar/RadarCard.test.tsx(13): setup nudge, pinned facts + bidi, done/undo, snooze/undo + persistence, chip promotion + overflow, deep-link, live progress, quip vs headline rotation, pause when hidden/hovered, reduced motion, minute ticks.e2e/radar.spec.ts: setup → homework due today → done in place → snooze survives reload; deep-link to the Homework tab.pnpm verifygreen (959 tests, coverage floors met: domain/radar 100% lines),pnpm e2e13/13, screenshots checked in light/dark, desktop/mobile, live/calm.🤖 Generated with Claude Code