diff --git a/frontend/src/ts/modals/quote-approve.ts b/frontend/src/ts/modals/quote-approve.ts
index f017c7f27bc1..988c7c5a3728 100644
--- a/frontend/src/ts/modals/quote-approve.ts
+++ b/frontend/src/ts/modals/quote-approve.ts
@@ -4,6 +4,7 @@ import * as Notifications from "../elements/notifications";
import { format } from "date-fns/format";
import AnimatedModal, { ShowOptions } from "../utils/animated-modal";
import { Quote } from "@monkeytype/schemas/quotes";
+import { escapeHTML } from "../utils/misc";
let quotes: Quote[] = [];
@@ -12,10 +13,10 @@ function updateList(): void {
quotes.forEach((quote, index) => {
const quoteEl = $(`
-
-
+
+
diff --git a/frontend/src/ts/test/test-ui.ts b/frontend/src/ts/test/test-ui.ts
index f8050950ac44..b647c4dcdcac 100644
--- a/frontend/src/ts/test/test-ui.ts
+++ b/frontend/src/ts/test/test-ui.ts
@@ -26,7 +26,10 @@ import {
} from "./funbox/list";
import * as TestState from "./test-state";
import * as PaceCaret from "./pace-caret";
-import { requestDebouncedAnimationFrame } from "../utils/debounced-animation-frame";
+import {
+ cancelPendingAnimationFramesStartingWith,
+ requestDebouncedAnimationFrame,
+} from "../utils/debounced-animation-frame";
import * as SoundController from "../controllers/sound-controller";
import * as Numbers from "@monkeytype/util/numbers";
import * as TestStats from "./test-stats";
@@ -165,6 +168,7 @@ export function setResultCalculating(val: boolean): void {
export function reset(): void {
currentTestLine = 0;
+ cancelPendingAnimationFramesStartingWith("test-ui");
}
export function focusWords(force = false): void {
@@ -254,7 +258,14 @@ export function updateActiveElement(
void scrollTape();
}
- if (!Config.showAllLines && previousActiveWordTop !== null) {
+ if (previousActiveWordTop === null) return;
+
+ const isTimedTest =
+ Config.mode === "time" ||
+ (Config.mode === "custom" && CustomText.getLimitMode() === "time") ||
+ (Config.mode === "custom" && CustomText.getLimitValue() === 0);
+
+ if (isTimedTest || !Config.showAllLines) {
const newActiveWordTop = newActiveWord.offsetTop;
if (newActiveWordTop > previousActiveWordTop) {
void lineJump(previousActiveWordTop);
diff --git a/frontend/src/ts/utils/debounced-animation-frame.ts b/frontend/src/ts/utils/debounced-animation-frame.ts
index a491768aabfe..246f970d3094 100644
--- a/frontend/src/ts/utils/debounced-animation-frame.ts
+++ b/frontend/src/ts/utils/debounced-animation-frame.ts
@@ -19,3 +19,15 @@ function cancelIfPending(frameId: string): void {
pendingFrames.delete(frameId);
}
}
+
+export function cancelPendingAnimationFrame(frameId: string): void {
+ cancelIfPending(frameId);
+}
+
+export function cancelPendingAnimationFramesStartingWith(prefix: string): void {
+ for (const frameId of pendingFrames.keys()) {
+ if (frameId.startsWith(prefix)) {
+ cancelIfPending(frameId);
+ }
+ }
+}
diff --git a/frontend/vite-plugins/env-config.ts b/frontend/vite-plugins/env-config.ts
index 414f509fbc0e..702193cd93fb 100644
--- a/frontend/vite-plugins/env-config.ts
+++ b/frontend/vite-plugins/env-config.ts
@@ -1,5 +1,10 @@
import { Plugin } from "vite";
import { EnvConfig } from "virtual:env-config";
+import { config as dotenvConfig } from "dotenv";
+
+const envFile =
+ process.env["NODE_ENV"] === "production" ? ".env.production" : ".env";
+dotenvConfig({ path: envFile });
const virtualModuleId = "virtual:env-config";
const resolvedVirtualModuleId = "\0" + virtualModuleId;