Skip to content

Commit 4c6e576

Browse files
authored
Merge pull request #12 from ger-benjamin/add-colors
Add colors
2 parents a260510 + f31c54d commit 4c6e576

File tree

10 files changed

+183
-29
lines changed

10 files changed

+183
-29
lines changed

package-lock.json

Lines changed: 81 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,9 @@
3030
"typescript": "^5.7.2",
3131
"typescript-eslint": "^8.18.0",
3232
"vitest": "^2.1.8"
33+
},
34+
"dependencies": {
35+
"chalk": "^5.4.1",
36+
"node-emoji": "^2.2.0"
3337
}
3438
}

src/enums.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,13 @@ export enum GameMode {
3737
export const validPositiveAnswers = ["yes", "y", "1", "true", "t"];
3838
/** Valid negative answers to yes or no questions. */
3939
export const validNegativeAnswers = ["no", "n", "0", "false", "f"];
40+
41+
/**
42+
* Available (background) colors for texts.
43+
*/
44+
export enum Colors {
45+
Red = "Red",
46+
Blue = "Blue",
47+
Green = "Green",
48+
White = "White",
49+
}

src/game-state.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import type { Item, Side, SourceJson } from "./source-json.js";
22
import type { Answer } from "./game-state-types.js";
33
import { EventValue } from "./event.js";
4-
import { GameMode } from "./enums.js";
54
import {
5+
Colors,
66
CorrectionStrategies,
7+
GameMode,
78
GameStateScene,
89
HintStrategies,
910
SelectionStrategies,
@@ -22,6 +23,7 @@ class GameState {
2223
private answers: Answer[] = [];
2324
private sourcePath: URL | null = null;
2425
private sourceJson: SourceJson | null = null;
26+
private cardColor: Colors = Colors.Blue;
2527
private gameMode: GameMode | null = null;
2628
private cardsLimit: number | null = null;
2729
private time: number | null = null;
@@ -55,6 +57,14 @@ class GameState {
5557
this.activeScene.setValue(value);
5658
}
5759

60+
getCardColor(): Colors {
61+
return this.cardColor;
62+
}
63+
64+
setCardColor(color: Colors) {
65+
this.cardColor = color;
66+
}
67+
5868
getGameMode(): GameMode | null {
5969
return this.gameMode;
6070
}

src/scenes/card.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import { CorrectionStrategy } from "../correction-strategy.js";
77
import { drawCard } from "./draw-card.js";
88
import { getCardWidth } from "./card-utils.js";
99
import { SelectionStrategy } from "../selection-strategy.js";
10-
import { GameStateScene } from "../enums.js";
10+
import { Colors, GameStateScene } from "../enums.js";
11+
import { colorize } from "./colorize-card.js";
12+
import { emojify } from "node-emoji";
1113

1214
/**
1315
* A UI for cards questions.
@@ -68,7 +70,7 @@ export class CardScene extends Scene {
6870
const question = getOneSideText(gs.getSideA(item));
6971
const hintText = hint ? `(${this.hintStrategy.getHint(item)})` : "";
7072
const card = drawCard([question, hintText], getCardWidth(this.tWidth));
71-
this.setContent("card", card);
73+
this.setContent("card", colorize(card));
7274
}
7375

7476
/**
@@ -121,12 +123,12 @@ export class CardScene extends Scene {
121123
const isCorrect = this.correctionStrategy.isCorrect(this.item, answer);
122124
this.handleAnswer(displayedQuestion, answer, isCorrect);
123125
if (!isCorrect) {
124-
this.setContent("info", `WRONG !`);
126+
gs.setCardColor(Colors.Red);
125127
gs.setLivesRemaining((gs.getLivesRemaining() ?? 1) - 1);
128+
this.showQuestion(this.item, this.hint);
126129
this.checkEnd(this.item);
127130
return;
128131
}
129-
this.setContent("info", `Correct :-)`);
130132
this.nextQuestion();
131133
}
132134

@@ -162,6 +164,7 @@ export class CardScene extends Scene {
162164
* @private
163165
*/
164166
private nextQuestion() {
167+
gs.setCardColor(Colors.Blue);
165168
gs.setQuestionIndex(gs.getQuestionIndex() + 1);
166169
const item = this.selectItem();
167170
if (this.checkEnd(item)) {
@@ -190,6 +193,7 @@ export class CardScene extends Scene {
190193
}
191194
const cardLimit = gs.getCardsLimit();
192195
if (!item || !cardLimit || gs.getQuestionIndex() >= cardLimit) {
196+
gs.setCardColor(Colors.Blue);
193197
this.exit(GameStateScene.RESULTS);
194198
return true;
195199
}
@@ -229,6 +233,11 @@ export class CardScene extends Scene {
229233
this.updateBanner();
230234
}
231235

236+
/**
237+
* Generate and print a "game-settings" banner, to let the user know
238+
* the current settings and some game states.
239+
* @private
240+
*/
232241
private updateBanner() {
233242
const gameMode = gs.getGameMode();
234243
const selectionStrategy = gs.getSelectionStrategy();
@@ -241,19 +250,19 @@ export class CardScene extends Scene {
241250
const lives = gs.getLivesRemaining();
242251
const hints = gs.getHintRemaining();
243252
const time = gs.getTime();
244-
let questionCounter = `Q:${questionIndex + 1}`;
253+
let questionCounter = emojify(`:books::${questionIndex + 1}`);
245254
if (cardLimit !== Infinity) {
246255
questionCounter = `${questionCounter}/${cardLimit}`;
247256
}
248257
gameInfos.push(questionCounter);
249258
if (lives !== Infinity) {
250-
gameInfos.push(`L:${lives}`);
259+
gameInfos.push(emojify(`:heart: :${lives}`));
251260
}
252261
if (hints !== Infinity) {
253-
gameInfos.push(`H:${hints}`);
262+
gameInfos.push(emojify(`:bulb::${hints}`));
254263
}
255264
if (time !== Infinity) {
256-
gameInfos.push(`T:${time}`);
265+
gameInfos.push(emojify(`:hourglass_flowing_sand::${time}`));
257266
}
258267
this.setContent("mode", mode, true);
259268
this.setContent("game", gameInfos.join(" - "), false);

src/scenes/colorize-card.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import gs from "../game-state.js";
2+
import { Colors } from "../enums.js";
3+
import chalk from "chalk";
4+
5+
/**
6+
* Use Chalk to colorize the text with the given (background) color.
7+
* If no color is provided, take the CardColor in the game-state.
8+
* BrightParam is to use the "bright" color variation.
9+
* @returns The colorized text or the text as is.
10+
*/
11+
export const colorize = (
12+
text: string,
13+
colorParam?: Colors,
14+
brightParam?: boolean,
15+
): string => {
16+
const color = colorParam ?? gs.getCardColor();
17+
const bright = brightParam ?? gs.getQuestionIsFront() !== false;
18+
if (color === Colors.Blue) {
19+
if (bright) {
20+
return chalk.bgBlueBright.black(text);
21+
}
22+
return chalk.bgBlue(text);
23+
}
24+
if (color === Colors.Red) {
25+
if (bright) {
26+
return chalk.bgRedBright.black(text);
27+
}
28+
return chalk.bgRed(text);
29+
}
30+
if (color === Colors.Green) {
31+
if (bright) {
32+
return chalk.bgGreenBright.black(text);
33+
}
34+
return chalk.bgGreen(text);
35+
}
36+
if (bright) {
37+
return chalk.bgWhite.black(text);
38+
}
39+
return text;
40+
};

src/scenes/exit.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import gs from "../game-state.js";
33
import { drawCard } from "./draw-card.js";
44
import { getCardWidth } from "./card-utils.js";
55
import { GameStateScene } from "../enums.js";
6+
import { colorize } from "./colorize-card.js";
7+
import { emojify } from "node-emoji";
68

79
/**
810
* A nice exit screen to the user.
@@ -11,8 +13,8 @@ export class ExitScene extends Scene {
1113
constructor() {
1214
super();
1315
this.canWrite = false;
14-
const card = drawCard(["Bye o/"], getCardWidth(this.tWidth));
15-
this.content.set("all", card);
16+
const card = drawCard([emojify("Bye :wave:")], getCardWidth(this.tWidth));
17+
this.content.set("all", colorize(card, undefined, false));
1618
}
1719

1820
override start() {

src/scenes/results.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import { getSideTexts } from "../utils.js";
66
import { drawCard } from "./draw-card.js";
77
import { getCardWidth } from "./card-utils.js";
88
import {
9+
Colors,
910
GameStateScene,
1011
validNegativeAnswers,
1112
validPositiveAnswers,
1213
} from "../enums.js";
1314
import { fromAnyItemToItem } from "../json-to-source.js";
15+
import { colorize } from "./colorize-card.js";
1416

1517
/**
1618
* A UI for results.
@@ -159,7 +161,7 @@ Results:
159161
getCardWidth(this.tWidth),
160162
);
161163
this.setContent("head", "", false);
162-
this.setContent("title", card);
164+
this.setContent("title", colorize(card, undefined, false));
163165
return false;
164166
}
165167

@@ -172,7 +174,7 @@ Results:
172174
["Ok, the results are left unsaved."],
173175
getCardWidth(this.tWidth),
174176
);
175-
this.setContent("title", card);
177+
this.setContent("title", colorize(card, undefined, false));
176178
}
177179

178180
/**
@@ -206,7 +208,7 @@ Results:
206208
return;
207209
}
208210
const card = drawCard(["Results saved!"], getCardWidth(this.tWidth));
209-
this.setContent("title", card);
211+
this.setContent("title", colorize(card, Colors.Green, false));
210212
}
211213

212214
/**

0 commit comments

Comments
 (0)