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 Winther
2026-10-18 01:55:16 +02:00
co-authored by Claude Opus 5.5
parent ddd9673f86
commit 50c6e91b00
284 changed files with 45100 additions and 1628 deletions
+24
View File
@@ -0,0 +1,24 @@
import { z } from "zod";
import { GameId } from "./schema.ts";
import { SourceHealth } from "./feed.ts";
export const RedeemCodeSchema = z.object({
id: z.string(),
game: GameId,
code: z.string().min(1).max(100),
reward: z.string().max(1000).nullable(),
expiresAt: z.string().datetime().nullable(),
expiresOn: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.nullable()
.optional(),
firstObservedAt: z.string().datetime(),
sourceUrl: z.string().url(),
});
export type RedeemCode = z.infer<typeof RedeemCodeSchema>;
export const CodesFeedSchema = z.object({
schemaVersion: z.literal(1),
codes: z.array(RedeemCodeSchema),
sources: z.array(SourceHealth),
});
export type CodesFeed = z.infer<typeof CodesFeedSchema>;