5 Commits

Author SHA1 Message Date
davide 82c997d475 Merge branch 'issue#19'
Migliora il referto di gara: nomi squadra al posto di A/B, icona
servizio a inizio set, allineamento "vinto da" e colori squadra
coerenti col segnapunti live.
2026-07-15 10:26:50 +02:00
davide 35c49247a8 style(referto): allinea i colori squadra a quelli del segnapunti live
Punti in striscia e nomi in "Formazione di partenza" ora usano lo
stesso giallo (#f5c518) per la squadra di casa e blu (#2196f3) per
gli ospiti già usati in display/controller, invece di una palette
scollegata dal resto dell'app.
2026-07-15 10:25:57 +02:00
davide fec140df62 style(referto): allinea "vinto da" a destra nell'header del set
Separa punteggio ed etichetta vincitore su un flex con
justify-content: space-between per migliorare la leggibilità.
2026-07-15 10:11:40 +02:00
davide c6eb493f25 feat(referto): mostra l'icona del servizio a inizio set
Aggiunge un'icona nera (nuovo asset serv-nero.png, più visibile del
serv.png bianco su sfondo chiaro) accanto al nome della squadra che
serviva all'inizio di ogni set nel referto stampabile.

Corregge inoltre generaReferto: la stampa partiva subito dopo
document.close(), prima che l'icona (risorsa esterna asincrona)
finisse di caricare, risultando in un riquadro vuoto. Ora attende
l'evento 'load' della finestra popup prima di chiamare print().
2026-07-15 10:05:47 +02:00
davide 7cf84a94d9 fix(referto): mostra i nomi delle squadre al posto delle etichette A/B
L'header e la tabella del risultato finale usavano segnaposto generici
"A"/"B"; ora indicano esplicitamente casa/ospiti e i nomi reali delle
squadre.
2026-07-15 09:55:51 +02:00
3 changed files with 29 additions and 13 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

+23 -12
View File
@@ -34,11 +34,11 @@ export function buildRefertoHtml(state, now = new Date()) {
return ` return `
<div class="form-row"> <div class="form-row">
<div class="form-team"> <div class="form-team">
<div class="form-team-name">${nomi.home}</div> <div class="form-team-name form-team-name-h">${nomi.home}</div>
<div class="giocatori">${formazioneSet.home.map(giocatoreHtml).join('')}</div> <div class="giocatori">${formazioneSet.home.map(giocatoreHtml).join('')}</div>
</div> </div>
<div class="form-team"> <div class="form-team">
<div class="form-team-name">${nomi.guest}</div> <div class="form-team-name form-team-name-g">${nomi.guest}</div>
<div class="giocatori">${formazioneSet.guest.map(giocatoreHtml).join('')}</div> <div class="giocatori">${formazioneSet.guest.map(giocatoreHtml).join('')}</div>
</div> </div>
</div>` </div>`
@@ -79,7 +79,11 @@ export function buildRefertoHtml(state, now = new Date()) {
const vinc = vincitoreSet(s) const vinc = vincitoreSet(s)
const nomeVinc = vinc === 'h' ? nomi.home : vinc === 'g' ? nomi.guest : '' const nomeVinc = vinc === 'h' ? nomi.home : vinc === 'g' ? nomi.guest : ''
const etichettaVinc = nomeVinc ? ` &nbsp;·&nbsp; vinto da <strong>${nomeVinc}</strong>` : '' const etichettaVinc = nomeVinc ? `<span class="set-vinc">vinto da <strong>${nomeVinc}</strong></span>` : ''
const servIcon = '<img src="/serv-nero.png" class="serv-icon" alt="Servizio">'
const servHomeIcon = s.serv === 'h' ? servIcon : ''
const servGuestIcon = s.serv === 'g' ? servIcon : ''
const puntiHtml = punti.map(p => const puntiHtml = punti.map(p =>
`<span class="punto punto-${p.chi}">${p.h}-${p.g}</span>` `<span class="punto punto-${p.chi}">${p.h}-${p.g}</span>`
@@ -90,7 +94,8 @@ export function buildRefertoHtml(state, now = new Date()) {
<div class="set-barra"><span>SET</span><span class="set-numero">${i + 1}</span></div> <div class="set-barra"><span>SET</span><span class="set-numero">${i + 1}</span></div>
<div class="set-corpo"> <div class="set-corpo">
<div class="set-header"> <div class="set-header">
${nomi.home} <strong>${h}</strong> · <strong>${g}</strong> ${nomi.guest}${etichettaVinc} <span>${servHomeIcon}${nomi.home} <strong>${h}</strong> · <strong>${g}</strong> ${nomi.guest}${servGuestIcon}</span>
${etichettaVinc}
</div> </div>
<div class="form-inizio"> <div class="form-inizio">
<div class="form-inizio-label">Formazione di partenza</div> <div class="form-inizio-label">Formazione di partenza</div>
@@ -130,7 +135,7 @@ export function buildRefertoHtml(state, now = new Date()) {
.meta { font-size: 11px; color: #333; margin-top: 3px; text-transform: uppercase; letter-spacing: 0.5px; } .meta { font-size: 11px; color: #333; margin-top: 3px; text-transform: uppercase; letter-spacing: 0.5px; }
.squadre-row { display: flex; align-items: center; gap: 14px; } .squadre-row { display: flex; align-items: center; gap: 14px; }
.badge-ab { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; border: 2px solid #111; font-weight: bold; font-size: 12px; flex-shrink: 0; } .badge-ab { display: inline-flex; align-items: center; justify-content: center; height: 22px; padding: 0 8px; border-radius: 11px; border: 2px solid #111; font-weight: bold; font-size: 12px; flex-shrink: 0; }
.nome-sq { font-size: 18px; font-weight: bold; } .nome-sq { font-size: 18px; font-weight: bold; }
.vs { font-size: 12px; color: #666; font-weight: bold; } .vs { font-size: 12px; color: #666; font-weight: bold; }
@@ -143,12 +148,14 @@ export function buildRefertoHtml(state, now = new Date()) {
.set-barra span:first-child { writing-mode: vertical-rl; transform: rotate(180deg); font-weight: bold; font-size: 11px; letter-spacing: 2px; } .set-barra span:first-child { writing-mode: vertical-rl; transform: rotate(180deg); font-weight: bold; font-size: 11px; letter-spacing: 2px; }
.set-numero { font-weight: bold; font-size: 15px; } .set-numero { font-weight: bold; font-size: 15px; }
.set-corpo { flex: 1; min-width: 0; } .set-corpo { flex: 1; min-width: 0; }
.set-header { background: #eaf7fb; padding: 6px 12px; font-size: 13px; border-bottom: 1px solid #111; } .set-header { background: #eaf7fb; padding: 6px 12px; font-size: 13px; border-bottom: 1px solid #111; display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.set-vinc { flex-shrink: 0; }
.serv-icon { width: 12px; height: 12px; vertical-align: middle; margin: 0 3px; }
.punti-grid { display: flex; flex-wrap: wrap; gap: 0; padding: 0; border-top: 1px solid #111; } .punti-grid { display: flex; flex-wrap: wrap; gap: 0; padding: 0; border-top: 1px solid #111; }
.punto { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; padding: 3px 4px; font-size: 11px; font-family: 'Courier New', monospace; white-space: nowrap; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; } .punto { display: inline-flex; align-items: center; justify-content: center; min-width: 34px; padding: 3px 4px; font-size: 11px; font-family: 'Courier New', monospace; white-space: nowrap; border-right: 1px solid #ccc; border-bottom: 1px solid #ccc; }
.punto-h { background: #d0e8ff; color: #003a6e; } .punto-h { background: #f5c518; color: #111; }
.punto-g { background: #ffddc0; color: #6e2700; } .punto-g { background: #2196f3; color: #fff; }
.eventi-set { padding: 6px 12px; border-bottom: 1px solid #111; } .eventi-set { padding: 6px 12px; border-bottom: 1px solid #111; }
.eventi-label { font-size: 10px; font-weight: bold; letter-spacing: 0.5px; text-transform: uppercase; color: #0f8faf; margin-bottom: 4px; } .eventi-label { font-size: 10px; font-weight: bold; letter-spacing: 0.5px; text-transform: uppercase; color: #0f8faf; margin-bottom: 4px; }
@@ -160,6 +167,8 @@ export function buildRefertoHtml(state, now = new Date()) {
.form-row { display: flex; gap: 40px; } .form-row { display: flex; gap: 40px; }
.form-team { flex: 1; } .form-team { flex: 1; }
.form-team-name { font-weight: bold; font-size: 12px; margin-bottom: 5px; } .form-team-name { font-weight: bold; font-size: 12px; margin-bottom: 5px; }
.form-team-name-h { color: #f5c518; }
.form-team-name-g { color: #2196f3; }
.giocatori { display: flex; gap: 5px; flex-wrap: wrap; } .giocatori { display: flex; gap: 5px; flex-wrap: wrap; }
.giocatore { background: #fff; border-radius: 50%; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 11px; border: 2px solid #111; } .giocatore { background: #fff; border-radius: 50%; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 11px; border: 2px solid #111; }
@@ -181,11 +190,11 @@ export function buildRefertoHtml(state, now = new Date()) {
<div class="meta">${dataOra} &nbsp;·&nbsp; Modalità: ${modalitaPartita}</div> <div class="meta">${dataOra} &nbsp;·&nbsp; Modalità: ${modalitaPartita}</div>
</div> </div>
<div class="squadre-row"> <div class="squadre-row">
<span class="badge-ab">A</span> <span class="badge-ab">Casa</span>
<span class="nome-sq">${nomi.home}</span> <span class="nome-sq">${nomi.home}</span>
<span class="vs">vs</span> <span class="vs">vs</span>
<span class="nome-sq">${nomi.guest}</span> <span class="nome-sq">${nomi.guest}</span>
<span class="badge-ab">B</span> <span class="badge-ab">Ospiti</span>
</div> </div>
</div> </div>
@@ -195,7 +204,7 @@ export function buildRefertoHtml(state, now = new Date()) {
<div class="finale-box"> <div class="finale-box">
<div class="finale-box-header">Risultato finale</div> <div class="finale-box-header">Risultato finale</div>
<table class="finale-tabella"> <table class="finale-tabella">
<thead><tr><th>Set</th><th>A</th><th>B</th></tr></thead> <thead><tr><th>Set</th><th>${nomi.home}</th><th>${nomi.guest}</th></tr></thead>
<tbody>${risultatoSetHtml}</tbody> <tbody>${risultatoSetHtml}</tbody>
</table> </table>
<div class="finale-vince">Vince ${setVinti.home >= setVinti.guest ? nomi.home : nomi.guest} &nbsp;${setVinti.home} ${setVinti.guest}</div> <div class="finale-vince">Vince ${setVinti.home >= setVinti.guest ? nomi.home : nomi.guest} &nbsp;${setVinti.home} ${setVinti.guest}</div>
@@ -219,5 +228,7 @@ export function generaReferto(state) {
const w = window.open('', '_blank') const w = window.open('', '_blank')
w.document.write(html) w.document.write(html)
w.document.close() w.document.close()
w.print() // Aspetta il caricamento delle immagini (icona servizio) prima di stampare,
// altrimenti la stampa parte con risorse ancora in caricamento e appaiono vuote.
w.addEventListener('load', () => w.print())
} }
@@ -11,10 +11,12 @@ describe('generaReferto (referto.js)', () => {
vi.restoreAllMocks() vi.restoreAllMocks()
}) })
it('apre una nuova scheda, scrive il referto e avvia la stampa', () => { it('apre una nuova scheda, scrive il referto e avvia la stampa dopo il caricamento', () => {
const listeners = {}
const popup = { const popup = {
document: { write: vi.fn(), close: vi.fn() }, document: { write: vi.fn(), close: vi.fn() },
print: vi.fn(), print: vi.fn(),
addEventListener: vi.fn((evt, cb) => { listeners[evt] = cb }),
} }
const openSpy = vi.spyOn(window, 'open').mockReturnValue(popup) const openSpy = vi.spyOn(window, 'open').mockReturnValue(popup)
@@ -26,6 +28,9 @@ describe('generaReferto (referto.js)', () => {
expect(popup.document.write).toHaveBeenCalledTimes(1) expect(popup.document.write).toHaveBeenCalledTimes(1)
expect(popup.document.write.mock.calls[0][0]).toContain('Antoniana') expect(popup.document.write.mock.calls[0][0]).toContain('Antoniana')
expect(popup.document.close).toHaveBeenCalledTimes(1) expect(popup.document.close).toHaveBeenCalledTimes(1)
expect(popup.print).not.toHaveBeenCalled()
listeners.load()
expect(popup.print).toHaveBeenCalledTimes(1) expect(popup.print).toHaveBeenCalledTimes(1)
}) })
}) })