feat(custom): let readers add their own games and events

The interface for PRD F13. A game (name and lane colour) and events against it,
or against a tracked game when a source missed one, managed from the settings
panel and from the event's own detail sheet.

Two things the forms are careful about:

- "I don't know when it ends" is an offered answer, not a blank field. A
  mandatory end date would push the reader into inventing one, which is the
  failure the parsers are forbidden from committing — it would just be the
  reader committing it instead. An unknown end behaves as it does for a scraped
  event: no countdown, no checklist.
- A hand-entered date is never dressed up as a source's. The row carries a
  "yours" chip, the sheet says so under the title, and the Source link is absent
  rather than dead.

Deleting a game is refused while it still holds events, and says how many.
Deleting an event leaves the marks and ticks attached to it alone.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
Lucas Winther
2026-08-17 18:24:09 +02:00
co-authored by Claude Opus 5
parent d046758671
commit c87ea4c602
8 changed files with 786 additions and 5 deletions
+22
View File
@@ -463,6 +463,17 @@ export function App() {
onToggleGame={toggleGame}
onUpdate={update}
ignoredCount={Object.keys(ignored.marks).length}
own={{
games: custom.games,
events: custom.events,
// Every lane, not just theirs: a source can miss an event in a game
// we do track, and that is the same job with the same form.
lanes: games,
onAddGame: custom.addGame,
onEditGame: custom.editGame,
onRemoveGame: custom.removeGame,
onAddEvent: custom.addEvent,
}}
onExport={() =>
exportProgress(prog.progress, daily.logs, ignored.marks, prefs, {
games: custom.games,
@@ -524,6 +535,17 @@ export function App() {
onNote={prog.setNote}
onIgnore={(id) => toggleIgnored(id, openRow.event.title)}
onClose={() => setOpenId(null)}
own={
custom.events[openRow.event.id] === undefined
? undefined
: {
record: custom.events[openRow.event.id]!,
lanes: games,
games: custom.games,
onSave: custom.editEvent,
onDelete: custom.removeEvent,
}
}
/>
)}
</Shell>