refactor: rework highlight mode, colorful, flipped and blind to pure css (#5568)

This commit is contained in:
Jack 2024-07-09 17:34:15 +02:00 committed by GitHub
parent 087bf55d4c
commit 9f924f345e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 371 additions and 313 deletions

View file

@ -1,27 +1,3 @@
@mixin highlightMode($color) {
&.highlight-next-word {
.word.active,
.word.active + .word {
color: $color;
}
}
&.highlight-next-two-words {
.word.active,
.word.active + .word,
.word.active + .word + .word {
color: $color;
}
}
&.highlight-next-three-words {
.word.active,
.word.active + .word,
.word.active + .word + .word,
.word.active + .word + .word + .word {
color: $color;
}
}
}
.highlightContainer {
position: absolute;
overflow: hidden;
@ -209,22 +185,84 @@
width: inherit;
}
letter {
border-bottom-style: solid;
border-bottom-width: 0.05em;
border-bottom-color: transparent;
&.dead {
--correct-letter-color: var(--text-color);
--correct-letter-animation: none;
--untyped-letter-color: var(--sub-color);
--untyped-letter-animation: none;
--incorrect-letter-color: var(--error-color);
--incorrect-letter-animation: none;
--extra-letter-color: var(--error-extra-color);
--extra-letter-animation: none;
.word {
letter {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
border-bottom-style: solid;
border-bottom-width: 0.05em;
border-bottom-color: var(--sub-color);
}
&.tabChar,
&.nlChar {
margin: 0 0.25rem;
opacity: 0.2;
i {
line-height: 0;
border-bottom-color: transparent;
&.dead {
border-bottom-width: 0.05em;
border-bottom-color: var(--untyped-letter-color);
}
&.tabChar,
&.nlChar {
margin: 0 0.25rem;
opacity: 0.2;
i {
line-height: 0;
}
}
&.correct {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
&.corrected {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
border-bottom: 2px dotted var(--main-color);
}
&.extraCorrected {
border-right: 2px dotted var(--main-color);
}
&.incorrect {
color: var(--incorrect-letter-color);
animation: var(--incorrect-letter-animation);
}
&.incorrect.extra {
color: var(--extra-letter-color);
animation: var(--extra-letter-animation);
}
&.missing {
opacity: 0.5;
}
}
& .hints hint {
position: absolute;
bottom: -1.1em;
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
line-height: initial;
font-size: 0.75em;
text-shadow: none;
padding: 1px;
left: 0;
opacity: 0.5;
text-align: center;
display: grid;
justify-content: center;
transform: translate(-50%);
}
}
&.tape .word {
margin: 0.25em 0.5em 0.75em 0;
}
/* a little hack for right-to-left languages */
@ -247,100 +285,141 @@
-webkit-filter: blur(4px);
}
&.flipped {
&.blind {
.word {
color: var(--text-color);
& letter.dead {
border-bottom-color: var(--sub-color) !important;
& letter.extra {
display: none;
}
& letter.correct {
color: var(--sub-color);
}
& letter.corrected {
color: var(--sub-color);
border-bottom: 2px dotted var(--main-color);
}
& letter.extraCorrected {
border-right: 2px dotted var(--main-color);
& letter.incorrect {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
}
}
@include highlightMode(var(--sub-color));
&.flipped {
--correct-letter-color: var(--sub-color);
--untyped-letter-color: var(--text-color);
--incorrect-letter-color: var(--error-color);
--extra-letter-color: var(--error-extra-color);
}
&.colorfulMode {
.word {
& letter.dead {
border-bottom-color: var(--main-color) !important;
}
& letter.correct {
color: var(--main-color);
}
& letter.corrected {
color: var(--main-color);
border-bottom: 2px dotted var(--text-color);
}
& letter.extraCorrected {
border-right: 2px dotted var(--text-color);
}
& letter.incorrect {
color: var(--colorful-error-color);
}
& letter.incorrect.extra {
color: var(--colorful-error-extra-color);
}
}
@include highlightMode(var(--main-color));
--correct-letter-color: var(--main-color);
--untyped-letter-color: var(--sub-color);
--incorrect-letter-color: var(--colorful-error-color);
--extra-letter-color: var(--colorful-error-extra-color);
}
&.flipped.colorfulMode {
--correct-letter-color: var(--sub-color);
--untyped-letter-color: var(--main-color);
--incorrect-letter-color: var(--colorful-error-color);
--extra-letter-color: var(--colorful-error-extra-color);
}
&.highlight-off {
.word {
color: var(--main-color);
& letter.dead {
border-bottom-color: var(--sub-color) !important;
}
& letter.correct {
color: var(--sub-color);
}
& letter.corrected {
color: var(--sub-color);
border-bottom: 2px dotted var(--main-color);
}
& letter.extraCorrected {
border-right: 2px dotted var(--main-color);
}
& letter.incorrect {
color: var(--colorful-error-color);
}
& letter.incorrect.extra {
color: var(--colorful-error-extra-color);
letter.correct {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
}
}
@include highlightMode(var(--sub-color));
}
&.tape .word {
margin: 0.25em 0.5em 0.75em 0;
&.highlight-word {
.word.typed {
letter {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
}
}
.word.active {
letter {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
}
.word.typed.error,
.word.active:has(letter.incorrect) {
letter {
color: var(--incorrect-letter-color);
animation: var(--incorrect-letter-animation);
}
}
}
@include highlightMode(var(--text-color));
&.highlight-next-word {
.word.typed {
letter {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
}
}
.word.active,
.word.active + .word {
letter {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
}
.word.typed.error,
.word.active:has(letter.incorrect) {
letter {
color: var(--incorrect-letter-color);
animation: var(--incorrect-letter-animation);
}
}
}
&.highlight-next-two-words {
.word.typed {
letter {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
}
}
.word.active,
.word.active + .word,
.word.active + .word + .word {
letter {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
}
.word.typed.error,
.word.active:has(letter.incorrect) {
letter {
color: var(--incorrect-letter-color);
animation: var(--incorrect-letter-animation);
}
}
}
&.highlight-next-three-words {
.word.typed {
letter {
color: var(--untyped-letter-color);
animation: var(--untyped-letter-animation);
}
}
.word.active,
.word.active + .word,
.word.active + .word + .word,
.word.active + .word + .word + .word {
letter {
color: var(--correct-letter-color);
animation: var(--correct-letter-animation);
}
}
.word.typed.error,
.word.active:has(letter.incorrect) {
letter {
color: var(--incorrect-letter-color);
animation: var(--incorrect-letter-animation);
}
}
}
}
.word {
@ -348,7 +427,6 @@
font-size: 1em;
line-height: 1em;
margin: 0.25em;
color: var(--sub-color);
font-variant: no-common-ligatures;
border-bottom: 2px solid transparent;
letter {
@ -416,53 +494,6 @@
text-shadow: none;
}
}
// .word letter {
// transition: .1s;
// height: 1rem;
// line-height: 1rem;
/* margin: 0 1px; */
// }
.word letter.correct {
color: var(--text-color);
}
.word letter.corrected {
color: var(--text-color);
border-bottom: 2px dotted var(--main-color);
}
.word letter.extraCorrected {
border-right: 2px dotted var(--main-color);
}
.word letter.incorrect {
color: var(--error-color);
}
.word .hints hint {
position: absolute;
bottom: -1.1em;
color: var(--text-color);
line-height: initial;
font-size: 0.75em;
text-shadow: none;
padding: 1px;
left: 0;
opacity: 0.5;
text-align: center;
display: grid;
justify-content: center;
transform: translate(-50%);
}
.word letter.incorrect.extra {
color: var(--error-extra-color);
}
.word letter.missing {
opacity: 0.5;
}
#words.flipped.colorfulMode .word.error,
#words.colorfulMode .word.error {
@ -626,13 +657,20 @@
.word {
position: relative;
margin: 0.18rem 0.6rem 0.15rem 0;
letter.correct {
& letter.corrected {
color: var(--text-color);
border-bottom: 2px dotted var(--main-color);
}
& letter.extraCorrected {
border-right: 2px dotted var(--main-color);
}
& letter.correct {
color: var(--text-color);
}
letter.incorrect {
& letter.incorrect {
color: var(--error-color);
}
letter.incorrect.extra {
& letter.incorrect.extra {
color: var(--error-extra-color);
}
&.heatmapInherit letter {

View file

@ -261,7 +261,7 @@ async function handleSpace(): Promise<void> {
if (Config.stopOnError === "word") {
dontInsertSpace = false;
Replay.addReplayEvent("incorrectLetter", "_");
void TestUI.updateWordElement(true);
void TestUI.updateWordElement();
void Caret.updatePosition();
}
return;
@ -661,7 +661,7 @@ function handleChar(
!thisCharCorrect
) {
if (!Config.blindMode) {
void TestUI.updateWordElement(undefined, TestInput.input.current + char);
void TestUI.updateWordElement(TestInput.input.current + char);
}
return;
}

View file

@ -178,7 +178,6 @@ ConfigEvent.subscribe((eventKey, eventValue, nosave) => {
if (typeof eventValue !== "boolean") return;
if (eventKey === "flipTestColors") flipColors(eventValue);
if (eventKey === "colorfulMode") colorful(eventValue);
if (eventKey === "highlightMode") void updateWordElement(eventValue);
if (eventKey === "burstHeatmap") void applyBurstHeatmap();
});
@ -238,19 +237,12 @@ export function updateActiveElement(
initial = false
): void {
const active = document.querySelector("#words .active");
if (!backspace) {
active?.classList.add("typed");
}
if (Config.mode === "zen" && backspace) {
active?.remove();
} else if (active !== null) {
if (
["word", "next_word", "next_two_words", "next_three_words"].includes(
Config.highlightMode
) &&
Config.theme !== "shadow"
) {
active.querySelectorAll("letter").forEach((e) => {
e.classList.remove("correct");
});
}
active.classList.remove("active");
}
const activeWord =
@ -262,13 +254,11 @@ export function updateActiveElement(
activeWord.classList.add("active");
activeWord.classList.remove("error");
activeWord.classList.remove("typed");
activeWordTop = (document.querySelector("#words .active") as HTMLElement)
.offsetTop;
if (Config.highlightMode === "word") {
activeWord.querySelectorAll("letter").forEach((e) => {
e.classList.add("correct");
});
}
if (!initial && shouldUpdateWordsInputPosition()) {
void updateWordsInputPosition();
}
@ -757,10 +747,7 @@ export async function screenshot(): Promise<void> {
}, 3000);
}
export async function updateWordElement(
showError = !Config.blindMode,
inputOverride?: string
): Promise<void> {
export async function updateWordElement(inputOverride?: string): Promise<void> {
const input = inputOverride ?? TestInput.input.current;
const wordAtIndex = document.querySelector(
"#words .word.active"
@ -821,26 +808,13 @@ export async function updateWordElement(
}
}
let wordHighlightClassString = correctSoFar ? "correct" : "incorrect";
if (Config.blindMode) {
wordHighlightClassString = "correct";
}
const funbox = FunboxList.get(Config.funbox).find(
(f) => f.functions?.getWordHtml
);
const isTts = FunboxList.get(Config.funbox).find((it) => it.name === "tts");
for (let i = 0; i < input.length; i++) {
const charCorrect = currentWord[i] === input[i];
let correctClass = "correct";
if (Config.highlightMode === "off") {
correctClass = "";
if (isTts) correctClass = "visible";
}
let currentLetter = currentWord[i] as string;
let tabChar = "";
let nlChar = "";
@ -858,53 +832,31 @@ export async function updateWordElement(
}
if (charCorrect) {
ret += `<letter class="${
Config.highlightMode === "word"
? wordHighlightClassString
: correctClass
} ${tabChar}${nlChar}">${currentLetter}</letter>`;
ret += `<letter class="correct ${tabChar}${nlChar}">${currentLetter}</letter>`;
} else if (
currentLetter !== undefined &&
CompositionState.getComposing() &&
i >= CompositionState.getStartPos() &&
!(containsKorean && !correctSoFar)
) {
ret += `<letter class="${
Config.highlightMode === "word" ? wordHighlightClassString : ""
} dead">${
ret += `<letter class="dead">${
Config.indicateTypos === "replace"
? input[i] === " "
? "_"
: input[i]
: currentLetter
}</letter>`;
} else if (!showError) {
if (currentLetter !== undefined) {
ret += `<letter class="${
Config.highlightMode === "word"
? wordHighlightClassString
: correctClass
} ${tabChar}${nlChar}">${currentLetter}</letter>`;
}
} else if (currentLetter === undefined) {
if (!Config.hideExtraLetters) {
let letter = input[i];
if (letter === " " || letter === "\t" || letter === "\n") {
letter = "_";
}
ret += `<letter class="${
Config.highlightMode === "word"
? wordHighlightClassString
: "incorrect"
} extra ${tabChar}${nlChar}">${letter}</letter>`;
ret += `<letter class="incorrect extra ${tabChar}${nlChar}">${letter}</letter>`;
}
} else {
ret +=
`<letter class="${
Config.highlightMode === "word"
? wordHighlightClassString
: "incorrect"
} ${tabChar}${nlChar}">` +
`<letter class="incorrect ${tabChar}${nlChar}">` +
(Config.indicateTypos === "replace"
? input[i] === " "
? "_"
@ -930,12 +882,7 @@ export async function updateWordElement(
} else if (currentWord[i] === "\n") {
ret += `<letter class='nlChar'><i class="fas fa-level-down-alt fa-rotate-90 fa-fw"></i></letter>`;
} else {
ret +=
`<letter class="${
Config.highlightMode === "word" ? wordHighlightClassString : ""
}">` +
currentWord[i] +
"</letter>";
ret += `<letter>` + currentWord[i] + "</letter>";
}
}

View file

@ -1,19 +1,3 @@
/* #words {
opacity: 0 !important;
} */
#words .word {
color: transparent !important;
}
#words .word letter.visible {
color: var(--sub-color) !important;
}
#words.flipped .word letter.visible {
color: var(--text-color) !important;
}
#words.flipped.colorfulMode .word letter.visible {
color: var(--main-color) !important;
#words {
--untyped-letter-color: transparent !important;
}

View file

@ -65,15 +65,33 @@ header .config .group .buttons .textButton.active,
#result .stats .group .bottom,
nav .textButton:hover,
header .config .group .buttons .textButton:hover,
a:hover,
#words.flipped .word {
a:hover {
animation: aurora 5s linear infinite;
}
#words.flipped .word letter.correct {
color: var(--sub-color);
#words {
--correct-letter-animation: aurora 5s linear infinite;
}
#words:not(.flipped) .word letter.correct {
#words.flipped {
--untyped-letter-color: var(--sub-color);
--correct-letter-animation: none;
--untyped-letter-animation: aurora 5s linear infinite;
}
#words .word.typed letter.correct,
#words.highlight-word .word.typed letter,
#words.highlight-next-word .word.typed letter,
#words.highlight-next-two-words .word.typed letter,
#words.highlight-next-three-words .word.typed letter {
animation: aurora 5s linear infinite;
}
#words.flipped .word.typed letter {
animation: none;
}
#words.highlight-off .word letter,
#words.highlight-off .word.typed letter {
animation: aurora 5s linear infinite;
}

View file

@ -65,15 +65,33 @@ header .config .group .buttons .textButton.active,
#result .stats .group .bottom,
nav .textButton:hover,
header .config .group .buttons .textButton:hover,
a:hover,
#words.flipped .word {
a:hover {
animation: fire 5s linear infinite;
}
#words.flipped .word letter.correct {
color: var(--sub-color);
#words {
--correct-letter-animation: fire 5s linear infinite;
}
#words:not(.flipped) .word letter.correct {
#words.flipped {
--untyped-letter-color: var(--sub-color);
--correct-letter-animation: none;
--untyped-letter-animation: fire 5s linear infinite;
}
#words .word.typed letter.correct,
#words.highlight-word .word.typed letter,
#words.highlight-next-word .word.typed letter,
#words.highlight-next-two-words .word.typed letter,
#words.highlight-next-three-words .word.typed letter {
animation: fire 5s linear infinite;
}
#words.flipped .word.typed letter {
animation: none;
}
#words.highlight-off .word letter,
#words.highlight-off .word.typed letter {
animation: fire 5s linear infinite;
}

View file

@ -65,15 +65,33 @@ header .config .group .buttons .textButton.active,
#result .stats .group .bottom,
nav .textButton:hover,
header .config .group .buttons .textButton:hover,
a:hover,
#words.flipped .word {
a:hover {
animation: pastel 5s linear infinite;
}
#words.flipped .word letter.correct {
color: var(--sub-color);
#words {
--correct-letter-animation: pastel 5s linear infinite;
}
#words:not(.flipped) .word letter.correct {
#words.flipped {
--untyped-letter-color: var(--sub-color);
--correct-letter-animation: none;
--untyped-letter-animation: pastel 5s linear infinite;
}
#words .word.typed letter.correct,
#words.highlight-word .word.typed letter,
#words.highlight-next-word .word.typed letter,
#words.highlight-next-two-words .word.typed letter,
#words.highlight-next-three-words .word.typed letter {
animation: pastel 5s linear infinite;
}
#words.flipped .word.typed letter {
animation: none;
}
#words.highlight-off .word letter,
#words.highlight-off .word.typed letter {
animation: pastel 5s linear infinite;
}

View file

@ -73,6 +73,56 @@ header #logo .top,
-webkit-text-fill-color: initial;
}
#liveStatsTextTop.timerMain,
#liveStatsTextBottom.timerMain,
#liveStatsMini.timerMain {
animation: rainbow-infinite-loop 30s linear infinite;
}
#words {
--correct-letter-animation: rainbow-infinite-loop 5s linear infinite;
--incorrect-letter-animation: error-repeat 1s alternate ease-in-out infinite;
--extra-letter-animation: error-repeat 1s alternate ease-in-out infinite;
}
#words .word.typed letter.correct,
#words.highlight-word .word.typed letter,
#words.highlight-next-word .word.typed letter,
#words.highlight-next-two-words .word.typed letter,
#words.highlight-next-three-words .word.typed letter {
animation: rainbow 7.5s ease-in-out forwards;
}
#words.highlight-word .word.active letter {
animation: var(--correct-letter-animation);
}
#words.flipped {
--correct-letter-animation: none;
--untyped-letter-animation: rainbow-infinite-loop 5s linear infinite;
}
#words.flipped .word.typed letter {
animation: none;
}
.button:hover {
animation: glowing-button 2s alternate ease-in-out infinite;
}
#words.highlight-off .word letter,
#words.highlight-off .word.typed letter {
animation: rainbow-infinite-loop 5s linear infinite;
}
.row .textButton:not(.active) {
color: #999999;
}
.textButton.active {
color: #111111;
}
@keyframes rainbow {
0% {
color: #60b6ce;
@ -169,40 +219,6 @@ header #logo .top,
}
}
#words.flipped .word {
animation: rainbow-infinite-loop 30s linear infinite;
}
#words.flipped .word letter.correct {
color: var(--sub-color);
}
#words:not(.flipped) .word letter.correct {
animation: rainbow 7.5s ease-in-out forwards;
}
#liveStatsTextTop.timerMain,
#liveStatsTextBottom.timerMain,
#liveStatsMini.timerMain {
animation: rainbow-infinite-loop 30s linear infinite;
}
.word letter.incorrect {
animation: error-repeat 1s alternate ease-in-out infinite;
}
.button:hover {
animation: glowing-button 2s alternate ease-in-out infinite;
}
.row .textButton:not(.active) {
color: #999999;
}
.textButton.active {
color: #111111;
}
@keyframes light-rainbow-infinite-loop {
0% {
color: #60b6ce;

View file

@ -100,17 +100,13 @@ a:hover,
animation: rgb 5s linear infinite;
}
/* .word letter.correct{
animation: rgb 5s linear infinite;
} */
#words.flipped .word letter.correct {
color: var(--sub-color);
#words {
--correct-letter-animation: rgb 5s linear infinite;
}
#words:not(.flipped) .word letter.correct {
animation: rgb 5s linear infinite;
#words.flipped {
--correct-letter-animation: none;
--untyped-letter-animation: rgb 5s linear infinite;
}
header #logo path {

View file

@ -48,6 +48,11 @@ a:hover {
}
#logo,
#typingTest .word letter.correct {
#typingTest .word letter.correct,
#typingTest #words.highlight-word .word.typed letter.correct,
#typingTest #words.highlight-next-word .word.typed letter.correct,
#typingTest #words.highlight-next-two-words .word.typed letter.correct,
#typingTest #words.highlight-next-three-words .word.typed letter.correct {
color: var(--correct-letter-color);
animation: shadow 5s linear 1 forwards;
}

View file

@ -53,15 +53,33 @@ header .config .group .buttons .textButton.active,
#result .stats .group .bottom,
nav .textButton:hover,
header .config .group .buttons .textButton:hover,
a:hover,
#words.flipped .word {
a:hover {
animation: trance 5s linear infinite;
}
#words.flipped .word letter.correct {
color: var(--sub-color);
#words {
--correct-letter-animation: trance 5s linear infinite;
}
#words:not(.flipped) .word letter.correct {
#words.flipped {
--untyped-letter-color: var(--sub-color);
--correct-letter-animation: none;
--untyped-letter-animation: trance 5s linear infinite;
}
#words .word.typed letter.correct,
#words.highlight-word .word.typed letter,
#words.highlight-next-word .word.typed letter,
#words.highlight-next-two-words .word.typed letter,
#words.highlight-next-three-words .word.typed letter {
animation: trance 5s linear infinite;
}
#words.flipped .word.typed letter {
animation: none;
}
#words.highlight-off .word letter,
#words.highlight-off .word.typed letter {
animation: trance 5s linear infinite;
}