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:
Albert 2023-02-21 16:57:31 -05:00 committed by GitHub
parent 702c36189c
commit 2b8690bf20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 275 additions and 34 deletions

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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">