mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-23 22:45:09 +08:00
Add word filter presets (#4018) albertying
* Add word filter presets * updated structure and styling * updated button classes and click handlers * removed timeouts to fix annoying jumping * typescript fixes * renamed function * converted file to using single object that defines presets * using spread * added right hand preset using spread added key position B to the right hand preset * removed line * changed text * Finish rewriting presets in new format * added home keys filter preset * removed comment * Fix home keys preset --------- Co-authored-by: Miodec <jack@monkeytype.com>
This commit is contained in:
parent
702c36189c
commit
2b8690bf20
3 changed files with 275 additions and 34 deletions
|
@ -226,13 +226,47 @@
|
|||
border-radius: var(--roundness);
|
||||
padding: 2rem;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
width: 400px;
|
||||
grid-template-areas: "top top top" "left divider right" "bottom bottom bottom";
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 2rem;
|
||||
width: 800px;
|
||||
|
||||
.top {
|
||||
grid-area: top;
|
||||
}
|
||||
|
||||
.leftSide {
|
||||
grid-area: left;
|
||||
}
|
||||
|
||||
.rightSide {
|
||||
grid-area: right;
|
||||
}
|
||||
|
||||
.bottom {
|
||||
grid-area: bottom;
|
||||
}
|
||||
|
||||
.leftSide,
|
||||
.rightSide,
|
||||
.bottom,
|
||||
.top {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wordFilterLanguage {
|
||||
grid-column: span 2;
|
||||
.title {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.group {
|
||||
display: grid;
|
||||
gap: 0.5rem;
|
||||
|
@ -253,6 +287,12 @@
|
|||
.loadingIndicator {
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 0.25rem;
|
||||
background-color: var(--sub-alt-color);
|
||||
border-radius: var(--roundness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,11 +7,104 @@ const wrapperId = "wordFilterPopupWrapper";
|
|||
|
||||
let initialised = false;
|
||||
|
||||
interface FilterPreset {
|
||||
display: string;
|
||||
getIncludeString: (layout: MonkeyTypes.Layout) => string[];
|
||||
getExcludeString: (layout: MonkeyTypes.Layout) => string[];
|
||||
}
|
||||
|
||||
const presets: Record<string, FilterPreset> = {
|
||||
homeKeys: {
|
||||
display: "home keys",
|
||||
getIncludeString: (layout) => {
|
||||
const homeKeysLeft = layout.keys.row3.slice(0, 4);
|
||||
const homeKeysRight = layout.keys.row3.slice(6, 10);
|
||||
return [...homeKeysLeft, ...homeKeysRight];
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const topRow = layout.keys.row2;
|
||||
const bottomRow = layout.keys.row4;
|
||||
const homeRowRight = layout.keys.row3.slice(10);
|
||||
const homeRowMiddle = layout.keys.row3.slice(4, 6);
|
||||
return [...topRow, ...homeRowMiddle, ...homeRowRight, ...bottomRow];
|
||||
},
|
||||
},
|
||||
leftHand: {
|
||||
display: "left hand",
|
||||
getIncludeString: (layout) => {
|
||||
const topRowInclude = layout.keys.row2.slice(0, 5);
|
||||
const homeRowInclude = layout.keys.row3.slice(0, 5);
|
||||
const bottomRowInclude = layout.keys.row4.slice(0, 5);
|
||||
return [...topRowInclude, ...homeRowInclude, ...bottomRowInclude];
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const topRowExclude = layout.keys.row2.slice(5);
|
||||
const homeRowExclude = layout.keys.row3.slice(5);
|
||||
const bottomRowExclude = layout.keys.row4.slice(5);
|
||||
return [...topRowExclude, ...homeRowExclude, ...bottomRowExclude];
|
||||
},
|
||||
},
|
||||
rightHand: {
|
||||
display: "right hand",
|
||||
getIncludeString: (layout) => {
|
||||
const topRowInclude = layout.keys.row2.slice(5);
|
||||
const homeRowInclude = layout.keys.row3.slice(5);
|
||||
const bottomRowInclude = layout.keys.row4.slice(4);
|
||||
return [...topRowInclude, ...homeRowInclude, ...bottomRowInclude];
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const topRowExclude = layout.keys.row2.slice(0, 5);
|
||||
const homeRowExclude = layout.keys.row3.slice(0, 5);
|
||||
const bottomRowExclude = layout.keys.row4.slice(0, 4);
|
||||
return [...topRowExclude, ...homeRowExclude, ...bottomRowExclude];
|
||||
},
|
||||
},
|
||||
homeRow: {
|
||||
display: "home row",
|
||||
getIncludeString: (layout) => {
|
||||
return layout.keys.row3;
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const topRowExclude = layout.keys.row2;
|
||||
const bottomRowExclude = layout.keys.row4;
|
||||
return [...topRowExclude, ...bottomRowExclude];
|
||||
},
|
||||
},
|
||||
topRow: {
|
||||
display: "top row",
|
||||
getIncludeString: (layout) => {
|
||||
return layout.keys.row2;
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const homeRowExclude = layout.keys.row3;
|
||||
const bottomRowExclude = layout.keys.row4;
|
||||
return [...homeRowExclude, ...bottomRowExclude];
|
||||
},
|
||||
},
|
||||
bottomRow: {
|
||||
display: "bottom row",
|
||||
getIncludeString: (layout) => {
|
||||
return layout.keys.row4;
|
||||
},
|
||||
getExcludeString: (layout) => {
|
||||
const topRowExclude = layout.keys.row2;
|
||||
const homeRowExclude = layout.keys.row3;
|
||||
return [...topRowExclude, ...homeRowExclude];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
async function init(): Promise<void> {
|
||||
if (!initialised) {
|
||||
$("#wordFilterPopup .languageInput").empty();
|
||||
|
||||
$("#wordFilterPopup .layoutInput").empty();
|
||||
|
||||
$("wordFilterPopup .presetInput").empty();
|
||||
|
||||
let LanguageList;
|
||||
let LayoutList;
|
||||
|
||||
try {
|
||||
LanguageList = await Misc.getLanguageList();
|
||||
} catch (e) {
|
||||
|
@ -31,6 +124,31 @@ async function init(): Promise<void> {
|
|||
<option value=${language}>${prettyLang}</option>
|
||||
`);
|
||||
});
|
||||
|
||||
try {
|
||||
LayoutList = await Misc.getLayoutsList();
|
||||
} catch (e) {
|
||||
console.error(
|
||||
Misc.createErrorMessage(
|
||||
e,
|
||||
"Failed to initialise word filter popup preset list"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const layout in LayoutList) {
|
||||
$("#wordFilterPopup .layoutInput").append(`
|
||||
<option value=${layout}>${layout}</option>
|
||||
`);
|
||||
}
|
||||
|
||||
for (const [presetId, preset] of Object.entries(presets)) {
|
||||
$("#wordFilterPopup .presetInput").append(
|
||||
`<option value=${presetId}>${preset.display}</option>`
|
||||
);
|
||||
}
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +166,14 @@ export async function show(
|
|||
$("#wordFilterPopup .languageInput").select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
$("#wordFilterPopup .layoutInput").select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
$("#wordFilterPopup .presetInput").select2({
|
||||
width: "100%",
|
||||
});
|
||||
$("#wordFilterPopupWrapper .loadingIndicator").addClass("hidden");
|
||||
$("#wordFilterPopupWrapper .button").removeClass("hidden");
|
||||
|
||||
|
@ -152,12 +278,37 @@ $("#wordFilterPopup .languageInput").one("select2:open", function () {
|
|||
$("input.select2-search__field").prop("placeholder", "search");
|
||||
});
|
||||
|
||||
$("#wordFilterPopupWrapper .button").on("mousedown", (e) => {
|
||||
$("#wordFilterPopupWrapper .button.addButton").on("mousedown", () => {
|
||||
$("#wordFilterPopupWrapper .loadingIndicator").removeClass("hidden");
|
||||
$("#wordFilterPopupWrapper .button").addClass("hidden");
|
||||
setTimeout(() => {
|
||||
apply($(e.target).is("#set"));
|
||||
}, 1);
|
||||
apply(false);
|
||||
});
|
||||
|
||||
$("#wordFilterPopupWrapper .button.setButton").on("mousedown", () => {
|
||||
$("#wordFilterPopupWrapper .loadingIndicator").removeClass("hidden");
|
||||
$("#wordFilterPopupWrapper .button").addClass("hidden");
|
||||
apply(true);
|
||||
});
|
||||
|
||||
$("#wordFilterPopup .button.generateButton").on("click", async () => {
|
||||
const presetName = $("#wordFilterPopup .presetInput").val() as string;
|
||||
const layoutName = $("#wordFilterPopup .layoutInput").val() as string;
|
||||
|
||||
const presetToApply = presets[presetName];
|
||||
const layout = await Misc.getLayout(layoutName);
|
||||
|
||||
$("#wordIncludeInput").val(
|
||||
presetToApply
|
||||
.getIncludeString(layout)
|
||||
.map((x) => x[0])
|
||||
.join(" ")
|
||||
);
|
||||
$("#wordExcludeInput").val(
|
||||
presetToApply
|
||||
.getExcludeString(layout)
|
||||
.map((x) => x[0])
|
||||
.join(" ")
|
||||
);
|
||||
});
|
||||
|
||||
Skeleton.save(wrapperId);
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
<i class="fas fa-fw fa-trash"></i>
|
||||
Delete all
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
<div class="list">
|
||||
<div class="nothing">Nothing to show</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator accountSeparator"></div>
|
||||
<div class="psas">
|
||||
|
@ -35,7 +37,9 @@
|
|||
<i class="fas fa-bullhorn"></i>
|
||||
Announcements
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
<div class="list">
|
||||
<div class="nothing">Nothing to show</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator"></div>
|
||||
<div class="notificationHistory">
|
||||
|
@ -43,7 +47,9 @@
|
|||
<i class="fas fa-comment-alt"></i>
|
||||
Notifications
|
||||
</div>
|
||||
<div class="list"><div class="nothing">Nothing to show</div></div>
|
||||
<div class="list">
|
||||
<div class="nothing">Nothing to show</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -553,35 +559,79 @@
|
|||
</div>
|
||||
<div id="wordFilterPopupWrapper" class="popupWrapper hidden">
|
||||
<div id="wordFilterPopup">
|
||||
<div class="group">
|
||||
<div class="title">language</div>
|
||||
<select class="languageInput" class=""></select>
|
||||
<div class="top">
|
||||
<div class="group">
|
||||
<div class="title">language</div>
|
||||
<select class="languageInput" class=""></select>
|
||||
</div>
|
||||
<div class="tip">
|
||||
You can manually filter words by length, words or characters (separated
|
||||
by spaces) on the left side. On the right side you can generate filters
|
||||
based on a preset and selected layout.
|
||||
</div>
|
||||
</div>
|
||||
<div class="group lengthgrid">
|
||||
<div class="title">min length</div>
|
||||
<div class="title">max length</div>
|
||||
<input class="wordLength wordMinInput" autocomplete="off" type="number" />
|
||||
<input class="wordLength wordMaxInput" autocomplete="off" type="number" />
|
||||
<div class="leftSide">
|
||||
<div class="group lengthgrid">
|
||||
<div class="title">min length</div>
|
||||
<div class="title">max length</div>
|
||||
|
||||
<input
|
||||
class="wordLength wordMinInput"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
/>
|
||||
<input
|
||||
class="wordLength wordMaxInput"
|
||||
autocomplete="off"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="title">include</div>
|
||||
<input
|
||||
class="wordIncludeInput"
|
||||
id="wordIncludeInput"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="title">exclude</div>
|
||||
<input
|
||||
class="wordExcludeInput"
|
||||
id="wordExcludeInput"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
<!-- <div class="tip">
|
||||
Use the above filters to include and exclude words or characters
|
||||
(separated by spaces)
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="title">include</div>
|
||||
<input class="wordIncludeInput" autocomplete="off" />
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="rightSide">
|
||||
<div class="group">
|
||||
<div class="title">presets</div>
|
||||
<select class="presetInput" class=""></select>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="title">layout</div>
|
||||
<select class="layoutInput"></select>
|
||||
</div>
|
||||
<!-- <div class="tip">Use the dropdowns above to generate presets</div> -->
|
||||
<div class="button generateButton">generate</div>
|
||||
</div>
|
||||
<div class="group">
|
||||
<div class="title">exclude</div>
|
||||
<input class="wordExcludeInput" autocomplete="off" />
|
||||
|
||||
<div class="bottom">
|
||||
<div class="tip">
|
||||
"Set" replaces the current custom word list with the filter result,
|
||||
"Add" appends the filter result to the current custom word list
|
||||
</div>
|
||||
<i class="fas fa-fw fa-spin fa-circle-notch hidden loadingIndicator"></i>
|
||||
<div class="button setButton">set</div>
|
||||
<div class="button addButton">add</div>
|
||||
</div>
|
||||
<div class="tip">
|
||||
Use the above filters to include and exclude words or characters
|
||||
(separated by spaces)
|
||||
</div>
|
||||
<div class="tip">
|
||||
"Set" replaces the current custom word list with the filter result, "Add"
|
||||
appends the filter result to the current custom word list
|
||||
</div>
|
||||
<i class="fas fa-fw fa-spin fa-circle-notch hidden loadingIndicator"></i>
|
||||
<div class="button" id="set">set</div>
|
||||
<div class="button">add</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="googleSignUpPopupWrapper" class="popupWrapper hidden">
|
||||
|
|
Loading…
Add table
Reference in a new issue