diff --git a/.gitignore b/.gitignore index 4ea2da6..7b572ee 100644 --- a/.gitignore +++ b/.gitignore @@ -517,4 +517,7 @@ save.txt Albedo/* plink/* plugins/plink/* -plugins/plink-static/* \ No newline at end of file +plugins/plink-static/* + +Overlord-Client/third_party/amf +Overlord-Client/third_party/onevpl \ No newline at end of file diff --git a/Overlord-Server/public/assets/login.js b/Overlord-Server/public/assets/login.js index bd795c9..e815616 100644 --- a/Overlord-Server/public/assets/login.js +++ b/Overlord-Server/public/assets/login.js @@ -33,7 +33,16 @@ const loginSupportLink = document.getElementById("login-support-link"); if (loginBrand && data.productName) loginBrand.textContent = data.productName; if (loginTitle && data.title) loginTitle.textContent = data.title; if (loginSubtitle && data.subtitle) loginSubtitle.textContent = data.subtitle; - if (data.productName) document.title = `${data.productName} Login`; + document.title = data.tabName || (data.productName ? `${data.productName} Login` : document.title); + if (data.faviconUrl) { + let favicon = document.querySelector('link[rel~="icon"]'); + if (!favicon) { + favicon = document.createElement("link"); + favicon.rel = "icon"; + document.head.appendChild(favicon); + } + favicon.href = data.faviconUrl; + } if (data.accentColor) document.documentElement.style.setProperty("--brand-accent", data.accentColor); if (loginIcon && data.iconClass) { diff --git a/Overlord-Server/public/assets/nav.js b/Overlord-Server/public/assets/nav.js index 002ce4b..02d910a 100644 --- a/Overlord-Server/public/assets/nav.js +++ b/Overlord-Server/public/assets/nav.js @@ -244,7 +244,12 @@ if (host) { }); installPageResourceTracker(); - setupSoftNavigation(host, { onPathChange: applyActivePath }); + setupSoftNavigation(host, { + onPathChange: (path) => { + applyActivePath(path); + applyBranding(); + }, + }); startPageTracking(); } @@ -253,6 +258,27 @@ async function applyBranding() { const res = await fetch("/api/login/branding"); if (!res.ok) return; const brand = await res.json(); + if (brand.tabName) document.title = brand.tabName; + if (brand.faviconUrl) { + let favicon = document.querySelector('link[rel~="icon"]'); + if (!favicon) { + favicon = document.createElement("link"); + favicon.rel = "icon"; + document.head.appendChild(favicon); + } + favicon.href = brand.faviconUrl; + } + const isDashboard = location.pathname === "/" || location.pathname === "/index.html"; + document.body.style.backgroundImage = ""; + document.body.style.backgroundSize = ""; + document.body.style.backgroundPosition = ""; + document.body.style.backgroundAttachment = ""; + if (isDashboard && brand.dashboardBackgroundUrl) { + document.body.style.backgroundImage = `linear-gradient(rgba(2, 6, 23, 0.72), rgba(2, 6, 23, 0.82)), url("${brand.dashboardBackgroundUrl.replace(/["\\\n\r]/g, "")}")`; + document.body.style.backgroundSize = "cover"; + document.body.style.backgroundPosition = "center"; + document.body.style.backgroundAttachment = "fixed"; + } if (brand.accentColor) { document.documentElement.style.setProperty("--brand-accent", brand.accentColor); } diff --git a/Overlord-Server/public/assets/settings.js b/Overlord-Server/public/assets/settings.js index 5047184..176f972 100644 --- a/Overlord-Server/public/assets/settings.js +++ b/Overlord-Server/public/assets/settings.js @@ -109,6 +109,11 @@ const appearancePermissionNote = document.getElementById("appearance-permission- const appearanceSaveBtn = document.getElementById("appearance-save-btn"); const appearanceCustomCssInput = document.getElementById("appearance-custom-css"); const brandProductNameInput = document.getElementById("brand-product-name"); +const brandTabNameInput = document.getElementById("brand-tab-name"); +const brandFaviconUrlInput = document.getElementById("brand-favicon-url"); +const brandFaviconFileInput = document.getElementById("brand-favicon-file"); +const brandDashboardBackgroundUrlInput = document.getElementById("brand-dashboard-background-url"); +const brandDashboardBackgroundFileInput = document.getElementById("brand-dashboard-background-file"); const brandNavNameInput = document.getElementById("brand-nav-name"); const brandAccentColorInput = document.getElementById("brand-accent-color"); const brandIconClassInput = document.getElementById("brand-icon-class"); @@ -1379,6 +1384,11 @@ function initSettingsSidebar() { const brandInputs = [ brandProductNameInput, + brandTabNameInput, + brandFaviconUrlInput, + brandFaviconFileInput, + brandDashboardBackgroundUrlInput, + brandDashboardBackgroundFileInput, brandNavNameInput, brandAccentColorInput, brandIconClassInput, @@ -1406,6 +1416,9 @@ function setAppearanceFormDisabled(disabled) { function applyBrandingForm(loginBranding = {}) { if (brandProductNameInput) brandProductNameInput.value = loginBranding.productName || "Overlord"; + if (brandTabNameInput) brandTabNameInput.value = loginBranding.tabName || loginBranding.productName || "Overlord"; + if (brandFaviconUrlInput) brandFaviconUrlInput.value = loginBranding.faviconUrl || ""; + if (brandDashboardBackgroundUrlInput) brandDashboardBackgroundUrlInput.value = loginBranding.dashboardBackgroundUrl || ""; if (brandNavNameInput) brandNavNameInput.value = loginBranding.navName || loginBranding.productName || "Overlord"; if (brandAccentColorInput) brandAccentColorInput.value = /^#[0-9a-fA-F]{6}$/.test(loginBranding.accentColor || "") ? loginBranding.accentColor : "#7a5bff"; if (brandIconClassInput) brandIconClassInput.value = loginBranding.iconClass || "fa-solid fa-crown"; @@ -1425,6 +1438,9 @@ function applyBrandingForm(loginBranding = {}) { function collectBrandingForm() { return { productName: String(brandProductNameInput?.value || "").trim(), + tabName: String(brandTabNameInput?.value || "").trim(), + faviconUrl: String(brandFaviconUrlInput?.value || "").trim(), + dashboardBackgroundUrl: String(brandDashboardBackgroundUrlInput?.value || "").trim(), navName: String(brandNavNameInput?.value || "").trim(), accentColor: String(brandAccentColorInput?.value || "").trim(), iconClass: String(brandIconClassInput?.value || "").trim(), @@ -1491,6 +1507,18 @@ async function uploadBrandingImage(fileInput, targetInput, kind, label) { } function initBrandingUploads() { + if (brandDashboardBackgroundFileInput) { + brandDashboardBackgroundFileInput.addEventListener("change", () => { + setBrandingUploadName(brandDashboardBackgroundFileInput); + uploadBrandingImage(brandDashboardBackgroundFileInput, brandDashboardBackgroundUrlInput, "dashboard-background", "Dashboard background"); + }); + } + if (brandFaviconFileInput) { + brandFaviconFileInput.addEventListener("change", () => { + setBrandingUploadName(brandFaviconFileInput); + uploadBrandingImage(brandFaviconFileInput, brandFaviconUrlInput, "tab-icon", "Browser tab icon"); + }); + } if (brandNavLogoFileInput) { brandNavLogoFileInput.addEventListener("change", () => { setBrandingUploadName(brandNavLogoFileInput); diff --git a/Overlord-Server/public/settings.html b/Overlord-Server/public/settings.html index 3a747b0..cfba0ea 100644 --- a/Overlord-Server/public/settings.html +++ b/Overlord-Server/public/settings.html @@ -1269,6 +1269,21 @@ Product name + +
+ Browser tab icon URL + +
+ + + No file chosen +
+