mirror of
https://github.com/screentinker/screentinker.git
synced 2026-05-15 07:32:23 -06:00
Fix white-label settings not applying on page load
Root cause: the Settings page loaded /api/white-label into the form inputs but never applied the saved values (primary_color, bg_color, brand_name, favicon, custom_css) to the actual document. Nothing in app.js bootstrap touched branding. So the save hit the DB correctly, reload kept the DB value correctly, but the page always rendered the hardcoded defaults from css/variables.css and the static "ScreenTinker" label in index.html — which looked like the save had reverted. Fix: new frontend/js/branding.js module that fetches /api/white-label once at startup (app.js) and applies values to: - --accent and --bg-primary CSS vars - document.title and the .sidebar-header .logo span text - all <link rel="icon">/apple-touch-icon hrefs - a <style id="wl-custom-css"> tag for custom_css - the theme-color meta tag Settings save now calls resetBranding() after POST so changes apply immediately without a reload. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
4392bb460a
commit
281a735e84
|
|
@ -18,6 +18,7 @@ import * as teams from './views/teams.js';
|
||||||
import * as admin from './views/admin.js';
|
import * as admin from './views/admin.js';
|
||||||
import * as designer from './views/designer.js';
|
import * as designer from './views/designer.js';
|
||||||
import * as playlists from './views/playlists.js';
|
import * as playlists from './views/playlists.js';
|
||||||
|
import { applyBranding } from './branding.js';
|
||||||
|
|
||||||
const app = document.getElementById('app');
|
const app = document.getElementById('app');
|
||||||
const sidebar = document.querySelector('.sidebar');
|
const sidebar = document.querySelector('.sidebar');
|
||||||
|
|
@ -203,6 +204,7 @@ function updateSidebarUser() {
|
||||||
// Initialize
|
// Initialize
|
||||||
if (isAuthenticated()) {
|
if (isAuthenticated()) {
|
||||||
connectSocket();
|
connectSocket();
|
||||||
|
applyBranding();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register PWA service worker
|
// Register PWA service worker
|
||||||
|
|
|
||||||
59
frontend/js/branding.js
Normal file
59
frontend/js/branding.js
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Applies the current user's saved white-label config to the DOM.
|
||||||
|
// Runs once after login/route bootstrap. Without this, saved values in the
|
||||||
|
// white_labels table are read into the Settings form but never applied to
|
||||||
|
// the actual page — so users see "ScreenTinker" and default colors after
|
||||||
|
// every reload, as if their save reverted.
|
||||||
|
|
||||||
|
let applied = false;
|
||||||
|
|
||||||
|
export async function applyBranding() {
|
||||||
|
if (applied) return;
|
||||||
|
applied = true;
|
||||||
|
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token) return;
|
||||||
|
|
||||||
|
let wl;
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/white-label', { headers: { Authorization: `Bearer ${token}` } });
|
||||||
|
if (!res.ok) return;
|
||||||
|
wl = await res.json();
|
||||||
|
} catch { return; }
|
||||||
|
if (!wl) return;
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
if (wl.primary_color) root.style.setProperty('--accent', wl.primary_color);
|
||||||
|
if (wl.bg_color) {
|
||||||
|
root.style.setProperty('--bg-primary', wl.bg_color);
|
||||||
|
const meta = document.querySelector('meta[name="theme-color"]');
|
||||||
|
if (meta) meta.setAttribute('content', wl.bg_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wl.brand_name) {
|
||||||
|
document.title = wl.brand_name;
|
||||||
|
const span = document.querySelector('.sidebar-header .logo span');
|
||||||
|
if (span) span.textContent = wl.brand_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wl.favicon_url) {
|
||||||
|
document.querySelectorAll('link[rel="icon"], link[rel="apple-touch-icon"]').forEach(l => {
|
||||||
|
l.setAttribute('href', wl.favicon_url);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wl.custom_css) {
|
||||||
|
let style = document.getElementById('wl-custom-css');
|
||||||
|
if (!style) {
|
||||||
|
style = document.createElement('style');
|
||||||
|
style.id = 'wl-custom-css';
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
style.textContent = wl.custom_css;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force a re-apply (called from settings.js after save)
|
||||||
|
export function resetBranding() {
|
||||||
|
applied = false;
|
||||||
|
return applyBranding();
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import { api } from '../api.js';
|
||||||
import { showToast } from '../components/toast.js';
|
import { showToast } from '../components/toast.js';
|
||||||
import { getLanguage, setLanguage, getAvailableLanguages } from '../i18n.js';
|
import { getLanguage, setLanguage, getAvailableLanguages } from '../i18n.js';
|
||||||
import { esc } from '../utils.js';
|
import { esc } from '../utils.js';
|
||||||
|
import { resetBranding } from '../branding.js';
|
||||||
|
|
||||||
export async function render(container) {
|
export async function render(container) {
|
||||||
const serverUrl = `${window.location.protocol}//${window.location.host}`;
|
const serverUrl = `${window.location.protocol}//${window.location.host}`;
|
||||||
|
|
@ -368,6 +369,7 @@ async function loadWhiteLabel() {
|
||||||
hide_branding: document.getElementById('wlHideBranding').checked ? 1 : 0,
|
hide_branding: document.getElementById('wlHideBranding').checked ? 1 : 0,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
await resetBranding();
|
||||||
showToast('Branding saved', 'success');
|
showToast('Branding saved', 'success');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(err.message, 'error');
|
showToast(err.message, 'error');
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue