From 7b5037bc18eedea7c12c6d59f7fafef9cbc21c7f Mon Sep 17 00:00:00 2001 From: KingKDot Date: Wed, 25 Mar 2026 09:50:41 -0500 Subject: [PATCH] allow custom css --- Overlord-Server/public/assets/nav.js | 7 +++ Overlord-Server/public/assets/settings.js | 62 +++++++++++++++++++ Overlord-Server/public/login.html | 1 + Overlord-Server/public/settings.html | 31 ++++++++++ Overlord-Server/src/config.ts | 24 +++++++ .../src/server/routes/assets-routes.ts | 11 ++++ .../src/server/routes/misc-routes.ts | 46 +++++++++++++- 7 files changed, 181 insertions(+), 1 deletion(-) diff --git a/Overlord-Server/public/assets/nav.js b/Overlord-Server/public/assets/nav.js index 9db86f5..2faaadc 100644 --- a/Overlord-Server/public/assets/nav.js +++ b/Overlord-Server/public/assets/nav.js @@ -5,6 +5,13 @@ import { subscribeStatus, subscribeUnread, } from "./notify-client.js"; + +(function injectCustomCSS() { + const link = document.createElement("link"); + link.rel = "stylesheet"; + link.href = "/assets/custom.css"; + document.head.appendChild(link); +})(); import { mountNav } from "./nav/template.js"; import { createAdaptiveNavController } from "./nav/layout.js"; import { applyUserRoleUI } from "./nav/role-ui.js"; diff --git a/Overlord-Server/public/assets/settings.js b/Overlord-Server/public/assets/settings.js index e8025d6..0665993 100644 --- a/Overlord-Server/public/assets/settings.js +++ b/Overlord-Server/public/assets/settings.js @@ -56,6 +56,11 @@ const tlsCertbotCertFileInput = document.getElementById("tls-certbot-cert-file") const tlsCertbotKeyFileInput = document.getElementById("tls-certbot-key-file"); const tlsCertbotCaFileInput = document.getElementById("tls-certbot-ca-file"); +const appearanceForm = document.getElementById("appearance-form"); +const appearancePermissionNote = document.getElementById("appearance-permission-note"); +const appearanceSaveBtn = document.getElementById("appearance-save-btn"); +const appearanceCustomCssInput = document.getElementById("appearance-custom-css"); + let currentUser = null; let securityConfig = null; let tlsConfig = null; @@ -605,12 +610,68 @@ async function handleUnbanClick(event) { await loadBannedIps(); } +async function loadAppearanceSettings() { + if (!currentUser) return; + + if (!isAdmin(currentUser.role)) { + if (appearancePermissionNote) appearancePermissionNote.classList.remove("hidden"); + if (appearanceCustomCssInput) appearanceCustomCssInput.disabled = true; + if (appearanceSaveBtn) appearanceSaveBtn.disabled = true; + return; + } + + if (appearancePermissionNote) appearancePermissionNote.classList.add("hidden"); + + try { + const res = await fetch("/api/settings/appearance", { credentials: "include" }); + if (!res.ok) { + showMessage("Failed to load custom CSS settings.", "error"); + return; + } + const data = await res.json().catch(() => ({})); + if (appearanceCustomCssInput) appearanceCustomCssInput.value = data.customCSS || ""; + if (appearanceSaveBtn) appearanceSaveBtn.disabled = false; + } catch { + showMessage("Failed to load custom CSS settings.", "error"); + } +} + +async function saveAppearanceSettings(event) { + event.preventDefault(); + if (!isAdmin(currentUser?.role)) { + showMessage("Admin role required.", "error"); + return; + } + + const customCSS = appearanceCustomCssInput ? appearanceCustomCssInput.value : ""; + if (customCSS.length > 51200) { + showMessage("CSS exceeds the 50 KB size limit.", "error"); + return; + } + + const res = await fetch("/api/settings/appearance", { + method: "PUT", + headers: { "Content-Type": "application/json" }, + credentials: "include", + body: JSON.stringify({ customCSS }), + }); + + const data = await res.json().catch(() => ({})); + if (!res.ok) { + showMessage(data.error || "Failed to save custom CSS.", "error"); + return; + } + + showMessage("Custom CSS saved. Reload the page to apply the new styles."); +} + async function init() { try { await loadCurrentUser(); loadPrefs(); await loadSecurityPolicy(); await loadTlsSettings(); + await loadAppearanceSettings(); await loadBannedIps(); passwordForm.addEventListener("submit", updatePassword); @@ -618,6 +679,7 @@ async function init() { securityForm.addEventListener("submit", saveSecurityPolicy); tlsForm.addEventListener("submit", saveTlsSettings); tlsCertbotAutoBtn.addEventListener("click", runCertbotAutoSetup); + if (appearanceForm) appearanceForm.addEventListener("submit", saveAppearanceSettings); refreshBansBtn.addEventListener("click", loadBannedIps); bansTableBody.addEventListener("click", handleUnbanClick); } catch (error) { diff --git a/Overlord-Server/public/login.html b/Overlord-Server/public/login.html index bbc5c5e..e41bab8 100644 --- a/Overlord-Server/public/login.html +++ b/Overlord-Server/public/login.html @@ -18,6 +18,7 @@ referrerpolicy="no-referrer" /> +