diff --git a/docs/PRD.md b/docs/PRD.md index 447a324..17abc94 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -279,7 +279,10 @@ Before any events are shown, the reader picks which games they play, and how the 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 — which is a storage +notice is worse than asking. **The games are listed alphabetically by name**, not in feed order: +everywhere else a lane's position carries meaning, but here the reader is scanning for the two or +three names they already know, and a list ordered by which game happened to hold the first event row +gives them nothing to scan by. The choice is stored as *hidden* games, the inverse — which is a storage shape, not a policy: what happens to a game added later is decided separately, below. **A game added later arrives switched off.** Adding a source is our decision, not the reader's, and diff --git a/src/client/components/Welcome.tsx b/src/client/components/Welcome.tsx index 78e8164..f78be83 100644 --- a/src/client/components/Welcome.tsx +++ b/src/client/components/Welcome.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { useGameMeta } from "../state/gameMeta.tsx"; import type { LaneId } from "../../shared/custom.ts"; import type { View } from "../state/usePrefs.ts"; @@ -37,6 +37,25 @@ export function Welcome({ prev.includes(id) ? prev.filter((g) => g !== id) : [...prev, id], ); + /** + * Alphabetical, by the name on the button. + * + * `available` arrives in feed order — whichever game happened to hold the + * first row — which is meaningful everywhere else in the app and meaningless + * here, where the reader is not reading the list but looking for the two or + * three names they already know. Sorted by `name` and not by `LaneId`, + * because the id is not what is printed: `hsr` is Honkai: Star Rail. And + * through `localeCompare`, because `<` orders by code point and would file + * hololive Dreams after every capitalised name on the screen. + */ + const ordered = useMemo( + () => + [...available].sort((a, b) => + gameMeta(a).name.localeCompare(gameMeta(b).name), + ), + [available, gameMeta], + ); + return (

@@ -55,7 +74,7 @@ export function Welcome({ pushes the view question and the way in off the bottom of the screen, on the one screen where both need to be seen. */}

- {available.map((id) => { + {ordered.map((id) => { const game = gameMeta(id); const on = chosen.includes(id); return ( @@ -111,7 +130,7 @@ export function Welcome({ gameMeta(id).hue)} + hues={ordered.slice(0, 3).map((id) => gameMeta(id).hue)} />
@@ -127,7 +146,7 @@ export function Welcome({