General code refactoring, move Notyf code into toast.ts

This commit is contained in:
wearrrrr 2024-11-24 00:42:35 -06:00
parent 5fc3995257
commit 10ac39b46f
13 changed files with 127 additions and 136 deletions

View file

@ -13,7 +13,7 @@ module.exports = {
"no-unused-vars": "error", "no-unused-vars": "error",
"no-undef": "off", "no-undef": "off",
"prefer-const": "error", "prefer-const": "error",
"no-case-declarations": "off" "no-case-declarations": "off",
}, },
ignorePatterns: ["env.d.ts", "middleware/", "public/"], ignorePatterns: ["env.d.ts", "middleware/", "public/"],
overrides: [ overrides: [
@ -35,7 +35,7 @@ module.exports = {
extends: ["plugin:@typescript-eslint/recommended"], extends: ["plugin:@typescript-eslint/recommended"],
rules: { rules: {
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
} },
}, },
{ {
// Define the configuration for `<script>` tag. // Define the configuration for `<script>` tag.

View file

@ -25,7 +25,7 @@ if (existsSync("exempt_masqr.txt")) {
const exemptDomains = file.split("\n"); const exemptDomains = file.split("\n");
exemptDomains.forEach((domain) => { exemptDomains.forEach((domain) => {
whiteListedDomains.push(domain.trim()); whiteListedDomains.push(domain.trim());
}) });
} }
const LICENSE_SERVER_URL = "https://license.mercurywork.shop/validate?license="; const LICENSE_SERVER_URL = "https://license.mercurywork.shop/validate?license=";

View file

@ -18,7 +18,7 @@ function loadExtensionScripts() {
let extensions = request.result.filter((extension) => extension.type == "serviceWorker"); let extensions = request.result.filter((extension) => extension.type == "serviceWorker");
extensions.forEach((extension) => { extensions.forEach((extension) => {
const decoder = new TextDecoder(); const decoder = new TextDecoder();
const contents = decoder.decode(extension.script); const contents = decoder.decode(extension.scriptCopy);
eval(contents); eval(contents);

7
src/alu.d.ts vendored
View file

@ -1,11 +1,4 @@
export declare global { export declare global {
type AluStore = {
get: (key: Alu.ValidStoreKeys) => Alu.KeyObj;
set: (key: Alu.ValidStoreKeys, value: Alu.KeyObj) => void;
remove: (key: Alu.ValidStoreKeys) => void;
reset: (key: Alu.ValidStoreKeys) => void;
};
// Hacky way to not have to cast the "event" type that lib.dom has to CustomEvent, which is what we actually use. // Hacky way to not have to cast the "event" type that lib.dom has to CustomEvent, which is what we actually use.
interface Document { interface Document {
addEventListener(type: "setting-tabLoad", listener: (this: Document, ev: CustomEvent) => any, options?: boolean | AddEventListenerOptions); addEventListener(type: "setting-tabLoad", listener: (this: Document, ev: CustomEvent) => any, options?: boolean | AddEventListenerOptions);

View file

@ -7,7 +7,6 @@ const { type } = Astro.props;
type Props = { type Props = {
type: ExtType; type: ExtType;
}; };
--- ---
<div class="marketplace-icon"> <div class="marketplace-icon">

View file

@ -12,4 +12,4 @@
<img width="30px" height="30px" id="nav-close" src="/img/nav/close.svg" alt="Close Page" /> <img width="30px" height="30px" id="nav-close" src="/img/nav/close.svg" alt="Close Page" />
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<script> <script>
import IDBManager from "@components/ts/IDBManager"; import IDBManager from "@components/ts/IDBManager";
const idb = IDBManager.loadIDB("AluDB", 1) const idb = IDBManager.loadIDB("AluDB", 1);
idb.onsuccess = () => { idb.onsuccess = () => {
IDBManager.GetStore("InstalledExtensions", "readonly").getAll().onsuccess = (event) => { IDBManager.GetStore("InstalledExtensions", "readonly").getAll().onsuccess = (event) => {
@ -25,6 +25,4 @@
} }
}; };
}; };
</script> </script>

View file

@ -23,7 +23,6 @@
const decoder = new TextDecoder(); const decoder = new TextDecoder();
const style = decoder.decode(extension.scriptCopy!); const style = decoder.decode(extension.scriptCopy!);
loadStyleFromString(style); loadStyleFromString(style);
document.addEventListener("astro:after-swap", () => { document.addEventListener("astro:after-swap", () => {

View file

@ -1,83 +1,51 @@
import "notyf/notyf.min.css";
import { Notyf } from "notyf";
import marketplaceManifest from "../../json/marketplace.json"; import marketplaceManifest from "../../json/marketplace.json";
import IDBManager, { loadIDBPromise } from "./IDBManager"; import IDBManager, { loadIDBPromise } from "./IDBManager";
import Toast from "./toast";
const installButtons = document.getElementsByClassName("btn-install"); const installButtons = document.getElementsByClassName("btn-install");
const extManifest = marketplaceManifest as ExtensionMetadataJSON; const extManifest = marketplaceManifest as ExtensionMetadataJSON;
// This just makes it shorter to type const EXT_RETURN = {
interface HTMLButton extends HTMLButtonElement {} INSTALL_FAILED: -1,
INSTALL_SUCCESS: 0,
enum EXT_RETURN { ALREADY_INSTALLED: 1,
ACTION_SUCCESS = 0,
INSTALL_FAILED = -1,
ALREADY_INSTALLED = 1,
} }
Array.from(installButtons).forEach((btn) => { Array.from(installButtons).forEach((btn) => {
btn.addEventListener("click", async (event) => { btn.addEventListener("click", async (event) => {
const ele = event.target as HTMLButton; const ele = event.target as HTMLButton;
const title = ele.dataset.title; const title = ele.dataset.title;
const notification = new Notyf({
duration: 999999,
position: { x: "right", y: "bottom" },
dismissible: true,
ripple: true,
});
const installNotif = notification.success(`Installing ${title}...`);
if (ele.dataset.slug) { if (ele.dataset.slug) {
const obj = await getMarketplaceObj(ele.dataset.slug); const ext = await getMarketplaceExt(ele.dataset.slug);
installExtension(obj, ele.dataset.slug) const install = await installExtension(ext, ele.dataset.slug)
.then((ret) => { switch (install.code) {
let notifMessage: string; case EXT_RETURN.INSTALL_SUCCESS:
let timeout = 2000; Toast.success(`Installed ${title} Successfully!`);
switch (ret.code) { if (ext.type === "serviceWorker") {
case EXT_RETURN.ACTION_SUCCESS:
notifMessage = `Installed ${title} Successfully!`;
// Unregister the service worker if it's a service worker
if (obj.type === "serviceWorker") {
navigator.serviceWorker.getRegistration().then((reg) => { navigator.serviceWorker.getRegistration().then((reg) => {
if (reg) { if (reg) {
reg.unregister().then(() => { // Unregister the SW so that the installed plugin is loaded when the page is refreshed (automatically)
console.log("Service worker unregistered!"); reg.unregister();
});
} }
}); });
} }
break; break;
case EXT_RETURN.ALREADY_INSTALLED: case EXT_RETURN.ALREADY_INSTALLED:
notifMessage = `${title} is already installed!`; Toast.success(`${title} is already installed!`);
timeout = 0;
break; break;
case EXT_RETURN.INSTALL_FAILED: case EXT_RETURN.INSTALL_FAILED:
// We should NEVER get here, but just in case. Toast.error(`Failed to install ${title}!`);
notifMessage = `Failed to install ${title}!`;
break;
} }
setTimeout(() => {
notification.dismiss(installNotif);
notification.options.duration = 2000;
notification.success(notifMessage);
setTimeout(() => { setTimeout(() => {
window.location.reload(); window.location.reload();
}, 1000); }, 1500);
notification.options.duration = 999999; const btn = document.querySelector(`button[data-slug="${install.slug}"]`) as HTMLButton;
const btn = document.querySelector(`button[data-slug="${ret.slug}"]`) as HTMLButton;
setInstallBtnText(btn); setInstallBtnText(btn);
}, timeout);
})
.catch(() => {
notification.dismiss(installNotif);
notification.options.duration = 2000;
notification.error(`Failed to install ${title}!`);
notification.options.duration = 999999;
});
} }
}); });
}); });
async function getMarketplaceObj(slug: string): Promise<ExtensionMetadata> { async function getMarketplaceExt(slug: string) {
const manifest = extManifest[slug]; const manifest = extManifest[slug];
if (manifest == null) { if (manifest == null) {
throw new Error("Extension not found!"); throw new Error("Extension not found!");
@ -89,7 +57,7 @@ async function getMarketplaceObj(slug: string): Promise<ExtensionMetadata> {
return manifest; return manifest;
} }
async function installExtension(ext: ExtensionMetadata, slug: string): Promise<InstallReturn> { async function installExtension(ext: ExtensionMetadata, slug: string) {
return new Promise<InstallReturn>((resolve, reject) => { return new Promise<InstallReturn>((resolve, reject) => {
const request = IDBManager.GetIDB(); const request = IDBManager.GetIDB();
const transaction = request.transaction("InstalledExtensions", "readwrite"); const transaction = request.transaction("InstalledExtensions", "readwrite");
@ -99,18 +67,18 @@ async function installExtension(ext: ExtensionMetadata, slug: string): Promise<I
...ext, ...ext,
}; };
const slugCheck = store.get(slug); const slugCheck = store.get(slug);
slugCheck.onsuccess = async () => { slugCheck.onsuccess = () => {
if (slugCheck.result != null) { if (slugCheck.result == null) {
resolve({ code: EXT_RETURN.ALREADY_INSTALLED, slug: slug });
} else {
const addRequest = store.add(extensionObject); const addRequest = store.add(extensionObject);
addRequest.onerror = () => { addRequest.onerror = () => {
console.error(`Error installing ${slug}!`); console.error(`Error installing ${slug}!`);
reject({ code: EXT_RETURN.INSTALL_FAILED, slug: slug }); reject({ code: EXT_RETURN.INSTALL_FAILED, slug: slug });
}; };
addRequest.onsuccess = () => { addRequest.onsuccess = () => {
resolve({ code: EXT_RETURN.ACTION_SUCCESS, slug: slug }); resolve({ code: EXT_RETURN.INSTALL_SUCCESS, slug: slug });
}; };
} else {
resolve({ code: EXT_RETURN.ALREADY_INSTALLED, slug: slug });
} }
}; };
}); });
@ -122,16 +90,11 @@ function addUninstallEventListeners() {
if (!confirm("Are you sure you want to uninstall this extension?")) { if (!confirm("Are you sure you want to uninstall this extension?")) {
return; return;
} }
const uninst = await uninstallExtension((event.target as HTMLButton).dataset.uninstallSlug!); const button = event.target as HTMLButton;
const notification = new Notyf({ const uninst = await uninstallExtension(button.dataset.uninstallSlug!);
duration: 999999,
position: { x: "right", y: "bottom" },
dismissible: true,
ripple: true,
});
switch (uninst.code) { switch (uninst.code) {
case EXT_RETURN.ACTION_SUCCESS: case EXT_RETURN.INSTALL_SUCCESS:
notification.success(`Uninstalled ${uninst.title}!`); Toast.success(`Uninstalled ${uninst.title}!`);
const btn = document.querySelector(`button[data-slug="${uninst.slug}"]`) as HTMLButton; const btn = document.querySelector(`button[data-slug="${uninst.slug}"]`) as HTMLButton;
btn.disabled = false; btn.disabled = false;
btn.textContent = "Install"; btn.textContent = "Install";
@ -139,7 +102,7 @@ function addUninstallEventListeners() {
(event.target as HTMLButton).classList.add("btn-hidden"); (event.target as HTMLButton).classList.add("btn-hidden");
break; break;
case EXT_RETURN.INSTALL_FAILED: case EXT_RETURN.INSTALL_FAILED:
notification.error(`Failed to uninstall ${uninst.title}!`); Toast.error(`Failed to uninstall ${uninst.title}!`);
break; break;
} }
setTimeout(() => { setTimeout(() => {
@ -187,7 +150,7 @@ async function uninstallExtension(slug: string): Promise<InstallReturn> {
}); });
} }
}); });
resolve({ code: EXT_RETURN.ACTION_SUCCESS, slug: slug, title: ext.result.title }); resolve({ code: EXT_RETURN.INSTALL_SUCCESS, slug: slug, title: ext.result.title });
}; };
}; };
}); });

View file

@ -0,0 +1,38 @@
import "notyf/notyf.min.css";
import { Notyf, NotyfNotification } from "notyf";
export default class Toast {
private static notyf = new Notyf({
duration: 999999,
position: { x: "right", y: "bottom" },
dismissible: true,
ripple: true,
});
public static get(): Notyf {
return this.notyf;
}
public static setDuration(duration: number) {
this.notyf.options.duration = duration;
}
public static success(message: string) {
return this.notyf.success(message);
}
public static error(message: string) {
return this.notyf.error(message);
}
public static info(message: string) {
return this.notyf.open({
type: "info",
message: message,
});
}
public static dismiss(toast: NotyfNotification) {
this.notyf.dismiss(toast);
}
}

View file

@ -102,9 +102,7 @@ export const getStaticPaths = () => {
width: 80%; width: 80%;
margin: 0 auto; margin: 0 auto;
overflow: hidden; overflow: hidden;
-webkit-line-clamp: 2; height: 80px;
-webkit-box-orient: vertical;
height: 40px;
} }
.marketplace-btn-container { .marketplace-btn-container {

View file

@ -9,9 +9,8 @@ const gamesList = games as GameList;
sitemap(async ({ setSitemap }) => { sitemap(async ({ setSitemap }) => {
const gamesList = games as GameList; const gamesList = games as GameList;
const urls = Object.keys(gamesList);
setSitemap( setSitemap(
urls.map((game) => ({ Object.keys(gamesList).map((game) => ({
sitemap: true, sitemap: true,
params: { params: {
game: game, game: game,

4
src/types.d.ts vendored
View file

@ -17,8 +17,12 @@ type Extension = {
name: string; name: string;
script: string; script: string;
type: ExtType; type: ExtType;
}; };
// This just makes it shorter to type
type HTMLButton = HTMLButtonElement;
/* /*
- title: The title of the extension - title: The title of the extension
- description: A description of the extension - description: A description of the extension