diff --git a/functions/index.js b/functions/index.js index be146432f..da364e40f 100644 --- a/functions/index.js +++ b/functions/index.js @@ -1627,7 +1627,7 @@ function updateDiscordRole(discordId, wpm) { }); } -function isTagValid(name) { +function isTagPresetNameValid(name) { if (name === null || name === undefined || name === "") return false; if (name.length > 16) return false; return /^[0-9a-zA-Z_.-]+$/.test(name); @@ -1635,7 +1635,7 @@ function isTagValid(name) { exports.addTag = functions.https.onCall((request, response) => { try { - if (!isTagValid(request.name)) { + if (!isTagPresetNameValid(request.name)) { return { resultCode: -1 }; } else { return db @@ -1665,7 +1665,7 @@ exports.addTag = functions.https.onCall((request, response) => { exports.editTag = functions.https.onCall((request, response) => { try { - if (!isTagValid(request.name)) { + if (!isTagPresetNameValid(request.name)) { return { resultCode: -1 }; } else { return db @@ -1765,7 +1765,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { if (request.uid === undefined || request.obj === undefined) { console.error(`error saving config for ${request.uid} - missing input`); return { - returnCode: -1, + resultCode: -1, message: "Missing input", }; } @@ -1807,7 +1807,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { )}` ); return { - returnCode: -1, + resultCode: -1, message: "Bad input. " + errorMessage, }; } @@ -1823,7 +1823,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { ) .then((e) => { return { - returnCode: 1, + resultCode: 1, message: "Saved", }; }) @@ -1832,7 +1832,7 @@ exports.saveConfig = functions.https.onCall((request, response) => { `error saving config to DB for ${request.uid} - ${e.message}` ); return { - returnCode: -1, + resultCode: -1, message: e.message, }; }); @@ -1845,6 +1845,151 @@ exports.saveConfig = functions.https.onCall((request, response) => { } }); +exports.addPreset = functions.https.onCall(async (request, response) => { + try { + if (!isTagPresetNameValid(request.obj.name)) { + return { resultCode: -1 }; + } else if (request.uid === undefined || request.obj === undefined) { + console.error(`error saving config for ${request.uid} - missing input`); + return { + resultCode: -1, + message: "Missing input", + }; + } else { + let config = request.obj.config; + let errorMessage = ""; + let err = false; + Object.keys(config).forEach((key) => { + if (err) return; + if (!isConfigKeyValid(key)) { + err = true; + console.error(`${key} failed regex check`); + errorMessage = `${key} failed regex check`; + } + if (err) return; + if (key === "resultFilters") return; + if (key === "customBackground") return; + let val = config[key]; + if (Array.isArray(val)) { + val.forEach((valarr) => { + if (!isConfigKeyValid(valarr)) { + err = true; + console.error(`${key}: ${valarr} failed regex check`); + errorMessage = `${key}: ${valarr} failed regex check`; + } + }); + } else { + if (!isConfigKeyValid(val)) { + err = true; + console.error(`${key}: ${val} failed regex check`); + errorMessage = `${key}: ${val} failed regex check`; + } + } + }); + if (err) { + console.error( + `error adding preset for ${ + request.uid + } - bad input - ${JSON.stringify(request.obj)}` + ); + return { + resultCode: -1, + message: "Bad input. " + errorMessage, + }; + } + + let presets = await db.collection(`users/${request.uid}/presets`).get(); + if (presets.docs.length >= 10) { + return { + resultCode: -2, + message: "Preset limit", + }; + } + + return db + .collection(`users/${request.uid}/presets`) + .add(request.obj) + .then((e) => { + return { + resultCode: 1, + message: "Saved", + id: e.id, + }; + }) + .catch((e) => { + console.error( + `error adding preset to DB for ${request.uid} - ${e.message}` + ); + return { + resultCode: -1, + message: e.message, + }; + }); + } + } catch (e) { + console.error(`error adding preset for ${request.uid} - ${e}`); + return { + resultCode: -999, + message: e, + }; + } +}); + +exports.editPreset = functions.https.onCall((request, response) => { + try { + if (!isTagPresetNameValid(request.name)) { + return { resultCode: -1 }; + } else { + return db + .collection(`users/${request.uid}/presets`) + .doc(request.presetid) + .set({ + config: request.config, + name: request.name, + }) + .then((e) => { + console.log(`user ${request.uid} updated a preset: ${request.name}`); + return { + resultCode: 1, + }; + }) + .catch((e) => { + console.error( + `error while updating preset for user ${request.uid}: ${e.message}` + ); + return { resultCode: -999, message: e.message }; + }); + } + } catch (e) { + console.error(`error updating preset for ${request.uid} - ${e}`); + return { resultCode: -999, message: e.message }; + } +}); + +exports.removePreset = functions.https.onCall((request, response) => { + try { + return db + .collection(`users/${request.uid}/presets`) + .doc(request.presetid) + .delete() + .then((e) => { + console.log(`user ${request.uid} deleted a tag`); + return { + resultCode: 1, + }; + }) + .catch((e) => { + console.error( + `error deleting tag for user ${request.uid}: ${e.message}` + ); + return { resultCode: -999 }; + }); + } catch (e) { + console.error(`error deleting tag for ${request.uid} - ${e}`); + return { resultCode: -999 }; + } +}); + // exports.saveLbMemory = functions.https.onCall((request, response) => { // try { // if (request.uid === undefined || request.obj === undefined) { diff --git a/gulpfile.js b/gulpfile.js index c6bc34ee3..6826f1e3b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -96,6 +96,7 @@ const refactoredSrc = [ "./src/js/theme-controller.js", "./src/js/config.js", "./src/js/tag-controller.js", + "./src/js/preset-controller.js", "./src/js/ui.js", "./src/js/commandline.js", "./src/js/commandline-lists.js", @@ -131,6 +132,7 @@ const refactoredSrc = [ "./src/js/popups/word-filter-popup.js", "./src/js/popups/result-tags-popup.js", "./src/js/popups/edit-tags-popup.js", + "./src/js/popups/edit-preset-popup.js", "./src/js/popups/custom-theme-popup.js", "./src/js/popups/import-settings-popup.js", "./src/js/popups/custom-background-filter.js", diff --git a/src/js/cloud-functions.js b/src/js/cloud-functions.js index 6bf8a2108..9dde1d1f8 100644 --- a/src/js/cloud-functions.js +++ b/src/js/cloud-functions.js @@ -8,6 +8,9 @@ export const updateResultTags = firebase .functions() .httpsCallable("updateResultTags"); export const saveConfig = firebase.functions().httpsCallable("saveConfig"); +export const addPreset = firebase.functions().httpsCallable("addPreset"); +export const editPreset = firebase.functions().httpsCallable("editPreset"); +export const removePreset = firebase.functions().httpsCallable("removePreset"); export const generatePairingCode = firebase .functions() .httpsCallable("generatePairingCode"); diff --git a/src/js/commandline-lists.js b/src/js/commandline-lists.js index 2ed4bfe10..1ca23ced5 100644 --- a/src/js/commandline-lists.js +++ b/src/js/commandline-lists.js @@ -13,6 +13,7 @@ import * as TestUI from "./test-ui"; import * as TestLogic from "./test-logic"; import * as Funbox from "./funbox"; import * as TagController from "./tag-controller"; +import * as PresetController from "./preset-controller"; import * as Commandline from "./commandline"; import * as CustomText from "./custom-text"; @@ -241,6 +242,30 @@ export function updateTagCommands() { } } +let commandsPresets = { + title: "Apply preset...", + list: [], +}; + +export function updatePresetCommands() { + if (DB.getSnapshot().presets.length > 0) { + commandsPresets.list = []; + + DB.getSnapshot().presets.forEach((preset) => { + let dis = preset.name; + + commandsPresets.list.push({ + id: "applyPreset" + preset.id, + display: dis, + exec: () => { + PresetController.apply(preset.id); + TestUI.updateModesNotice(); + }, + }); + }); + } +} + let commandsRepeatQuotes = { title: "Change repeat quotes...", list: [ @@ -1320,6 +1345,17 @@ export let defaultCommands = { Commandline.show(); }, }, + { + visible: false, + id: "applyPreset", + display: "Apply preset...", + subgroup: true, + exec: () => { + updatePresetCommands(); + current.push(commandsPresets); + Commandline.show(); + }, + }, { id: "changeConfidenceMode", display: "Change confidence mode...", diff --git a/src/js/config.js b/src/js/config.js index f43807ff3..cf396d15b 100644 --- a/src/js/config.js +++ b/src/js/config.js @@ -1743,6 +1743,18 @@ export function loadFromLocalStorage() { loadDone(); } +export function getConfigChanges() { + let configChanges = {}; + Object.keys(config) + .filter((key) => { + return config[key] != defaultConfig[key]; + }) + .forEach((key) => { + configChanges[key] = config[key]; + }); + return configChanges; +} + export function setConfig(newConfig) { config = newConfig; } diff --git a/src/js/db.js b/src/js/db.js index 4ba0e7ba0..3dbd8168c 100644 --- a/src/js/db.js +++ b/src/js/db.js @@ -33,6 +33,7 @@ export async function initSnapshot() { results: undefined, personalBests: {}, name: undefined, + presets: [], tags: [], favouriteThemes: [], refactored: false, @@ -81,6 +82,29 @@ export async function initSnapshot() { .catch((e) => { throw e; }); + await db + .collection(`users/${user.uid}/presets/`) + .get() + .then((data) => { + data.docs.forEach((doc) => { + // console.log(doc); + let preset = doc.data(); + preset.id = doc.id; + snap.presets.push(preset); + }); + snap.presets = snap.presets.sort((a, b) => { + if (a.name > b.name) { + return 1; + } else if (a.name < b.name) { + return -1; + } else { + return 0; + } + }); + }) + .catch((e) => { + throw e; + }); await db .collection("users") .doc(user.uid) @@ -119,6 +143,7 @@ export async function initSnapshot() { .catch((e) => { throw e; }); + // console.log(snap.presets); dbSnapshot = snap; } catch (e) { console.error(e); @@ -486,7 +511,7 @@ export async function saveConfig(config) { obj: config, }).then((d) => { AccountButton.loading(false); - if (d.data.returnCode !== 1) { + if (d.data.resultCode !== 1) { Notifications.add(`Error saving config to DB! ${d.data.message}`, 4000); } return; diff --git a/src/js/popups/custom-text-popup.js b/src/js/popups/custom-text-popup.js index a50d8a17d..bac873f4d 100644 --- a/src/js/popups/custom-text-popup.js +++ b/src/js/popups/custom-text-popup.js @@ -10,7 +10,7 @@ let popup = "#customTextPopup"; export function show() { if ($(wrapper).hasClass("hidden")) { - if ($(`${popup} .check input`).prop("checked")) { + if ($(`${popup} .checkbox input`).prop("checked")) { $(`${popup} .inputs .randomInputFields`).removeClass("hidden"); } else { $(`${popup} .inputs .randomInputFields`).addClass("hidden"); @@ -60,8 +60,8 @@ $(wrapper).mousedown((e) => { } }); -$(`${popup} .inputs .check input`).change(() => { - if ($(`${popup} .check input`).prop("checked")) { +$(`${popup} .inputs .checkbox input`).change(() => { + if ($(`${popup} .checkbox input`).prop("checked")) { $(`${popup} .inputs .randomInputFields`).removeClass("hidden"); } else { $(`${popup} .inputs .randomInputFields`).addClass("hidden"); @@ -106,11 +106,11 @@ $("#customTextPopup .apply").click(() => { CustomText.setTime(parseInt($("#customTextPopup .time input").val())); CustomText.setIsWordRandom( - $("#customTextPopup .check input").prop("checked") && + $("#customTextPopup .checkbox input").prop("checked") && !isNaN(CustomText.word) ); CustomText.setIsTimeRandom( - $("#customTextPopup .check input").prop("checked") && + $("#customTextPopup .checkbox input").prop("checked") && !isNaN(CustomText.time) ); diff --git a/src/js/popups/edit-preset-popup.js b/src/js/popups/edit-preset-popup.js new file mode 100644 index 000000000..675058641 --- /dev/null +++ b/src/js/popups/edit-preset-popup.js @@ -0,0 +1,160 @@ +import * as Loader from "./loader"; +import * as DB from "./db"; +import * as CloudFunctions from "./cloud-functions"; +import * as Notifications from "./notifications"; +import * as Settings from "./settings"; +import * as Config from "./config"; + +export function show(action, id, name) { + if (action === "add") { + $("#presetWrapper #presetEdit").attr("action", "add"); + $("#presetWrapper #presetEdit .title").html("Create new preset"); + $("#presetWrapper #presetEdit .button").html(``); + $("#presetWrapper #presetEdit input.text").val(""); + $("#presetWrapper #presetEdit input.text").removeClass("hidden"); + $("#presetWrapper #presetEdit label").addClass("hidden"); + } else if (action === "edit") { + $("#presetWrapper #presetEdit").attr("action", "edit"); + $("#presetWrapper #presetEdit").attr("presetid", id); + $("#presetWrapper #presetEdit .title").html("Edit preset"); + $("#presetWrapper #presetEdit .button").html(``); + $("#presetWrapper #presetEdit input.text").val(name); + $("#presetWrapper #presetEdit input.text").removeClass("hidden"); + $("#presetWrapper #presetEdit label input").prop("checked", false); + $("#presetWrapper #presetEdit label").removeClass("hidden"); + } else if (action === "remove") { + $("#presetWrapper #presetEdit").attr("action", "remove"); + $("#presetWrapper #presetEdit").attr("presetid", id); + $("#presetWrapper #presetEdit .title").html("Remove preset " + name); + $("#presetWrapper #presetEdit .button").html( + `` + ); + $("#presetWrapper #presetEdit input.text").addClass("hidden"); + $("#presetWrapper #presetEdit label").addClass("hidden"); + } + + if ($("#presetWrapper").hasClass("hidden")) { + $("#presetWrapper") + .stop(true, true) + .css("opacity", 0) + .removeClass("hidden") + .animate({ opacity: 1 }, 100, () => { + $("#presetWrapper #presetEdit input").focus(); + }); + } +} + +function hide() { + if (!$("#presetWrapper").hasClass("hidden")) { + $("#presetWrapper #presetEdit").attr("action", ""); + $("#presetWrapper #presetEdit").attr("tagid", ""); + $("#presetWrapper") + .stop(true, true) + .css("opacity", 1) + .animate( + { + opacity: 0, + }, + 100, + () => { + $("#presetWrapper").addClass("hidden"); + } + ); + } +} + +function apply() { + let action = $("#presetWrapper #presetEdit").attr("action"); + let inputVal = $("#presetWrapper #presetEdit input").val(); + let presetid = $("#presetWrapper #presetEdit").attr("presetid"); + let configChanges = Config.getConfigChanges(); + hide(); + if (action === "add") { + Loader.show(); + CloudFunctions.addPreset({ + uid: firebase.auth().currentUser.uid, + obj: { + name: inputVal, + config: configChanges, + }, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Preset added", 1, 2); + DB.getSnapshot().presets.push({ + name: inputVal, + config: configChanges, + id: e.data.id, + }); + Settings.update(); + } else if (status === -1) { + Notifications.add("Invalid preset name", 0); + } else if (status === -2) { + Notifications.add("You can't add any more presets", 0); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } else if (action === "edit") { + Loader.show(); + CloudFunctions.editPreset({ + uid: firebase.auth().currentUser.uid, + name: inputVal, + presetid, + config: configChanges, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Preset updated", 1); + let preset = DB.getSnapshot().presets.filter( + (preset) => preset.id == presetid + )[0]; + preset.name = inputVal; + preset.config = configChanges; + Settings.update(); + } else if (status === -1) { + Notifications.add("Invalid preset name", 0); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } else if (action === "remove") { + Loader.show(); + CloudFunctions.removePreset({ + uid: firebase.auth().currentUser.uid, + presetid, + }).then((e) => { + Loader.hide(); + let status = e.data.resultCode; + if (status === 1) { + Notifications.add("Preset removed", 1); + DB.getSnapshot().presets.forEach((preset, index) => { + if (preset.id === presetid) { + DB.getSnapshot().presets.splice(index, 1); + } + }); + Settings.update(); + } else if (status < -1) { + Notifications.add("Unknown error: " + e.data.message, -1); + } + }); + } +} + +$("#presetWrapper").click((e) => { + if ($(e.target).attr("id") === "presetWrapper") { + hide(); + } +}); + +$("#presetWrapper #presetEdit .button").click(() => { + apply(); +}); + +$("#presetWrapper #presetEdit input").keypress((e) => { + if (e.keyCode == 13) { + apply(); + } +}); diff --git a/src/js/popups/edit-tags-popup.js b/src/js/popups/edit-tags-popup.js index 2b33c2c2b..f71cacc30 100644 --- a/src/js/popups/edit-tags-popup.js +++ b/src/js/popups/edit-tags-popup.js @@ -59,6 +59,7 @@ function hide() { } function apply() { + // console.log(DB.getSnapshot()); let action = $("#tagsWrapper #tagsEdit").attr("action"); let inputVal = $("#tagsWrapper #tagsEdit input").val(); let tagid = $("#tagsWrapper #tagsEdit").attr("tagid"); diff --git a/src/js/preset-controller.js b/src/js/preset-controller.js new file mode 100644 index 000000000..f50f2354e --- /dev/null +++ b/src/js/preset-controller.js @@ -0,0 +1,16 @@ +import * as Config from "./config"; +import * as DB from "./db"; +import * as Notifications from "./notifications"; +import * as Settings from "./settings"; + +export function apply(id) { + // console.log(DB.getSnapshot().presets); + DB.getSnapshot().presets.forEach((preset) => { + if (preset.id == id) { + Config.apply(JSON.parse(JSON.stringify(preset.config))); + Notifications.add("Preset applied", 1, 2); + Config.saveToLocalStorage(); + Settings.update(); + } + }); +} diff --git a/src/js/settings.js b/src/js/settings.js index 138b72e27..56a446856 100644 --- a/src/js/settings.js +++ b/src/js/settings.js @@ -10,8 +10,10 @@ import * as Loader from "./loader"; import * as CloudFunctions from "./cloud-functions"; import * as Funbox from "./funbox"; import * as TagController from "./tag-controller"; +import * as PresetController from "./preset-controller"; import * as SimplePopups from "./simple-popups"; import * as EditTagsPopup from "./edit-tags-popup"; +import * as EditPresetPopup from "./edit-preset-popup"; import * as ThemePicker from "./theme-picker"; export let groups = {}; @@ -454,35 +456,18 @@ function refreshTagsSettingsSection() { if (tag.pb != undefined && tag.pb > 0) { tagPbString = `PB: ${tag.pb}`; } - if (tag.active === true) { - tagsEl.append(` + tagsEl.append(` +
+
+ +
+
${tag.name}
+
+ +
+
-
-
- -
-
${tag.name}
-
- -
-
- - `); - } else { - tagsEl.append(` - -
-
- -
-
${tag.name}
-
- -
-
- - `); - } + `); }); $(".pageSettings .section.tags").removeClass("hidden"); } else { @@ -490,10 +475,36 @@ function refreshTagsSettingsSection() { } } +function refreshPresetsSettingsSection() { + if (firebase.auth().currentUser !== null && DB.getSnapshot() !== null) { + let presetsEl = $(".pageSettings .section.presets .presetsList").empty(); + DB.getSnapshot().presets.forEach((preset) => { + presetsEl.append(` +
+
+
${preset.name}
+
+
+ +
+
+ +
+
+ + `); + }); + $(".pageSettings .section.presets").removeClass("hidden"); + } else { + $(".pageSettings .section.presets").addClass("hidden"); + } +} + export function showAccountSection() { $(`.sectionGroupTitle[group='account']`).removeClass("hidden"); $(`.settingsGroup.account`).removeClass("hidden"); refreshTagsSettingsSection(); + refreshPresetsSettingsSection(); updateDiscordSection(); } @@ -503,6 +514,7 @@ export function update() { }); refreshTagsSettingsSection(); + refreshPresetsSettingsSection(); LanguagePicker.setActiveGroup(); setActiveFunboxButton(); ThemePicker.updateActiveTab(); @@ -660,6 +672,37 @@ $(document).on("click", ".pageSettings .section.tags .addTagButton", (e) => { EditTagsPopup.show("add"); }); +$(document).on( + "click", + ".pageSettings .section.presets .addPresetButton", + (e) => { + EditPresetPopup.show("add"); + } +); + +$(document).on("click", ".pageSettings .section.presets .editButton", (e) => { + let presetid = $(e.currentTarget).parent(".preset").attr("id"); + let name = $(e.currentTarget).siblings(".button").children(".title").text(); + EditPresetPopup.show("edit", presetid, name); +}); + +$(document).on("click", ".pageSettings .section.presets .removeButton", (e) => { + let presetid = $(e.currentTarget).parent(".preset").attr("id"); + let name = $(e.currentTarget).siblings(".button").children(".title").text(); + EditPresetPopup.show("remove", presetid, name); +}); + +$(document).on( + "click", + ".pageSettings .section.presets .presetsList .preset .presetButton", + (e) => { + let target = e.currentTarget; + let presetid = $(target).parent(".preset").attr("id"); + console.log("Applying Preset"); + PresetController.apply(presetid); + } +); + $(document).on( "click", ".pageSettings .section.tags .tagsList .tag .clearPbButton", diff --git a/src/sass/style.scss b/src/sass/style.scss index e1a4f069d..8272fa511 100644 --- a/src/sass/style.scss +++ b/src/sass/style.scss @@ -499,7 +499,7 @@ a:hover { } } -#tagsWrapper { +.wrapper { width: 100%; height: 100%; background: rgba(0, 0, 0, 0.75); @@ -520,6 +520,15 @@ a:hover { gap: 1rem; overflow-y: scroll; } + + #presetEdit { + background: var(--bg-color); + border-radius: var(--roundness); + padding: 2rem; + display: grid; + gap: 1rem; + overflow-y: scroll; + } } #customTextPopupWrapper { @@ -579,71 +588,37 @@ a:hover { text-align: center; align-items: center; } + } +} - .check { - span { - display: block; - font-size: 0.76rem; - color: var(--sub-color); - margin-left: 1.5rem; - } +label.checkbox { + span { + display: block; + font-size: 0.76rem; + color: var(--sub-color); + margin-left: 1.5rem; + } - input { - margin: 0 !important; - cursor: pointer; - width: 0; - height: 0; - display: none; + input { + margin: 0 !important; + cursor: pointer; + width: 0; + height: 0; + display: none; - & ~ .customTextRandomCheckbox { - width: 12px; - height: 12px; - background: rgba(0, 0, 0, 0.1); - border-radius: 2px; - box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1); - display: inline-block; - margin: 0 0.5rem 0 0.25rem; - transition: 0.25s; - } - - &:checked ~ .customTextRandomCheckbox { - background: var(--main-color); - } - } + & ~ .customTextCheckbox { + width: 12px; + height: 12px; + background: rgba(0, 0, 0, 0.1); + border-radius: 2px; + box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1); + display: inline-block; + margin: 0 0.5rem 0 0.25rem; + transition: 0.25s; } - .typographyCheck { - grid-row: 2; - grid-column: 1/3; - span { - display: block; - font-size: 0.76rem; - color: var(--sub-color); - margin-left: 1.5rem; - } - - input { - margin: 0 !important; - cursor: pointer; - width: 0; - height: 0; - display: none; - - & ~ .customTextTypographyCheckbox { - width: 12px; - height: 12px; - background: rgba(0, 0, 0, 0.1); - border-radius: 2px; - box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1); - display: inline-block; - margin: 0 0.5rem 0 0.25rem; - transition: 0.25s; - } - - &:checked ~ .customTextTypographyCheckbox { - background: var(--main-color); - } - } + &:checked ~ .customTextCheckbox { + background: var(--main-color); } } } @@ -2619,36 +2594,6 @@ key { form { grid-area: form; - - #rememberMe { - color: var(--sub-color); - -moz-user-select: none; - user-select: none; - cursor: pointer; - - input { - margin: 0 !important; - cursor: pointer; - width: 0; - height: 0; - display: none; - - & ~ .customCheckbox { - width: 12px; - height: 12px; - background: rgba(0, 0, 0, 0.1); - border-radius: 2px; - box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.1); - display: inline-block; - margin: 0 0.5rem 0 0.25rem; - transition: 0.25s; - } - - &:checked ~ .customCheckbox { - background: var(--main-color); - } - } - } } } } @@ -3006,6 +2951,46 @@ key { } } + &.presets { + .presetsListAndButton { + grid-area: buttons; + } + + .preset { + grid-template-columns: 5fr 1fr 1fr; + margin-bottom: 0.5rem; + } + + .addPresetButton { + margin-top: 0.5rem; + color: var(--text-color); + cursor: pointer; + transition: 0.25s; + padding: 0.2rem 0.5rem; + border-radius: var(--roundness); + + background: rgba(0, 0, 0, 0.1); + text-align: center; + -webkit-user-select: none; + display: grid; + align-content: center; + height: min-content; + height: -moz-min-content; + + &.active { + background: var(--main-color); + color: var(--bg-color); + } + + &:hover, + &:focus { + color: var(--bg-color); + background: var(--text-color); + outline: none; + } + } + } + &.fontSize .buttons { grid-template-columns: 1fr 1fr 1fr 1fr; } @@ -3493,11 +3478,6 @@ key { height: -moz-min-content; line-height: 1rem; - .fas, - .far { - margin-right: 0.5rem; - } - &:hover { color: var(--bg-color); background: var(--text-color); diff --git a/static/index.html b/static/index.html index 6680bc9a6..8760e585d 100644 --- a/static/index.html +++ b/static/index.html @@ -138,9 +138,9 @@
-
-