From da4a87eb8603c8fa34442b5b43f8e20010681c27 Mon Sep 17 00:00:00 2001
From: Leon Mika <lmika@lmika.org>
Date: Fri, 14 Mar 2025 22:00:13 +1100
Subject: [PATCH] Added animation revealing the word colors

---
 site/assets/scripts/controllers/playfield.js | 65 ++++++++++++++------
 site/assets/scripts/models/gamecontroller.js | 14 -----
 site/assets/styles/main.css                  | 15 +++++
 3 files changed, 60 insertions(+), 34 deletions(-)

diff --git a/site/assets/scripts/controllers/playfield.js b/site/assets/scripts/controllers/playfield.js
index 20e478a..18cb0e2 100644
--- a/site/assets/scripts/controllers/playfield.js
+++ b/site/assets/scripts/controllers/playfield.js
@@ -71,7 +71,7 @@ export default class extends Controller {
     }
   }
 
-  _verifyGuess(rowElem) {
+  async _verifyGuess(rowElem) {
     let guessedWord = Array.from(rowElem.querySelectorAll("span")).map((x) => x.innerText).join("");
     console.log("The guessed word is: " + guessedWord);
 
@@ -91,7 +91,8 @@ export default class extends Controller {
       }));
       break;
     case GUESS_RESULT.MISS:
-      this._colorizeRow(rowElem, results);
+      await this._colorizeRow(rowElem, results, true);
+      this._broadcastGuessResults(results);
 
       this._activeRowIndex += 1;
       if (this._activeRowIndex >= this._gameController.guesses()) {
@@ -103,7 +104,8 @@ export default class extends Controller {
 
       break;
     case GUESS_RESULT.WIN:
-      this._colorizeRow(rowElem, results);
+      await this._colorizeRow(rowElem, results, true);
+      this._broadcastGuessResults(results);
       this._showWin();
       break;
     }
@@ -139,6 +141,7 @@ export default class extends Controller {
     window.dispatchEvent(new CustomEvent("resetKeyColors"));
 
     let newRows = [];
+    let lastGuessResults = null;
     for (let r = 0; r < rows; r++) {
       let currentGuess = null;
       let currentGuessResults = null;
@@ -150,12 +153,14 @@ export default class extends Controller {
 
       newRows.push(this._buildPlayfieldRow(wordLength, currentGuess, currentGuessResults));
       if (currentGuessResults) {
-        window.dispatchEvent(new CustomEvent("guessResults", {
-          detail: currentGuessResults
-        }));
+        lastGuessResults = currentGuessResults;
       }
     }
 
+    if (lastGuessResults != null) {
+      this._broadcastGuessResults(lastGuessResults);
+    }
+
     if (wasWin) {
       this._showWin();
     } else if (currentGuesses.length >= rows) {
@@ -185,34 +190,54 @@ export default class extends Controller {
     }
 
     if (currentGuess) {
-      this._colorizeRow(divElem, currentGuessResults);
+      this._colorizeRow(divElem, currentGuessResults, false);
     }
 
     return divElem;
   }
 
-  _colorizeRow(row, results) {
+  async _colorizeRow(row, results, delayed) {
     let markers = results.markers;
 
-    for (let i = 0; i < this._gameController.wordLength(); i++) {
-      switch (markers[i]) {
-      case MARKERS.RIGHT_POS:
-        row.children[i].classList.add("right-pos");
-        break;
-      case MARKERS.RIGHT_CHAR:
-        row.children[i].classList.add("right-char");
-        break;
-      case MARKERS.MISS:
-        row.children[i].classList.add("miss");
-        break;
-      }
+    if (delayed) {
+      row.classList.add("animated-colors");
     }
 
+    for (let i = 0; i < this._gameController.wordLength(); i++) {
+      this._colorizeCell(row, results, i);
+    }
+
+    if (delayed) {
+      return new Promise(resolve => {
+        row.children[row.children.length - 1].addEventListener("transitionend", () => {
+          resolve();
+        });
+      });
+    }
+    return Promise.resolve();
+  }
+
+  _broadcastGuessResults(results) {
     window.dispatchEvent(new CustomEvent("guessResults", {
       detail: results
     }));
   }
 
+  _colorizeCell(row, results, cellIndex) {
+    let markers = results.markers;
+    switch (markers[cellIndex]) {
+    case MARKERS.RIGHT_POS:
+      row.children[cellIndex].classList.add("right-pos");
+      break;
+    case MARKERS.RIGHT_CHAR:
+      row.children[cellIndex].classList.add("right-char");
+      break;
+    case MARKERS.MISS:
+      row.children[cellIndex].classList.add("miss");
+      break;
+    }
+  }
+
   _showHints(row) {
     let hint = this._gameController.showHint();
 
diff --git a/site/assets/scripts/models/gamecontroller.js b/site/assets/scripts/models/gamecontroller.js
index 291dbc3..bea56af 100644
--- a/site/assets/scripts/models/gamecontroller.js
+++ b/site/assets/scripts/models/gamecontroller.js
@@ -149,20 +149,6 @@ export class GameController {
     let misses = {};
     let hits = {};
 
-    // if (this._currentWord.length <= 5) {
-    //   if (!this._wordSource.isWord(guess)) {
-    //     hits = {};
-    //     for (let i = 0; i < guess.length; i++) {
-    //       hits[guess[i]] = MARKERS.ATTEMPTED;
-    //     }
-    //
-    //     return {
-    //       hits: hits,
-    //       guessResult: GUESS_RESULT.FOUL,
-    //     };
-    //   }
-    // }
-    
     for (let i = 0; i < guess.length; i++) {
       if (guess[i] == this._currentWord[i]) {
         markers[i] = MARKERS.RIGHT_POS;
diff --git a/site/assets/styles/main.css b/site/assets/styles/main.css
index cbee3f8..ce77ab1 100644
--- a/site/assets/styles/main.css
+++ b/site/assets/styles/main.css
@@ -152,6 +152,21 @@ div.playfield div.row span {
     margin: 5px;
 }
 
+div.playfield div.row.animated-colors span {
+    transition-property: background-color, color;
+    transition-duration: 0.15s;
+}
+
+div.playfield div.row.animated-colors span:nth-child(1) { transition-delay: 0s; }
+div.playfield div.row.animated-colors span:nth-child(2) { transition-delay: 0.2s; }
+div.playfield div.row.animated-colors span:nth-child(3) { transition-delay: 0.4s; }
+div.playfield div.row.animated-colors span:nth-child(4) { transition-delay: 0.6s; }
+div.playfield div.row.animated-colors span:nth-child(5) { transition-delay: 0.8s; }
+div.playfield div.row.animated-colors span:nth-child(6) { transition-delay: 1.0s; }
+div.playfield div.row.animated-colors span:nth-child(7) { transition-delay: 1.2s; }
+div.playfield div.row.animated-colors span:nth-child(8) { transition-delay: 1.4s; }
+
+
 div.playfield div.row span.hint {
     color: var(--color-hint);
 }