Add BrandColorLight to portal settings page

Updated the portal settings brand color picker to show both dark
and light colors. Light swatch shown alongside dark swatch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
John Mizerek 2026-03-05 15:09:30 -08:00
parent 3bd7585383
commit 771f70f2f3
2 changed files with 64 additions and 13 deletions

View file

@ -650,12 +650,15 @@
</button>
</div>
<div>
<label style="display: block; margin-bottom: 8px; font-weight: 500;">Brand Color</label>
<p style="color: #666; font-size: 13px; margin-bottom: 8px;">Used for accents and fallback backgrounds</p>
<label style="display: block; margin-bottom: 8px; font-weight: 500;">Brand Colors</label>
<p style="color: #666; font-size: 13px; margin-bottom: 8px;">Dark for accents/gradients, Light for card tinting</p>
<div style="display: flex; gap: 12px; align-items: center;">
<span id="brandColorSwatch" style="width: 40px; height: 40px; border-radius: 8px; background: #1B4D3E; border: 2px solid rgba(255,255,255,0.2); cursor: pointer;" onclick="Portal.showBrandColorPicker()"></span>
<div style="display: flex; gap: 6px; align-items: center;">
<span id="brandColorSwatch" style="width: 40px; height: 40px; border-radius: 8px; background: #1B4D3E; border: 2px solid rgba(255,255,255,0.2); cursor: pointer;" onclick="Portal.showBrandColorPicker()" title="Dark"></span>
<span id="brandColorLightSwatch" style="width: 40px; height: 40px; border-radius: 8px; background: #fff; border: 2px solid rgba(255,255,255,0.2); cursor: pointer;" onclick="Portal.showBrandColorPicker()" title="Light"></span>
</div>
<button class="btn btn-secondary" onclick="Portal.showBrandColorPicker()" style="flex: 1;">
Change Color
Change Colors
</button>
</div>
</div>

View file

@ -817,13 +817,19 @@ const Portal = {
document.getElementById('settingState').value = biz.ADDRESSSTATE || biz.AddressState || '';
document.getElementById('settingZip').value = biz.ADDRESSZIP || biz.AddressZip || '';
// Load brand color if set
// Load brand colors
const brandColor = biz.BRANDCOLOR || biz.BrandColor;
if (brandColor) {
this.brandColor = brandColor;
const swatch = document.getElementById('brandColorSwatch');
if (swatch) swatch.style.background = brandColor;
}
const brandColorLight = biz.BRANDCOLORLIGHT || biz.BrandColorLight || '';
if (brandColorLight) {
this.brandColorLight = brandColorLight;
const lSwatch = document.getElementById('brandColorLightSwatch');
if (lSwatch) lSwatch.style.background = brandColorLight;
}
// Load header preview
const headerPreview = document.getElementById('headerPreview');
@ -1316,10 +1322,12 @@ const Portal = {
// Show brand color picker
showBrandColorPicker() {
const currentColor = this.brandColor || '#1B4D3E';
document.getElementById('modalTitle').textContent = 'Brand Color';
const currentLight = this.brandColorLight || '';
document.getElementById('modalTitle').textContent = 'Brand Colors';
document.getElementById('modalBody').innerHTML = `
<div style="padding: 8px;">
<p style="color: #999; margin-bottom: 16px;">This color is used for accents and fallback backgrounds in your menu.</p>
<label style="display: block; font-weight: 600; margin-bottom: 6px;">Brand Color (Dark)</label>
<p style="color: #999; margin-bottom: 12px; font-size: 12px;">Used for accents and gradients in the customer app.</p>
<div style="display: flex; gap: 16px; align-items: flex-start;">
<input type="color" id="brandColorInput" value="${currentColor}"
style="width: 80px; height: 80px; border: none; cursor: pointer; border-radius: 8px;">
@ -1329,16 +1337,29 @@ const Portal = {
style="width: 100%; padding: 8px; border: 1px solid #444; border-radius: 4px; background: #222; color: #fff; font-family: monospace;">
</div>
</div>
<div id="brandColorPreview" style="margin-top: 16px; height: 60px; border-radius: 8px; background: linear-gradient(to bottom, ${currentColor}44, ${currentColor}00, ${currentColor}66);"></div>
<div id="brandColorPreview" style="margin-top: 12px; height: 40px; border-radius: 8px; background: linear-gradient(to bottom, ${currentColor}44, ${currentColor}00, ${currentColor}66);"></div>
<div style="border-top: 1px solid #333; margin-top: 20px; padding-top: 16px;">
<label style="display: block; font-weight: 600; margin-bottom: 6px;">Brand Color (Light)</label>
<p style="color: #999; margin-bottom: 12px; font-size: 12px;">Subtle tint for menu builder cards. Leave empty for white.</p>
<div style="display: flex; gap: 16px; align-items: center;">
<input type="color" id="brandColorLightInput" value="${currentLight || '#F5F5F5'}"
style="width: 60px; height: 40px; border: none; cursor: pointer; border-radius: 4px;">
<input type="text" id="brandColorLightHex" value="${currentLight}"
style="width: 120px; padding: 8px; border: 1px solid #444; border-radius: 4px; background: #222; color: #fff; font-family: monospace;"
placeholder="#F5F5F5" maxlength="7">
<div id="brandColorLightPreview" style="flex: 1; height: 40px; border-radius: 4px; border: 1px solid #333; background: ${currentLight || '#1a1a1a'};"></div>
<button type="button" class="btn btn-secondary" style="font-size: 12px; padding: 6px 10px;" onclick="document.getElementById('brandColorLightHex').value='';document.getElementById('brandColorLightPreview').style.background='#1a1a1a';">Clear</button>
</div>
</div>
<div style="margin-top: 20px; display: flex; gap: 12px; justify-content: flex-end;">
<button type="button" class="btn btn-secondary" onclick="Portal.closeModal()">Cancel</button>
<button type="button" class="btn btn-primary" onclick="Portal.saveBrandColor()">Save Color</button>
<button type="button" class="btn btn-primary" onclick="Portal.saveBrandColor()">Save Colors</button>
</div>
</div>
`;
this.showModal();
// Sync inputs
// Sync dark inputs
const colorInput = document.getElementById('brandColorInput');
const hexInput = document.getElementById('brandColorHex');
const preview = document.getElementById('brandColorPreview');
@ -1357,30 +1378,57 @@ const Portal = {
preview.style.background = `linear-gradient(to bottom, ${color}44, ${color}00, ${color}66)`;
}
});
// Sync light inputs
const lightInput = document.getElementById('brandColorLightInput');
const lightHex = document.getElementById('brandColorLightHex');
const lightPreview = document.getElementById('brandColorLightPreview');
lightInput.addEventListener('input', () => {
lightHex.value = lightInput.value.toUpperCase();
lightPreview.style.background = lightInput.value;
});
lightHex.addEventListener('input', () => {
let val = lightHex.value;
if (/^[0-9A-Fa-f]{6}$/.test(val)) val = '#' + val;
if (/^#[0-9A-Fa-f]{6}$/.test(val)) {
lightInput.value = val;
lightPreview.style.background = val;
}
});
},
// Save brand color
// Save brand colors
async saveBrandColor() {
const color = document.getElementById('brandColorHex').value.toUpperCase();
if (!/^#?[0-9A-Fa-f]{6}$/.test(color)) {
this.toast('Please enter a valid hex color (e.g., #1B4D3E or 1B4D3E)', 'error');
return;
}
const lightColor = (document.getElementById('brandColorLightHex')?.value || '').toUpperCase();
if (lightColor && !/^#?[0-9A-Fa-f]{6}$/.test(lightColor)) {
this.toast('Invalid light color format. Use #RRGGBB or leave empty', 'error');
return;
}
try {
const response = await fetch(`${this.config.apiBaseUrl}/businesses/saveBrandColor.cfm`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ BusinessID: this.config.businessId, BrandColor: color })
body: JSON.stringify({ BusinessID: this.config.businessId, BrandColor: color, BrandColorLight: lightColor })
});
const data = await response.json();
if (data.OK) {
this.brandColor = color;
this.brandColorLight = lightColor;
const swatch = document.getElementById('brandColorSwatch');
if (swatch) swatch.style.background = color;
const lSwatch = document.getElementById('brandColorLightSwatch');
if (lSwatch) lSwatch.style.background = lightColor || '#1a1a1a';
this.closeModal();
this.toast('Brand color saved!', 'success');
this.toast('Brand colors saved!', 'success');
} else {
this.toast(data.MESSAGE || 'Failed to save color', 'error');
}