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 <jack@monkeytype.com>
This commit is contained in:
Gian Peña 2025-11-27 05:50:16 -05:00 committed by GitHub
parent f910c8a567
commit d18408700b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 74 additions and 2 deletions

View file

@ -856,13 +856,16 @@
</button>
</div>
<div class="text">
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.
</div>
<div class="buttons">
<button data-config-value="off">off</button>
<button data-config-value="bar">bar</button>
<button data-config-value="text">text</button>
<button data-config-value="mini">mini</button>
<button data-config-value="flash text">flash text</button>
<button data-config-value="flash mini">flash mini</button>
</div>
</div>
<div class="section" data-config-name="liveSpeedStyle">

View file

@ -339,6 +339,12 @@
}
}
&[data-config-name="timerStyle"] {
.buttons {
grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
}
}
&.tags {
.tagsListAndButton {
grid-area: buttons;

View file

@ -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 = "<div>" + displayTime + "</div>";
}
} 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 = "<div>" + displayTime + "</div>";
}
} else if (Config.timerStyle === "flash text") {
let displayTime = DateTime.secondsToString(maxtime - time);
if (maxtime === 0) {
displayTime = DateTime.secondsToString(time);
}
if (textEl !== null) {
textEl.innerHTML =
"<div>" +
`${(maxtime - time) % 15 !== 0 ? "" : displayTime}` +
"</div>";
}
} 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 = `<div>${getCurrentCount()}/${outof}</div>`;
}
} 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 = `<div>${TestInput.input.getHistory().length}</div>`;
} else {
textEl.innerHTML = `<div>${getCurrentCount()}/${outof}</div>`;
}
} 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 = `<div>${TestInput.input.getHistory().length}</div>`;
} else if (Config.timerStyle === "flash mini") {
miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
} else if (Config.timerStyle === "flash text") {
textEl.innerHTML = `<div>${TestInput.input.getHistory().length}</div>`;
} else {
miniEl.innerHTML = `${TestInput.input.getHistory().length}`;
}

View file

@ -54,7 +54,14 @@ 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 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<typeof TimerStyleSchema>;
export const LiveSpeedAccBurstStyleSchema = z.enum(["off", "text", "mini"]);