From 33a15343195aa16ba138d64cf5d6f55ccc285ddb Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Wed, 28 Jan 2026 18:08:18 +0100 Subject: [PATCH 1/6] feat(cambi): dialog cambi con tabella IN/OUT, validazioni e aggiornamento formazione MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dialog “CAMBI” con tabella 2x2 e intestazioni IN/OUT - etichette riga con nomi squadre - conferma solo con righe complete (almeno un cambio) - sostituzione OUT→IN in formazione con controlli errori --- src/components/HomePage/HomePage.html | 32 ++++++++++ src/components/HomePage/HomePage.js | 84 +++++++++++++++++++++++++++ src/style.css | 25 ++++++++ 3 files changed, 141 insertions(+) diff --git a/src/components/HomePage/HomePage.html b/src/components/HomePage/HomePage.html index 06e7993..b806753 100644 --- a/src/components/HomePage/HomePage.html +++ b/src/components/HomePage/HomePage.html @@ -68,6 +68,35 @@ Ok + +
CAMBI
+ + + + + + + + + + + + + + + + + + + + +
INOUT
{{ sp.nomi.home }}
{{ sp.nomi.guest }}
+ + + CONFERMA + + +
@@ -193,6 +222,9 @@ PUNTEGGIO FORMAZIONI + + CAMBI + STRISCIA diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js index e426b20..96d88ba 100644 --- a/src/components/HomePage/HomePage.js +++ b/src/components/HomePage/HomePage.js @@ -11,6 +11,11 @@ export default { home: "", guest: "", }, + diaCambi: { + show: false, + guest: { in: "", out: "" }, + home: { in: "", out: "" }, + }, visuForm: false, visuButt: true, visuStriscia: true, @@ -42,6 +47,22 @@ export default { computed: { isPunteggioZeroZero() { return this.sp.punt.home === 0 && this.sp.punt.guest === 0; + }, + cambiConfermabili() { + const guestIn = (this.diaCambi.guest.in || "").trim(); + const guestOut = (this.diaCambi.guest.out || "").trim(); + const homeIn = (this.diaCambi.home.in || "").trim(); + const homeOut = (this.diaCambi.home.out || "").trim(); + + const guestEmpty = !guestIn && !guestOut; + const homeEmpty = !homeIn && !homeOut; + const guestComplete = !!guestIn && !!guestOut; + const homeComplete = !!homeIn && !!homeOut; + + const noIncomplete = (guestEmpty || guestComplete) && (homeEmpty || homeComplete); + const atLeastOne = guestComplete || homeComplete; + + return noIncomplete && atLeastOne; } }, methods: { @@ -214,6 +235,65 @@ export default { this.disabilitaTastiSpeciali(); this.diaNomi.show = true; }, + resettaCambi() { + this.diaCambi.guest.in = ""; + this.diaCambi.guest.out = ""; + this.diaCambi.home.in = ""; + this.diaCambi.home.out = ""; + }, + apriDialogCambi() { + this.disabilitaTastiSpeciali(); + this.resettaCambi(); + this.diaCambi.show = true; + }, + chiudiDialogCambi() { + this.diaCambi.show = false; + this.resettaCambi(); + this.abilitaTastiSpeciali(); + }, + confermaCambi() { + if (!this.cambiConfermabili) { + return; + } + + const cambi = [ + { team: "guest", in: (this.diaCambi.guest.in || "").trim(), out: (this.diaCambi.guest.out || "").trim() }, + { team: "home", in: (this.diaCambi.home.in || "").trim(), out: (this.diaCambi.home.out || "").trim() }, + ]; + + const cambiDaApplicare = []; + for (const cambio of cambi) { + if (!cambio.in && !cambio.out) { + continue; + } + + const form = this.sp.form[cambio.team].map((val) => String(val).trim()); + + if (form.includes(cambio.in)) { + this.$waveui.notify(`Numero ${cambio.in} già presente in formazione ${cambio.team}`, "warning"); + return; + } + if (!form.includes(cambio.out)) { + this.$waveui.notify(`Numero ${cambio.out} non presente in formazione ${cambio.team}`, "warning"); + return; + } + if (cambio.in === cambio.out) { + this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); + return; + } + + cambiDaApplicare.push({ ...cambio }); + } + + for (const cambio of cambiDaApplicare) { + const idx = this.sp.form[cambio.team].findIndex((val) => String(val).trim() === cambio.out); + if (idx !== -1) { + this.sp.form[cambio.team].splice(idx, 1, cambio.in); + } + } + + this.chiudiDialogCambi(); + }, disabilitaTastiSpeciali() { window.removeEventListener("keydown", this.funzioneTastiSpeciali); }, @@ -221,6 +301,10 @@ export default { window.addEventListener("keydown", this.funzioneTastiSpeciali); }, funzioneTastiSpeciali(e) { + const target = e.target; + if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)) { + return; + } e.preventDefault(); if (e.ctrlKey && e.key == "m") { this.diaNomi.show = true diff --git a/src/style.css b/src/style.css index b061700..2949bbd 100644 --- a/src/style.css +++ b/src/style.css @@ -190,3 +190,28 @@ button:focus-visible { height: 0; margin: 0; } + +.cambi-table { + width: 100%; + border-collapse: collapse; +} + +.cambi-table th, +.cambi-table td { + padding: 8px; + text-align: center; +} + +.cambi-table th { + font-weight: bold; +} + +.cambi-table .row-label { + text-align: left; + font-weight: bold; + width: 90px; +} + +.cambi-input { + min-width: 110px; +} -- 2.49.1 From 44617f2f862ecdd561e6ad6358c3bb81fb4ae7ed Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Wed, 28 Jan 2026 18:14:51 +0100 Subject: [PATCH 2/6] Aggiunge shortcut per cambi e aggiorna README.md --- README.md | 2 ++ src/components/HomePage/HomePage.js | 49 +++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 74f0530..4b48f13 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Applicazione web **Progressive Web App (PWA)** per tracciare i punteggi di parti - Visualizzazione interattiva dei 6 giocatori in campo - Rotazione automatica regolamentare al cambio palla - Configurazione manuale dei numeri di maglia + - Dialog cambi con sostituzione IN/OUT e validazioni - Supporto logica pallavolo ufficiale (25 punti + 2 di vantaggio, tie-break a 15 nel set decisivo) - **Controlli Multimodali** @@ -171,6 +172,7 @@ Serve i file dalla cartella `/dist` per testare la build prima del deploy. | `Ctrl + F` | Attiva/disattiva fullscreen | | `Ctrl + S` | Annuncio vocale punteggio corrente | | `Ctrl + Z` | Switch tra visualizzazione formazioni e punteggio | +| `Ctrl + C` | Apri dialog cambi | --- diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js index 96d88ba..d32d011 100644 --- a/src/components/HomePage/HomePage.js +++ b/src/components/HomePage/HomePage.js @@ -301,36 +301,79 @@ export default { window.addEventListener("keydown", this.funzioneTastiSpeciali); }, funzioneTastiSpeciali(e) { - const target = e.target; - if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable)) { + if (this.diaNomi.show || this.diaCambi.show) { return; } - e.preventDefault(); + + const target = e.target; + const path = typeof e.composedPath === "function" ? e.composedPath() : []; + const elements = [target, ...path].filter(Boolean); + const isTypingField = elements.some((el) => { + if (!el || !el.tagName) { + return false; + } + const tag = String(el.tagName).toLowerCase(); + if (tag === "input" || tag === "textarea") { + return true; + } + if (el.isContentEditable) { + return true; + } + if (el.classList && (el.classList.contains("w-input") || el.classList.contains("w-textarea"))) { + return true; + } + const contentEditable = el.getAttribute && el.getAttribute("contenteditable"); + return contentEditable === "true"; + }); + if (isTypingField) { + return; + } + + let handled = false; if (e.ctrlKey && e.key == "m") { this.diaNomi.show = true + handled = true; } else if (e.ctrlKey && e.key == "b") { this.visuButt = !this.visuButt + handled = true; } else if (e.ctrlKey && e.key == "f") { document.documentElement.requestFullscreen(); + handled = true; } else if (e.ctrlKey && e.key == "s") { this.speak(); + handled = true; } else if (e.ctrlKey && e.key == "z") { this.visuForm = !this.visuForm + handled = true; } else if (e.ctrlKey && e.key == "ArrowUp") { this.incPunt("home") + handled = true; } else if (e.ctrlKey && e.key == "ArrowDown") { this.decPunt("home") + handled = true; } else if (e.ctrlKey && e.key == "ArrowRight") { this.incSet("home") + handled = true; } else if (e.shiftKey && e.key == "ArrowUp") { this.incPunt("guest") + handled = true; } else if (e.shiftKey && e.key == "ArrowDown") { this.decPunt("guest") + handled = true; } else if (e.shiftKey && e.key == "ArrowRight") { this.incSet("guest") + handled = true; } else if (e.ctrlKey && e.key == "ArrowLeft") { this.cambiaPalla() + handled = true; + } else if (e.ctrlKey && (e.key == "c" || e.key == "C")) { + this.apriDialogCambi() + handled = true; } else { return false } + + if (handled) { + e.preventDefault(); + } } } } -- 2.49.1 From 9df74a760fa1f132391fff791aaa6c99c3bb6172 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Wed, 28 Jan 2026 18:27:50 +0100 Subject: [PATCH 3/6] feat(cambi): dialog squadra, scorciatoie dedicate e aggiornamenti README Dettagli: - richiesta squadra prima del cambio e tabella a riga singola - scorciatoie Ctrl+C (home) e Shift+C (guest) - conferma cambio con validazioni e sostituzione in formazione - README aggiornato con nuovi shortcut e funzione cambi --- README.md | 3 +- src/components/HomePage/HomePage.html | 11 ++- src/components/HomePage/HomePage.js | 103 +++++++++++++------------- 3 files changed, 62 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 4b48f13..8d2f445 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ Serve i file dalla cartella `/dist` per testare la build prima del deploy. | `Ctrl + ↑` | Incrementa punti | | `Ctrl + ↓` | Decrementa punti | | `Ctrl + →` | Incrementa set | +| `Ctrl + C` | Apri dialog cambi | ### Controlli Tastiera Squadra Guest @@ -161,6 +162,7 @@ Serve i file dalla cartella `/dist` per testare la build prima del deploy. | `Shift + ↑` | Incrementa punti | | `Shift + ↓` | Decrementa punti | | `Shift + →` | Incrementa set | +| `Shift + C` | Apri dialog cambi | ### Comandi Globali @@ -172,7 +174,6 @@ Serve i file dalla cartella `/dist` per testare la build prima del deploy. | `Ctrl + F` | Attiva/disattiva fullscreen | | `Ctrl + S` | Annuncio vocale punteggio corrente | | `Ctrl + Z` | Switch tra visualizzazione formazioni e punteggio | -| `Ctrl + C` | Apri dialog cambi | --- diff --git a/src/components/HomePage/HomePage.html b/src/components/HomePage/HomePage.html index b806753..cef59bd 100644 --- a/src/components/HomePage/HomePage.html +++ b/src/components/HomePage/HomePage.html @@ -68,6 +68,13 @@ Ok + +
Scegli squadra
+ + {{ sp.nomi.home }} + {{ sp.nomi.guest }} + +
CAMBI
@@ -79,12 +86,12 @@ - + - + diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js index d32d011..22c9cfe 100644 --- a/src/components/HomePage/HomePage.js +++ b/src/components/HomePage/HomePage.js @@ -13,9 +13,13 @@ export default { }, diaCambi: { show: false, + team: "home", guest: { in: "", out: "" }, home: { in: "", out: "" }, }, + diaCambiTeam: { + show: false, + }, visuForm: false, visuButt: true, visuStriscia: true, @@ -49,20 +53,11 @@ export default { return this.sp.punt.home === 0 && this.sp.punt.guest === 0; }, cambiConfermabili() { - const guestIn = (this.diaCambi.guest.in || "").trim(); - const guestOut = (this.diaCambi.guest.out || "").trim(); - const homeIn = (this.diaCambi.home.in || "").trim(); - const homeOut = (this.diaCambi.home.out || "").trim(); + const team = this.diaCambi.team; + const teamIn = (this.diaCambi[team].in || "").trim(); + const teamOut = (this.diaCambi[team].out || "").trim(); - const guestEmpty = !guestIn && !guestOut; - const homeEmpty = !homeIn && !homeOut; - const guestComplete = !!guestIn && !!guestOut; - const homeComplete = !!homeIn && !!homeOut; - - const noIncomplete = (guestEmpty || guestComplete) && (homeEmpty || homeComplete); - const atLeastOne = guestComplete || homeComplete; - - return noIncomplete && atLeastOne; + return !!teamIn && !!teamOut; } }, methods: { @@ -235,20 +230,30 @@ export default { this.disabilitaTastiSpeciali(); this.diaNomi.show = true; }, - resettaCambi() { - this.diaCambi.guest.in = ""; - this.diaCambi.guest.out = ""; - this.diaCambi.home.in = ""; - this.diaCambi.home.out = ""; + resettaCambi(team) { + const teams = team ? [team] : ["home", "guest"]; + teams.forEach((t) => { + this.diaCambi[t].in = ""; + this.diaCambi[t].out = ""; + }); }, apriDialogCambi() { this.disabilitaTastiSpeciali(); - this.resettaCambi(); + this.diaCambiTeam.show = true; + }, + apriDialogCambiTeam(team) { + this.disabilitaTastiSpeciali(); + this.diaCambi.team = team; + this.resettaCambi(team); this.diaCambi.show = true; }, + selezionaTeamCambi(team) { + this.diaCambiTeam.show = false; + this.apriDialogCambiTeam(team); + }, chiudiDialogCambi() { this.diaCambi.show = false; - this.resettaCambi(); + this.resettaCambi(this.diaCambi.team); this.abilitaTastiSpeciali(); }, confermaCambi() { @@ -256,40 +261,31 @@ export default { return; } - const cambi = [ - { team: "guest", in: (this.diaCambi.guest.in || "").trim(), out: (this.diaCambi.guest.out || "").trim() }, - { team: "home", in: (this.diaCambi.home.in || "").trim(), out: (this.diaCambi.home.out || "").trim() }, - ]; + const team = this.diaCambi.team; + const cambio = { + team, + in: (this.diaCambi[team].in || "").trim(), + out: (this.diaCambi[team].out || "").trim(), + }; - const cambiDaApplicare = []; - for (const cambio of cambi) { - if (!cambio.in && !cambio.out) { - continue; - } + const form = this.sp.form[cambio.team].map((val) => String(val).trim()); - const form = this.sp.form[cambio.team].map((val) => String(val).trim()); - - if (form.includes(cambio.in)) { - this.$waveui.notify(`Numero ${cambio.in} già presente in formazione ${cambio.team}`, "warning"); - return; - } - if (!form.includes(cambio.out)) { - this.$waveui.notify(`Numero ${cambio.out} non presente in formazione ${cambio.team}`, "warning"); - return; - } - if (cambio.in === cambio.out) { - this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); - return; - } - - cambiDaApplicare.push({ ...cambio }); + if (form.includes(cambio.in)) { + this.$waveui.notify(`Numero ${cambio.in} già presente in formazione ${cambio.team}`, "warning"); + return; + } + if (!form.includes(cambio.out)) { + this.$waveui.notify(`Numero ${cambio.out} non presente in formazione ${cambio.team}`, "warning"); + return; + } + if (cambio.in === cambio.out) { + this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); + return; } - for (const cambio of cambiDaApplicare) { - const idx = this.sp.form[cambio.team].findIndex((val) => String(val).trim() === cambio.out); - if (idx !== -1) { - this.sp.form[cambio.team].splice(idx, 1, cambio.in); - } + const idx = this.sp.form[cambio.team].findIndex((val) => String(val).trim() === cambio.out); + if (idx !== -1) { + this.sp.form[cambio.team].splice(idx, 1, cambio.in); } this.chiudiDialogCambi(); @@ -301,7 +297,7 @@ export default { window.addEventListener("keydown", this.funzioneTastiSpeciali); }, funzioneTastiSpeciali(e) { - if (this.diaNomi.show || this.diaCambi.show) { + if (this.diaNomi.show || this.diaCambi.show || this.diaCambiTeam.show) { return; } @@ -367,7 +363,10 @@ export default { this.cambiaPalla() handled = true; } else if (e.ctrlKey && (e.key == "c" || e.key == "C")) { - this.apriDialogCambi() + this.apriDialogCambiTeam("home") + handled = true; + } else if (e.shiftKey && (e.key == "c" || e.key == "C")) { + this.apriDialogCambiTeam("guest") handled = true; } else { return false } -- 2.49.1 From f190db2161016f703449cdae8953a43c7d4bf7cd Mon Sep 17 00:00:00 2001 From: davide3011 Date: Thu, 29 Jan 2026 11:08:25 +0100 Subject: [PATCH 4/6] Feat(cambi): supporto cambi multipli con UI migliorata MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consente di effettuare fino a 2 cambi simultanei per squadra con una nuova interfaccia utente più compatta e visuale. Gli input IN sono colorati di verde, gli OUT di rosso, e una freccia indica la direzione del cambio. La validazione permette cambi parziali (campi vuoti) ma richiede che ogni cambio inserito sia completo (sia IN che OUT) e che almeno un cambio sia presente per confermare --- src/components/HomePage/HomePage.html | 39 ++++++------- src/components/HomePage/HomePage.js | 80 +++++++++++++++++---------- src/style.css | 73 +++++++++++++++++++----- 3 files changed, 128 insertions(+), 64 deletions(-) diff --git a/src/components/HomePage/HomePage.html b/src/components/HomePage/HomePage.html index cef59bd..718083e 100644 --- a/src/components/HomePage/HomePage.html +++ b/src/components/HomePage/HomePage.html @@ -75,29 +75,22 @@ {{ sp.nomi.guest }} - -
CAMBI
-
{{ sp.nomi.home }}
{{ sp.nomi.guest }}
- - - - - - - - - - - - - - - - - - - -
INOUT
{{ sp.nomi.home }}
{{ sp.nomi.guest }}
+ +
+
{{ sp.nomi[diaCambi.team] }}: CAMBIO
+
+
+ + + +
+
+ + + +
+
+
CONFERMA diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js index 22c9cfe..e51d1a4 100644 --- a/src/components/HomePage/HomePage.js +++ b/src/components/HomePage/HomePage.js @@ -14,8 +14,8 @@ export default { diaCambi: { show: false, team: "home", - guest: { in: "", out: "" }, - home: { in: "", out: "" }, + guest: { cambi: [{ in: "", out: "" }, { in: "", out: "" }] }, + home: { cambi: [{ in: "", out: "" }, { in: "", out: "" }] }, }, diaCambiTeam: { show: false, @@ -54,10 +54,25 @@ export default { }, cambiConfermabili() { const team = this.diaCambi.team; - const teamIn = (this.diaCambi[team].in || "").trim(); - const teamOut = (this.diaCambi[team].out || "").trim(); + const cambi = this.diaCambi[team].cambi || []; + let hasComplete = false; + let allValid = true; - return !!teamIn && !!teamOut; + cambi.forEach((cambio) => { + const teamIn = (cambio.in || "").trim(); + const teamOut = (cambio.out || "").trim(); + + if (!teamIn && !teamOut) { + return; + } + if (!teamIn || !teamOut) { + allValid = false; + return; + } + hasComplete = true; + }); + + return allValid && hasComplete; } }, methods: { @@ -233,8 +248,10 @@ export default { resettaCambi(team) { const teams = team ? [team] : ["home", "guest"]; teams.forEach((t) => { - this.diaCambi[t].in = ""; - this.diaCambi[t].out = ""; + this.diaCambi[t].cambi.forEach((cambio) => { + cambio.in = ""; + cambio.out = ""; + }); }); }, apriDialogCambi() { @@ -262,31 +279,38 @@ export default { } const team = this.diaCambi.team; - const cambio = { - team, - in: (this.diaCambi[team].in || "").trim(), - out: (this.diaCambi[team].out || "").trim(), - }; + const cambi = (this.diaCambi[team].cambi || []) + .map((cambio) => ({ + team, + in: (cambio.in || "").trim(), + out: (cambio.out || "").trim(), + })) + .filter((cambio) => cambio.in || cambio.out); - const form = this.sp.form[cambio.team].map((val) => String(val).trim()); + const form = this.sp.form[team].map((val) => String(val).trim()); + const formAggiornata = [...form]; - if (form.includes(cambio.in)) { - this.$waveui.notify(`Numero ${cambio.in} già presente in formazione ${cambio.team}`, "warning"); - return; - } - if (!form.includes(cambio.out)) { - this.$waveui.notify(`Numero ${cambio.out} non presente in formazione ${cambio.team}`, "warning"); - return; - } - if (cambio.in === cambio.out) { - this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); - return; + for (const cambio of cambi) { + if (cambio.in === cambio.out) { + this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); + return; + } + if (formAggiornata.includes(cambio.in)) { + this.$waveui.notify(`Numero ${cambio.in} già presente in formazione ${cambio.team}`, "warning"); + return; + } + if (!formAggiornata.includes(cambio.out)) { + this.$waveui.notify(`Numero ${cambio.out} non presente in formazione ${cambio.team}`, "warning"); + return; + } + + const idx = formAggiornata.findIndex((val) => String(val).trim() === cambio.out); + if (idx !== -1) { + formAggiornata.splice(idx, 1, cambio.in); + } } - const idx = this.sp.form[cambio.team].findIndex((val) => String(val).trim() === cambio.out); - if (idx !== -1) { - this.sp.form[cambio.team].splice(idx, 1, cambio.in); - } + this.sp.form[team] = formAggiornata; this.chiudiDialogCambi(); }, diff --git a/src/style.css b/src/style.css index 2949bbd..f00b946 100644 --- a/src/style.css +++ b/src/style.css @@ -191,27 +191,74 @@ button:focus-visible { margin: 0; } -.cambi-table { - width: 100%; - border-collapse: collapse; +.cambi-rows { + display: flex; + flex-direction: column; + gap: 12px; + padding: 8px 0; } -.cambi-table th, -.cambi-table td { - padding: 8px; +.cambi-dialog { + padding: 8px 6px 2px; +} + +.cambi-title { text-align: center; + font-weight: 800; + letter-spacing: 0.5px; + margin-bottom: 8px; + padding-bottom: 6px; + border-bottom: 1px solid rgba(255, 255, 255, 0.15); } -.cambi-table th { - font-weight: bold; +.cambi-row { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; } -.cambi-table .row-label { - text-align: left; - font-weight: bold; - width: 90px; +.cambi-arrow { + font-weight: 700; + font-size: 18px; + line-height: 1; + padding: 6px 8px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + white-space: nowrap; } .cambi-input { - min-width: 110px; + min-width: 48px; + max-width: 64px; +} + +.cambi-input input, +.cambi-input .w-input__input, +.cambi-input .w-input__field { + border: 2px solid rgba(255, 255, 255, 0.35); + border-radius: 8px; + padding: 6px 10px; + color: #000; + text-align: center; + box-sizing: border-box; +} + +.cambi-in input, +.cambi-in .w-input__input, +.cambi-in .w-input__field { + background: rgba(120, 200, 120, 0.4); +} + +.cambi-out input, +.cambi-out .w-input__input, +.cambi-out .w-input__field { + background: rgba(200, 120, 120, 0.4); +} + +.cambi-input input:focus, +.cambi-input .w-input__input:focus, +.cambi-input .w-input__field:focus { + border-color: rgba(255, 255, 255, 0.7); + outline: none; } -- 2.49.1 From ea4d8ec5234da8241c1063ecde74c462d32fc8a5 Mon Sep 17 00:00:00 2001 From: davide3011 Date: Thu, 29 Jan 2026 13:26:19 +0100 Subject: [PATCH 5/6] Aggiorna README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d2f445..3a523a3 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,14 @@ Applicazione web **Progressive Web App (PWA)** per tracciare i punteggi di parti - Tracciamento punti in tempo reale per entrambe le squadre - Conteggio automatico dei set (modalità 2/3 o 3/5) - Indicatore visivo del servizio + - Blocco incremento punti a set concluso - Cronologia punti con striscia visiva - **Formazioni Squadra** - Visualizzazione interattiva dei 6 giocatori in campo - Rotazione automatica regolamentare al cambio palla - Configurazione manuale dei numeri di maglia - - Dialog cambi con sostituzione IN/OUT e validazioni + - Dialog cambi con uno o due cambi (IN → OUT) e validazioni - Supporto logica pallavolo ufficiale (25 punti + 2 di vantaggio, tie-break a 15 nel set decisivo) - **Controlli Multimodali** -- 2.49.1 From 1972fd37a4f7ddeee33dc88e8316c7a87af0ced8 Mon Sep 17 00:00:00 2001 From: davide3011 Date: Thu, 29 Jan 2026 13:42:10 +0100 Subject: [PATCH 6/6] Fix(cambi): valida input numerici per i cambi - Blocca conferma se IN/OUT contengono caratteri non numerici - Mostra un warning con messaggio dedicato --- src/components/HomePage/HomePage.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js index e51d1a4..9c27938 100644 --- a/src/components/HomePage/HomePage.js +++ b/src/components/HomePage/HomePage.js @@ -291,6 +291,10 @@ export default { const formAggiornata = [...form]; for (const cambio of cambi) { + if (!/^\d+$/.test(cambio.in) || !/^\d+$/.test(cambio.out)) { + this.$waveui.notify("Inserisci solo numeri nei campi", "warning"); + return; + } if (cambio.in === cambio.out) { this.$waveui.notify(`Numero IN e OUT uguali per ${cambio.team}`, "warning"); return; -- 2.49.1