From 605d478e4d42dd2fd78c754553ae31435fd418d4 Mon Sep 17 00:00:00 2001
From: Lynn
Date: Wed, 12 Jan 2022 12:48:46 +0100
Subject: [PATCH 1/4] Don't put in
---
src/App.tsx | 134 +++++++++++++++++++++++++++-------------------------
1 file changed, 70 insertions(+), 64 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 028f4e5..ca867c1 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -5,9 +5,77 @@ import { useState } from "react";
import { Row, RowState } from "./Row";
import { Clue } from "./clue";
+const maxGuesses = 6;
+
+function About() {
+ return (
+
+
+ hello wordl is a remake of the word game{" "}
+
+ Wordle
+ {" "}
+ by powerlanguage, which
+ I think is based on the TV show Lingo.
+
+
+ You get {maxGuesses} tries to guess a target word.
+
+ After each guess, you get Mastermind-style feedback:
+
+
|
+
+ W and O aren't in the target word at all.
+
+ R is correct! The third letter is R
+ .
+ D occurs elsewhere in the target word.
+
+
+ Let's move the D in our next guess:
+
+
|
+
So close!
+
|
+
Got it!
+
+ Report issues{" "}
+ here, or tweet{" "}
+ @chordbug.
+
+
+ );
+}
+
function App() {
const [about, setAbout] = useState(false);
- const maxGuesses = 6;
return (
hello wordl
@@ -29,69 +97,7 @@ function App() {
{seed ? "Random" : "Today's"}
- {about && (
-
-
- hello wordl is a remake of the word game{" "}
-
- Wordle
-
- , which I think is based on the TV show Lingo.
-
-
- You get {maxGuesses} tries to guess a target word.
-
- After each guess, you get Mastermind-style feedback:
-
-
-
-
-
- W and O aren't in the target word at all.
-
- R is correct! The third letter is R
- .
- D occurs elsewhere in the target word.
-
-
- Let's move the D in our next guess:
-
- So close!
-
- Got it!
-
- Report issues{" "}
-
here, or
- tweet
@chordbug.
-
- )}
+ {about &&
}
);
From 4a084672371d69773289f3b143588e01e4390beb Mon Sep 17 00:00:00 2001
From: Lynn
Date: Wed, 12 Jan 2022 17:40:23 +0100
Subject: [PATCH 2/4] Some screen reader thingies
---
src/App.css | 9 +++++++++
src/Game.tsx | 21 +++++++++++++++------
src/Row.tsx | 12 +++++++++++-
3 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/src/App.css b/src/App.css
index 89fe02b..69bc7ba 100644
--- a/src/App.css
+++ b/src/App.css
@@ -170,3 +170,12 @@ a:active {
margin-top: 1em;
font-variant-numeric: tabular-nums;
}
+
+.Game-sr-feedback {
+ position: absolute;
+ left: -10000px;
+ top: auto;
+ width: 1px;
+ height: 1px;
+ overflow: hidden;
+}
diff --git a/src/Game.tsx b/src/Game.tsx
index 03f2044..3770520 100644
--- a/src/Game.tsx
+++ b/src/Game.tsx
@@ -17,8 +17,7 @@ interface GameProps {
hidden: boolean;
}
-const targets = targetList
- .slice(0, targetList.indexOf("murky") + 1); // Words no rarer than this one
+const targets = targetList.slice(0, targetList.indexOf("murky") + 1); // Words no rarer than this one
function randomTarget(wordLength: number) {
const eligible = targets.filter((word) => word.length === wordLength);
@@ -31,6 +30,7 @@ function Game(props: GameProps) {
const [currentGuess, setCurrentGuess] = useState("");
const [wordLength, setWordLength] = useState(5);
const [hint, setHint] = useState(`Make your first guess!`);
+ const [srStatus, setSrStatus] = useState(``);
const [target, setTarget] = useState(() => {
resetRng();
return randomTarget(wordLength);
@@ -81,6 +81,7 @@ function Game(props: GameProps) {
setGameState(GameState.Lost);
} else {
setHint("");
+ setSrStatus("Feedback goes here");
}
}
};
@@ -117,7 +118,13 @@ function Game(props: GameProps) {
);
@@ -146,7 +153,6 @@ function Game(props: GameProps) {
setTarget(randomTarget(length));
setWordLength(length);
setHint(`${length} letters`);
- (document.activeElement as HTMLElement)?.blur();
}}
>
*/}
{seed ? (
diff --git a/src/Keyboard.tsx b/src/Keyboard.tsx
index ceb1c24..3413d53 100644
--- a/src/Keyboard.tsx
+++ b/src/Keyboard.tsx
@@ -13,7 +13,7 @@ export function Keyboard(props: KeyboardProps) {
];
return (
-
+
{keyboard.map((row, i) => (
{row.map((label, j) => {
@@ -29,6 +29,7 @@ export function Keyboard(props: KeyboardProps) {
{
props.onKey(label);
diff --git a/src/Row.tsx b/src/Row.tsx
index 342c16d..6c9fa49 100644
--- a/src/Row.tsx
+++ b/src/Row.tsx
@@ -1,4 +1,4 @@
-import { Clue, clueClass, CluedLetter } from "./clue";
+import { Clue, clueClass, CluedLetter, clueWord } from "./clue";
export enum RowState {
LockedIn,
@@ -24,20 +24,22 @@ export function Row(props: RowProps) {
letterClass += " " + clueClass(clue);
}
return (
-
+
{letter}
-
+ |
);
});
let rowClass = "Row";
if (isLockedIn) rowClass += " Row-locked-in";
- return (
-
- {letterDivs}
-
- );
+ return
{letterDivs}
;
}
diff --git a/src/clue.ts b/src/clue.ts
index eeaa94e..c93940f 100644
--- a/src/clue.ts
+++ b/src/clue.ts
@@ -39,3 +39,19 @@ export function clueClass(clue: Clue): string {
return "letter-correct";
}
}
+
+export function clueWord(clue: Clue): string {
+ if (clue === Clue.Absent) {
+ return "no";
+ } else if (clue === Clue.Elsewhere) {
+ return "yellow";
+ } else {
+ return "correct";
+ }
+}
+
+export function describeClue(clue: CluedLetter[]): string {
+ return clue
+ .map(({ letter, clue }) => letter.toUpperCase() + " " + clueWord(clue!))
+ .join(", ");
+}
diff --git a/src/util.ts b/src/util.ts
index eab07fe..62dad2e 100644
--- a/src/util.ts
+++ b/src/util.ts
@@ -24,3 +24,24 @@ export function resetRng(): void {
export function pick
(array: Array): T {
return array[Math.floor(array.length * random())];
}
+
+// https://a11y-guidelines.orange.com/en/web/components-examples/make-a-screen-reader-talk/
+export function speak(
+ text: string,
+ priority: "polite" | "assertive" = "assertive"
+) {
+ var el = document.createElement("div");
+ var id = "speak-" + Date.now();
+ el.setAttribute("id", id);
+ el.setAttribute("aria-live", priority || "polite");
+ el.classList.add("sr-only");
+ document.body.appendChild(el);
+
+ window.setTimeout(function () {
+ document.getElementById(id)!.innerHTML = text;
+ }, 100);
+
+ window.setTimeout(function () {
+ document.body.removeChild(document.getElementById(id)!);
+ }, 1000);
+}
From a688c304274bc542e763ad09c4626d3672a562bc Mon Sep 17 00:00:00 2001
From: Lynn
Date: Fri, 14 Jan 2022 17:19:42 +0100
Subject: [PATCH 4/4] Cherry-pick the good stuff from input-per-letter
---
src/Game.tsx | 8 ++++++--
src/Row.tsx | 2 +-
src/clue.ts | 2 +-
src/targets.json | 1 -
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/Game.tsx b/src/Game.tsx
index eabdea2..af28dc4 100644
--- a/src/Game.tsx
+++ b/src/Game.tsx
@@ -73,7 +73,9 @@ function Game(props: GameProps) {
setGuesses((guesses) => guesses.concat([currentGuess]));
setCurrentGuess((guess) => "");
if (currentGuess === target) {
- setHint("You won! (Enter to play again)");
+ setHint(
+ `You won! The answer was ${target.toUpperCase()}. (Enter to play again)`
+ );
setGameState(GameState.Won);
} else if (guesses.length + 1 === props.maxGuesses) {
setHint(
@@ -170,7 +172,9 @@ function Game(props: GameProps) {
Give up
-
+
{hint || `\u00a0`}
{/*
{srStatus}
diff --git a/src/Row.tsx b/src/Row.tsx
index 6c9fa49..44e599d 100644
--- a/src/Row.tsx
+++ b/src/Row.tsx
@@ -27,7 +27,7 @@ export function Row(props: RowProps) {
|