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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+21 -9
View File
@@ -546,15 +546,15 @@ a[role=button]:active {
<div> <div>
<label class="text-xs text-on-surface-variant mb-2 block">Primary Color</label> <label class="text-xs text-on-surface-variant mb-2 block">Primary Color</label>
<div class="flex items-center gap-3"> <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 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"/> <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> </div>
<div> <div>
<label class="text-xs text-on-surface-variant mb-2 block">Secondary Color</label> <label class="text-xs text-on-surface-variant mb-2 block">Secondary Color</label>
<div class="flex items-center gap-3"> <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 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"/> <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> </div>
<div class="glass rounded-xl p-4"> <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('b-secondary-hex').value = d.secondary_color||'#95d3ba';
document.getElementById('preview-primary').style.background = d.primary_color||'#4edea3'; document.getElementById('preview-primary').style.background = d.primary_color||'#4edea3';
document.getElementById('preview-secondary').style.background = d.secondary_color||'#95d3ba'; document.getElementById('preview-secondary').style.background = d.secondary_color||'#95d3ba';
// Apply colors live to admin CSS variables // Apply colors live to admin CSS variables + override Tailwind classes
if(d.primary_color) document.documentElement.style.setProperty('--primary', d.primary_color); if(d.primary_color || d.secondary_color) {
if(d.secondary_color) document.documentElement.style.setProperty('--secondary', 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 // Logo
if(d.logo_url) document.getElementById('b-logo').value = d.logo_url; 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; if(d.logo_size) document.getElementById('b-logo-size').value = d.logo_size;
@@ -1548,8 +1554,14 @@ async function saveBranding() {
toast('Branding saved!','success'); toast('Branding saved!','success');
const p=document.getElementById('b-primary-hex')?.value; const p=document.getElementById('b-primary-hex')?.value;
const s=document.getElementById('b-secondary-hex')?.value; const s=document.getElementById('b-secondary-hex')?.value;
if(p) document.documentElement.style.setProperty('--primary',p); if(p||s){
if(s) document.documentElement.style.setProperty('--secondary',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'); } } else { alert('Save failed'); }
} catch(e) { alert('Error: '+e.message); } } 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=>{ 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_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.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.primary_color || b.secondary_color) {
if(b.secondary_color) document.documentElement.style.setProperty('--secondary', 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){ if(b.logo_url){
const logo=document.getElementById('brand-logo'); 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');} 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 ─────────────────────────────────────────────────────────────── // ── Branding ───────────────────────────────────────────────────────────────
fetch('/branding').then(r=>r.json()).then(b=>{ 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(()=>{}); }).catch(()=>{});
// ── Auth Nav ─────────────────────────────────────────────────────────────── // ── Auth Nav ───────────────────────────────────────────────────────────────