Skip to content

Commit

Permalink
add WIP themes tab
Browse files Browse the repository at this point in the history
  • Loading branch information
twnlink committed Dec 8, 2023
1 parent 46827dd commit e8dff52
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 73 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"idb-keyval": "^6.2.1",
"quartz-plugin-url-import": "^1.0.1",
"spitroast": "^1.4.3",
"voby": "^0.54.0"
"voby": "^0.57.1"
},
"type": "module",
"devDependencies": {
Expand Down
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 28 additions & 24 deletions src/api/plugins.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { store } from "voby";
import { createPersistentObject, neptuneIdbStore } from "./utils.js";
import { createPersistentObject, neptuneIdbStore, parseManifest } from "./utils.js";
import { del } from "idb-keyval";
import quartz from "@uwu/quartz";
import urlImport from "quartz-plugin-url-import";
Expand Down Expand Up @@ -122,9 +122,9 @@ export async function fetchPluginFromURL(url) {

if (!parsedURL.endsWith("/")) parsedURL += "/";

const manifest = await (await fetch(parsedURL + "manifest.json", { cache: "no-store" })).json();
if (!["name", "author", "description", "hash"].every((i) => typeof manifest[i] === "string"))
throw "Manifest doesn't contain required properties!";
const manifest = parseManifest(
await (await fetch(parsedURL + "manifest.json", { cache: "no-store" })).json(),
);

const plugin = getPluginById(url);
let code = plugin?.code;
Expand Down Expand Up @@ -159,7 +159,7 @@ export async function reloadPlugin(plugin) {
} catch {}
}

if (pluginWasEnabled) enablePlugin(plugin.id)
if (pluginWasEnabled) enablePlugin(plugin.id);
}

export async function installPluginFromURL(url, enabled = true) {
Expand All @@ -186,24 +186,28 @@ export async function installPluginFromURL(url, enabled = true) {
}

// Load as early as we possibly can.
intercept("session/RECEIVED_COUNTRY_CODE", async () => {
// We don't attempt to load plugins if CSP exists because loading every plugin will fail and automatically disable the plugin.
if (document.querySelector(`[http-equiv="Content-Security-Policy"]`)) return;

for (const plugin of pluginStore) {
if (plugin.update) {
try {
const [code, manifest] = await fetchPluginFromURL(plugin.id);

plugin.manifest = manifest;
plugin.code = code;
} catch {
console.log("[neptune] failed to update plugin");
intercept(
"session/RECEIVED_COUNTRY_CODE",
async () => {
// We don't attempt to load plugins if CSP exists because loading every plugin will fail and automatically disable the plugin.
if (document.querySelector(`[http-equiv="Content-Security-Policy"]`)) return;

for (const plugin of pluginStore) {
if (plugin.update) {
try {
const [code, manifest] = await fetchPluginFromURL(plugin.id);

plugin.manifest = manifest;
plugin.code = code;
} catch {
console.log("[neptune] failed to update plugin");
}
}
}

// We do not currently account for plugin updates, but this will be handled once
// remote plugin installation is handled.
if (plugin.enabled) runPlugin(plugin);
}
}, true);
// We do not currently account for plugin updates, but this will be handled once
// remote plugin installation is handled.
if (plugin.enabled) runPlugin(plugin);
}
},
true,
);
57 changes: 57 additions & 0 deletions src/api/themes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { appendStyle, createPersistentObject, parseManifest } from "./utils.js";

export const [themesStore, themesStoreReady] = createPersistentObject("NEPTUNE_THEMES", true);

let updateThemeStyle = () => {};

document.addEventListener("DOMContentLoaded", () => {
updateThemeStyle = appendStyle("");

reloadThemes();
});

function reloadThemes() {
updateThemeStyle(themesStore.filter(t => t.enabled).map((t) => `@import url("${t.url}")`).join(";"));
}

export function removeTheme(url) {
themesStore.splice(
themesStore.findIndex((t) => t.url == url),
1,
);

// Spamming this everywhere sucks but we'll get reactive objects working a little bit better in a bit.
reloadThemes();
}

export function toggleTheme(url) {
const theme = themesStore.find((t) => t.url == url);
theme.enabled = !theme.enabled;

reloadThemes();
}

export async function importTheme(url, enabled = true) {
let manifest;

try {
manifest = parseManifest(await (await fetch(url)).text());
} catch {
throw "Failed to parse theme manifest!";
}

if (!["name", "author", "description"].every((i) => typeof manifest[i] === "string"))
throw "Manifest doesn't contain required properties!";

const { name, author, description } = manifest;

themesStore.unshift({
name,
author,
description,
enabled,
url,
});

reloadThemes();
}
15 changes: 15 additions & 0 deletions src/api/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function appendStyle(style) {

export const neptuneIdbStore = createIdbStore("__NEPTUNE_IDB_STORAGE", "__NEPTUNE_IDB_STORAGE");

// store.on appears to not work upon isArray being true. This makes me a very sad toonlink.
export function createPersistentObject(id, isArray = false) {
// This is fucking moronic. But fine, we'll do this dumb shit just for you.
const persistentObject = store(isArray ? { value: [] } : {});
Expand All @@ -35,5 +36,19 @@ export function createPersistentObject(id, isArray = false) {
];
}

export const parseManifest = (manifest) => {
try {
if (typeof manifest == "string")
manifest = JSON.parse(manifest.slice(manifest.indexOf("/*") + 2, manifest.indexOf("*/")));
} catch {
throw "Failed to parse manifest!";
}

if (!["name", "author", "description"].every((i) => typeof manifest[i] === "string"))
throw "Manifest doesn't contain required properties!";

return manifest;
};

export const getMediaURLFromID = (id, path = "/1280x1280.jpg") =>
"https://resources.tidal.com/images/" + id.split("-").join("/") + path;
8 changes: 5 additions & 3 deletions src/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function loadStyles() {
width: calc(100% - var(--defaultPadding)*2);
}
.neptune-plugin-card {
.neptune-card {
background-color: var(--wave-color-solid-base-brighter, var(--wave-color-opacity-contrast-fill-ultra-thick));
border: 1px solid var(--wave-color-opacity-contrast-fill-ultra-thin);
border-radius: 12px;
Expand All @@ -18,7 +18,7 @@ export default function loadStyles() {
justify-content: center;
}
.neptune-plugin-card-content {
.neptune-card-content {
display: flex;
justify-content: space-between;
padding: 0 15px 0px 15px;
Expand All @@ -29,7 +29,7 @@ export default function loadStyles() {
box-shadow: 0px 2px var(--cyan-blue);
}
.neptune-plugin-title {
.neptune-card-title {
font-weight: 600;
font-size: medium;
}
Expand Down Expand Up @@ -87,6 +87,8 @@ export default function loadStyles() {
color: var(--glass-white-2);
display: block;
width: 100%;
height: 40px;
box-sizing: border-box;
}
.neptune-text-input:not([readonly]):focus {
Expand Down
42 changes: 36 additions & 6 deletions src/ui/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ customElements.define(
constructor() {
super();
this.c = () => {};
};
}

connectedCallback() {
this.style.display = "contents"
this.style.display = "contents";
this.dispose?.();
this.dispose = render(html`${this.c()}`, this)
};
this.dispose = render(html`${this.c()}`, this);
}

disconnectedCallback() {
this.dispose?.()
this.dispose?.();
}
},
);

export function ReactiveRoot({ children }) {
const root = html`<neptune-reactive-root></neptune-reactive-root>`()
const root = html`<neptune-reactive-root></neptune-reactive-root>`();
root.c = () => children;

return root;
Expand Down Expand Up @@ -63,3 +63,33 @@ export function TextInput({ placeholder = "", type = "text", value = "", onEnter
export function Button({ onClick = () => {}, children }) {
return html` <button class="neptune-button" onClick=${onClick}>${children}</button> `;
}

export function ReloadIcon() {
return html`<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99" />
</svg>`;
}

export function TrashIcon() {
return html`<svg
style="width: 22px;"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"></path>
</svg>`;
}
Loading

0 comments on commit e8dff52

Please sign in to comment.