mirror of
https://github.com/LucasKalil-Programador/world-2026-hub.git
synced 2026-07-04 17:41:28 -03:00
feat(pwa): add Tier 1 support — installable app with manifest and icons
This commit is contained in:
parent
2ad27084d5
commit
715ecedbcb
17 changed files with 156 additions and 2 deletions
|
|
@ -66,6 +66,10 @@ Use checkboxes to track progress. Items marked **🔴 BLOCKER** prevent release;
|
|||
- [ ] Real stadium photos + team flag SVGs in `assets/images/` (10 new-team flags created 2026-06-12 in placeholder style)
|
||||
- [ ] **Pós-Copa: estado final da home.** Quando a Final encerrar, o hero fica vazio (por design atual). Criar um estado pós-torneio (campeão/epílogo) na home — ver entrada "Hero cronômetro inteligente (2026-06-15)" em project-memory; provavelmente converge com a aba Stats (`stats-screen-plan.md`).
|
||||
|
||||
### 🟢 OPTIONAL
|
||||
- [x] ~~PWA Tier 1 — instalável (manifest + ícones + meta tags; 2026-06-16). Atende todos os critérios de aceitação da issue.~~
|
||||
- [ ] PWA Tier 2 — service worker + offline (deferido; ver `.agents/issues.md` → "PWA Tier 2". DEVE excluir `data/*.json` do cache p/ não quebrar o live-refresh + `DATA_VERSION`).
|
||||
|
||||
---
|
||||
|
||||
## Quick final checklist
|
||||
|
|
|
|||
|
|
@ -60,6 +60,41 @@ Only if:
|
|||
|
||||
---
|
||||
|
||||
## PWA Tier 2 — Service Worker + Offline (2026-06-16)
|
||||
|
||||
**Status:** Analyzed, deferred (Tier 1 shipped 2026-06-16 — see project-memory "PWA — installable app").
|
||||
|
||||
### Context
|
||||
The PWA install issue was delivered as **Tier 1** (manifest + icons + meta tags), which already meets
|
||||
every acceptance criterion (installable, correct name/icon, standalone launch from the OS shortcut, no
|
||||
app-pipeline risk). Tier 2 — a service worker for offline launch and the strongest cross-browser
|
||||
"app feel" — was intentionally left out. It is **not** required for the install prompt in modern
|
||||
Chrome/Edge.
|
||||
|
||||
### Why deferred (the real risk)
|
||||
A naïve precaching SW would cache `data/*.json` and **silently defeat the 2026-06-16 live-refresh
|
||||
system** (the 90s `results.json` poll with `cache:'no-store'` + the `DATA_VERSION` cache-buster) —
|
||||
open tabs would stop seeing new scores, and `DATA_VERSION` bumps would do nothing. It would also make
|
||||
the "stale JS module" gotcha (#5) *permanent* (cached assets live until the cache name changes).
|
||||
|
||||
### How to implement (if revisited) — constraints, not optional
|
||||
1. **Never cache `data/*.json`.** Use network-only, or network-first with the cache only as an
|
||||
offline fallback (so an offline launch shows the last-seen results). The 90s poll must stay the
|
||||
owner of freshness.
|
||||
2. **Version the SW cache** with a constant mirroring/derived from `DATA_VERSION`; clean up old caches
|
||||
on `activate` — otherwise every code deploy risks serving stale JS forever (gotcha #5).
|
||||
3. **Register at the subpath** (`worldcup2026/sw.js`) so the SW scope matches the deploy (gotcha #7);
|
||||
keep `start_url`/`scope` relative as they already are.
|
||||
4. App-shell strategy: cache-first (versioned) for `index.html` + `assets/css` + `assets/js` +
|
||||
`assets/icons`; precache on `install`.
|
||||
5. Verify the poll still updates an open tab **with the SW active** (the easy thing to regress).
|
||||
|
||||
### When to implement
|
||||
Only if offline launch / a fuller install experience is actually wanted, and only with the data-cache
|
||||
exclusion + cache-versioning above. Otherwise Tier 1 is sufficient.
|
||||
|
||||
---
|
||||
|
||||
## Live Data Refresh — Stale Results Until Page Reload (2026-06-15)
|
||||
|
||||
**Status:** ✅ **Implemented 2026-06-16** (Option A⁺ — "Fixed polling done right"). The analysis below
|
||||
|
|
|
|||
|
|
@ -24,7 +24,14 @@ worldcup2026/
|
|||
│
|
||||
├── index.html ★ SPA shell — header, nav tabs (Home, Matches,
|
||||
│ Groups, Knockout, Stadiums, Stats), hero, dashboard,
|
||||
│ modal container; loads app.js as ES module
|
||||
│ modal container; loads app.js as ES module.
|
||||
│ <head> has the PWA block (manifest link, theme-color,
|
||||
│ favicons, apple-mobile-web-app-* meta)
|
||||
│
|
||||
├── manifest.json PWA web app manifest (name/short_name, standalone,
|
||||
│ theme/background #081421, icons[]) — relative paths
|
||||
│ (start_url ".", scope "./") for the subpath deploy
|
||||
│ favicon.ico Root favicon (16+32, from the trophy logo)
|
||||
│
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
|
|
@ -59,7 +66,11 @@ worldcup2026/
|
|||
│ │ │ matches only), hero pulse + overview + goals-by-stage.
|
||||
│ │ │ PARTIAL (during-cup) — grows into the post-cup plan.
|
||||
│ │ └── calendar.js .ics export (RFC 5545, CRLF, Blob download)
|
||||
│ └── images/ Team flag SVGs, stadium placeholders
|
||||
│ ├── images/ Team flag SVGs, stadium placeholders
|
||||
│ └── icons/ PWA app icons (from the header trophy logo): icon.svg
|
||||
│ (master + manifest SVG), icon-192/512.png (purpose any),
|
||||
│ icon-maskable-192/512.png (safe-zone padded),
|
||||
│ apple-touch-icon.png (180), favicon-16/32.png, favicon.ico
|
||||
│
|
||||
├── data/ All content — REAL WC2026 data since 2026-06-12
|
||||
│ ├── teams.json 48 real qualifiers: { id, name, flag } (FIFA codes)
|
||||
|
|
@ -149,6 +160,7 @@ matches.json time (UTC) ── formatMatchTime(match, stadium, mode)
|
|||
| Where is simulation state stored/cleared? | `localStorage` key `wc2026_simulation`, via `assets/js/storage.js` |
|
||||
| Where do I change colors/theme? | CSS variables at the top of `assets/css/style.css` |
|
||||
| Where do I add a stadium? | `data/stadiums.json` + image in `assets/images/` |
|
||||
| Where do I change the app name / install icon / theme color? | `manifest.json` (name/short_name/theme) + `assets/icons/` (regenerate PNGs from `icon.svg`) + PWA `<meta>` in `index.html` `<head>` |
|
||||
| How do I replace mock data with real WC2026 data? | `how-update.md` (root) — done 2026-06-12; kept as schema reference |
|
||||
| How do I update scores during the tournament? | `how-refresh-data.md` (root) — daily results.json routine + thirdPlaceAssignment how-to |
|
||||
|
||||
|
|
|
|||
|
|
@ -231,6 +231,15 @@ Static web app showing the FIFA World Cup 2026 (Mexico/USA/Canada, 48 teams) —
|
|||
- **Não tratado (aceito, baixo risco — mudanças raras, poucas/dia):** modal aberto não auto-atualiza (relê no próximo open); re-render durante interação (drag do bracket / digitação no filtro) — filtros sobrevivem (state módulo-level), scroll pode pular.
|
||||
- **Verificado (preview, sem tocar no disco — `window.fetch` interceptado pra simular jogo 16 IRN×NZL finished 3–0, `visibilitychange` disparando `pollResults`):** dashboard Encerradas 15→16 / Próximas 89→88; hero trocou IRN×NZL→FRA×SEN (jogo 16 virou `over`); Group G recomputou (Irã `1 1 0 0 3 0 +3 3`); bracket(32)/stats(4 tiles)/matches(104) re-renderizaram; **console limpo**. Restaurado o `fetch` real → poll seguinte **auto-revertou** pra 15/89 (prova a assinatura nos dois sentidos). `DATA_VERSION` **não** bumpado (nenhum dado mudou no disco — só código).
|
||||
|
||||
### PWA — installable app (Tier 1, 2026-06-16)
|
||||
- **O site virou um PWA instalável** (issue "Adicionar suporte a instalação como aplicativo"). Escopo entregue = **Tier 1** (manifest + ícones + meta tags) — atende a TODOS os critérios de aceitação (instalável, nome/ícone corretos, abre standalone pelo atalho do SO). **Service worker / offline ficou de fora de propósito** (Tier 2, registrado em `.agents/issues.md`).
|
||||
- **Decisão-chave (por quê só Tier 1):** um SW que cacheasse `data/*.json` **quebraria** o poll de 90s + `DATA_VERSION` (live-refresh de 2026-06-16) — abas abertas parariam de ver placares novos. Tier 1 não toca em nada do pipeline de dados/JS → risco zero pro live-refresh. Se Tier 2 entrar, o SW **precisa excluir `data/*.json`** do cache (network-only/network-first) e versionar junto com `DATA_VERSION` (senão piora a gotcha #5 de módulo velho).
|
||||
- **Arquivos novos:** `manifest.json` (raiz), `favicon.ico` (raiz), `assets/icons/` (icon.svg master + icon-192/512.png `purpose:any` + icon-maskable-192/512.png + apple-touch-icon.png 180 + favicon-16/32.png + favicon.ico). **Nenhum JS mudou.** `index.html` ganhou um bloco PWA no `<head>` (link manifest, `<meta theme-color #081421>`, favicons, `apple-mobile-web-app-capable/-status-bar-style black-translucent/-title "WC 2026 Hub"`).
|
||||
- **Ícones derivados do logo do header** (o troféu SVG inline) sobre o gradiente escuro `#10243b→#081421` com o dourado `#d4af37`. Fontes em `assets/icons/icon.svg` (any, troféu a ~60%) e `icon-maskable.svg` (troféu a ~46%, dentro da safe-zone do maskable). **Rasterizados com ImageMagick** (`magick -background none icon.svg -resize NxN ...`); `favicon.ico` = 16+32 combinados. **Para trocar o ícone:** editar o(s) SVG e re-rodar os mesmos comandos `magick` (não há build step; é geração de asset 1x).
|
||||
- **Manifest:** `name "World Cup 2026 Hub"` / `short_name "WC 2026 Hub"` (nome estático, EN — manifest não faz i18n runtime); `display:standalone`; `background_color`+`theme_color` = `#081421` (`--bg-primary`, evita flash branco no splash); `start_url:"."` + `scope:"./"` **relativos** (gotcha #7 — site mora em `…/worldcup2026/`; absoluto quebraria). Nomeado `manifest.json` (não `.webmanifest`) p/ MIME seguro na Hostinger.
|
||||
- **Deploy:** os arquivos novos (manifest.json, favicon.ico, assets/icons/) **não** estão no `exclude` do `deploy.yml` → sobem normalmente. HTTPS da Hostinger já satisfaz o requisito de PWA.
|
||||
- **Verificado (preview localhost:8126, contexto seguro):** manifest 200 e parseado (name/short/start `.`/scope `./`/display standalone/theme `#081421`); todos os ícones 200 `image/png`; `favicon.ico` 200; `<meta theme-color>` + apple tags presentes; **console limpo**; app intacto (hero FRA×SEN, 4 cards do dashboard, 16 encerradas/88 próximas — sem regressão visual). **Não testável pelo preview:** o prompt de instalação real / "Add to Home Screen" + ícone no SO — confirmar no Chrome/Edge devtools (aba Application) ou num celular após o deploy.
|
||||
|
||||
### How to update real-world data (scores, schedule)
|
||||
Follow `how-refresh-data.md` (project root). In short:
|
||||
1. Edit `data/results.json` (scores/status) or `data/matches.json` (schedule, rare).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue