mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-12-29 03:20:46 +08:00
feat: add tape margin
This commit is contained in:
parent
b490056e36
commit
c9789d6b1b
10 changed files with 153 additions and 8 deletions
|
|
@ -826,6 +826,30 @@
|
|||
<button data-config-value="word">word</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" data-config-name="tapeMargin">
|
||||
<div class="groupTitle">
|
||||
<i class="fas fa-tape"></i>
|
||||
<span>tape margin</span>
|
||||
</div>
|
||||
<div class="text">
|
||||
When in tape mode, set the carets position from the left edge of the
|
||||
typing test as a percentage (for example, 50% centers it).
|
||||
</div>
|
||||
<div class="inputs">
|
||||
<div class="inputAndButton">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="tape margin"
|
||||
class="input"
|
||||
min="10"
|
||||
max="90"
|
||||
/>
|
||||
<button class="save no-auto-handle">
|
||||
<i class="fas fa-save fa-fw"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" data-config-name="smoothLineScroll">
|
||||
<div class="groupTitle">
|
||||
<i class="fas fa-align-left"></i>
|
||||
|
|
|
|||
|
|
@ -1254,6 +1254,8 @@
|
|||
}
|
||||
}
|
||||
#liveStatsMini {
|
||||
width: 0;
|
||||
justify-content: start;
|
||||
height: 0;
|
||||
margin-left: 0.25em;
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import TimerColorCommands from "./lists/timer-color";
|
|||
import TimerOpacityCommands from "./lists/timer-opacity";
|
||||
import HighlightModeCommands from "./lists/highlight-mode";
|
||||
import TapeModeCommands from "./lists/tape-mode";
|
||||
import TapeMarginCommands from "./lists/tape-margin";
|
||||
import BritishEnglishCommands from "./lists/british-english";
|
||||
import KeymapModeCommands from "./lists/keymap-mode";
|
||||
import KeymapStyleCommands from "./lists/keymap-style";
|
||||
|
|
@ -273,6 +274,7 @@ export const commands: CommandsSubgroup = {
|
|||
...TimerOpacityCommands,
|
||||
...HighlightModeCommands,
|
||||
...TapeModeCommands,
|
||||
...TapeMarginCommands,
|
||||
...SmoothLineScrollCommands,
|
||||
...ShowAllLinesCommands,
|
||||
...TypingSpeedUnitCommands,
|
||||
|
|
|
|||
19
frontend/src/ts/commandline/lists/tape-margin.ts
Normal file
19
frontend/src/ts/commandline/lists/tape-margin.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import Config, * as UpdateConfig from "../../config";
|
||||
import { Command } from "../types";
|
||||
|
||||
const commands: Command[] = [
|
||||
{
|
||||
id: "changeTapeMargin",
|
||||
display: "Tape margin...",
|
||||
icon: "fa-tape",
|
||||
input: true,
|
||||
defaultValue: (): string => {
|
||||
return Config.tapeMargin.toString();
|
||||
},
|
||||
exec: ({ input }): void => {
|
||||
if (input === undefined || input === "") return;
|
||||
UpdateConfig.setTapeMargin(parseFloat(input));
|
||||
},
|
||||
},
|
||||
];
|
||||
export default commands;
|
||||
|
|
@ -918,6 +918,34 @@ export function setTapeMode(
|
|||
return true;
|
||||
}
|
||||
|
||||
export function setTapeMargin(
|
||||
value: ConfigSchemas.TapeMargin,
|
||||
nosave?: boolean
|
||||
): boolean {
|
||||
if (value < 10) {
|
||||
value = 10;
|
||||
}
|
||||
if (value > 90) {
|
||||
value = 90;
|
||||
}
|
||||
|
||||
if (
|
||||
!isConfigValueValid("max line width", value, ConfigSchemas.TapeMarginSchema)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config.tapeMargin = value;
|
||||
|
||||
saveToLocalStorage("tapeMargin", nosave);
|
||||
ConfigEvent.dispatch("tapeMargin", config.tapeMargin, nosave);
|
||||
|
||||
// trigger a resize event to update the layout - handled in ui.ts:108
|
||||
$(window).trigger("resize");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function setHideExtraLetters(val: boolean, nosave?: boolean): boolean {
|
||||
if (!isConfigValueValidBoolean("hide extra letters", val)) return false;
|
||||
|
||||
|
|
@ -2053,6 +2081,7 @@ export async function apply(
|
|||
setLazyMode(configObj.lazyMode, true);
|
||||
setShowAverage(configObj.showAverage, true);
|
||||
setTapeMode(configObj.tapeMode, true);
|
||||
setTapeMargin(configObj.tapeMargin, true);
|
||||
|
||||
ConfigEvent.dispatch(
|
||||
"configApplied",
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ const obj = {
|
|||
lazyMode: false,
|
||||
showAverage: "off",
|
||||
tapeMode: "off",
|
||||
tapeMargin: 10,
|
||||
maxLineWidth: 0,
|
||||
} as Config;
|
||||
|
||||
|
|
|
|||
|
|
@ -379,6 +379,11 @@ async function initGroups(): Promise<void> {
|
|||
UpdateConfig.setTapeMode,
|
||||
"button"
|
||||
) as SettingsGroup<ConfigValue>;
|
||||
groups["tapeMargin"] = new SettingsGroup(
|
||||
"tapeMargin",
|
||||
UpdateConfig.setTapeMargin,
|
||||
"button"
|
||||
) as SettingsGroup<ConfigValue>;
|
||||
groups["timerOpacity"] = new SettingsGroup(
|
||||
"timerOpacity",
|
||||
UpdateConfig.setTimerOpacity,
|
||||
|
|
@ -694,6 +699,10 @@ async function fillSettingsPage(): Promise<void> {
|
|||
Config.customLayoutfluid.replace(/#/g, " ")
|
||||
);
|
||||
|
||||
$(".pageSettings .section[data-config-name='tapeMargin'] input").val(
|
||||
Config.tapeMargin
|
||||
);
|
||||
|
||||
setEventDisabled(true);
|
||||
if (!groupsInitialized) {
|
||||
await initGroups();
|
||||
|
|
@ -1159,6 +1168,42 @@ $(
|
|||
}
|
||||
});
|
||||
|
||||
$(
|
||||
".pageSettings .section[data-config-name='tapeMargin'] .inputAndButton button.save"
|
||||
).on("click", () => {
|
||||
const didConfigSave = UpdateConfig.setTapeMargin(
|
||||
parseFloat(
|
||||
$(
|
||||
".pageSettings .section[data-config-name='tapeMargin'] .inputAndButton input"
|
||||
).val() as string
|
||||
)
|
||||
);
|
||||
if (didConfigSave) {
|
||||
Notifications.add("Saved", 1, {
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(
|
||||
".pageSettings .section[data-config-name='tapeMargin'] .inputAndButton input"
|
||||
).on("keypress", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
const didConfigSave = UpdateConfig.setTapeMargin(
|
||||
parseFloat(
|
||||
$(
|
||||
".pageSettings .section[data-config-name='tapeMargin'] .inputAndButton input"
|
||||
).val() as string
|
||||
)
|
||||
);
|
||||
if (didConfigSave) {
|
||||
Notifications.add("Saved", 1, {
|
||||
duration: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(
|
||||
".pageSettings .section[data-config-name='maxLineWidth'] .inputAndButton button.save"
|
||||
).on("click", () => {
|
||||
|
|
|
|||
|
|
@ -106,8 +106,10 @@ function getTargetPositionLeft(
|
|||
} else {
|
||||
const wordsWrapperWidth =
|
||||
$(document.querySelector("#wordsWrapper") as HTMLElement).width() ?? 0;
|
||||
const tapeMargin = wordsWrapperWidth * (Config.tapeMargin / 100);
|
||||
|
||||
result =
|
||||
wordsWrapperWidth / 2 -
|
||||
tapeMargin -
|
||||
(fullWidthCaret && isLanguageRightToLeft ? fullWidthCaretWidth : 0);
|
||||
|
||||
if (Config.tapeMode === "word" && inputLen > 0) {
|
||||
|
|
|
|||
|
|
@ -184,13 +184,14 @@ ConfigEvent.subscribe((eventKey, eventValue, nosave) => {
|
|||
if (eventKey === "tapeMode" && !nosave) {
|
||||
if (eventValue === "off") {
|
||||
$("#words").css("margin-left", "unset");
|
||||
$("#liveStatsMini").css("display", "").css("justify-content", "");
|
||||
} else {
|
||||
scrollTape();
|
||||
$("#liveStatsMini")
|
||||
.css("display", "flex")
|
||||
.css("justify-content", "center");
|
||||
}
|
||||
updateLiveStatsMargin();
|
||||
}
|
||||
|
||||
if (eventKey === "tapeMargin" && !nosave) {
|
||||
updateLiveStatsMargin();
|
||||
}
|
||||
|
||||
if (typeof eventValue !== "boolean") return;
|
||||
|
|
@ -474,7 +475,7 @@ export async function updateWordsInputPosition(initial = false): Promise<void> {
|
|||
|
||||
if (Config.tapeMode !== "off") {
|
||||
el.style.top = targetTop + "px";
|
||||
el.style.left = "50%";
|
||||
el.style.left = Config.tapeMargin + "%";
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -949,7 +950,7 @@ export function scrollTape(): void {
|
|||
.stop(true, false)
|
||||
.animate(
|
||||
{
|
||||
marginLeft: "50%",
|
||||
marginLeft: Config.tapeMargin + "%",
|
||||
},
|
||||
SlowTimer.get() ? 0 : 125
|
||||
);
|
||||
|
|
@ -1000,7 +1001,9 @@ export function scrollTape(): void {
|
|||
}
|
||||
}
|
||||
}
|
||||
const newMargin = wordsWrapperWidth / 2 - (fullWordsWidth + currentWordWidth);
|
||||
|
||||
const tapeMargin = wordsWrapperWidth * (Config.tapeMargin / 100);
|
||||
const newMargin = tapeMargin - (fullWordsWidth + currentWordWidth);
|
||||
if (Config.smoothLineScroll) {
|
||||
$("#words")
|
||||
.stop(true, false)
|
||||
|
|
@ -1478,6 +1481,20 @@ function updateWordsWidth(): void {
|
|||
}
|
||||
}
|
||||
|
||||
function updateLiveStatsMargin(): void {
|
||||
if (Config.tapeMode === "off") {
|
||||
$("#liveStatsMini").css({
|
||||
"justify-content": "start",
|
||||
"margin-left": "unset",
|
||||
});
|
||||
} else {
|
||||
$("#liveStatsMini").css({
|
||||
"justify-content": "center",
|
||||
"margin-left": Config.tapeMargin + "%",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function updateLiveStatsOpacity(value: TimerOpacity): void {
|
||||
$("#barTimerProgress").css("opacity", parseFloat(value as string));
|
||||
$("#liveStatsTextTop").css("opacity", parseFloat(value as string));
|
||||
|
|
|
|||
|
|
@ -158,6 +158,9 @@ export type HighlightMode = z.infer<typeof HighlightModeSchema>;
|
|||
export const TapeModeSchema = z.enum(["off", "letter", "word"]);
|
||||
export type TapeMode = z.infer<typeof TapeModeSchema>;
|
||||
|
||||
export const TapeMarginSchema = z.number().min(10).max(90);
|
||||
export type TapeMargin = z.infer<typeof TapeMarginSchema>;
|
||||
|
||||
export const TypingSpeedUnitSchema = z.enum([
|
||||
"wpm",
|
||||
"cpm",
|
||||
|
|
@ -354,6 +357,7 @@ export const ConfigSchema = z
|
|||
minWpmCustomSpeed: MinWpmCustomSpeedSchema,
|
||||
highlightMode: HighlightModeSchema,
|
||||
tapeMode: TapeModeSchema,
|
||||
tapeMargin: TapeMarginSchema,
|
||||
typingSpeedUnit: TypingSpeedUnitSchema,
|
||||
ads: AdsSchema,
|
||||
hideExtraLetters: z.boolean(),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue