refactor: move layout names to contracts (@fehmer) (#6495)

This commit is contained in:
Christian Fehmer 2025-04-28 11:29:52 +02:00 committed by GitHub
parent ab9cef010e
commit b36bc9f39e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 257 additions and 250 deletions

View file

@ -46,13 +46,16 @@ For iso the number of keys need to be exactly thirteen for `row1`, twelve for `r
In addition to the layout file you need to add your layout to the `frontend/src/ts/constants/layouts.ts` file. Just append your layout name (without the `.json`) at the __end__ of the array. Remember to add a comma like this:
In addition to the layout file you need to add your layout to the `packages/contracts/src/schemas/layouts.ts` file. Just append your layout name (without the `.json`) at the __end__ of the `LayoutNameSchema`. Remember to add a comma like this:
```ts
"ergopti",
"sword",
"YOUR_LAYOUT",
];
export const LayoutNameSchema = z.enum([
"qwerty",
"dvorak",
"colemak",
...
"your_layout_name",
]);
```
### Committing Layouts

View file

@ -1,5 +1,6 @@
import { readdirSync } from "fs";
import { LayoutsList } from "../../src/ts/constants/layouts";
import { LayoutName } from "@monkeytype/contracts/schemas/layouts";
describe("layouts", () => {
it("should not have duplicates", () => {
@ -32,7 +33,7 @@ describe("layouts", () => {
});
function listLayoutFiles() {
return readdirSync(import.meta.dirname + "/../../static/layouts").map((it) =>
it.substring(0, it.length - 5)
return readdirSync(import.meta.dirname + "/../../static/layouts").map(
(it) => it.substring(0, it.length - 5) as LayoutName
);
}

View file

@ -439,21 +439,15 @@ describe("Config", () => {
});
it("setKeymapLayout", () => {
expect(Config.setKeymapLayout("overrideSync")).toBe(true);
expect(Config.setKeymapLayout("override_sync")).toBe(true);
expect(Config.setKeymapLayout("override sync")).toBe(false);
expect(Config.setKeymapLayout("override-sync!")).toBe(false);
expect(Config.setKeymapLayout(stringOfLength(50))).toBe(true);
expect(Config.setKeymapLayout(stringOfLength(51))).toBe(false);
expect(Config.setKeymapLayout("override_sync" as any)).toBe(false);
expect(Config.setKeymapLayout("override sync" as any)).toBe(false);
expect(Config.setKeymapLayout("override-sync!" as any)).toBe(false);
});
it("setLayout", () => {
expect(Config.setLayout("semimak")).toBe(true);
expect(Config.setLayout("semi_mak")).toBe(true);
expect(Config.setLayout(stringOfLength(50))).toBe(true);
expect(Config.setLayout("semi mak")).toBe(false);
expect(Config.setLayout("semi-mak")).toBe(true);
expect(Config.setLayout(stringOfLength(51))).toBe(false);
expect(Config.setLayout("default")).toBe(true);
expect(Config.setLayout("semi_mak" as any)).toBe(false);
expect(Config.setLayout("overrideSync" as any)).toBe(false);
});
it("setFontSize", () => {
expect(Config.setFontSize(1)).toBe(true);

View file

@ -1,3 +1,4 @@
import { KeymapLayout } from "@monkeytype/contracts/schemas/configs";
import * as UpdateConfig from "../../config";
import { LayoutsList } from "../../constants/layouts";
import * as TestLogic from "../../test/test-logic";
@ -23,7 +24,7 @@ const subgroup: CommandsSubgroup = {
display: layout.replace(/_/g, " "),
configValue: layout,
exec: (): void => {
UpdateConfig.setKeymapLayout(layout);
UpdateConfig.setKeymapLayout(layout as KeymapLayout);
TestLogic.restart();
},
})),

View file

@ -31,6 +31,7 @@ import { migrateConfig } from "./utils/config";
import { roundTo1 } from "@monkeytype/util/numbers";
import { getDefaultConfig } from "./constants/default-config";
import { LayoutsList } from "./constants/layouts";
import { LayoutName } from "@monkeytype/contracts/schemas/layouts";
const configLS = new LocalStorageWithSchema({
key: "config",
@ -1884,7 +1885,7 @@ export function setCustomLayoutfluid(
const invalidLayouts = trimmed
.split(/[# ]+/) //can be space or hash
.filter((it) => !LayoutsList.includes(it));
.filter((it) => !LayoutsList.includes(it as LayoutName));
if (invalidLayouts.length !== 0) {
notifyInvalid(

View file

@ -1,214 +1,3 @@
export const LayoutsList:string[] = [
"qwerty",
"dvorak",
"colemak",
"colemak_wide",
"colemak_dh",
"colemak_dh_iso",
"colemak_dh_wide",
"colemak_dh_iso_wide",
"colemak_dhk",
"colemak_dh_matrix",
"colemak_dhk_iso",
"colemak_dhv",
"qwertz",
"swiss_german",
"swiss_french",
"workman",
"prog_workman",
"turkish_q",
"turkish_f",
"turkish_e",
"MTGAP_ASRT",
"norman",
"halmak",
"QGMLWB",
"QGMLWY",
"qwpr",
"uk_qwerty",
"spanish_qwerty",
"italian_qwerty",
"latam_qwerty",
"prog_dvorak",
"prog_dvorak_prime",
"german_dvorak",
"german_dvorak_imp",
"spanish_dvorak",
"swedish_colemak",
"swedish_dvorak",
"dvorak_L",
"dvorak_R",
"dvorak_fr",
"azerty",
"bepo",
"bepo_AFNOR",
"alpha",
"handsdown",
"hungarian",
"handsdown_alt",
"handsdown_promethium",
"typehack",
"MTGAP",
"MTGAP_full",
"ina",
"soul",
"niro",
"mongolian",
"JCUKEN",
"Diktor",
"Diktor_VoronovMod",
"Redaktor",
"JUIYAF",
"Zubachev",
"ISRT",
"ISRT_Angle",
"colemak_Qix",
"colemak_Qi",
"colemaQ",
"colemaQ_F",
"engram",
"engrammer",
"semimak",
"semimak_jq",
"semimak_jqc",
"canary",
"canary_matrix",
"japanese_hiragana",
"boo",
"boo_mangle",
"APT",
"APT_angle",
"middlemak",
"middlemak-nh",
"hindi_inscript",
"thai_kedmanee",
"thai_pattachote",
"thai_manoonchai",
"persian_standard",
"persian_farsi",
"arabic_101",
"arabic_102",
"arabic_mac",
"hebrew",
"urdu_phonetic",
"brasileiro_nativo",
"Foalmak",
"quartz",
"arensito",
"ARTS",
"beakl_15",
"beakl_19",
"beakl_19_bis",
"capewell_dvorak",
"colman",
"heart",
"klauser",
"oneproduct",
"pine",
"real",
"rolll",
"stndc",
"three",
"uciea",
"asset",
"dwarf",
"flaw",
"whorf",
"whorf6",
"whorfmax",
"whorfmax_ortho",
"sertain",
"ctgap",
"octa8",
"polish_programmers",
"bulgarian",
"bulgarian_phonetic_traditional",
"belarusian",
"ukrainian",
"russian",
"neo",
"bone",
"AdNW",
"mine",
"noted",
"koy",
"3l",
"korean",
"ekverto_b",
"nerps",
"sturdy_angle_ansi",
"sturdy_angle_iso",
"sturdy_ortho",
"ABNT2",
"HiYou",
"xenia",
"xenia_alt",
"burmese",
"gallium",
"gallium_angle",
"gallium_v2",
"gallium_v2_matrix",
"maya",
"gallaya_angle_ansi",
"gallaya_angle_iso",
"gallaya_matrix",
"nila",
"minimak_4k",
"minimak_8k",
"minimak_12k",
"optimot",
"norwegian_qwerty",
"portuguese_pt_qwerty_iso",
"portuguese_pt_qwerty_ansi",
"swedish_qwerty",
"danish_qwerty",
"noctum",
"graphite",
"graphite_angle",
"graphite_angle_vc",
"graphite_angle_kp",
"graphite_matrix",
"macedonian",
"UGJRMV",
"pashto",
"ORNATE",
"estonian",
"stronk",
"dhorf",
"recurva",
"seht-drai",
"ints",
"rollla",
"wreathy",
"saiga",
"saiga-e",
"krai",
"mir",
"ergol",
"cascade",
"vylet",
"hyperroll",
"romak",
"scythe",
"inqwerted",
"rain",
"night",
"whix2",
"haruka",
"kuntum",
"anishtro",
"Kuntem",
"BEAKL_Zi",
"snorkle",
"MALTRON",
"PRSTEN",
"RSTHD",
"dusk",
"zenith",
"focal",
"panini",
"panini_wide",
"ergopti",
"sword",
"opy",
];
import { LayoutName, LayoutNameSchema } from "@monkeytype/contracts/schemas/layouts";
export const LayoutsList:LayoutName[] = LayoutNameSchema._def.values;

View file

@ -23,6 +23,7 @@ import * as WeakSpot from "../weak-spot";
import * as IPAddresses from "../../utils/ip-addresses";
import * as TestState from "../test-state";
import { WordGenError } from "../../utils/word-gen-error";
import { KeymapLayout, Layout } from "@monkeytype/contracts/schemas/configs";
export type FunboxFunctions = {
getWord?: (wordset?: Wordset, wordIndex?: number) => string;
@ -345,8 +346,8 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
applyConfig(): void {
const layout = Config.customLayoutfluid.split("#")[0] ?? "qwerty";
UpdateConfig.setLayout(layout, true);
UpdateConfig.setKeymapLayout(layout, true);
UpdateConfig.setLayout(layout as Layout, true);
UpdateConfig.setKeymapLayout(layout as KeymapLayout, true);
},
rememberSettings(): void {
save("keymapMode", Config.keymapMode, UpdateConfig.setKeymapMode);
@ -357,8 +358,8 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
if (Config.mode !== "time") {
// here I need to check if Config.customLayoutFluid exists because of my
// scuffed solution of returning whenever value is undefined in the setCustomLayoutfluid function
const layouts: string[] = Config.customLayoutfluid
? Config.customLayoutfluid.split("#")
const layouts: Layout[] = Config.customLayoutfluid
? (Config.customLayoutfluid.split("#") as Layout[])
: ["qwerty", "dvorak", "colemak"];
const outOf: number = TestWords.words.length;
const wordsPerLayout = Math.floor(outOf / layouts.length);
@ -379,8 +380,8 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
LayoutfluidFunboxTimer.hide();
}
if (mod === wordsPerLayout) {
UpdateConfig.setLayout(layouts[index] as string);
UpdateConfig.setKeymapLayout(layouts[index] as string);
UpdateConfig.setLayout(layouts[index] as Layout);
UpdateConfig.setKeymapLayout(layouts[index] as KeymapLayout);
if (mod > 3) {
LayoutfluidFunboxTimer.hide();
}

View file

@ -16,6 +16,7 @@ import * as TestState from "./test-state";
import * as Time from "../states/time";
import * as TimerEvent from "../observables/timer-event";
import * as LayoutfluidFunboxTimer from "../test/funbox/layoutfluid-funbox-timer";
import { KeymapLayout, Layout } from "@monkeytype/contracts/schemas/configs";
type TimerStats = {
dateNow: number;
@ -118,8 +119,8 @@ function layoutfluid(): void {
if (Config.layout !== layout && layout !== undefined) {
LayoutfluidFunboxTimer.hide();
UpdateConfig.setLayout(layout, true);
UpdateConfig.setKeymapLayout(layout, true);
UpdateConfig.setLayout(layout as Layout, true);
UpdateConfig.setKeymapLayout(layout as KeymapLayout, true);
}
}
if (timerDebug) console.timeEnd("layoutfluid");

View file

@ -1,6 +1,7 @@
import { z, ZodSchema } from "zod";
import { LanguageSchema, token } from "./util";
import * as Shared from "./shared";
import * as Layouts from "./layouts";
export const SmoothCaretSchema = z.enum(["off", "slow", "medium", "fast"]);
export type SmoothCaret = z.infer<typeof SmoothCaretSchema>;
@ -269,15 +270,11 @@ export const ThemeNameSchema = token().max(50);
export type ThemeName = z.infer<typeof ThemeNameSchema>;
export const KeymapLayoutSchema = z
.string()
.max(50)
.regex(/^[a-zA-Z0-9\-_]+$/gi);
.literal("overrideSync")
.or(Layouts.LayoutNameSchema);
export type KeymapLayout = z.infer<typeof KeymapLayoutSchema>;
export const LayoutSchema = z
.string()
.max(50)
.regex(/^[a-zA-Z0-9\-_]+$/gi);
export const LayoutSchema = z.literal("default").or(Layouts.LayoutNameSchema);
export type Layout = z.infer<typeof LayoutSchema>;
export const FontSizeSchema = z.number().positive();

View file

@ -0,0 +1,219 @@
import { z } from "zod";
export const LayoutNameSchema = z.enum([
"qwerty",
"dvorak",
"colemak",
"colemak_wide",
"colemak_dh",
"colemak_dh_iso",
"colemak_dh_wide",
"colemak_dh_iso_wide",
"colemak_dhk",
"colemak_dh_matrix",
"colemak_dhk_iso",
"colemak_dhv",
"qwertz",
"swiss_german",
"swiss_french",
"workman",
"prog_workman",
"turkish_q",
"turkish_f",
"turkish_e",
"MTGAP_ASRT",
"norman",
"halmak",
"QGMLWB",
"QGMLWY",
"qwpr",
"uk_qwerty",
"spanish_qwerty",
"italian_qwerty",
"latam_qwerty",
"prog_dvorak",
"prog_dvorak_prime",
"german_dvorak",
"german_dvorak_imp",
"spanish_dvorak",
"swedish_colemak",
"swedish_dvorak",
"dvorak_L",
"dvorak_R",
"dvorak_fr",
"azerty",
"bepo",
"bepo_AFNOR",
"alpha",
"handsdown",
"hungarian",
"handsdown_alt",
"handsdown_promethium",
"typehack",
"MTGAP",
"MTGAP_full",
"ina",
"soul",
"niro",
"mongolian",
"JCUKEN",
"Diktor",
"Diktor_VoronovMod",
"Redaktor",
"JUIYAF",
"Zubachev",
"ISRT",
"ISRT_Angle",
"colemak_Qix",
"colemak_Qi",
"colemaQ",
"colemaQ_F",
"engram",
"engrammer",
"semimak",
"semimak_jq",
"semimak_jqc",
"canary",
"canary_matrix",
"japanese_hiragana",
"boo",
"boo_mangle",
"APT",
"APT_angle",
"middlemak",
"middlemak-nh",
"hindi_inscript",
"thai_kedmanee",
"thai_pattachote",
"thai_manoonchai",
"persian_standard",
"persian_farsi",
"arabic_101",
"arabic_102",
"arabic_mac",
"hebrew",
"urdu_phonetic",
"brasileiro_nativo",
"Foalmak",
"quartz",
"arensito",
"ARTS",
"beakl_15",
"beakl_19",
"beakl_19_bis",
"capewell_dvorak",
"colman",
"heart",
"klauser",
"oneproduct",
"pine",
"real",
"rolll",
"stndc",
"three",
"uciea",
"asset",
"dwarf",
"flaw",
"whorf",
"whorf6",
"whorfmax",
"whorfmax_ortho",
"sertain",
"ctgap",
"octa8",
"polish_programmers",
"bulgarian",
"bulgarian_phonetic_traditional",
"belarusian",
"ukrainian",
"russian",
"neo",
"bone",
"AdNW",
"mine",
"noted",
"koy",
"3l",
"korean",
"ekverto_b",
"nerps",
"sturdy_angle_ansi",
"sturdy_angle_iso",
"sturdy_ortho",
"ABNT2",
"HiYou",
"xenia",
"xenia_alt",
"burmese",
"gallium",
"gallium_angle",
"gallium_v2",
"gallium_v2_matrix",
"maya",
"gallaya_angle_ansi",
"gallaya_angle_iso",
"gallaya_matrix",
"nila",
"minimak_4k",
"minimak_8k",
"minimak_12k",
"optimot",
"norwegian_qwerty",
"portuguese_pt_qwerty_iso",
"portuguese_pt_qwerty_ansi",
"swedish_qwerty",
"danish_qwerty",
"noctum",
"graphite",
"graphite_angle",
"graphite_angle_vc",
"graphite_angle_kp",
"graphite_matrix",
"macedonian",
"UGJRMV",
"pashto",
"ORNATE",
"estonian",
"stronk",
"dhorf",
"recurva",
"seht-drai",
"ints",
"rollla",
"wreathy",
"saiga",
"saiga-e",
"krai",
"mir",
"ergol",
"cascade",
"vylet",
"hyperroll",
"romak",
"scythe",
"inqwerted",
"rain",
"night",
"whix2",
"haruka",
"kuntum",
"anishtro",
"Kuntem",
"BEAKL_Zi",
"snorkle",
"MALTRON",
"PRSTEN",
"RSTHD",
"dusk",
"zenith",
"focal",
"panini",
"panini_wide",
"ergopti",
"sword",
"opy",
]
);
export type LayoutName = z.infer<typeof LayoutNameSchema>;