Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 41 additions & 25 deletions README.md

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions docs/ACCESSIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ The “Skip to main content” link is visually hidden until focused. The app us
- The desktop results table has a screen-reader caption, column headers, and `scope="col"` relationships. On narrow screens the results are presented as cards instead.
- Disabled actions for removed catalog items reference the explanatory text with `aria-describedby`.

**Where:** [ElementsPage.tsx](../src/components/elements/ElementsPage.tsx), [ResultsTable.tsx](../src/components/elements/ResultsTable.tsx), [ElementActions.tsx](../src/components/elements/ElementActions.tsx).
**Where:** [ElementsPage.tsx](../src/pages/ElementsPage.tsx), [ResultsTable.tsx](../src/components/elements/ResultsTable.tsx), [ElementActions.tsx](../src/components/elements/ElementActions.tsx).

### Status messages and errors

Dynamic updates such as loading, result counts, and action feedback use status semantics (`role="status"` and, where needed, `aria-live`). Errors use alert semantics so important feedback is exposed to assistive technology.

**Where:** [ElementsPage.tsx](../src/components/elements/ElementsPage.tsx), [ElementActions.tsx](../src/components/elements/ElementActions.tsx), [ElementDetailPage.tsx](../src/components/elements/ElementDetailPage.tsx), and [YourGymnastsPage.tsx](../src/components/gymnasts/YourGymnastsPage.tsx).
**Where:** [ElementsPage.tsx](../src/pages/ElementsPage.tsx), [ElementActions.tsx](../src/components/elements/ElementActions.tsx), [ElementDetailPage.tsx](../src/pages/ElementDetailPage.tsx), and [YourGymnastsPage.tsx](../src/pages/YourGymnastsPage.tsx).

### Themes, contrast, and reduced motion

The interface supports light and dark themes with separate color tokens. Interactive controls and links include visible focus styling. Animations and transitions use reduced-motion variants so they can be suppressed when the user requests reduced motion.

**Where:** theme state in [App.tsx](../src/App.tsx), theme colors in [variables.css](../src/styles/variables.css), and reduced-motion styles in [ElementsPage.tsx](../src/components/elements/ElementsPage.tsx), [ResultsTable.tsx](../src/components/elements/ResultsTable.tsx), and [ElementDetailPage.tsx](../src/components/elements/ElementDetailPage.tsx).
**Where:** theme state in [App.tsx](../src/App.tsx), theme colors in [variables.css](../src/styles/variables.css), and reduced-motion styles in [ElementsPage.tsx](../src/pages/ElementsPage.tsx), [ResultsTable.tsx](../src/components/elements/ResultsTable.tsx), and [ElementDetailPage.tsx](../src/pages/ElementDetailPage.tsx).

The color themes have not yet been comprehensively measured against WCAG contrast criteria. Focus, contrast, zoom, and screen-reader behavior need verification in the complete application.

Expand Down
6 changes: 6 additions & 0 deletions docs/AI_USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,3 +526,9 @@
- **Tool:** Claude Code
- **What the team did:** Found in a review that the element page shows the long description of a vault group under "Element group", and wrote issue #125: show "Group N" for a vault, with the same rule as the Elements list.
- **What Claude did:** Added `number` (and `id`, so Apollo's cache can recognise the group across queries) to the `catalogItem` query, and let the element page use `groupLabel` from the Elements list, so the two pages cannot disagree. Wrote one test for an element and one for a vault (with the real group of VT-1.22-a), and checked that each fails when the page shows the name for every item or "Group N" for every item. After a review of its own work, split one test that checked two cases, and replaced test data for the vault that was half an element.

## The pages in `src/pages/` (`src/pages/`, `src/App.tsx`)

- **Tool:** Claude Code
- **What the team did:** Wrote issue #97: move the pages out of `src/components/`, so it is clear which files are routes and which are parts of pages, and describe the folders in the README.
- **What Claude did:** Moved the four pages and their tests with `git mv` (so their history follows them), and moved the three placeholder pages out of `App.tsx` into their own files, so every route has a file in `src/pages/`. Updated the imports, the links in the README and the docs, and the "Project structure" table. Found that `src/styles/gymnastTheme.test.ts` reads the files of the gymnasts and login pages by folder, so after the move it would have stopped checking the two pages without failing; added them to the list. The shared components in `components/ui/` were left where they are (see the issue). After that, asked to move the frontend tests to `src/tests/` as well: moved all 29 with `git mv` into the same folders as the code they test, changed their relative imports to the `@/` alias (so a test does not depend on where it is), and updated the paths that `gymnastTheme.test.ts` reads files from.
4 changes: 2 additions & 2 deletions docs/AUTHENTICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ AuthProvider --asks--> me { id name email } (the server)
- A visitor who is not logged in is sent to `/login` with the page they wanted in the state of the navigation. After the login they go there, but only if it is a path on this site (a `from` such as `//evil.example` is ignored).
- Logging out goes to `/elements` first, so the page the coach leaves does not send them to the login page.

The whole path (log in, save a gymnast, reload, log out, log in again, see the gymnast, delete it) is tested as one test in `src/App.flow.test.tsx`.
The whole path (log in, save a gymnast, reload, log out, log in again, see the gymnast, delete it) is tested as one test in `src/tests/App.flow.test.tsx`.

## What we would do in a real production system

Expand All @@ -123,7 +123,7 @@ With https and a real login, in this order of importance:
| -------------------------------- | ------------------------------------------------------------------------ |
| The question `me` | `src/lib/authOperations.ts` |
| The provider and the hook | `src/components/auth/AuthProvider.tsx`, `src/components/auth/useAuth.ts` |
| The login page | `src/components/auth/LoginPage.tsx` |
| The login page | `src/pages/LoginPage.tsx` |
| The test login form | `src/components/gymnasts/DevLoginButton.tsx` |
| The protected pages | `src/components/ProtectedRoute.tsx`, `src/App.tsx` |
| The menu | `src/components/navbar/Navbar.tsx` |
Expand Down
4 changes: 2 additions & 2 deletions docs/SUSTAINABILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ With GraphQL, each operation selects the fields its page uses instead of downloa

The search waits **300 ms after the user stops typing** before updating the address and sending the query. It requests **20 results per page**, with a “Load more” action for additional results, rather than downloading the whole catalog at once. This avoids requests for every keystroke and limits the initial response.

**Where:** `SEARCH_DELAY_MS` and `PAGE_SIZE` in [searchOperations.ts](../src/lib/searchOperations.ts); the debounce, initial query, and “Load more” behavior in [ElementsPage.tsx](../src/components/elements/ElementsPage.tsx).
**Where:** `SEARCH_DELAY_MS` and `PAGE_SIZE` in [searchOperations.ts](../src/lib/searchOperations.ts); the debounce, initial query, and “Load more” behavior in [ElementsPage.tsx](../src/pages/ElementsPage.tsx).

### Bound the cost of counting results

Expand All @@ -32,7 +32,7 @@ Catalog drawings use WebP. Result-card images are lazy-loaded and decoded asynch

The catalog JSON is no longer imported into the frontend to build the element detail view; the page fetches the selected item from the GraphQL API instead. The project history records the JavaScript bundle changing from **665 kB to 522 kB** after this move. On the current version, `npm run build` reports a JavaScript bundle of **548.06 kB (170.79 kB gzip)**. These are build-output sizes, not per-visit measurements; the historical before/after comparison and current build can differ because the code and build tooling have changed.

**Where:** the API-backed detail query in [catalogOperations.ts](../src/lib/catalogOperations.ts) and its use in [ElementDetailPage.tsx](../src/components/elements/ElementDetailPage.tsx); the historical comparison is recorded in [AI_USAGE.md](./AI_USAGE.md).
**Where:** the API-backed detail query in [catalogOperations.ts](../src/lib/catalogOperations.ts) and its use in [ElementDetailPage.tsx](../src/pages/ElementDetailPage.tsx); the historical comparison is recorded in [AI_USAGE.md](./AI_USAGE.md).

### Reuse cached search results

Expand Down
Loading