v1.8.11: fix branding colors — inject style overrides for Tailwind classes, sync color picker with hex input

This commit is contained in:
2026-05-28 20:54:56 +00:00
parent 4f8692cc77
commit 9f489fbbcb
15 changed files with 49 additions and 12 deletions
+21 -9
View File
@@ -546,15 +546,15 @@ a[role=button]:active {
<div>
<label class="text-xs text-on-surface-variant mb-2 block">Primary Color</label>
<div class="flex items-center gap-3">
<input type="color" id="b-primary" class="w-12 h-12 rounded-xl border border-outline-variant cursor-pointer bg-transparent"/>
<input id="b-primary-hex" class="flex-1 bg-surface-high border border-outline-variant rounded-xl px-4 py-3 text-sm font-mono outline-none focus:border-primary transition-colors"/>
<input type="color" id="b-primary" class="w-12 h-12 rounded-xl border border-outline-variant cursor-pointer bg-transparent" oninput="document.getElementById('b-primary-hex').value=this.value;document.getElementById('preview-primary').style.background=this.value"/>
<input id="b-primary-hex" class="flex-1 bg-surface-high border border-outline-variant rounded-xl px-4 py-3 text-sm font-mono outline-none focus:border-primary transition-colors" oninput="if(this.value.match(/^#[0-9a-fA-F]{6}$/)){document.getElementById('b-primary').value=this.value;document.getElementById('preview-primary').style.background=this.value}"/>
</div>
</div>
<div>
<label class="text-xs text-on-surface-variant mb-2 block">Secondary Color</label>
<div class="flex items-center gap-3">
<input type="color" id="b-secondary" class="w-12 h-12 rounded-xl border border-outline-variant cursor-pointer bg-transparent"/>
<input id="b-secondary-hex" class="flex-1 bg-surface-high border border-outline-variant rounded-xl px-4 py-3 text-sm font-mono outline-none focus:border-primary transition-colors"/>
<input type="color" id="b-secondary" class="w-12 h-12 rounded-xl border border-outline-variant cursor-pointer bg-transparent" oninput="document.getElementById('b-secondary-hex').value=this.value;document.getElementById('preview-secondary').style.background=this.value"/>
<input id="b-secondary-hex" class="flex-1 bg-surface-high border border-outline-variant rounded-xl px-4 py-3 text-sm font-mono outline-none focus:border-primary transition-colors" oninput="if(this.value.match(/^#[0-9a-fA-F]{6}$/)){document.getElementById('b-secondary').value=this.value;document.getElementById('preview-secondary').style.background=this.value}"/>
</div>
</div>
<div class="glass rounded-xl p-4">
@@ -1525,9 +1525,15 @@ async function loadBranding() {
document.getElementById('b-secondary-hex').value = d.secondary_color||'#95d3ba';
document.getElementById('preview-primary').style.background = d.primary_color||'#4edea3';
document.getElementById('preview-secondary').style.background = d.secondary_color||'#95d3ba';
// Apply colors live to admin CSS variables
if(d.primary_color) document.documentElement.style.setProperty('--primary', d.primary_color);
if(d.secondary_color) document.documentElement.style.setProperty('--secondary', d.secondary_color);
// Apply colors live to admin CSS variables + override Tailwind classes
if(d.primary_color || d.secondary_color) {
const p=d.primary_color||'#4edea3', s=d.secondary_color||'#95d3ba';
document.documentElement.style.setProperty('--primary', p);
document.documentElement.style.setProperty('--secondary', s);
let bs = document.getElementById('branding-color-override');
if(!bs){bs=document.createElement('style');bs.id='branding-color-override';document.head.appendChild(bs);}
bs.textContent=`.text-primary{color:${p}!important}.bg-primary{background-color:${p}!important}.border-primary{border-color:${p}!important}.text-secondary{color:${s}!important}.bg-secondary{background-color:${s}!important}.hover\:text-primary:hover{color:${p}!important}.focus\:border-primary:focus{border-color:${p}!important}`;
}
// Logo
if(d.logo_url) document.getElementById('b-logo').value = d.logo_url;
if(d.logo_size) document.getElementById('b-logo-size').value = d.logo_size;
@@ -1548,8 +1554,14 @@ async function saveBranding() {
toast('Branding saved!','success');
const p=document.getElementById('b-primary-hex')?.value;
const s=document.getElementById('b-secondary-hex')?.value;
if(p) document.documentElement.style.setProperty('--primary',p);
if(s) document.documentElement.style.setProperty('--secondary',s);
if(p||s){
const pc=p||'#4edea3', sc=s||'#95d3ba';
document.documentElement.style.setProperty('--primary',pc);
document.documentElement.style.setProperty('--secondary',sc);
let bs=document.getElementById('branding-color-override');
if(!bs){bs=document.createElement('style');bs.id='branding-color-override';document.head.appendChild(bs);}
bs.textContent=`.text-primary{color:${pc}!important}.bg-primary{background-color:${pc}!important}.border-primary{border-color:${pc}!important}.text-secondary{color:${sc}!important}.hover\:text-primary:hover{color:${pc}!important}`;
}
} else { alert('Save failed'); }
} catch(e) { alert('Error: '+e.message); }
}
+21 -2
View File
@@ -373,8 +373,27 @@ let currentUser = null;
fetch('/branding').then(r=>r.json()).then(b=>{
if(b.site_name){document.title=b.site_name;const bn=document.getElementById('brand-name');if(bn)bn.textContent=b.site_name;}
if(b.site_subtitle){const bs=document.getElementById('brand-sub');if(bs)bs.textContent=b.site_subtitle;}
if(b.primary_color) document.documentElement.style.setProperty('--primary', b.primary_color);
if(b.secondary_color) document.documentElement.style.setProperty('--secondary', b.secondary_color);
if(b.primary_color || b.secondary_color) {
const p = b.primary_color || '#4edea3';
const s = b.secondary_color || '#95d3ba';
document.documentElement.style.setProperty('--primary', p);
document.documentElement.style.setProperty('--secondary', s);
// Override Tailwind hardcoded colors with dynamic style injection
const style = document.createElement('style');
style.textContent = `
.text-primary { color: ${p} !important; }
.bg-primary { background-color: ${p} !important; }
.border-primary { border-color: ${p} !important; }
.text-secondary { color: ${s} !important; }
.bg-secondary { background-color: ${s} !important; }
.border-secondary { border-color: ${s} !important; }
.hover\\:text-primary:hover { color: ${p} !important; }
.hover\\:bg-primary:hover { background-color: ${p} !important; }
.focus\\:border-primary:focus { border-color: ${p} !important; }
.shadow-primary { --tw-shadow-color: ${p}; }
`;
document.head.appendChild(style);
}
if(b.logo_url){
const logo=document.getElementById('brand-logo');
if(logo){logo.src=b.logo_url;logo.style.height=(b.logo_size||'40')+'px';logo.classList.remove('hidden');}
+7 -1
View File
@@ -651,7 +651,13 @@ async function toggleFav(bookId, btn, e) {
// ── Branding ───────────────────────────────────────────────────────────────
fetch('/branding').then(r=>r.json()).then(b=>{
if(b.site_name) document.getElementById('brand-name').textContent=b.site_name;
if(b.site_name){const bn=document.getElementById('brand-name');if(bn)bn.textContent=b.site_name;}
if(b.primary_color || b.secondary_color) {
const p=b.primary_color||'#4edea3', s=b.secondary_color||'#95d3ba';
const style=document.createElement('style');
style.textContent=`.text-primary{color:${p}!important}.bg-primary{background-color:${p}!important}.border-primary{border-color:${p}!important}.text-secondary{color:${s}!important}.bg-secondary{background-color:${s}!important}.hover\\:text-primary:hover{color:${p}!important}.focus\\:border-primary:focus{border-color:${p}!important}`;
document.head.appendChild(style);
}
}).catch(()=>{});
// ── Auth Nav ───────────────────────────────────────────────────────────────