Simple, customizable countdown with shareable short URLs, admin review tools, and theming.
Create a countdown by visiting the editor (root path) and filling in the form, or by providing URL parameters:
time(required, ISO UTC like2025-01-01T00:00:00Z)title,description,footer,completecolor(text color),bgcolor(background color)image(provider:id, e.g.,openverse:<uuid>ortenor:<id>)
Publishing generates a short URL /v/:slug that can be viewed without loading the editor. Protected slugs require a password to edit or delete. Admins can review reports and clear/delete via privileged headers.
src/— React app (editor/viewer, theming, UI components)netlify/functions/— API endpoints (/publish,/v/:slug,/admin-stats,/api/admin/reports,/api/admin/reports/:slug,/report, etc.)cypress/— E2E testsdocs/design/— feature designsdocs/pr/— PR plans derived from designs
pnpm start— Vite dev server + Netlify functions (PORTdefault 8080,FUNCTIONS_PORTdefault 8888 viascripts/serve-functions.js)pnpm dev— Vite dev server onlypnpm build— Build app todist/pnpm preview— Preview production buildpnpm test— Unit/integration tests (Vitest)pnpm bundle:check— Assert bundle size split (requires priorpnpm build)pnpm lint— ESLintpnpm types— Typecheckpnpm test:e2e— Cypress against local dev + functions (requires available ports 4173/8889)
CI runs pnpm bundle:check automatically after pnpm build.
ADMIN_SECRET— Required for admin endpoints (/api/admin/reports,/api/admin/reports/:slug,/admin-stats, admin override delete)VITE_TENOR_CLIENT_KEY,VITE_IMAGE_API_KEY_TENOR— Tenor image searchVITE_OPENVERSE_BASE— OpenVerse API base (for image search)COUNTDOWN_STORAGE_DIR— Override local blob shim root (defaults to/tmp/.netlify/published-datain Netlify functions,.netlify/published-datawhen running tests locally)COUNTDOWN_STORAGE_DRIVER— Optional override for storage (fsorblobs)COUNTDOWN_BLOBS_SITE_ID— Netlify site ID for manual Blobs configurationCOUNTDOWN_BLOBS_TOKEN— Netlify API token for manual Blobs configurationCOUNTDOWN_BLOBS_API_URL— Optional Netlify API base URL override
POST /publish— Create/update countdowns (short slugs)GET /v/:slug— Fetch published payload + metadataDELETE /v/:slug— Delete published countdown (owner password orx-admin-override)POST /v/:slug/report— Submit a report (rate limited)GET /api/admin/reports— List reported slugs (requiresx-admin-secret)GET /api/admin/published— List published slugs with metadata (paginated, requiresx-admin-secret)PATCH /api/admin/reports/:slug— Mark reviewedDELETE /api/admin/reports/:slug— Clear reports (optionalpurgeBlobs=true)GET /admin/stats— Admin stats (requiresx-admin-secret)
Admin UI:
/admin— landing hub for admin tools (requires admin secret, includes a Settings card to clear the session secret)/admin/reports— toggles between reported and published slugs, calls/api/admin/reports*and/api/admin/published
Requires Node 25.2.x (see .nvmrc) and pnpm 10+.
pnpm install
# Optional helpers used in scripts on Linux/macOS
sudo apt-get install jq # Ubuntu/Debian
brew install jq # macOSLocal dev with functions:
pnpm start
# App: http://localhost:8080 (or PORT)
# Functions: http://localhost:8888/.netlify/functions (or FUNCTIONS_PORT)Tests:
pnpm types
pnpm lint
pnpm test
npm run test:e2e # requires free ports 4173/8889Build output lives in dist/. Netlify Functions reside in netlify/functions/. Set ADMIN_SECRET and image API keys in your deploy environment. Production uses Netlify Blobs; local dev uses the .netlify/published-data shim. Refer to design docs in docs/design/ and PR briefs in docs/pr/ for feature-specific details.

