diff --git a/frontend/src/html/pages/settings.html b/frontend/src/html/pages/settings.html
index 8abbd84c2..3640a70d7 100644
--- a/frontend/src/html/pages/settings.html
+++ b/frontend/src/html/pages/settings.html
@@ -568,6 +568,26 @@
on
+
diff --git a/frontend/src/ts/commandline/commandline-metadata.ts b/frontend/src/ts/commandline/commandline-metadata.ts
index 199658377..68ed146e4 100644
--- a/frontend/src/ts/commandline/commandline-metadata.ts
+++ b/frontend/src/ts/commandline/commandline-metadata.ts
@@ -323,6 +323,11 @@ export const commandlineConfigMetadata: CommandlineConfigMetadataObject = {
options: "fromSchema",
},
},
+ compositionDisplay: {
+ subgroup: {
+ options: "fromSchema",
+ },
+ },
hideExtraLetters: {
subgroup: {
options: "fromSchema",
diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts
index b303fbda4..dae0636b6 100644
--- a/frontend/src/ts/commandline/lists.ts
+++ b/frontend/src/ts/commandline/lists.ts
@@ -134,6 +134,7 @@ export const commands: CommandsSubgroup = {
confidenceModeCommand,
"quickEnd",
"indicateTypos",
+ "compositionDisplay",
"hideExtraLetters",
lazyModeCommand,
layoutCommand,
diff --git a/frontend/src/ts/config-metadata.ts b/frontend/src/ts/config-metadata.ts
index 1cd44f864..2dfa38ae0 100644
--- a/frontend/src/ts/config-metadata.ts
+++ b/frontend/src/ts/config-metadata.ts
@@ -365,6 +365,11 @@ export const configMetadata: ConfigMetadataObject = {
displayString: "indicate typos",
changeRequiresRestart: false,
},
+ compositionDisplay: {
+ icon: "fa-language",
+ displayString: "composition display",
+ changeRequiresRestart: false,
+ },
hideExtraLetters: {
icon: "fa-eye-slash",
displayString: "hide extra letters",
diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts
index 0fb967fb5..8c14cc3bb 100644
--- a/frontend/src/ts/constants/default-config.ts
+++ b/frontend/src/ts/constants/default-config.ts
@@ -42,6 +42,7 @@ const obj: Config = {
funbox: [],
confidenceMode: "off",
indicateTypos: "off",
+ compositionDisplay: "replace",
timerStyle: "mini",
liveSpeedStyle: "off",
liveAccStyle: "off",
diff --git a/frontend/src/ts/elements/composition-display.ts b/frontend/src/ts/elements/composition-display.ts
index 13b2a6b7d..987bfef7f 100644
--- a/frontend/src/ts/elements/composition-display.ts
+++ b/frontend/src/ts/elements/composition-display.ts
@@ -1,15 +1,7 @@
-import Config from "../config";
-
const compositionDisplay = document.getElementById(
"compositionDisplay",
) as HTMLElement;
-const languagesToShow = ["korean", "japanese", "chinese"];
-
-export function shouldShow(): boolean {
- return languagesToShow.some((lang) => Config.language.startsWith(lang));
-}
-
export function update(data: string): void {
compositionDisplay.innerText = data;
}
diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts
index 61368477b..7e18d3527 100644
--- a/frontend/src/ts/test/test-logic.ts
+++ b/frontend/src/ts/test/test-logic.ts
@@ -83,7 +83,6 @@ import * as Loader from "../elements/loader";
import * as TestInitFailed from "../elements/test-init-failed";
import { canQuickRestart } from "../utils/quick-restart";
import { animate } from "animejs";
-import * as CompositionDisplay from "../elements/composition-display";
import {
getInputElement,
isInputElementFocused,
@@ -329,13 +328,6 @@ export function restart(options = {} as RestartOptions): void {
getInputElement().style.left = "0";
setInputElementValue("");
- if (CompositionDisplay.shouldShow()) {
- CompositionDisplay.update(" ");
- CompositionDisplay.show();
- } else {
- CompositionDisplay.hide();
- }
-
Focus.set(false);
if (ActivePage.get() === "test") {
AdController.updateFooterAndVerticalAds(false);
@@ -381,8 +373,9 @@ export function restart(options = {} as RestartOptions): void {
if (isInputElementFocused()) OutOfFocus.hide();
TestUI.focusWords(true);
- const typingTestEl = document.querySelector("#typingTest") as HTMLElement;
+ TestUI.onTestRestart();
+ const typingTestEl = document.querySelector("#typingTest") as HTMLElement;
animate(typingTestEl, {
opacity: [0, 1],
onBegin: () => {
diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts
index f98ab36c3..0b3f727c8 100644
--- a/frontend/src/ts/test/test-ui.ts
+++ b/frontend/src/ts/test/test-ui.ts
@@ -49,6 +49,7 @@ import {
} from "../input/input-element";
import * as MonkeyPower from "../elements/monkey-power";
import * as SlowTimer from "../states/slow-timer";
+import * as CompositionDisplay from "../elements/composition-display";
const debouncedZipfCheck = debounce(250, async () => {
const supports = await JSONData.checkIfLanguageSupportsZipf(Config.language);
@@ -89,10 +90,9 @@ ConfigEvent.subscribe((eventKey, eventValue, nosave) => {
debouncedZipfCheck();
}
if (eventKey === "fontSize") {
- $("#caret, #paceCaret, #liveStatsMini, #typingTest, #wordsInput").css(
- "fontSize",
- (eventValue as number) + "rem",
- );
+ $(
+ "#caret, #paceCaret, #liveStatsMini, #typingTest, #wordsInput, #compositionDisplay",
+ ).css("fontSize", (eventValue as number) + "rem");
if (!nosave) {
OutOfFocus.hide();
updateWordWrapperClasses();
@@ -880,7 +880,7 @@ export async function updateWordLetters({
let charToShow =
currentWordChars[input.length + i] ?? compositionChar;
- if (Config.indicateTypos === "replace") {
+ if (Config.compositionDisplay === "replace") {
charToShow = compositionChar === " " ? "_" : compositionChar;
}
@@ -1919,6 +1919,15 @@ export function afterTestStart(): void {
TimerProgress.update();
}
+export function onTestRestart(): void {
+ if (Config.compositionDisplay === "below") {
+ CompositionDisplay.update(" ");
+ CompositionDisplay.show();
+ } else {
+ CompositionDisplay.hide();
+ }
+}
+
$(".pageTest #copyWordsListButton").on("click", async () => {
let words;
if (Config.mode === "zen") {
@@ -2043,4 +2052,12 @@ ConfigEvent.subscribe((key, value) => {
if (key === "showOutOfFocusWarning" && value === false) {
OutOfFocus.hide();
}
+ if (key === "compositionDisplay") {
+ if (value === "below") {
+ CompositionDisplay.update(" ");
+ CompositionDisplay.show();
+ } else {
+ CompositionDisplay.hide();
+ }
+ }
});
diff --git a/packages/schemas/src/configs.ts b/packages/schemas/src/configs.ts
index e7246854f..d8d1f54ab 100644
--- a/packages/schemas/src/configs.ts
+++ b/packages/schemas/src/configs.ts
@@ -54,6 +54,9 @@ export type ConfidenceMode = z.infer;
export const IndicateTyposSchema = z.enum(["off", "below", "replace", "both"]);
export type IndicateTypos = z.infer;
+export const CompositionDisplaySchema = z.enum(["off", "below", "replace"]);
+export type CompositionDisplay = z.infer;
+
export const TimerStyleSchema = z.enum([
"off",
"bar",
@@ -408,6 +411,7 @@ export const ConfigSchema = z
confidenceMode: ConfidenceModeSchema,
quickEnd: z.boolean(),
indicateTypos: IndicateTyposSchema,
+ compositionDisplay: CompositionDisplaySchema,
hideExtraLetters: z.boolean(),
lazyMode: z.boolean(),
layout: LayoutSchema,
@@ -544,6 +548,7 @@ export const ConfigGroupsLiteral = {
confidenceMode: "input",
quickEnd: "input",
indicateTypos: "input",
+ compositionDisplay: "input",
hideExtraLetters: "input",
lazyMode: "input",
layout: "input",