diff --git a/frontend/__tests__/input/helpers/validation.spec.ts b/frontend/__tests__/input/helpers/validation.spec.ts index 51b28969eae6..9554f01c6168 100644 --- a/frontend/__tests__/input/helpers/validation.spec.ts +++ b/frontend/__tests__/input/helpers/validation.spec.ts @@ -14,10 +14,15 @@ vi.mock("../../../src/ts/test/funbox/list", () => ({ findSingleActiveFunboxWithFunction: vi.fn(), })); -vi.mock("../../../src/ts/utils/strings", () => ({ - areCharactersVisuallyEqual: vi.fn(), - isSpace: vi.fn(), -})); +vi.mock("../../../src/ts/utils/strings", async () => { + const actual = await vi.importActual( + "../../../src/ts/utils/strings" + ); + return { + ...actual, + areCharactersVisuallyEqual: vi.fn(), + }; +}); describe("isCharCorrect", () => { beforeEach(() => { @@ -34,7 +39,6 @@ describe("isCharCorrect", () => { null ); (Strings.areCharactersVisuallyEqual as any).mockReturnValue(false); - (Strings.isSpace as any).mockReturnValue(false); }); afterAll(() => { @@ -133,7 +137,6 @@ describe("isCharCorrect", () => { describe("shouldInsertSpaceCharacter", () => { beforeEach(() => { - (Strings.isSpace as any).mockReturnValue(true); replaceConfig({ mode: "time", stopOnError: "off", @@ -147,7 +150,6 @@ describe("shouldInsertSpaceCharacter", () => { }); it("returns null if data is not a space", () => { - (Strings.isSpace as any).mockReturnValue(false); expect( shouldInsertSpaceCharacter({ data: "a", diff --git a/frontend/__tests__/utils/strings.spec.ts b/frontend/__tests__/utils/strings.spec.ts index 3122c746e0bd..ce49da897fd3 100644 --- a/frontend/__tests__/utils/strings.spec.ts +++ b/frontend/__tests__/utils/strings.spec.ts @@ -474,14 +474,14 @@ describe("string utils", () => { ["\u2003", 0x2003, "em space", true], ["\u2009", 0x2009, "thin space", true], [" ", 0x3000, "ideographic space", true], + ["\u00A0", 0x00a0, "non-breaking space", true], + ["\u2007", 0x2007, "figure space", true], + ["\u2008", 0x2008, "punctuation space", true], + ["\u200A", 0x200a, "hair space", true], + ["​", 0x200b, "zero-width space", true], // Should return false for other characters ["\t", 0x0009, "tab", false], - ["\u00A0", 0x00a0, "non-breaking space", false], - ["\u2007", 0x2007, "figure space", false], - ["\u2008", 0x2008, "punctuation space", false], - ["\u200A", 0x200a, "hair space", false], - ["​", 0x200b, "zero-width space", false], ["a", 0x0061, "letter a", false], ["A", 0x0041, "letter A", false], ["1", 0x0031, "digit 1", false], diff --git a/frontend/src/ts/commandline/commandline-metadata.ts b/frontend/src/ts/commandline/commandline-metadata.ts index fb105f009b66..4d2d2ebb12af 100644 --- a/frontend/src/ts/commandline/commandline-metadata.ts +++ b/frontend/src/ts/commandline/commandline-metadata.ts @@ -703,6 +703,12 @@ export const commandlineConfigMetadata: CommandlineConfigMetadataObject = { options: "fromSchema", }, }, + showPb: { + subgroup: { + options: "fromSchema", + }, + alias: "pb", + }, monkeyPowerLevel: { alias: "powermode", isVisible: false, diff --git a/frontend/src/ts/commandline/lists.ts b/frontend/src/ts/commandline/lists.ts index 1dbe01c36674..5cc8b61749ba 100644 --- a/frontend/src/ts/commandline/lists.ts +++ b/frontend/src/ts/commandline/lists.ts @@ -52,6 +52,7 @@ const confidenceModeCommand = buildCommandForConfigKey("confidenceMode"); const lazyModeCommand = buildCommandForConfigKey("lazyMode"); const layoutCommand = buildCommandForConfigKey("layout"); const showAverageCommand = buildCommandForConfigKey("showAverage"); +const showPbCommand = buildCommandForConfigKey("showPb"); const keymapLayoutCommand = buildCommandForConfigKey("keymapLayout"); const customThemeCommand = buildCommandForConfigKey("customTheme"); const adsCommand = buildCommandForConfigKey("ads"); @@ -216,6 +217,7 @@ export const commands: CommandsSubgroup = { "showOutOfFocusWarning", "capsLockWarning", showAverageCommand, + showPbCommand, "monkeyPowerLevel", "monkey" ), @@ -377,6 +379,7 @@ const lists = { lazyMode: lazyModeCommand.subgroup, paceCaretMode: paceCaretCommand.subgroup, showAverage: showAverageCommand.subgroup, + showPb: showPbCommand.subgroup, minWpm: minSpeedCommand.subgroup, minAcc: minAccCommand.subgroup, minBurst: MinBurstCommands[0]?.subgroup, diff --git a/frontend/src/ts/config-metadata.ts b/frontend/src/ts/config-metadata.ts index 7dc8726e8678..62650b386c79 100644 --- a/frontend/src/ts/config-metadata.ts +++ b/frontend/src/ts/config-metadata.ts @@ -742,6 +742,11 @@ export const configMetadata: ConfigMetadataObject = { displayString: "show average", changeRequiresRestart: false, }, + showPb: { + icon: "fa-crown", + displayString: "show personal best", + changeRequiresRestart: false, + }, // other (hidden) accountChart: { diff --git a/frontend/src/ts/constants/default-config.ts b/frontend/src/ts/constants/default-config.ts index fa08f54bc6ab..0fb967fb5c02 100644 --- a/frontend/src/ts/constants/default-config.ts +++ b/frontend/src/ts/constants/default-config.ts @@ -97,6 +97,7 @@ const obj: Config = { britishEnglish: false, lazyMode: false, showAverage: "off", + showPb: false, tapeMode: "off", tapeMargin: 50, maxLineWidth: 0, diff --git a/frontend/src/ts/elements/modes-notice.ts b/frontend/src/ts/elements/modes-notice.ts index aa2888565dcd..43c708eca211 100644 --- a/frontend/src/ts/elements/modes-notice.ts +++ b/frontend/src/ts/elements/modes-notice.ts @@ -9,8 +9,8 @@ import { isAuthenticated } from "../firebase"; import * as CustomTextState from "../states/custom-text-name"; import { getLanguageDisplayString } from "../utils/strings"; import Format from "../utils/format"; -import { getActiveFunboxNames } from "../test/funbox/list"; -import { escapeHTML } from "../utils/misc"; +import { getActiveFunboxes, getActiveFunboxNames } from "../test/funbox/list"; +import { escapeHTML, getMode2 } from "../utils/misc"; ConfigEvent.subscribe((eventKey) => { const configKeys: ConfigEvent.ConfigEventKey[] = [ @@ -26,6 +26,7 @@ ConfigEvent.subscribe((eventKey) => { "confidenceMode", "layout", "showAverage", + "showPb", "typingSpeedUnit", "quickRestart", "customPolyglot", @@ -191,6 +192,36 @@ export async function update(): Promise { } } + if (Config.showPb) { + if (!isAuthenticated()) { + return; + } + const mode2 = getMode2(Config, TestWords.currentQuote); + const pb = await DB.getLocalPB( + Config.mode, + mode2, + Config.punctuation, + Config.numbers, + Config.language, + Config.difficulty, + Config.lazyMode, + getActiveFunboxes() + ); + + let str = "no pb"; + + if (pb !== undefined) { + str = `${Format.typingSpeed(pb.wpm, { + showDecimalPlaces: true, + suffix: ` ${Config.typingSpeedUnit}`, + })} ${pb?.acc}% acc`; + } + + $(".pageTest #testModesNotice").append( + `` + ); + } + if (Config.minWpm !== "off") { $(".pageTest #testModesNotice").append( `