Skip to content

hamst-p/poa-modal

Repository files navigation

Proof of Aussie — Next.js + React

A Next.js (App Router) implementation of the Proof of Aussie beer CAPTCHA: a playful re-skin of Google reCAPTCHA where users must select all true blue Aussie beers before they can continue.

Quick start

Requirements:

  • Node.js 20+ (recommended)

Install dependencies and start the dev server:

npm install
npm run dev

Open http://localhost:3000 in your browser.

Other scripts:

npm run lint    # ESLint
npm run build   # Production build
npm start       # Start the production server (after build)

How the UI works

The page renders only one element from the captcha by default — the inline "I'm a true blue Aussie" checkbox row, modeled after Google reCAPTCHA's "I'm not a robot" entry point. Clicking the checkbox triggers the actual image challenge in a floating popup.

[ I'm a true blue Aussie ] ────────  Proof of Aussie / Privacy · Terms
        │
        ▼ click
┌──────────────────────────┐
│  Select all images of    │  ← popup, blue header
│  a true blue Aussie beer │
│ ┌───┬───┬───┐            │
│ │   │   │   │ ← 3x3 grid │
│ ├───┼───┼───┤            │
│ │   │   │   │            │
│ ├───┼───┼───┤            │
│ │   │   │   │            │
│ └───┴───┴───┘            │
│  ↻  🎧  ?       [VERIFY] │
└──────────────────────────┘

Responsive behaviour

The popup is rendered through a portal directly into document.body and is displayed as a centered modal with a dim semi-transparent backdrop on every screen size. The dialog is anchored to the visual center of the viewport (both horizontally and vertically) using flexbox, so it stays centered when the window is resized. On small screens (≤ 480px) the dialog grows up to a 360px max width to remain readable down to ~320px wide phones.

The popup can be dismissed by:

  • Pressing Escape
  • Clicking the overlay (anywhere outside the popup)

Project layout

poa-next/
├── public/                          # beer photos used by tiles (with SVG fallbacks)
└── src/
    ├── app/
    │   ├── globals.css              # all styling (modal, checkbox row, popup, captcha)
    │   ├── layout.tsx
    │   └── page.tsx                 # renders <ProofOfAussieCaptcha /> in the modal body
    ├── components/
    │   ├── Banner.tsx               # success/error banner inside the popup
    │   ├── BeerCaptcha.tsx          # the 3x3 challenge (header + grid + footer)
    │   ├── BeerTileButton.tsx       # single tile (image only — no labels)
    │   ├── CaptchaPopup.tsx         # portal-based centered modal popup
    │   ├── MiladycareHeader.tsx     # outer modal header
    │   ├── PoaCheckboxRow.tsx       # in-page reCAPTCHA-style checkbox row
    │   └── ProofOfAussieCaptcha.tsx # orchestrator (checkbox state + popup open/close)
    └── lib/
        └── beerCaptcha.ts           # beer catalogue, SVG art, puzzle generator

Components in one paragraph

ProofOfAussieCaptcha owns the verification state. It renders PoaCheckboxRow inline (in the modal body) and, when the user clicks it, mounts CaptchaPopup which portals a floating dialog into document.body. The dialog hosts BeerCaptcha, which generates a fresh puzzle on every mount. On a correct answer, BeerCaptcha calls onSuccess, the popup unmounts, and the checkbox flips to its checked state.

Notes

  • Audio challenge / Help buttons are intentionally stubbed (they show a banner message inside the popup).
  • Beer tiles prefer image assets from public/ when available; otherwise they fall back to inline SVG art (src/lib/beerCaptcha.ts > ART).
  • Tile labels were intentionally removed to mirror the original Google reCAPTCHA UI — only images are shown.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors