Skip to main content

@curator/web

Browser UI over @curator/api: Vite, React 19, Mantine, TanStack Router and TanStack Query, laid out like ats/apps/web.

Running​

pnpm --filter @curator/api dev # the API on :14100
pnpm --filter @curator/web dev # this app on :14102

Vite proxies /api to the API and strips the prefix, so the browser stays same-origin. A production deployment needs the same: the API reachable at /api on the app's origin.

Pages​

PathDoes
/Opens the TV this browser last looked at, else the first one, else /tvs
/tvsThe stored TVs (rename, remove), and adding one: search the network or type its address, then pair
/tvs/$tvIdNow showing: the artwork on screen, and an art-mode switch
/tvs/$tvId/libraryThe TV's art by category (?category=) as a thumbnail grid, or a list (?view=list), with Show on TV, Change matte and Delete
/tvs/$tvId/uploadDrop a JPEG or PNG (up to 20MB), pick its mattes, and optionally show it at once
/tvs/$tvId/statusThe TV's address, model, power state and art API version

The header's TV picker switches TV and stays on the same page. A link to a TV that has been removed says so and points back to /tvs.

The TV doesn't confirm most writes, so pages read its state back afterwards rather than trusting the request. Delete is offered only for uploads (anything in My Photos, or with an upload's MY-F/MY_F id). MY-C0008 is shown as Other: the reference calls it the Art Store, but a 2025 Frame lists uploads there too. Each category's TV id shows on hover. Mattes are a style and a colour from the lists the reference library documents; a matte that doesn't fit the image is refused by the TV.

Thumbnails load lazily from the API, which batches and caches them; a piece the TV has no thumbnail for shows a placeholder.

Clicking a thumbnail (or a content id in the list) opens the piece in a viewer: the image, its categories, mattes, original size and date, and its actions. ← and → step through the current filter and Esc closes it; the open piece is in the URL (?piece=), so Back closes it too. The TV only gives thumbnails (384×216 on a 2025 Frame), so the viewer shows them at up to twice that.

Layout​

src/
main.tsx providers and the router
api/ api.client.ts (typed fetch: `api` for TVs, `tvApi(tvId)` for one TV's art), query options and keys
tvs/ the TV a page is about (`useTv()`), and the TV this browser last looked at
routes/ TanStack file routes; routeTree.gen.ts is generated by the Vite plugin and committed
components/ pages and pieces, one folder per area
tests/
fake.api.ts stubs fetch with a table of "METHOD /path" responders
test.render.tsx renders the real route tree at a path under the app's providers

TV failures surface as the API reports them (src/api/api.error.ts): unreachable, didn't answer, refused, or rejected.