Ajoute un résumé modal à la fin du cube
This commit is contained in:
165
app.js
165
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 &&
|
||||
!(
|
||||
|
||||
54
cube.html
54
cube.html
@@ -135,6 +135,60 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="modal hidden" id="cubeResultModal" aria-hidden="true">
|
||||
<div class="modal-backdrop" data-close-cube-result-modal="true"></div>
|
||||
<div class="modal-card result-modal-card">
|
||||
<div class="modal-head">
|
||||
<div>
|
||||
<p class="eyebrow">Fin de phase cube</p>
|
||||
<h2 id="cubeResultModalTitle">Résumé du cube</h2>
|
||||
</div>
|
||||
<button class="button ghost small" id="closeCubeResultButton" type="button">
|
||||
Fermer
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="section-copy" id="cubeResultSummary"></p>
|
||||
|
||||
<div class="cube-result-overview">
|
||||
<article class="result-pill-card">
|
||||
<span>Vainqueur cube</span>
|
||||
<strong id="cubeResultWinner">--</strong>
|
||||
</article>
|
||||
<article class="result-pill-card">
|
||||
<span>Suite</span>
|
||||
<strong id="cubeResultOutcome">--</strong>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="cube-result-player-grid">
|
||||
<article class="cube-result-player-card">
|
||||
<span class="seat-tag light-seat">Blanc</span>
|
||||
<strong id="cubeResultWhiteName">Blanc</strong>
|
||||
<span id="cubeResultWhiteTime">Temps cube --</span>
|
||||
<span id="cubeResultWhiteDetail">Résultat --</span>
|
||||
<span id="cubeResultWhiteClock">Chrono après --</span>
|
||||
</article>
|
||||
<article class="cube-result-player-card">
|
||||
<span class="seat-tag dark-seat">Noir</span>
|
||||
<strong id="cubeResultBlackName">Noir</strong>
|
||||
<span id="cubeResultBlackTime">Temps cube --</span>
|
||||
<span id="cubeResultBlackDetail">Résultat --</span>
|
||||
<span id="cubeResultBlackClock">Chrono après --</span>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="modal-actions">
|
||||
<button class="button primary" id="cubeResultActionButton" type="button">
|
||||
Appliquer et ouvrir la page chrono
|
||||
</button>
|
||||
<button class="button ghost" id="cubeResultDismissButton" type="button">
|
||||
Revenir à la phase cube
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script type="module" src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
46
styles.css
46
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;
|
||||
|
||||
Reference in New Issue
Block a user