Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
"madge": " madge --circular --extensions ts ./src",
"start": "vite preview --port 3000",
"dev": "vite dev",
"deploy-live": "npm run check-assets && npm run build && firebase deploy -P live --only hosting",
"deploy-preview": "npm run check-assets && npm run build && firebase hosting:channel:deploy preview -P live --expires 2h",
"test": "vitest run",
"test-coverage": "vitest run --coverage",
"dev-test": "concurrently --kill-others \"vite dev\" \"vitest\"",
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/html/pages/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,26 @@
<button data-config-value="true">on</button>
</div>
</div>
<div class="section" data-config-name="compositionDisplay">
<div class="groupTitle">
<i class="fas fa-language"></i>
<span>composition display</span>
<button class="text" tabindex="-1">
<i class="fas fa-fw fa-link"></i>
</button>
</div>
<div class="text">
Change how composition is displayed. "off" will just underline the
letter if composition is active. "below" will show the composed
character below the test. "replace" will replace the letter in the test
with the composed character.
</div>
<div class="buttons">
<button data-config-value="off">off</button>
<button data-config-value="below">below</button>
<button data-config-value="replace">replace</button>
</div>
</div>
<div class="section" data-config-name="lazyMode">
<div class="groupTitle">
<i class="fas fa-couch"></i>
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/ts/commandline/commandline-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ export const commandlineConfigMetadata: CommandlineConfigMetadataObject = {
options: "fromSchema",
},
},
compositionDisplay: {
subgroup: {
options: "fromSchema",
},
},
hideExtraLetters: {
subgroup: {
options: "fromSchema",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/ts/commandline/lists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ export const commands: CommandsSubgroup = {
confidenceModeCommand,
"quickEnd",
"indicateTypos",
"compositionDisplay",
"hideExtraLetters",
lazyModeCommand,
layoutCommand,
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/ts/config-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions frontend/src/ts/constants/default-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const obj: Config = {
funbox: [],
confidenceMode: "off",
indicateTypos: "off",
compositionDisplay: "replace",
timerStyle: "mini",
liveSpeedStyle: "off",
liveAccStyle: "off",
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/ts/elements/composition-display.ts
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
11 changes: 1 addition & 10 deletions frontend/src/ts/input/handlers/keydown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import * as JSONData from "../../utils/json-data";
import * as Notifications from "../../elements/notifications";
import * as KeyConverter from "../../utils/key-converter";
import * as ShiftTracker from "../../test/shift-tracker";
import * as CompositionState from "../../states/composition";
import * as ManualRestart from "../../test/manual-restart-tracker";
import { canQuickRestart } from "../../utils/quick-restart";
import * as CustomText from "../../test/custom-text";
Expand Down Expand Up @@ -45,7 +44,7 @@ export async function handleTab(e: KeyboardEvent, now: number): Promise<void> {

export async function handleEnter(
e: KeyboardEvent,
now: number,
_now: number,
): Promise<void> {
if (e.shiftKey) {
if (Config.mode === "zen") {
Expand Down Expand Up @@ -92,14 +91,6 @@ export async function handleEnter(
return;
}
}
if (
TestWords.hasNewline ||
(Config.mode === "zen" && !CompositionState.getComposing())
) {
await emulateInsertText({ data: "\n", now });
e.preventDefault();
return;
}
}

export async function handleOppositeShift(event: KeyboardEvent): Promise<void> {
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/ts/input/listeners/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import {
import * as TestUI from "../../test/test-ui";
import { onBeforeInsertText } from "../handlers/before-insert-text";
import { onBeforeDelete } from "../handlers/before-delete";
import * as TestInput from "../../test/test-input";
import * as TestWords from "../../test/test-words";
import * as CompositionState from "../../states/composition";
import { activeWordIndex } from "../../test/test-state";
import { areAllTestWordsGenerated } from "../../test/test-logic";

const inputEl = getInputElement();

Expand Down Expand Up @@ -114,6 +119,26 @@ inputEl.addEventListener("input", async (event) => {
inputType === "insertCompositionText" ||
inputType === "insertFromComposition"
) {
const allWordsTyped = activeWordIndex >= TestWords.words.length - 1;
const inputPlusComposition =
TestInput.input.current + (CompositionState.getData() ?? "");
const inputPlusCompositionIsCorrect =
TestWords.words.getCurrent() === inputPlusComposition;

// composition quick end
// if the user typed the entire word correctly but is still in composition
// dont wait for them to end the composition manually, just end the test
// by dispatching a compositionend which will trigger onInsertText
if (
areAllTestWordsGenerated() &&
allWordsTyped &&
inputPlusCompositionIsCorrect
) {
getInputElement().dispatchEvent(
new CompositionEvent("compositionend", { data: event.data ?? "" }),
);
}

// in case the data is the same as the last one, just ignore it
if (getLastInsertCompositionTextData() !== event.data) {
setLastInsertCompositionTextData(event.data ?? "");
Expand Down
11 changes: 2 additions & 9 deletions frontend/src/ts/test/test-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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: () => {
Expand Down
34 changes: 28 additions & 6 deletions frontend/src/ts/test/test-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -880,11 +880,16 @@ export async function updateWordLetters({
let charToShow =
currentWordChars[input.length + i] ?? compositionChar;

if (Config.indicateTypos === "replace") {
if (Config.compositionDisplay === "replace") {
charToShow = compositionChar === " " ? "_" : compositionChar;
}

ret += `<letter class="dead">${charToShow}</letter>`;
let correctClass = "";
if (compositionChar === currentWordChars[input.length + i]) {
correctClass = "correct";
}

ret += `<letter class="dead ${correctClass}">${charToShow}</letter>`;
}

for (
Expand Down Expand Up @@ -1914,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") {
Expand Down Expand Up @@ -2038,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();
}
}
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"start-fe": "turbo run start --filter @monkeytype/frontend",
"docker": "cd backend && npm run docker",
"audit-fe": "cd frontend && npm run audit",
"preview-fe": "monkeytype-release --preview-fe",
"release": "monkeytype-release",
"release-fe": "monkeytype-release --fe",
"release-be": "monkeytype-release --be",
Expand Down
29 changes: 29 additions & 0 deletions packages/release/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const isBackend = args.has("--be");
const isDryRun = args.has("--dry");
const noSyncCheck = args.has("--no-sync-check");
const hotfix = args.has("--hotfix");
const previewFe = args.has("--preview-fe");

const PROJECT_ROOT = path.resolve(__dirname, "../../../");

Expand Down Expand Up @@ -252,6 +253,34 @@ const createGithubRelease = async (version, changelogContent) => {
};

const main = async () => {
if (previewFe) {
console.log(`Starting frontend preview deployment process...`);
installDependencies();
runProjectRootCommand(
"NODE_ENV=production npx turbo lint test check-assets build --filter @monkeytype/frontend --force",
);

const name = readlineSync.question(
"Enter preview channel name (default: preview): ",
);
const channelName = name.trim() || "preview";

const expirationTime = readlineSync.question(
"Enter expiration time (e.g., 2h, default: 1d): ",
);
const expires = expirationTime.trim() || "1d";

console.log(
`Deploying frontend preview to channel "${channelName}" with expiration "${expires}"...`,
);
const result = runProjectRootCommand(
`cd frontend && npx firebase hosting:channel:deploy ${channelName} -P live --expires ${expires}`,
);
console.log(result);
console.log("Frontend preview deployed successfully.");
process.exit(0);
}

console.log(`Starting ${hotfix ? "hotfix" : "release"} process...`);

if (!hotfix) checkBranchSync();
Expand Down
5 changes: 5 additions & 0 deletions packages/schemas/src/configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export type ConfidenceMode = z.infer<typeof ConfidenceModeSchema>;
export const IndicateTyposSchema = z.enum(["off", "below", "replace", "both"]);
export type IndicateTypos = z.infer<typeof IndicateTyposSchema>;

export const CompositionDisplaySchema = z.enum(["off", "below", "replace"]);
export type CompositionDisplay = z.infer<typeof CompositionDisplaySchema>;

export const TimerStyleSchema = z.enum([
"off",
"bar",
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -544,6 +548,7 @@ export const ConfigGroupsLiteral = {
confidenceMode: "input",
quickEnd: "input",
indicateTypos: "input",
compositionDisplay: "input",
hideExtraLetters: "input",
lazyMode: "input",
layout: "input",
Expand Down
Loading