From f322061c8868f0eccd6be9843a15b243eb5c97b4 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Fri, 16 Oct 2026 03:00:21 +0200 Subject: [PATCH] feat(routines): say "weekly and monthly" for built-ins Built-ins now include monthly items, so the strip's question, Settings and Your own say "weekly and monthly". The per-game tooltip quotes the oldest source date when a game has several. Co-Authored-By: Claude Opus 5.5 --- src/client/components/Controls.tsx | 11 +++++++---- src/client/components/Dailies.tsx | 8 ++++---- src/client/components/YourOwn.tsx | 2 +- src/shared/routines.ts | 2 +- test/controls.test.tsx | 8 ++++---- test/custom-ui.test.tsx | 2 +- test/views.test.tsx | 8 ++++---- 7 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/client/components/Controls.tsx b/src/client/components/Controls.tsx index 6283426..39f1a8b 100644 --- a/src/client/components/Controls.tsx +++ b/src/client/components/Controls.tsx @@ -281,14 +281,17 @@ export function Controls({ onUpdate({ showRoutines })} - label="Show built-in weekly tasks" - hint="Weekly tasks the app knows for some games, each from a cited page and dated by it. Off hides them; your ticks and numbers are kept." + label="Show built-in weekly and monthly tasks" + hint="Weekly and monthly tasks the app knows for some games, each from a cited page and dated by it. Off hides them; your ticks and numbers are kept." rule={routines} games={routineGames} - chipsLabel="Built-in weekly tasks per game" + chipsLabel="Built-in weekly and monthly tasks per game" titleFor={(game) => { const list = routinesFor(game); - return `${list.map((r) => r.title).join(", ")} — from a source as of ${asOfLabel(list[0]!.asOf)}`; + // Several pages per game now: quote the oldest, so the + // tooltip never makes a year-old figure look current. + const oldest = list.map((r) => r.asOf).sort()[0]!; + return `${list.map((r) => r.title).join(", ")} — ${list.length > 1 ? "from sources, the oldest" : "from a source"} as of ${asOfLabel(oldest)}`; }} onSet={(game, value) => { const { on, off } = setFor(routines, game, value); diff --git a/src/client/components/Dailies.tsx b/src/client/components/Dailies.tsx index 2db539a..eae661f 100644 --- a/src/client/components/Dailies.tsx +++ b/src/client/components/Dailies.tsx @@ -334,7 +334,7 @@ export function Dailies({ tasks?: readonly StripTask[] | undefined; taskStatusFor?: ((task: StripTask) => GoalStatus | undefined) | undefined; /** - * A game whose built-in weekly tasks the reader has not been asked about yet, + * A game whose built-in weekly and monthly tasks the reader has not been asked about yet, * and how to record the answer. Asked here because this is where the tasks * would appear; one line, never a modal, never twice. */ @@ -427,13 +427,13 @@ export function Dailies({ ask === undefined ? null : (

- Track {gameMeta(ask.game).name}'s built-in weekly tasks? + Track {gameMeta(ask.game).name}'s built-in weekly and monthly tasks?