11 Commits
Author SHA1 Message Date
TehRiehlDeal ef7b8aa878 feat(icons): render the app icons from the Movie Loop mark
frontend-ci / secrets-scan (push) Successful in 4s
frontend-ci / sast (push) Successful in 7s
frontend-ci / fs-scan (push) Successful in 14s
frontend-ci / typecheck (push) Successful in 24s
frontend-ci / lint (push) Successful in 26s
frontend-ci / test (push) Successful in 32s
frontend-ci / build (push) Successful in 38s
frontend-ci / push (push) Skipped
frontend-ci / lint (pull_request) Successful in 24s
frontend-ci / test (pull_request) Successful in 31s
frontend-ci / secrets-scan (pull_request) Successful in 5s
frontend-ci / sast (pull_request) Successful in 8s
frontend-ci / fs-scan (pull_request) Successful in 15s
frontend-ci / typecheck (pull_request) Successful in 14s
frontend-ci / build (pull_request) Successful in 38s
frontend-ci / push (pull_request) Skipped
Safari, the iOS home screen, Android install and push notifications
still showed the old film-reel artwork beside the new theme colour. The
PNGs are now rendered from the SVG mark by `npm run icons` (Inkscape,
no image library in node_modules): the bare mark for the 32px favicon,
the mark on the stage colour for app icons, and a maskable variant with
the extra margin Android's adaptive crop needs.
2026-09-12 22:52:39 -07:00
TehRiehlDeal 8d0b7f39ee feat(ui): give the app one visual identity as Movie Loop
Gold is the primary in both themes, Bricolage Grotesque carries the
wordmark, titles and the score, and Movie A / Movie B wear the blue and
magenta of three-strip Technicolor on their posters instead of colouring
whole rows. The loop closes on screen - connectors light, a gold line
draws back to Movie A, the row glows, then the result arrives - in place
of confetti, on every play mode, scaled to the chain's length. Every
page shares one header and hairline lists; copy is sentence case with
one verb per flow, and the Home hero shows a real finished loop.

Also clamps link counts at zero: an opponent who had not moved yet
showed "-1 links".
2026-09-12 22:42:55 -07:00
TehRiehlDeal 5a7e8cebc3 feat: repo hygiene - push opt-in, paged admin jobs, shared game screen (2.2.0)
WP-17. Minor: push notifications become usable and nothing a player could
reach was removed. The admin console's jobs need backend 3.0.0.

Push (M35): the whole browser half - the service worker's handlers, the
subscribe/unsubscribe calls, the server's VAPID key - had shipped with
nothing calling it, so no browser ever held a subscription. The toggle
lives in Profile because the permission prompt has to come from a click.
The old isPushSubscribed awaited serviceWorker.ready, which never settles
with no worker registered; it uses getRegistration() now.

Admin: each job pages and the button becomes Continue with the server's
cursor; the recalculate card also stopped printing "undefined leaderboard
entries" for a field the server had not sent for several releases. The
three copy-pasted job cards are one component.

Consolidation: the four game screens share use-game-screen and one search
panel; the review page's static chain is ChainDisplay in a static mode
(21 rendered states verified byte-identical); formatTime and error
extraction exist once; Endless and quick play share a franchise-aware
picker instead of two divergent sort(() => Math.random() - 0.5) copies.
The dead api/index barrel and the fourteen functions only it referenced
are gone. noUncheckedIndexedAccess is on. Whiplash's TMDB id is corrected
and every preset title is checked against TMDB.
2026-09-12 00:01:42 -07:00
TehRiehlDeal e67692006f perf: load pages on demand, split vendor chunks, and replace the 888 KB favicon
App.tsx imported all 24 pages statically, so a first-time visitor
downloaded the admin panel, three multiplayer modes and the preset-pair
table before the landing page could render - one 682 KB chunk. Every
page except Home is now React.lazy behind a Suspense boundary: 56
chunks, pages at 2-11 KB. Verified in a browser against the production
build - the landing page fetches only the app and vendor chunks, a
navigation fetches that route's chunks and renders, and a deep link into
an authenticated route lazy-loads it, redirects to sign-in, and
lazy-loads that too.

Vendor code is split into vendor-react, vendor-router, vendor-ui and
vendor-net via manualChunks. The main chunk was 95% dependencies, so the
first load is not much smaller - the dependency set is the load - but
the chunk that changes on every deploy is now 50 KB (14 KB gzipped)
rather than 682 KB. A returning visitor after a deploy re-downloads the
app, not React.

The favicon was 888 KB: PNG data under a .jpg name, 768x768, with a
fully opaque alpha channel, fetched on every page load. It is a 2.6 KB
32px PNG now, with a 180px apple-touch-icon, and manifest.json points at
real 192px and 512px PNGs with the correct type instead of declaring the
same mislabelled file at both sizes. The service worker's notification
icon pointed at a /favicon.ico that never existed.

The useGameStore selector item from M26 was already done in WP-10.

Addresses M26.
2026-09-11 18:19:36 -07:00
TehRiehlDeal 470a67607b fix(lint): resolve every eslint warning without suppressions
react-hooks/set-state-in-effect and react-hooks/purity had been demoted
to warnings "so CI passes", and CI ran without --max-warnings 0, so all
22 violations were invisible there. Both rules are back at error.

- Confetti is rolled once per mount instead of during render, where it
  re-rolled on every re-render and made pieces visibly jump.
- Loading flags are derived from a "last settled request" key rather than
  set synchronously inside an effect. That also adds the cancellation
  these fetches were missing, so a resolved request can no longer write
  into a unmounted or superseded view.
- Effect dependency arrays corrected; the two eslint-disable-line
  comments in Profile.tsx are gone, and the split of its two effects
  removes the guard that silently never re-ran.
- GameCompletionModal derives visibility from status instead of mirroring
  it into state, with a ref so the sound and localStorage write fire once.
- ValidationFeedback adjusts state during render, the documented pattern,
  instead of paying an extra committed render per link.
- The three react-refresh suppressions in ui/ are resolved properly by
  extracting the variants into their own modules, so the component files
  export only components. badgeVariants had no consumers and is no longer
  exported.
- Drops a stale eslint-disable directive in sw.js.

The lint script now fails on warnings so this cannot quietly regress.
2026-09-09 19:59:10 -07:00
TehRiehlDeal 77e894e164 Added temporary sound effect files 2026-03-14 20:51:47 -07:00
TehRiehlDeal e011f3bafa Add web app manifest and register service worker on login 2026-03-11 20:58:21 -07:00
TehRiehlDeal c35c20faeb Add service worker for push notifications 2026-03-11 20:46:49 -07:00
TehRiehlDeal 9d94efb7a3 Added new icon 2026-03-10 18:49:13 -07:00
TehRiehlDeal 0ceb2fac12 Initial commit 2026-03-09 15:03:08 -07:00
TehRiehlDeal 4a0d0d1855 feat: initial commit 2026-03-08 00:11:16 -08:00