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

+22 -1
View File
@@ -180,7 +180,7 @@ describe("restorePrefsValue", () => {
regionConfirmed: true,
onboarded: true,
};
expect(restorePrefsValue(exported)).toEqual(exported);
expect(restorePrefsValue(exported)).toEqual({ ...exported, interface: "structured", density: "standard" });
});
test("falls back to defaults for missing fields from older exports", () => {
@@ -225,3 +225,24 @@ describe("restorePrefsValue", () => {
expect(restored.view).toBe(defaults().view);
});
});
describe("redesign presentation preferences", () => {
test("defaults to Structured and Standard without changing the reader's main view", () => {
const p = restorePrefsValue({ view: "timeline" });
expect(p.interface).toBe("structured");
expect(p.density).toBe("standard");
expect(p.view).toBe("timeline");
});
test("keeps Structured and Compact on restore", () => {
const p = restorePrefsValue({ interface: "structured", density: "compact" });
expect(p.interface).toBe("structured");
expect(p.density).toBe("compact");
});
test("invalid choices fall back to the supported defaults", () => {
const p = restorePrefsValue({ interface: "other", density: 42 });
expect(p.interface).toBe("structured");
expect(p.density).toBe("standard");
});
});
test("a saved Relaxed interface survives preference normalization", () => { expect(restorePrefsValue({interface:"relaxed"}).interface).toBe("relaxed"); });