refactor(ape keys modal): use new modal system

This commit is contained in:
Miodec 2024-03-24 23:01:33 +01:00
parent 7f5e3aa73e
commit 6f75abef70
6 changed files with 180 additions and 196 deletions

View file

@ -689,14 +689,14 @@
<button>submit</button>
</div>
</dialog>
<div id="apeKeysPopupWrapper" class="hidden popupWrapper">
<div id="apeKeysPopup" mode="">
<dialog id="apeKeysModal" class="hidden modalWrapper">
<div class="modal">
<div class="top">
<div class="title">Ape Keys</div>
<div class="button generateApeKey">
<button class="generateApeKey">
<i class="fas fa-plus"></i>
Generate new key
</div>
</button>
</div>
<table>
<thead>
@ -712,7 +712,7 @@
<tbody></tbody>
</table>
</div>
</div>
</dialog>
<dialog id="quoteReportModal" class="modalWrapper hidden">
<div class="modal">
<div class="title">Report a quote</div>

View file

@ -932,108 +932,99 @@
}
}
}
#apeKeysModal {
.modal {
max-width: 1000px;
#apeKeysPopup {
background: var(--bg-color);
border-radius: var(--roundness);
padding: 2rem;
display: grid;
gap: 1rem;
width: 1000px;
max-width: calc(100vw - 4rem);
// height: 100%;
// max-height: 40rem;
min-height: 18rem;
overflow-y: scroll;
grid-template-rows: max-content auto;
align-items: baseline;
gap: 1rem;
grid-template-rows: max-content auto;
align-items: baseline;
.top {
display: grid;
grid-template-columns: 1fr auto;
.title {
font-size: 1.5rem;
color: var(--sub-color);
}
.button {
padding: 0.4rem 2rem;
}
}
.textButton {
justify-content: center;
}
.keyButtons {
display: grid;
grid-auto-flow: column;
gap: 1rem;
.button {
width: 3rem;
}
}
table {
width: 100%;
border-spacing: 0;
border-collapse: collapse;
tr td:first-child {
text-align: center;
}
tr.me {
td {
color: var(--main-color);
// font-weight: 900;
.top {
display: grid;
grid-template-columns: 1fr auto;
.title {
font-size: 1.5rem;
color: var(--sub-color);
}
button {
padding: 0.5em 2em;
}
}
td {
padding: 0.5rem 0.5rem;
.textButton {
justify-content: center;
}
thead {
color: var(--sub-color);
font-size: 0.75rem;
.keyButtons {
display: grid;
grid-auto-flow: column;
gap: 1rem;
.button {
width: 3rem;
}
}
table {
width: 100%;
border-spacing: 0;
border-collapse: collapse;
tr td:first-child {
text-align: center;
}
tr.me {
td {
color: var(--main-color);
// font-weight: 900;
}
}
td {
padding: 0.5rem;
background: var(--bg-color);
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 99;
padding: 0.5rem 0.5rem;
}
}
tbody {
color: var(--text-color);
thead {
color: var(--sub-color);
font-size: 0.75rem;
tr:nth-child(odd) td {
background: var(--sub-alt-color);
td {
padding: 0.5rem;
background: var(--bg-color);
position: -webkit-sticky;
position: sticky;
top: 0;
z-index: 99;
}
}
}
tfoot {
td {
padding: 1rem 0.5rem;
position: -webkit-sticky;
position: sticky;
bottom: -5px;
background: var(--bg-color);
color: var(--main-color);
z-index: 4;
}
}
tbody {
color: var(--text-color);
tr {
td:first-child {
padding-left: 1rem;
tr:nth-child(odd) td {
background: var(--sub-alt-color);
}
}
td:last-child {
padding-right: 1rem;
tfoot {
td {
padding: 1rem 0.5rem;
position: -webkit-sticky;
position: sticky;
bottom: -5px;
background: var(--bg-color);
color: var(--main-color);
z-index: 4;
}
}
tr {
td:first-child {
padding-left: 1rem;
}
td:last-child {
padding-right: 1rem;
}
}
}
}

View file

@ -3,6 +3,7 @@ import * as CookiesModal from "../modals/cookies";
import * as StreakHourOffsetModal from "../modals/streak-hour-offset";
import * as EditPresetPopup from "../modals/edit-preset";
import * as EditTagPopup from "../modals/edit-tag";
import * as ApeKeysModal from "../modals/ape-keys";
import * as Notifications from "../elements/notifications";
@ -131,3 +132,9 @@ settingsPage?.querySelector(".section.tags")?.addEventListener("click", (e) => {
EditTagPopup.show("remove", tagid, name);
}
});
settingsPage
?.querySelector(".section.apeKeys #showApeKeysPopup")
?.addEventListener("click", () => {
void ApeKeysModal.show();
});

View file

@ -3,13 +3,11 @@ import * as Loader from "../elements/loader";
import * as Notifications from "../elements/notifications";
import format from "date-fns/format";
import * as ConnectionState from "../states/connection";
import * as Skeleton from "../utils/skeleton";
import { isPopupVisible } from "../utils/misc";
import AnimatedModal, { ShowOptions } from "../utils/animated-modal";
import { showPopup } from "../popups/simple-popups";
let apeKeys: Ape.ApeKeys.GetApeKeys | null = {};
const wrapperId = "apeKeysPopupWrapper";
async function getData(): Promise<void> {
Loader.show();
const response = await Ape.apeKeys.get();
@ -26,7 +24,7 @@ async function getData(): Promise<void> {
function refreshList(): void {
const data = apeKeys;
if (data === undefined || data === null) return;
const table = $("#apeKeysPopupWrapper table tbody");
const table = $("#apeKeysModal table tbody");
table.empty();
const apeKeyIds = Object.keys(data);
if (apeKeyIds.length === 0) {
@ -40,15 +38,15 @@ function refreshList(): void {
table.append(`
<tr keyId="${apeKeyId}">
<td>
<div class="textButton">
<button class="textButton toggleActive">
${
key.enabled
? `<i class="fas fa-fw fa-check-square"></i>`
: `<i class="far fa-fw fa-square"></i>`
}
</div>
</button>
</td>
<td>${key.name}</td>
<td onClick=${console.log(key)}>${key.name}</td>
<td>${format(new Date(key.createdOn), "dd MMM yyyy HH:mm")}</td>
<td>${format(new Date(key.modifiedOn), "dd MMM yyyy HH:mm")}</td>
<td>${
@ -58,81 +56,59 @@ function refreshList(): void {
}</td>
<td>
<div class="keyButtons">
<div class="button edit">
<button class="editButton">
<i class="fas fa-fw fa-pen"></i>
</div>
<div class="button delete">
</button>
<button class="deleteButton">
<i class="fas fa-fw fa-trash-alt"></i>
</div>
</button>
</div>
</td>
</tr>
`);
});
}
function hide(): void {
if (isPopupVisible(wrapperId)) {
$("#apeKeysPopupWrapper")
.stop(true, true)
.css("opacity", 1)
.animate(
{
opacity: 0,
},
125,
() => {
$("#apeKeysPopupWrapper").addClass("hidden");
Skeleton.remove(wrapperId);
}
);
for (const tr of table.find("tr")) {
const keyid = tr.getAttribute("keyid") as string;
tr.querySelector("button.deleteButton")?.addEventListener("click", (e) => {
showPopup("deleteApeKey", [keyid], {
modalChain: modal,
});
});
tr.querySelector("button.editButton")?.addEventListener("click", (e) => {
showPopup("editApeKey", [keyid], {
modalChain: modal,
});
});
tr.querySelector("button.toggleActive")?.addEventListener("click", (e) => {
void toggleActiveKey(keyid);
});
}
}
// function hide(clearModalChain = false): void {
// void modal.hide({
// clearModalChain,
// });
// }
//show the popup
export async function show(): Promise<void> {
export async function show(showOptions?: ShowOptions): Promise<void> {
if (!ConnectionState.get()) {
Notifications.add("You are offline", 0, {
duration: 2,
});
return;
}
Skeleton.append(wrapperId, "popups");
if (!isPopupVisible(wrapperId)) {
await getData();
refreshList();
$("#apeKeysPopupWrapper")
.stop(true, true)
.css("opacity", 0)
.removeClass("hidden")
.animate(
{
opacity: 1,
},
125,
() => {
$("#apeKeysPopup textarea").trigger("focus").trigger("select");
}
);
}
void modal.show({
...showOptions,
beforeAnimation: async () => {
await getData();
refreshList();
},
});
}
$("#apeKeysPopupWrapper").on("mousedown", (e) => {
if ($(e.target).attr("id") === "apeKeysPopupWrapper") {
hide();
}
});
$("#apeKeysPopup .generateApeKey").on("click", () => {
hide();
});
$("#popups").on("click", "#apeKeysPopup table .keyButtons .button", () => {
hide();
});
$("#popups").on("click", "#apeKeysPopup table .textButton", async (e) => {
const keyId = $(e.target).closest("tr").attr("keyId") as string;
async function toggleActiveKey(keyId: string): Promise<void> {
const key = apeKeys?.[keyId];
if (!key || apeKeys === undefined) return;
Loader.show();
@ -148,13 +124,19 @@ $("#popups").on("click", "#apeKeysPopup table .textButton", async (e) => {
} else {
Notifications.add("Key inactive", 1);
}
});
}
$(document).on("keydown", (event) => {
if (event.key === "Escape" && isPopupVisible(wrapperId)) {
hide();
event.preventDefault();
}
});
async function setup(modalEl: HTMLElement): Promise<void> {
modalEl
.querySelector(".generateApeKey")
?.addEventListener("click", async () => {
showPopup("generateApeKey", [], {
modalChain: modal,
});
});
}
Skeleton.save(wrapperId);
const modal = new AnimatedModal({
dialogId: "apeKeysModal",
setup,
});

View file

@ -11,7 +11,6 @@ import * as Notifications from "../elements/notifications";
import * as ImportExportSettingsModal from "../modals/import-export-settings";
import * as ConfigEvent from "../observables/config-event";
import * as ActivePage from "../states/active-page";
import * as ApeKeysPopup from "../popups/ape-keys-popup";
import Page from "./page";
import { getAuthenticatedUser, isAuthenticated } from "../firebase";
import Ape from "../ape";
@ -1141,10 +1140,6 @@ $(".pageSettings .sectionGroupTitle").on("click", (e) => {
toggleSettingsGroup($(e.currentTarget).attr("group") as string);
});
$(".pageSettings .section.apeKeys #showApeKeysPopup").on("click", () => {
void ApeKeysPopup.show();
});
$(
".pageSettings .section[data-config-name='customBackgroundSize'] .inputAndButton button.save"
).on("click", () => {

View file

@ -5,7 +5,6 @@ import * as UpdateConfig from "../config";
import * as Loader from "../elements/loader";
import * as Notifications from "../elements/notifications";
import * as Settings from "../pages/settings";
import * as ApeKeysPopup from "../popups/ape-keys-popup";
import * as ThemePicker from "../settings/theme-picker";
import * as CustomText from "../test/custom-text";
import * as SavedTextsPopup from "./saved-texts-popup";
@ -30,7 +29,10 @@ import {
} from "../utils/misc";
import * as CustomTextState from "../states/custom-text-name";
import * as ThemeController from "../controllers/theme-controller";
import AnimatedModal, { ShowOptions } from "../utils/animated-modal";
import AnimatedModal, {
HideOptions,
ShowOptions,
} from "../utils/animated-modal";
type Input = {
placeholder?: string;
@ -48,6 +50,7 @@ type ExecReturn = {
message: string;
showNotification?: false;
notificationOptions?: MonkeyTypes.AddNotificationOptions;
hideOptions?: HideOptions;
afterHide?: () => void;
};
@ -117,6 +120,7 @@ type SimplePopupOptions = {
beforeShowFn?: (thisPopup: SimplePopup) => void;
canClose?: boolean;
onlineOnly?: boolean;
hideCallsExec?: boolean;
};
const modal = new AnimatedModal({
@ -150,6 +154,7 @@ class SimplePopup {
beforeShowFn: ((thisPopup: SimplePopup) => void) | undefined;
canClose: boolean;
onlineOnly: boolean;
hideCallsExec: boolean;
constructor(options: SimplePopupOptions) {
this.parameters = [];
this.id = options.id;
@ -165,6 +170,7 @@ class SimplePopup {
this.beforeShowFn = options.beforeShowFn;
this.canClose = options.canClose ?? true;
this.onlineOnly = options.onlineOnly ?? false;
this.hideCallsExec = options.hideCallsExec ?? false;
}
reset(): void {
this.element.innerHTML = `
@ -306,7 +312,7 @@ class SimplePopup {
Notifications.add(res.message, res.status, res.notificationOptions);
}
if (res.status === 1) {
void this.hide().then(() => {
void this.hide(true, res.hideOptions).then(() => {
if (res.afterHide) {
res.afterHide();
}
@ -348,10 +354,14 @@ class SimplePopup {
});
}
async hide(): Promise<void> {
async hide(callerIsExec?: boolean, hideOptions?: HideOptions): Promise<void> {
if (!this.canClose) return;
activePopup = null;
await modal.hide();
if (this.hideCallsExec && !callerIsExec) {
this.exec();
} else {
activePopup = null;
await modal.hide(hideOptions);
}
}
}
@ -1211,11 +1221,19 @@ list.generateApeKey = new SimplePopup({
//if response is 200 data is guaranteed to not be null
const data = response.data as Ape.ApeKeys.GenerateApeKey;
const modalChain = modal.getPreviousModalInChain();
return {
status: 1,
message: "Key generated",
hideOptions: {
clearModalChain: true,
animationMode: "modalOnly",
},
afterHide: (): void => {
showPopup("viewApeKey", [data.apeKey]);
showPopup("viewApeKey", [data.apeKey], {
modalChain,
animationMode: "modalOnly",
});
},
};
},
@ -1235,11 +1253,15 @@ list.viewApeKey = new SimplePopup({
],
text: "This is your new Ape Key. Please keep it safe. You will only see it once!",
buttonText: "close",
hideCallsExec: true,
execFn: async (_thisPopup): Promise<ExecReturn> => {
void ApeKeysPopup.show();
return {
status: 1,
message: "Key generated",
showNotification: false,
hideOptions: {
clearModalChain: true,
},
};
},
beforeInitFn: (_thisPopup): void => {
@ -1273,11 +1295,12 @@ list.deleteApeKey = new SimplePopup({
};
}
void ApeKeysPopup.show();
return {
status: 1,
message: "Key deleted",
hideOptions: {
clearModalChain: true,
},
};
},
});
@ -1304,12 +1327,12 @@ list.editApeKey = new SimplePopup({
message: "Failed to update key: " + response.message,
};
}
void ApeKeysPopup.show();
return {
status: 1,
message: "Key updated",
hideOptions: {
clearModalChain: true,
},
};
},
});
@ -1526,7 +1549,7 @@ function isUsingPasswordAuthentication(): boolean {
);
}
function showPopup(
export function showPopup(
key: PopupKey,
showParams = [] as string[],
showOptions: ShowOptions = {}
@ -1603,10 +1626,6 @@ $(".pageSettings #optOutOfLeaderboardsButton").on("click", () => {
showPopup("optOutOfLeaderboards");
});
$("#popups").on("click", "#apeKeysPopup .generateApeKey", () => {
showPopup("generateApeKey");
});
$(".pageSettings").on(
"click",
".section.themes .customTheme .delButton",
@ -1654,16 +1673,6 @@ $("#popups").on(
}
);
$("#popups").on("click", "#apeKeysPopup table tbody tr .button.delete", (e) => {
const keyId = $(e.target).closest("tr").attr("keyId") as string;
showPopup("deleteApeKey", [keyId]);
});
$("#popups").on("click", "#apeKeysPopup table tbody tr .button.edit", (e) => {
const keyId = $(e.target).closest("tr").attr("keyId") as string;
showPopup("editApeKey", [keyId]);
});
$(".pageSettings").on(
"click",
".section[data-config-name='fontFamily'] button[data-config-value='custom']",