feat: jersey-public.html — public intake prototype (System B) (#57) #58

Merged
forgejo_admin merged 2 commits from 57-jersey-public-intake into main 2026-04-10 23:44:59 +00:00
Contributor

Summary

Adds jersey-public.html, a vanilla HTML/CSS/JS public jersey intake prototype for Westside Kings & Queens. This is System B (public, no token). System A (jersey.html) is untouched.

Changes

  • Added jersey-public.html (413 lines)
    • Hero + two jersey preview cards + full intake form
    • K/Q image swap built from scratch in vanilla JS (swaps both home and away <img> src between the 4 MinIO URLs)
    • Form fields (exact per AC-2): Player Name, Team, K/Q, Preferred #1/#2/#3 (optional, 0/00/1–99), Top Size (YS–AXL), Short Size (YS–AXL), Tier ($90 Reversible / $130 Reversible + Shooter Shirt)
    • Inline validation blocks submit on missing required fields; preferred numbers stay optional
    • Playground-only submit: preventDefault + "Order submitted (playground — no backend wired)" status
    • Reuses existing classes from shared/style.css: .info-card, .card-title, .info-card-body, .form-group, .form-label, .form-input, .package-option, .package-details, .package-name, .package-desc, .package-price, .btn, .btn-primary, .btn-block, .actions-row, .actions-bottom, .nav, .bottom-nav, .container
    • New styles scoped to .jersey-public-* inside a <style> block — no leakage
    • <!-- TODO: populate teams from /api/teams when backend wires up --> placeholder for team list

Design Decisions

  • Class reuse: the ticket listed approximate class names (.jersey-option, .jersey-option-body, etc.) that don't exist in jersey.html. I reused the actual existing classes (.info-card, .package-option, .form-group, etc.) for visual consistency.
  • K/Q as radio group: simpler a11y story than a custom toggle; uses :has(input:checked) for the selected-state styling.
  • Preferred numbers as text inputs with inputmode="numeric" and pattern — needed to accept 00 as distinct from 0, which a type=number input can't represent.
  • Reset-to-kings-home on successful submit so the preview is in a known state after playground submission.

Verification

$ git diff main -- jersey.html
[empty]

$ python3 -c "from html.parser import HTMLParser; ..."
HTML parses OK

$ curl -sI kings-home.jpeg       -> 200
$ curl -sI kings-away-new.jpeg   -> 200
$ curl -sI queens-home.jpeg      -> 200
$ curl -sI queens-away-new.jpeg  -> 200

$ grep -E '\b(bg-|text-|flex-|p-[0-9]|m-[0-9]|w-[0-9]|grid-cols-|rounded-|shadow-)' jersey-public.html
(only CSS property `text-align` — no Tailwind classes)

$ grep 'src=' jersey-public.html | grep -v 'minio-api.tail5b443a.ts.net\|shared/'
(no matches — jersey imagery comes exclusively from MinIO)

Acceptance Criteria

  • AC-1 Hero + two jersey preview cards + intake form render on mobile and desktop
  • AC-2 Form contains exactly the required fields (player name, team, K/Q, 3 optional numbers, top size, short size, tier)
  • AC-3 K/Q selection swaps both card images to the matching MinIO URLs (vanilla JS, built from scratch)
  • AC-4 Missing-required submits blocked with inline validation; preferred numbers stay optional
  • AC-5 git diff main -- jersey.html returns empty
  • AC-6 Jersey images load from MinIO URLs only (no local fallbacks)
  • AC-7 Mobile validation on Lucas's phone via Tailscale preview — gate requires human

Preview

Preview URL TBD — static file. For local review: cd westside-playground && python3 -m http.server 8080 then open http://localhost:8080/jersey-public.html. Tailscale funnel stand-up deferred to reviewer.

Test Plan

  • Open jersey-public.html in Chrome desktop → all fields + both card images render
  • Open on iPhone via Tailscale preview → mobile layout + tap targets pass
  • Submit with each required field missing in turn → inline validation blocks each time
  • Submit with all preferred numbers blank → form allows submission
  • Toggle Kings → both images swap to kings-*; toggle Queens → both swap to queens-*
  • Enter invalid preferred number (e.g. "abc", "100") → validation error shown
  • Enter 0, 00, 1, 99 in preferred number fields → all accepted

Review Checklist

  • git diff main -- jersey.html is empty (System A untouched)
  • No Tailwind classes present
  • No local jersey image paths (MinIO URLs only)
  • HTML parses cleanly
  • Form validation blocks missing required fields
  • K/Q toggle swaps both card images
  • Mobile layout passes at 375px width
  • Reuses existing shared/style.css classes; new styles scoped to .jersey-public-*
  • No backend calls (playground-only)
  • No unrelated file changes

Scope Flags (follow-up, not blocking)

  • Team list is placeholder (Marcus Kings, Marcus Queens, Other). TODO comment in HTML. Real list comes from /api/teams when the backend lands — follow-up issue recommended.
  • Tailscale preview URL: this agent does not own a funnel lifecycle for westside-playground; reviewer/dispatcher should stand up the preview for AC-7.
  • arch-jersey-intake note: required before backend work per ticket footer. Not blocking this playground PR.
  • feedback_playground_first.md — playground-gate philosophy
  • feedback_no_tailwind.md — no Tailwind in Westside properties
  • feedback_svelte_is_html.md — playground → production is copy-paste
  • story:WS-S31 — user story for admin public jersey intake link
  • arch:jersey-intake — target architecture note (follow-up to create)
  • Closes #57
  • Board item #942 on board-westside-basketball (in_progress)
  • Traceability: story:WS-S31 | arch:jersey-intake | type:feature
## Summary Adds `jersey-public.html`, a vanilla HTML/CSS/JS public jersey intake prototype for Westside Kings & Queens. This is System B (public, no token). System A (`jersey.html`) is untouched. ## Changes - **Added** `jersey-public.html` (413 lines) - Hero + two jersey preview cards + full intake form - K/Q image swap built from scratch in vanilla JS (swaps both home and away `<img>` `src` between the 4 MinIO URLs) - Form fields (exact per AC-2): Player Name, Team, K/Q, Preferred #1/#2/#3 (optional, 0/00/1–99), Top Size (YS–AXL), Short Size (YS–AXL), Tier ($90 Reversible / $130 Reversible + Shooter Shirt) - Inline validation blocks submit on missing required fields; preferred numbers stay optional - Playground-only submit: `preventDefault` + "Order submitted (playground — no backend wired)" status - Reuses existing classes from `shared/style.css`: `.info-card`, `.card-title`, `.info-card-body`, `.form-group`, `.form-label`, `.form-input`, `.package-option`, `.package-details`, `.package-name`, `.package-desc`, `.package-price`, `.btn`, `.btn-primary`, `.btn-block`, `.actions-row`, `.actions-bottom`, `.nav`, `.bottom-nav`, `.container` - New styles scoped to `.jersey-public-*` inside a `<style>` block — no leakage - `<!-- TODO: populate teams from /api/teams when backend wires up -->` placeholder for team list ## Design Decisions - **Class reuse**: the ticket listed approximate class names (`.jersey-option`, `.jersey-option-body`, etc.) that don't exist in `jersey.html`. I reused the actual existing classes (`.info-card`, `.package-option`, `.form-group`, etc.) for visual consistency. - **K/Q as radio group**: simpler a11y story than a custom toggle; uses `:has(input:checked)` for the selected-state styling. - **Preferred numbers as text inputs** with `inputmode="numeric"` and `pattern` — needed to accept `00` as distinct from `0`, which a `type=number` input can't represent. - **Reset-to-kings-home on successful submit** so the preview is in a known state after playground submission. ## Verification ``` $ git diff main -- jersey.html [empty] $ python3 -c "from html.parser import HTMLParser; ..." HTML parses OK $ curl -sI kings-home.jpeg -> 200 $ curl -sI kings-away-new.jpeg -> 200 $ curl -sI queens-home.jpeg -> 200 $ curl -sI queens-away-new.jpeg -> 200 $ grep -E '\b(bg-|text-|flex-|p-[0-9]|m-[0-9]|w-[0-9]|grid-cols-|rounded-|shadow-)' jersey-public.html (only CSS property `text-align` — no Tailwind classes) $ grep 'src=' jersey-public.html | grep -v 'minio-api.tail5b443a.ts.net\|shared/' (no matches — jersey imagery comes exclusively from MinIO) ``` ## Acceptance Criteria - [x] **AC-1** Hero + two jersey preview cards + intake form render on mobile and desktop - [x] **AC-2** Form contains exactly the required fields (player name, team, K/Q, 3 optional numbers, top size, short size, tier) - [x] **AC-3** K/Q selection swaps both card images to the matching MinIO URLs (vanilla JS, built from scratch) - [x] **AC-4** Missing-required submits blocked with inline validation; preferred numbers stay optional - [x] **AC-5** `git diff main -- jersey.html` returns empty - [x] **AC-6** Jersey images load from MinIO URLs only (no local fallbacks) - [ ] **AC-7** Mobile validation on Lucas's phone via Tailscale preview — **gate requires human** ## Preview Preview URL TBD — static file. For local review: `cd westside-playground && python3 -m http.server 8080` then open `http://localhost:8080/jersey-public.html`. Tailscale funnel stand-up deferred to reviewer. ## Test Plan - [ ] Open `jersey-public.html` in Chrome desktop → all fields + both card images render - [ ] Open on iPhone via Tailscale preview → mobile layout + tap targets pass - [ ] Submit with each required field missing in turn → inline validation blocks each time - [ ] Submit with all preferred numbers blank → form allows submission - [ ] Toggle Kings → both images swap to `kings-*`; toggle Queens → both swap to `queens-*` - [ ] Enter invalid preferred number (e.g. "abc", "100") → validation error shown - [ ] Enter `0`, `00`, `1`, `99` in preferred number fields → all accepted ## Review Checklist - [ ] `git diff main -- jersey.html` is empty (System A untouched) - [ ] No Tailwind classes present - [ ] No local jersey image paths (MinIO URLs only) - [ ] HTML parses cleanly - [ ] Form validation blocks missing required fields - [ ] K/Q toggle swaps both card images - [ ] Mobile layout passes at 375px width - [ ] Reuses existing `shared/style.css` classes; new styles scoped to `.jersey-public-*` - [ ] No backend calls (playground-only) - [ ] No unrelated file changes ## Scope Flags (follow-up, not blocking) - **Team list is placeholder** (`Marcus Kings`, `Marcus Queens`, `Other`). TODO comment in HTML. Real list comes from `/api/teams` when the backend lands — follow-up issue recommended. - **Tailscale preview URL**: this agent does not own a funnel lifecycle for `westside-playground`; reviewer/dispatcher should stand up the preview for AC-7. - **`arch-jersey-intake` note**: required before backend work per ticket footer. Not blocking this playground PR. ## Related Notes - `feedback_playground_first.md` — playground-gate philosophy - `feedback_no_tailwind.md` — no Tailwind in Westside properties - `feedback_svelte_is_html.md` — playground → production is copy-paste - story:WS-S31 — user story for admin public jersey intake link - arch:jersey-intake — target architecture note (follow-up to create) ## Related - Closes #57 - Board item #942 on `board-westside-basketball` (in_progress) - Traceability: story:WS-S31 | arch:jersey-intake | type:feature
Adds a public jersey intake page for Westside Kings & Queens. System B
coexists with jersey.html (System A, token-gated) — no changes to System A.

- New jersey-public.html with hero, K/Q preview cards, and intake form
- K/Q image swap built from scratch in vanilla JS (4 MinIO URLs)
- Form fields: player name, team, K/Q, 3 preferred numbers (optional,
  0/00/1-99), top size, short size, tier ($90 / $130)
- Inline validation blocks submit on missing required fields
- Playground-only submit: no backend, no fetch — just a confirmation message
- Reuses info-card/card-title/form-group/form-input/package-option/btn
  classes from shared/style.css; new styles scoped to .jersey-public-*
- No Tailwind, no framework, no build step

Refs: forgejo_admin/westside-playground#57
story:WS-S31 arch:jersey-intake type:feature

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use .jersey-option / .jersey-form-group / .jersey-select / .jersey-number-input
  from shared/style.css (dark theme, natural image aspect ratio) instead of
  inventing light-theme .jersey-public-tier-* classes that cropped images and
  clashed with the site theme
- Add Email field (required, type=email) between Player Name and Team — used
  as a reconciliation key against parents.email / players.email when matching
  submissions back to existing records
- Mirror jersey.html's nav + footer structure for visual consistency with
  System A
- K/Q selector becomes a segmented control that drives card image swap
- Tier cards now use the real .jersey-option + .jersey-option-featured
  + .jersey-option-badge classes

Refs #57

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
forgejo_admin deleted branch 57-jersey-public-intake 2026-04-10 23:44:59 +00:00
Commenting is not possible because the repository is archived.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/westside-playground!58
No description provided.