From d18408700baaf2f189fa7de72060091fff0bd1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gian=20Pe=C3=B1a?= <36643266+gianpena@users.noreply.github.com> Date: Thu, 27 Nov 2025 05:50:16 -0500 Subject: [PATCH] impr(timer/progress style): add flashing timer style (@gianpena) (#7139) ### Description This copies the existing `text` timerstyle except on timed modes, where it will only show the remaining progress (seconds) on every 15th second (shows on 1:00, 45, 30, 15 and 0). The motivation for this addition was that I wanted a middle ground between the `text` timerstyle (in my opinion just a _little_ too distracting) and no live progress indicator at all (I lose track of how much time remains in the test), and I believe this achieves that middle ground. --------- Co-authored-by: Miodec --- frontend/src/html/pages/settings.html | 5 ++- frontend/src/styles/settings.scss | 6 +++ frontend/src/ts/test/timer-progress.ts | 56 ++++++++++++++++++++++++++ packages/schemas/src/configs.ts | 9 ++++- 4 files changed, 74 insertions(+), 2 deletions(-) diff --git a/frontend/src/html/pages/settings.html b/frontend/src/html/pages/settings.html index b8557e36f..a2c2d6646 100644 --- a/frontend/src/html/pages/settings.html +++ b/frontend/src/html/pages/settings.html @@ -856,13 +856,16 @@
- Change the style of the timer/word count during a test. + Change the style of the timer/word count during a test. "Flash" styles + will briefly show the timer in timed modes every 15 seconds.
+ +
diff --git a/frontend/src/styles/settings.scss b/frontend/src/styles/settings.scss index 4c7c2d3c0..f37ed4b68 100644 --- a/frontend/src/styles/settings.scss +++ b/frontend/src/styles/settings.scss @@ -339,6 +339,12 @@ } } + &[data-config-name="timerStyle"] { + .buttons { + grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); + } + } + &.tags { .tagsListAndButton { grid-area: buttons; diff --git a/frontend/src/ts/test/timer-progress.ts b/frontend/src/ts/test/timer-progress.ts index 12f337545..cbf5b2103 100644 --- a/frontend/src/ts/test/timer-progress.ts +++ b/frontend/src/ts/test/timer-progress.ts @@ -36,6 +36,22 @@ export function show(): void { textEl.classList.remove("hidden"); }, }); + } else if (Config.timerStyle === "flash mini") { + animate(miniEl, { + opacity: [0, 1], + duration: applyReducedMotion(125), + onBegin: () => { + miniEl.classList.remove("hidden"); + }, + }); + } else if (Config.timerStyle === "flash text") { + animate(textEl, { + opacity: [0, 1], + duration: applyReducedMotion(125), + onBegin: () => { + textEl.classList.remove("hidden"); + }, + }); } else if (Config.mode === "zen" || Config.timerStyle === "mini") { animate(miniEl, { opacity: [0, 1], @@ -124,6 +140,30 @@ export function update(): void { if (textEl !== null) { textEl.innerHTML = "
" + displayTime + "
"; } + } else if (Config.timerStyle === "flash mini") { + let displayTime = DateTime.secondsToString(maxtime - time); + if (maxtime === 0) { + displayTime = DateTime.secondsToString(time); + } + if (miniEl !== null) { + if ((maxtime - time) % 15 !== 0) { + miniEl.style.opacity = "0"; + } else { + miniEl.style.opacity = "1"; + } + miniEl.innerHTML = "
" + displayTime + "
"; + } + } else if (Config.timerStyle === "flash text") { + let displayTime = DateTime.secondsToString(maxtime - time); + if (maxtime === 0) { + displayTime = DateTime.secondsToString(time); + } + if (textEl !== null) { + textEl.innerHTML = + "
" + + `${(maxtime - time) % 15 !== 0 ? "" : displayTime}` + + "
"; + } } else if (Config.timerStyle === "mini") { let displayTime = DateTime.secondsToString(maxtime - time); if (maxtime === 0) { @@ -163,6 +203,18 @@ export function update(): void { } else { textEl.innerHTML = `
${getCurrentCount()}/${outof}
`; } + } else if (Config.timerStyle === "flash mini") { + if (outof === 0) { + miniEl.innerHTML = `${TestInput.input.getHistory().length}`; + } else { + miniEl.innerHTML = `${getCurrentCount()}/${outof}`; + } + } else if (Config.timerStyle === "flash text") { + if (outof === 0) { + textEl.innerHTML = `
${TestInput.input.getHistory().length}
`; + } else { + textEl.innerHTML = `
${getCurrentCount()}/${outof}
`; + } } else if (Config.timerStyle === "mini") { if (outof === 0) { miniEl.innerHTML = `${TestInput.input.getHistory().length}`; @@ -173,6 +225,10 @@ export function update(): void { } else if (Config.mode === "zen") { if (Config.timerStyle === "text") { textEl.innerHTML = `
${TestInput.input.getHistory().length}
`; + } else if (Config.timerStyle === "flash mini") { + miniEl.innerHTML = `${TestInput.input.getHistory().length}`; + } else if (Config.timerStyle === "flash text") { + textEl.innerHTML = `
${TestInput.input.getHistory().length}
`; } else { miniEl.innerHTML = `${TestInput.input.getHistory().length}`; } diff --git a/packages/schemas/src/configs.ts b/packages/schemas/src/configs.ts index 9eaf3b8b5..e5a2f698f 100644 --- a/packages/schemas/src/configs.ts +++ b/packages/schemas/src/configs.ts @@ -54,7 +54,14 @@ export type ConfidenceMode = z.infer; export const IndicateTyposSchema = z.enum(["off", "below", "replace", "both"]); export type IndicateTypos = z.infer; -export const TimerStyleSchema = z.enum(["off", "bar", "text", "mini"]); +export const TimerStyleSchema = z.enum([ + "off", + "bar", + "text", + "mini", + "flash text", + "flash mini", +]); export type TimerStyle = z.infer; export const LiveSpeedAccBurstStyleSchema = z.enum(["off", "text", "mini"]);