Add eruda plugin, stylize navbar elements to be better, and patch some issues with marketplace manifests

This commit is contained in:
wearrrrr 2024-11-20 19:56:56 -06:00
parent b0760dd553
commit a05e112de9
17 changed files with 95 additions and 317 deletions

3
public/img/nav/close.svg Normal file
View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
<path fill="#fc847c" d="M376.6 84.5c11.3-13.6 9.5-33.8-4.1-45.1s-33.8-9.5-45.1 4.1L192 206 56.6 43.5C45.3 29.9 25.1 28.1 11.5 39.4S-3.9 70.9 7.4 84.5L150.3 256 7.4 427.5c-11.3 13.6-9.5 33.8 4.1 45.1s33.8 9.5 45.1-4.1L192 306 327.4 468.5c11.3 13.6 31.5 15.4 45.1 4.1s15.4-31.5 4.1-45.1L233.7 256 376.6 84.5z" />
</svg>

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,19 +0,0 @@
self.vencordExt = {};
async function loadVC() {
console.log("Loading Vencord...");
const vencordJS = await fetch("/marketplace/vencord/bundle/browser.js");
const vencordCSS = await fetch("https://raw.githubusercontent.com/Vencord/builds/main/browser.css");
self.vencordJS = await vencordJS.text();
self.vencordCSS = await vencordCSS.text();
if (uv.config.inject === undefined) {
uv.config.inject = [];
};
uv.config.inject.push({
"host": "discord.com",
"html": `<script>${self.vencordJS}</script><style>${self.vencordCSS}</style>`,
"injectTo": "head",
});
}
self.vencordExt.loadVC = loadVC;

View file

@ -15,9 +15,13 @@ function loadExtensionScripts() {
let store = transaction.objectStore("InstalledExtensions"); let store = transaction.objectStore("InstalledExtensions");
let request = store.getAll(); let request = store.getAll();
request.onsuccess = () => { request.onsuccess = () => {
let extensions = request.result.filter((extension) => extension.type != "theme"); let extensions = request.result.filter((extension) => extension.type == "serviceWorker");
extensions.forEach((extension) => { extensions.forEach((extension) => {
eval(atob(extension.scriptCopy)); const decoder = new TextDecoder();
const contents = decoder.decode(extension.script);
eval(contents);
const func = self[extension.entryNamespace][extension.entryFunc]; const func = self[extension.entryNamespace][extension.entryFunc];
switch (extension.type) { switch (extension.type) {
case "serviceWorker": case "serviceWorker":

View file

@ -84,7 +84,7 @@
const iframe = document.getElementById("proxy-frame") as HTMLIFrameElement; const iframe = document.getElementById("proxy-frame") as HTMLIFrameElement;
const topbar = document.getElementById("top-bar") as HTMLDivElement; const topbar = document.getElementById("top-bar") as HTMLDivElement;
const closeButton = document.getElementById("close-button")!; const closeButton = document.getElementById("nav-close")!;
const backwardsButton = document.getElementById("nav-backwards")!; const backwardsButton = document.getElementById("nav-backwards")!;
const forwardsButton = document.getElementById("nav-forwards")!; const forwardsButton = document.getElementById("nav-forwards")!;
const reloadButton = document.getElementById("nav-reload")!; const reloadButton = document.getElementById("nav-reload")!;
@ -168,7 +168,7 @@
position: { x: "right", y: "bottom" }, position: { x: "right", y: "bottom" },
dismissible: true, dismissible: true,
ripple: true, ripple: true,
}).success("Copied to clipboard!"); }).success("Copied URL to clipboard!");
}; };
} }
}, 100); }, 100);

View file

@ -8,11 +8,10 @@ type Props = {
type: ExtType; type: ExtType;
}; };
const abbrTitle = type === "theme" ? "Theme" : "Script";
--- ---
<div class="marketplace-icon"> <div class="marketplace-icon">
<abbr title={abbrTitle}> <abbr title={type === "theme" ? "Theme" : "Script"}>
{type === "theme" ? <Paintbrush class="icon" /> : <Scroll class="icon" />} {type === "theme" ? <Paintbrush class="icon" /> : <Scroll class="icon" />}
</abbr> </abbr>
</div> </div>

View file

@ -0,0 +1,15 @@
<div id="top-bar">
<div class="top-bar-left">
<img id="proxied-favicon" alt="favicon" />
<span id="url-text"></span>
</div>
<div class="top-bar-right">
<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-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="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" />
</div>
</div>
</div>

View file

@ -0,0 +1,30 @@
<script>
import IDBManager from "@components/ts/IDBManager";
const idb = IDBManager.loadIDB("AluDB", 1)
idb.onsuccess = () => {
IDBManager.GetStore("InstalledExtensions", "readonly").getAll().onsuccess = (event) => {
// TODO: Get rid of this ugly type assertion!!
const result = (event.target as IDBRequest).result;
if (result) {
result.forEach((extension: ExtensionMetadata) => {
if (extension.type === "page") {
const decoder = new TextDecoder();
const script = decoder.decode(extension.scriptCopy!);
const scriptEl = document.createElement("script");
scriptEl.textContent = script;
document.head.appendChild(scriptEl);
// Call extension.init if it exists
if (extension.init) {
const init = new Function(extension.init);
init();
}
}
});
}
};
};
</script>

View file

@ -3,7 +3,7 @@
function switchTheme() { function switchTheme() {
const currentTheme = Alu.store.get("theme"); const currentTheme = Alu.store.get("theme");
document.documentElement.setAttribute("data-theme", currentTheme.value); document.documentElement.setAttribute("data-theme", currentTheme.value!);
} }
switchTheme(); switchTheme();
@ -20,17 +20,21 @@
result.forEach((extension: ExtensionMetadata) => { result.forEach((extension: ExtensionMetadata) => {
if (extension.type === "theme" && extension.themeName) { if (extension.type === "theme" && extension.themeName) {
// Load theme CSS // Load theme CSS
loadStyleFromAtob(atob(extension.scriptCopy!)); const decoder = new TextDecoder();
const style = decoder.decode(extension.scriptCopy!);
loadStyleFromString(style);
document.addEventListener("astro:after-swap", () => { document.addEventListener("astro:after-swap", () => {
loadStyleFromAtob(atob(extension.scriptCopy!)); loadStyleFromString(style);
}); });
} }
}); });
} }
}; };
}; };
function loadStyleFromAtob(style: string) { function loadStyleFromString(style: string) {
const styleEl = document.createElement("style"); const styleEl = document.createElement("style");
styleEl.textContent = style; styleEl.textContent = style;
document.head.appendChild(styleEl); document.head.appendChild(styleEl);

View file

@ -79,7 +79,13 @@ Array.from(installButtons).forEach((btn) => {
async function getMarketplaceObj(slug: string): Promise<ExtensionMetadata> { async function getMarketplaceObj(slug: string): Promise<ExtensionMetadata> {
const manifest = extManifest[slug]; const manifest = extManifest[slug];
manifest.scriptCopy = btoa(await fetch(manifest.script).then((res) => res.text())); if (manifest == null) {
throw new Error("Extension not found!");
}
// This is for the scriptCopy field, which is a uint8 array of the script
const contents = await fetch(manifest.script).then((res) => res.text());
const encoder = new TextEncoder();
manifest.scriptCopy = encoder.encode(contents);
return manifest; return manifest;
} }

View file

@ -9,6 +9,15 @@
"entryNamespace": "adblockExt", "entryNamespace": "adblockExt",
"entryFunc": "filterRequest" "entryFunc": "filterRequest"
}, },
"dev.wearr.eruda": {
"title": "Eruda",
"description": "Eruda provides a complete inspect element experience for devices where it is not available.",
"version": "1.0.0",
"image": "/marketplace/eruda/banner.png",
"script": "/marketplace/eruda/eruda.js",
"type": "page",
"init": "eruda.init()"
},
"dev.wearr.oled-theme": { "dev.wearr.oled-theme": {
"title": "OLED Theme", "title": "OLED Theme",
"description": "A beautiful OLED theme for Alu.", "description": "A beautiful OLED theme for Alu.",

View file

@ -2,8 +2,9 @@
import { ViewTransitions } from "astro:transitions"; import { ViewTransitions } from "astro:transitions";
import Header from "@components/UI/Header.astro"; import Header from "@components/UI/Header.astro";
import Footer from "@components/UI/Footer.astro"; import Footer from "@components/UI/Footer.astro";
import ThemeLoader from "@components/ThemeLoader.astro"; import ThemeLoader from "@components/loaders/ThemeLoader.astro";
import CloakLoader from "@components/CloakLoader.astro"; import CloakLoader from "@components/loaders/CloakLoader.astro";
import PageScriptLoader from "@components/loaders/PageScriptLoader.astro";
import WelcomeLogging from "@components/WelcomeLogging.astro"; import WelcomeLogging from "@components/WelcomeLogging.astro";
import SchemaData from "@components/SchemaData.astro"; import SchemaData from "@components/SchemaData.astro";
interface Props { interface Props {
@ -23,6 +24,7 @@ const DESCRIPTION =
<link href="/varela-round.css" rel="stylesheet" /> <link href="/varela-round.css" rel="stylesheet" />
<ThemeLoader transition:persist /> <ThemeLoader transition:persist />
<CloakLoader transition:persist /> <CloakLoader transition:persist />
<PageScriptLoader transition:persist />
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" /> <meta name="viewport" content="width=device-width" />
<meta name="title" content="Alu" /> <meta name="title" content="Alu" />
@ -259,18 +261,13 @@ const DESCRIPTION =
height: 32px; height: 32px;
width: 32px; width: 32px;
} }
#close-button {
padding: 5px;
padding-inline: 40px;
border: none;
background-color: var(--background-highlight);
color: var(--text-color-accent);
border-radius: 15px;
cursor: pointer;
}
.nav-container { .nav-container {
margin-top: 5px; height: 100%;
display: flex;
gap: 10px;
justify-content: center;
align-items: center;
} }
@media (max-width: 484px) { @media (max-width: 484px) {
.nav-container { .nav-container {

View file

@ -6,6 +6,7 @@ import Link from "@components/UI/Link.astro";
import ProxyRegistrar from "@components/ProxyRegistrar.astro"; import ProxyRegistrar from "@components/ProxyRegistrar.astro";
import Input from "@components/UI/Input.astro"; import Input from "@components/UI/Input.astro";
import FaqCard from "@components/FaqCard.astro"; import FaqCard from "@components/FaqCard.astro";
import IFrameNav from "@components/frame/IFrameNav.astro";
const t = i18n.inferLangUseTranslations(Astro.url); const t = i18n.inferLangUseTranslations(Astro.url);
@ -27,21 +28,7 @@ export function getStaticPaths() {
<div id="search-suggestions"></div> <div id="search-suggestions"></div>
</form> </form>
<div id="top-bar"> <IFrameNav />
<div class="top-bar-left">
<img id="proxied-favicon" alt="favicon" />
<span id="url-text"></span>
</div>
<div class="top-bar-right">
<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-forwards" src="/img/nav/forwards.svg" alt="Forward" />
<img width="28px" height="32px" id="nav-reload" src="/img/nav/reload.svg" alt="Reload Page" />
<img width="28px" height="32px" id="nav-share" src="/img/nav/share.svg" alt="Share Page" />
</div>
<button id="close-button">Close</button>
</div>
</div>
<iframe title="proxy-iframe" id="proxy-frame"></iframe> <iframe title="proxy-iframe" id="proxy-frame"></iframe>
</div> </div>
</section> </section>

3
src/types.d.ts vendored
View file

@ -39,7 +39,8 @@ interface ExtensionMetadata {
pages?: string[]; pages?: string[];
entryNamespace?: string; entryNamespace?: string;
entryFunc?: string; entryFunc?: string;
scriptCopy?: string; init?: string;
scriptCopy?: Uint8Array | null;
type: ExtType; type: ExtType;
themeName?: string; themeName?: string;
} }