General code refactoring, move Notyf code into toast.ts
This commit is contained in:
parent
5fc3995257
commit
10ac39b46f
13 changed files with 127 additions and 136 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
2
index.js
2
index.js
|
|
@ -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=";
|
||||||
|
|
|
||||||
|
|
@ -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
7
src/alu.d.ts
vendored
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ const { type } = Astro.props;
|
||||||
type Props = {
|
type Props = {
|
||||||
type: ExtType;
|
type: ExtType;
|
||||||
};
|
};
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="marketplace-icon">
|
<div class="marketplace-icon">
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
<div id="top-bar">
|
<div id="top-bar">
|
||||||
<div class="top-bar-left">
|
<div class="top-bar-left">
|
||||||
<img id="proxied-favicon" alt="favicon" />
|
<img id="proxied-favicon" alt="favicon" />
|
||||||
<span id="url-text"></span>
|
<span id="url-text"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="top-bar-right">
|
<div class="top-bar-right">
|
||||||
<div class="nav-container">
|
<div class="nav-container">
|
||||||
<img width="32px" height="32px" id="nav-backwards" src="/img/nav/backwards.svg" alt="Backward" />
|
<img width="32px" height="32px" id="nav-backwards" src="/img/nav/backwards.svg" alt="Backward" />
|
||||||
<img width="32px" height="32px" id="nav-forwards" src="/img/nav/forwards.svg" alt="Forward" />
|
<img width="32px" height="32px" id="nav-forwards" src="/img/nav/forwards.svg" alt="Forward" />
|
||||||
<img width="26px" height="28px" id="nav-reload" src="/img/nav/reload.svg" alt="Reload Page" />
|
<img width="26px" height="28px" id="nav-reload" src="/img/nav/reload.svg" alt="Reload Page" />
|
||||||
<img width="25px" height="26px" id="nav-share" src="/img/nav/share.svg" alt="Share Page" />
|
<img width="25px" height="26px" id="nav-share" src="/img/nav/share.svg" alt="Share Page" />
|
||||||
<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>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,28 @@
|
||||||
<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) => {
|
||||||
// TODO: Get rid of this ugly type assertion!!
|
// TODO: Get rid of this ugly type assertion!!
|
||||||
const result = (event.target as IDBRequest).result;
|
const result = (event.target as IDBRequest).result;
|
||||||
if (result) {
|
if (result) {
|
||||||
result.forEach((extension: ExtPageMetadata) => {
|
result.forEach((extension: ExtPageMetadata) => {
|
||||||
if (extension.type === "page") {
|
if (extension.type === "page") {
|
||||||
const decoder = new TextDecoder();
|
const decoder = new TextDecoder();
|
||||||
const script = decoder.decode(extension.scriptCopy!);
|
const script = decoder.decode(extension.scriptCopy!);
|
||||||
const scriptEl = document.createElement("script");
|
const scriptEl = document.createElement("script");
|
||||||
scriptEl.textContent = script;
|
scriptEl.textContent = script;
|
||||||
document.head.appendChild(scriptEl);
|
document.head.appendChild(scriptEl);
|
||||||
|
|
||||||
// Call extension.init if it exists
|
// Call extension.init if it exists
|
||||||
if (extension.init) {
|
if (extension.init) {
|
||||||
const init = new Function(extension.init);
|
const init = new Function(extension.init);
|
||||||
init();
|
init();
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -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", () => {
|
||||||
|
|
|
||||||
|
|
@ -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:
|
navigator.serviceWorker.getRegistration().then((reg) => {
|
||||||
notifMessage = `Installed ${title} Successfully!`;
|
if (reg) {
|
||||||
// Unregister the service worker if it's a service worker
|
// Unregister the SW so that the installed plugin is loaded when the page is refreshed (automatically)
|
||||||
if (obj.type === "serviceWorker") {
|
reg.unregister();
|
||||||
navigator.serviceWorker.getRegistration().then((reg) => {
|
|
||||||
if (reg) {
|
|
||||||
reg.unregister().then(() => {
|
|
||||||
console.log("Service worker unregistered!");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
break;
|
});
|
||||||
case EXT_RETURN.ALREADY_INSTALLED:
|
|
||||||
notifMessage = `${title} is already installed!`;
|
|
||||||
timeout = 0;
|
|
||||||
break;
|
|
||||||
case EXT_RETURN.INSTALL_FAILED:
|
|
||||||
// We should NEVER get here, but just in case.
|
|
||||||
notifMessage = `Failed to install ${title}!`;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
break;
|
||||||
notification.dismiss(installNotif);
|
case EXT_RETURN.ALREADY_INSTALLED:
|
||||||
notification.options.duration = 2000;
|
Toast.success(`${title} is already installed!`);
|
||||||
notification.success(notifMessage);
|
break;
|
||||||
setTimeout(() => {
|
case EXT_RETURN.INSTALL_FAILED:
|
||||||
window.location.reload();
|
Toast.error(`Failed to install ${title}!`);
|
||||||
}, 1000);
|
}
|
||||||
notification.options.duration = 999999;
|
setTimeout(() => {
|
||||||
const btn = document.querySelector(`button[data-slug="${ret.slug}"]`) as HTMLButton;
|
window.location.reload();
|
||||||
setInstallBtnText(btn);
|
}, 1500);
|
||||||
}, timeout);
|
const btn = document.querySelector(`button[data-slug="${install.slug}"]`) as HTMLButton;
|
||||||
})
|
setInstallBtnText(btn);
|
||||||
.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 });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
38
src/components/ts/toast.ts
Normal file
38
src/components/ts/toast.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
4
src/types.d.ts
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue