feat(prefs): ask which view to open on, and remember the answer
`view` was component state, so a reader who preferred the timeline was put back on the list by every reload — and which view opened at all had been decided for them twice over: the PRD said calendar, the app shipped the list. Neither was the reader's answer. So the first run asks, and the tabs write to `prefs` from then on. The question ships pre-answered with the list, because a reader cannot choose between two layouts they have not seen and that is the one that answers "what expires next" in a look — and each option is drawn rather than described, for the same reason. The screen says where to change it afterwards, since the tabs are small text in a corner. Adds `view` to the prefs key space. Additive and defaulted, so an existing reader's stored prefs open exactly where they did before. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
41046899f9
commit
7804a08863
@@ -108,7 +108,7 @@ src/
|
||||
Fireworks.tsx the burst when the last daily lands
|
||||
GameFocus.tsx one game at a time (F4a)
|
||||
Controls.tsx games, region, export/import(F4, F5, F6)
|
||||
Welcome.tsx first-run game picker (F8)
|
||||
Welcome.tsx first-run games and view (F8)
|
||||
Toast.tsx undo an ignore
|
||||
UpdateNotice a newer app is installed and waiting (F14)
|
||||
YourOwn.tsx the reader's own games, in settings (F13)
|
||||
@@ -119,7 +119,7 @@ src/
|
||||
useMarkSet.ts ignores (and the superseded completions shape)
|
||||
useProgress.ts status, effort, note, daily override (F12)
|
||||
useDailyLog.ts which game-days are ticked off
|
||||
usePrefs.ts region, filters, focus, onboarding flags
|
||||
usePrefs.ts region, filters, focus, view, onboarding flags
|
||||
useCustom.ts the reader's own games and events (F13)
|
||||
gameMeta.tsx lane id → name, label, hue; resolves custom lanes too
|
||||
sort.ts deadline order, or what you're partway through
|
||||
|
||||
+1
-1
@@ -200,7 +200,7 @@ Namespaced, versioned, and small. Nothing here ever goes to the server.
|
||||
"gacha-tracker:v1:progress" // { [eventId]: { status?, effort?, note?, at } }
|
||||
"gacha-tracker:v1:daily" // { [id]: { days: ["2026-08-15", ...], at } }
|
||||
"gacha-tracker:v1:ignored" // { [eventId]: { at } } — "stop showing me this"
|
||||
"gacha-tracker:v1:prefs" // { region, hiddenGames[], focusGame, sort, detectDaily,
|
||||
"gacha-tracker:v1:prefs" // { region, hiddenGames[], focusGame, sort, view, detectDaily,
|
||||
// showCompleted, showIgnored, regionConfirmed, onboarded }
|
||||
"gacha-tracker:v1:completions" // SUPERSEDED — read once to migrate, never written
|
||||
```
|
||||
|
||||
+1
-1
@@ -303,7 +303,7 @@ diagnosis in each item still holds — what changed is whether it has been acted
|
||||
| P1a Arknights | **Done.** `arknights-akwiki-events`, via the new `akwiki` parser |
|
||||
| P1b `NextUp` → three | **Done** (2026-08-18). One headline and two behind it, off `nextToExpire` |
|
||||
| P1b cap the long list | **Not done.** No "show all N" expander |
|
||||
| P1b persist `view` | **Not done.** Still `useState` in `App.tsx` |
|
||||
| P1b persist `view` | **Done** (2026-08-18). `prefs.view`, and the first run now asks which one to open on (PRD F8) |
|
||||
| P1b Calendar → Timeline | **Done.** The tab reads "Timeline" |
|
||||
| P1c more games | **Done, four of them.** Infinity Nikki, Persona 5: The Phantom X, Reverse: 1999, Blue Archive — one commit each. Of the games named in the thread, Azur Lane and Umamusume are **declined on conduct** rather than pending, and the declined and cleared-but-unbuilt candidates are recorded in `AGENTS.md` § Scraping conduct so they are not re-litigated |
|
||||
| P1c roadmap in the colophon | **Not done** |
|
||||
|
||||
+15
-4
@@ -70,8 +70,13 @@ unknown" — it must be visually distinct from an event that ends far in the fut
|
||||
**F2 — Ends-soonest list.**
|
||||
A flat list of all *currently running* events sorted ascending by end date, with a relative
|
||||
countdown ("ends in 2 days", "ends in 4 hours"). Under 24 hours, the row is emphasized. This is the
|
||||
view that justifies the app; it should be reachable in one tap from the calendar and is the better
|
||||
default on narrow screens.
|
||||
view that justifies the app, and it is one tap from the timeline.
|
||||
|
||||
**Which view opens is the reader's answer, not ours.** This spec said "calendar (default)" and the
|
||||
app shipped opening on the list; both were a decision made on the reader's behalf and then forgotten
|
||||
on every reload. So the first run asks (F8) and the answer is stored in `prefs.view`. The list is
|
||||
what the question ships pre-answered with — a reader cannot choose between two layouts they have not
|
||||
seen, and it is the view that answers "what expires next" in one look.
|
||||
|
||||
**F3 — Mark completed.**
|
||||
A toggle on every event, in both views. State is written to `localStorage` immediately and
|
||||
@@ -149,13 +154,19 @@ Four constraints, each protecting something that already exists:
|
||||
which is the same argument the code already makes for streaks. This is the *only* copy — there is
|
||||
no server to restore from.
|
||||
|
||||
**F8 — First-run game picker.**
|
||||
Before any events are shown, the reader picks which games they play. A calendar full of games they
|
||||
**F8 — First-run setup.**
|
||||
Before any events are shown, the reader picks which games they play, and how they want to read
|
||||
them. A calendar full of games they
|
||||
don't play is worse than an empty one — it buries the thing they came for. Nothing is preselected
|
||||
and the button stays disabled until something is chosen; guessing on their behalf and hoping they
|
||||
notice is worse than asking. The choice is stored as *hidden* games, the inverse, so a game added
|
||||
later appears by default rather than staying invisible forever.
|
||||
|
||||
The view question (F2) sits under it, with each option drawn rather than only described — the words
|
||||
"list" and "timeline" mean nothing until you have seen this app's version of them. Unlike the games,
|
||||
it arrives already answered, and the screen says where to change it afterwards: the tabs are small
|
||||
text in a corner, which is the one control a first-time reader will not find on their own.
|
||||
|
||||
**F9 — Ignore an event.**
|
||||
Distinct from completing one. "Done" keeps an event visible and counted; "not interested" removes it
|
||||
from both views entirely. Ignored events stay recoverable: a count and a reveal toggle appear in
|
||||
|
||||
Reference in New Issue
Block a user