more branding options and fix gitignore

This commit is contained in:
KingKDot
2026-07-12 15:23:23 -05:00
parent 26702510eb
commit ddc8b970d5
11 changed files with 183 additions and 20 deletions
+10 -1
View File
@@ -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) {
+27 -1
View File
@@ -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);
}
+28
View File
@@ -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);
+26
View File
@@ -1269,6 +1269,21 @@
<span class="text-sm text-slate-300">Product name</span>
<input id="brand-product-name" type="text" placeholder="Overlord" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />
</label>
<label class="block">
<span class="text-sm text-slate-300">Browser tab name</span>
<input id="brand-tab-name" type="text" placeholder="Overlord" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />
</label>
<div class="block">
<span class="text-sm text-slate-300">Browser tab icon URL</span>
<input id="brand-favicon-url" type="text" inputmode="url" placeholder="/api/branding/image/tab-icon" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />
<div class="mt-2 flex items-center gap-2 min-w-0">
<input id="brand-favicon-file" type="file" accept="image/png,image/jpeg,image/gif,image/webp,image/x-icon,image/vnd.microsoft.icon,.ico" class="sr-only" />
<label for="brand-favicon-file" class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs text-slate-100 transition-colors cursor-pointer">
<i class="fa-solid fa-upload"></i>Upload image
</label>
<span id="brand-favicon-file-name" class="min-w-0 truncate text-xs text-slate-500">No file chosen</span>
</div>
</div>
<label class="block">
<span class="text-sm text-slate-300">Navigation name</span>
<input id="brand-nav-name" type="text" placeholder="Overlord" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />
@@ -1284,6 +1299,17 @@
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
<div class="block">
<span class="text-sm text-slate-300">Dashboard background image URL</span>
<input id="brand-dashboard-background-url" type="text" inputmode="url" placeholder="/api/branding/image/dashboard-background" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />
<div class="mt-2 flex items-center gap-2 min-w-0">
<input id="brand-dashboard-background-file" type="file" accept="image/png,image/jpeg,image/gif,image/webp" class="sr-only" />
<label for="brand-dashboard-background-file" class="inline-flex items-center gap-2 px-3 py-1.5 rounded-md bg-slate-800 hover:bg-slate-700 border border-slate-700 text-xs text-slate-100 transition-colors cursor-pointer">
<i class="fa-solid fa-upload"></i>Upload image
</label>
<span id="brand-dashboard-background-file-name" class="min-w-0 truncate text-xs text-slate-500">No file chosen</span>
</div>
</div>
<div class="block">
<span class="text-sm text-slate-300">Navigation logo URL</span>
<input id="brand-nav-logo-url" type="text" inputmode="url" placeholder="/assets/company-logo.png" class="mt-1 w-full px-3 py-2 rounded-lg bg-slate-900 border border-slate-700 focus:outline-none focus:ring-2 focus:ring-fuchsia-500" />