feat: the redesigned Event Clock

The new reader app replaces the old UI: Checklist with a rail (focus
pills, Next to expire, today's dailies, pinned routines), Timeline in a
new and a classic look, Routines, Archive and a Settings area, in a
Structured (default) and a Relaxed interface. It follows the approved
Round 6 B and Round 7 mockups, corrected screen by screen with the owner.

Reader data moves to a v2 store (gacha-tracker:v2:*). Existing v1 data
is migrated on first load, a recovery copy is written first, and the v1
keys are never removed, so a rollback finds them unchanged. Redeem codes
for Genshin arrive as their own feed.

Also: live's urgency ramp, editable per theme; completion and
section-complete fireworks; a returning-user tour; the design mockups,
specs, plans, reviews and handoff record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5.5 committed 2026-10-18 01:55:16 +02:00
1 parent ddd9673f86
commit 50c6e91b00
284 files changed
+45100 -1628

No files matched your search

+6 -3
View File
@@ -1,3 +1,4 @@
import type { ResetTiming } from "../../shared/time.ts";
import {
CATCH_UP_DAYS,
catchUpDays,
@@ -33,7 +34,9 @@ export function DailyChecklist({
logged,
onToggleDay,
goal,
timing,
}: {
timing?: ResetTiming | undefined;
startsMs: number;
endsMs: number | null;
region: Region;
@@ -49,7 +52,7 @@ export function DailyChecklist({
*/
goal?: GoalStatus | undefined;
}) {
const summary = dailySummary({ startsMs, endsMs, region, game, now, logged });
const summary = dailySummary({ startsMs, endsMs, region, game, now, logged, ...(timing === undefined ? {} : { timing }) });
const { days, today, doneToday, todayInWindow } = summary;
const started = now >= startsMs;
@@ -58,7 +61,7 @@ export function DailyChecklist({
<div className="flex items-baseline justify-between gap-3">
<p className="eyebrow">Daily checklist</p>
<p className="tnum text-[0.6875rem] text-faint">
resets in {formatRemaining(msUntilReset(now, region, game))}
resets in {formatRemaining(msUntilReset(now, region, game, timing))}
</p>
</div>
@@ -113,7 +116,7 @@ export function DailyChecklist({
yesterday could never say so. Only the past, and only as far back
as `catchUpDays` goes. */}
<div className="mt-3 flex flex-wrap gap-1">
{catchUpDays(now, region, game, startsMs).map((day) => (
{catchUpDays(now, region, game, startsMs, undefined, timing).map((day) => (
<DayPip
key={day}
day={day}