Trivia quiz app hosted on Dokploy
Find a file
Brian Ladner 9cd085f4b6
All checks were successful
CI / check (push) Successful in 54s
CI / deploy (push) Successful in 52s
ci: deploy to Cloudflare Workers on push to main (#2)
Adds a deploy job to the Forgejo workflow, gated on check passing and
limited to pushes to main. Uses CLOUDFLARE_API_TOKEN and
CLOUDFLARE_ACCOUNT_ID repo secrets (Vikunja #301).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

Reviewed-on: https://forgejo.theladners.com/LabNerd/trivia-app/pulls/2
Co-authored-by: Brian Ladner <git@theladners.com>
Co-committed-by: Brian Ladner <git@theladners.com>
2026-11-11 14:33:52 -08:00
.forgejo/workflows ci: deploy to Cloudflare Workers on push to main (#2) 2026-11-11 14:33:52 -08:00
context feat: portfolio polish, offline default provider and README rewrite 2026-11-03 00:36:03 -06:00
docs docs: move description above screenshots and use offline-default screenshots 2026-11-03 00:40:41 -06:00
public fix: dedupe card import and update counts in localProviders 2026-11-03 00:16:44 -06:00
scripts fix: dedupe card import and update counts in localProviders 2026-11-03 00:16:44 -06:00
src feat: portfolio polish, offline default provider and README rewrite 2026-11-03 00:36:03 -06:00
tests feat: portfolio polish, offline default provider and README rewrite 2026-11-03 00:36:03 -06:00
.gitignore chore: untrack scanner output (local-only card data) 2026-11-03 00:05:44 -06:00
CLAUDE.md ci: Forgejo Actions check (lint, typecheck, test, build) (#1) 2026-11-11 13:57:51 -08:00
eslint.config.js Initialize web application via create-cloudflare CLI 2025-11-12 20:03:46 -06:00
index.html feat: add Umami analytics tracking script 2026-08-06 12:11:23 -05:00
LICENSE Add MIT license, CI/CD workflow, and clean up TODO 2026-03-05 16:37:00 -06:00
package-lock.json fix: replace partial regex decodeHtml with he library (#9 #21 #8) 2026-03-26 18:26:45 -05:00
package.json docs: standardize README headings and add license field 2026-11-03 20:39:59 +00:00
README.md docs: standardize README headings and add license field 2026-11-03 20:39:59 +00:00
tsconfig.json Migrate codebase from JavaScript to TypeScript 2026-02-22 11:20:59 -06:00
vite.config.ts Remove GitHub Actions workflow — Dokploy deploys directly from GitHub 2026-03-05 16:44:45 -06:00
wrangler.jsonc chore: add compatibility_date to wrangler config 2026-05-31 10:12:47 -05:00

Trivia App

License: MIT

Live demo: https://trivia-app.labnerd.net/

A trivia quiz app built with React and TypeScript, deployed as a static site on Cloudflare Workers. There is no backend: every request goes straight from the browser to the question source.

Quiz setup screen, dark theme Quiz setup screen, light theme

Features

  • Four question sources behind one interface: two live APIs (Open Trivia Database, The Trivia API) and offline snapshots of both
  • Filter by category, difficulty, and question type; the form adapts to what each source supports
  • Paginated sessions: fetch the next 10 questions without leaving the quiz
  • Light and dark themes, persisted per browser
  • Opens on an offline snapshot, so the app works even when the live APIs are down

Engineering Highlights

  • Provider abstraction. Each source is a plain object implementing one Provider interface (src/api/providers.ts, src/api/adapters/). Responses are normalized to a single question shape, and the UI adapts to each provider's declared difficulties and types. Adding a source means implementing the interface and registering it.
  • State and data fetching. Provider selection, session tokens, and category live in a context (src/context/ProviderContext.tsx). A useFetch hook owns loading, error, retry, and AbortController cleanup, with a cancelled-flag guard against state updates after unmount.
  • Input validation. Route params for category, difficulty, and type are checked against the provider's allowlists before any request is made.
  • Offline data pipeline. scripts/download-trivia.mjs builds the offline snapshots from the live APIs.
  • Card-scanning pipeline. scripts/scanner.py extracts questions from photographed trivia cards using the Anthropic vision API, and scripts/import-cards.js merges and dedupes the output. See docs/scanner/ARCHITECTURE.md. The resulting datasets come from commercial card games, so they are kept local and are not part of this repository or the deployed site.
  • Testing and deployment. Vitest and Testing Library cover providers, context, hooks, and pages. Cloudflare Workers Builds deploys on every push to main.

Local Development

npm install
npm run dev        # dev server on port 3000
npm run build      # production build to dist/
npm run preview    # build + serve preview on port 3000
npm run lint       # ESLint
npm run typecheck  # TypeScript type check
npm run test       # Vitest

To enable the local-only card game providers, generate their data with the scanner pipeline and set VITE_LOCAL_CARDS=true in .env.local.

Tech Stack

  • React 19, React Router 7
  • TypeScript 5 (strict mode)
  • Vite 7, Vitest, Testing Library
  • Axios
  • Cloudflare Workers (static assets with SPA fallback)

Analytics

The deployed site loads a self-hosted Umami script for anonymous page-view counts. It sets no cookies.

License

MIT