From 8eeb359a0880b739dd446456e9c97531b733ec4c Mon Sep 17 00:00:00 2001 From: Christophe Date: Sun, 12 Apr 2026 20:09:44 +0200 Subject: [PATCH] =?UTF-8?q?Ajoute=20un=20r=C3=A9sum=C3=A9=20modal=20=C3=A0?= =?UTF-8?q?=20la=20fin=20du=20cube?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.js | 165 ++++++++++++++++++++++++++++++++++++++++++++++++----- cube.html | 54 ++++++++++++++++++ styles.css | 46 +++++++++++++++ 3 files changed, 252 insertions(+), 13 deletions(-) diff --git a/app.js b/app.js index da4a0ef..aff7da3 100644 --- a/app.js +++ b/app.js @@ -661,6 +661,22 @@ function initCubePage() { closeHelpButton: document.querySelector("#closeCubeHelpButton"), helpModal: document.querySelector("#cubeHelpModal"), helpStatus: document.querySelector("#cubeHelpStatus"), + resultModal: document.querySelector("#cubeResultModal"), + closeResultButton: document.querySelector("#closeCubeResultButton"), + resultModalTitle: document.querySelector("#cubeResultModalTitle"), + resultSummary: document.querySelector("#cubeResultSummary"), + resultWinner: document.querySelector("#cubeResultWinner"), + resultOutcome: document.querySelector("#cubeResultOutcome"), + resultWhiteName: document.querySelector("#cubeResultWhiteName"), + resultBlackName: document.querySelector("#cubeResultBlackName"), + resultWhiteTime: document.querySelector("#cubeResultWhiteTime"), + resultBlackTime: document.querySelector("#cubeResultBlackTime"), + resultWhiteDetail: document.querySelector("#cubeResultWhiteDetail"), + resultBlackDetail: document.querySelector("#cubeResultBlackDetail"), + resultWhiteClock: document.querySelector("#cubeResultWhiteClock"), + resultBlackClock: document.querySelector("#cubeResultBlackClock"), + resultActionButton: document.querySelector("#cubeResultActionButton"), + resultDismissButton: document.querySelector("#cubeResultDismissButton"), replayCubeButton: document.querySelector("#replayCubeButton"), resetButton: document.querySelector("#cubeResetButton"), }; @@ -669,9 +685,12 @@ function initCubePage() { black: createCubeHoldIntent(), }; let cubeHoldAnimationFrameId = null; + let resultModalKey = null; const openModal = () => toggleModal(refs.helpModal, true); const closeModal = () => toggleModal(refs.helpModal, false); + const openResultModal = () => toggleModal(refs.resultModal, true); + const closeResultModal = () => toggleModal(refs.resultModal, false); refs.openHelpButton?.addEventListener("click", openModal); refs.closeHelpButton?.addEventListener("click", closeModal); @@ -681,6 +700,14 @@ function initCubePage() { closeModal(); } }); + refs.closeResultButton?.addEventListener("click", closeResultModal); + refs.resultDismissButton?.addEventListener("click", closeResultModal); + refs.resultModal?.addEventListener("click", (event) => { + const target = event.target; + if (target instanceof HTMLElement && target.dataset.closeCubeResultModal === "true") { + closeResultModal(); + } + }); bindCubeButton("white", refs.whiteButton); bindCubeButton("black", refs.blackButton); @@ -697,27 +724,47 @@ function initCubePage() { } if (match.cube.times.white !== null && match.cube.times.black !== null) { - if (match.config.mode === "twice" && match.cube.times.white === match.cube.times.black) { - replayCubePhase(match); - dirty = true; - render(); - return; - } - - applyCubeOutcome(match); - dirty = true; - persistMatch(); - navigateTo("chrono.html"); + openResultModal(); } }); + refs.resultActionButton?.addEventListener("click", () => { + if (!match || match.result || match.phase !== "cube") { + closeResultModal(); + return; + } + + if (match.cube.times.white === null || match.cube.times.black === null) { + closeResultModal(); + return; + } + + if (match.config.mode === "twice" && match.cube.times.white === match.cube.times.black) { + closeResultModal(); + resultModalKey = null; + replayCubePhase(match); + dirty = true; + render(); + return; + } + + closeResultModal(); + applyCubeOutcome(match); + dirty = true; + persistMatch(); + navigateTo("chrono.html"); + }); + refs.replayCubeButton?.addEventListener("click", () => { + closeResultModal(); + resultModalKey = null; replayCubePhase(match); dirty = true; render(); }); refs.resetButton?.addEventListener("click", () => { + closeResultModal(); clearMatch(); replaceTo(SETUP_PAGE); }); @@ -975,6 +1022,97 @@ function initCubePage() { hint.textContent = "Maintenez la grande zone 2 secondes, puis relachez pour lancer votre chrono."; } + function getCubeResultState() { + if (!match || match.phase !== "cube") { + return null; + } + + const white = match.cube.times.white; + const black = match.cube.times.black; + if (white === null || black === null) { + return null; + } + + const whiteName = playerName(match, "white"); + const blackName = playerName(match, "black"); + + if (match.config.mode === "time") { + const preview = getTimeAdjustmentPreview(match, white, black); + if (!preview) { + return null; + } + + return { + key: `time:${match.blockNumber}:${match.cube.round}:${white}:${black}`, + title: "Résumé du cube", + winner: preview.winner ? playerName(match, preview.winner) : "Egalite", + outcome: + preview.blockType === "minus" ? "Bloc - a appliquer" : "Bloc + a appliquer", + summary: + "Validez ce résumé pour appliquer les impacts chrono puis revenir à la page chrono.", + actionLabel: "Appliquer et ouvrir la page chrono", + whiteName, + blackName, + whiteTime: `Temps cube ${formatStopwatch(white)}`, + blackTime: `Temps cube ${formatStopwatch(black)}`, + whiteDetail: `Impact chrono ${formatSignedStopwatch(preview.whiteDelta)}`, + blackDetail: `Impact chrono ${formatSignedStopwatch(preview.blackDelta)}`, + whiteClock: `Chrono apres ${formatSignedClock(preview.whiteAfter)}`, + blackClock: `Chrono apres ${formatSignedClock(preview.blackAfter)}`, + }; + } + + const winner = white < black ? "white" : black < white ? "black" : null; + const isTie = winner === null; + + return { + key: `twice:${match.blockNumber}:${match.cube.round}:${white}:${black}`, + title: isTie ? "Egalite parfaite" : "Résumé du cube", + winner: winner ? playerName(match, winner) : "Egalite parfaite", + outcome: isTie ? "Rejouer la phase cube" : `${playerName(match, winner)} ouvrira la partie suivante`, + summary: isTie + ? "Le règlement Twice impose de rejouer immédiatement la phase cube." + : "Validez ce résultat pour préparer la partie suivante.", + actionLabel: isTie ? "Rejouer la phase cube" : "Appliquer et ouvrir la page chrono", + whiteName, + blackName, + whiteTime: `Temps cube ${formatStopwatch(white)}`, + blackTime: `Temps cube ${formatStopwatch(black)}`, + whiteDetail: winner === "white" ? "Gagne la phase cube" : isTie ? "Egalite parfaite" : "Ne gagne pas la phase cube", + blackDetail: winner === "black" ? "Gagne la phase cube" : isTie ? "Egalite parfaite" : "Ne gagne pas la phase cube", + whiteClock: "Aucun impact chrono en mode Twice", + blackClock: "Aucun impact chrono en mode Twice", + }; + } + + function renderResultModal() { + const resultState = getCubeResultState(); + if (!resultState) { + closeResultModal(); + resultModalKey = null; + return; + } + + refs.resultModalTitle.textContent = resultState.title; + refs.resultSummary.textContent = resultState.summary; + refs.resultWinner.textContent = resultState.winner; + refs.resultOutcome.textContent = resultState.outcome; + refs.resultWhiteName.textContent = resultState.whiteName; + refs.resultBlackName.textContent = resultState.blackName; + refs.resultWhiteTime.textContent = resultState.whiteTime; + refs.resultBlackTime.textContent = resultState.blackTime; + refs.resultWhiteDetail.textContent = resultState.whiteDetail; + refs.resultBlackDetail.textContent = resultState.blackDetail; + refs.resultWhiteClock.textContent = resultState.whiteClock; + refs.resultBlackClock.textContent = resultState.blackClock; + refs.resultActionButton.textContent = resultState.actionLabel; + + if (resultState.key !== resultModalKey) { + resultModalKey = resultState.key; + openResultModal(); + } + } + function render() { const blockHeading = formatBlockHeading(match, match.blockNumber); const timePreview = @@ -1009,7 +1147,7 @@ function initCubePage() { refs.spineLabel.textContent = "Reglement"; refs.spineHeadline.textContent = "Rejouer la phase cube"; refs.spineText.textContent = "Le mode Twice impose de relancer immediatement la phase cube en cas d'egalite parfaite."; - refs.primaryButton.textContent = "Rejouer la phase cube"; + refs.primaryButton.textContent = "Voir le résumé du cube"; refs.helpStatus.textContent = refs.spineText.textContent; } else if (match.cube.times.white !== null && match.cube.times.black !== null) { if (timePreview) { @@ -1030,7 +1168,7 @@ function initCubePage() { refs.spineHeadline.textContent = "Ouvrir la page chrono"; refs.spineText.textContent = "Appliquer le resultat du cube pour preparer la partie suivante."; } - refs.primaryButton.textContent = "Appliquer et ouvrir la page chrono"; + refs.primaryButton.textContent = "Voir le résumé du cube"; refs.helpStatus.textContent = refs.spineText.textContent; } else if (match.cube.running) { refs.centerLabel.textContent = "Etat"; @@ -1060,6 +1198,7 @@ function initCubePage() { renderCubeZone("black"); renderCubeZone("white"); + renderResultModal(); refs.primaryButton.disabled = !match.result && !( diff --git a/cube.html b/cube.html index dd75c1c..89a600e 100644 --- a/cube.html +++ b/cube.html @@ -135,6 +135,60 @@ + + diff --git a/styles.css b/styles.css index 4f79b29..4dc4536 100644 --- a/styles.css +++ b/styles.css @@ -888,6 +888,47 @@ body[data-page="cube"] .zone-button.cube-hold-ready::after { margin-top: 1rem; } +.result-modal-card { + width: min(880px, 100%); +} + +.cube-result-overview { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.8rem; + margin-top: 1rem; +} + +.result-pill-card, +.cube-result-player-card { + display: grid; + gap: 0.35rem; + padding: 1rem; + border-radius: 22px; + border: 1px solid var(--panel-border); + background: var(--panel-alt); +} + +.result-pill-card span, +.cube-result-player-card span { + color: var(--muted); +} + +.result-pill-card strong { + font-size: clamp(1.3rem, 3vw, 2rem); +} + +.cube-result-player-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.8rem; + margin-top: 1rem; +} + +.cube-result-player-card strong { + font-size: clamp(1.15rem, 2.8vw, 1.8rem); +} + .rules-shell { position: relative; width: min(1220px, calc(100% - 2rem)); @@ -1219,6 +1260,11 @@ body[data-page="cube"] .zone-button.cube-hold-ready::after { display: grid; } + .cube-result-overview, + .cube-result-player-grid { + grid-template-columns: 1fr; + } + .phase-shell { gap: 0.55rem; padding: 0.55rem 0 0.55rem;