From 45a31075a52fbc407db55ae6cc68fdb19eb75480 Mon Sep 17 00:00:00 2001 From: Julien Maille Date: Fri, 26 Dec 2025 12:28:05 +0100 Subject: [PATCH] Improve vibrant color contrast in light mode Modified setVibrantColor in ui.js to darken bright colors when in light mode and lighten dark colors in dark mode, ensuring text and button readability. --- js/ui.js | 58 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/js/ui.js b/js/ui.js index fa23d2a..3b78783 100644 --- a/js/ui.js +++ b/js/ui.js @@ -268,24 +268,60 @@ export class UIRenderer { if (!color) return; const root = document.documentElement; + const theme = root.getAttribute('data-theme'); + const isLightMode = theme === 'light'; + + let hex = color.replace('#', ''); + // Handle shorthand hex + if (hex.length === 3) { + hex = hex.split('').map(char => char + char).join(''); + } + + let r = parseInt(hex.substr(0, 2), 16); + let g = parseInt(hex.substr(2, 2), 16); + let b = parseInt(hex.substr(4, 2), 16); + + // Calculate perceived brightness + let brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000; + + if (isLightMode) { + // In light mode, the background is white. + // We need the color (used for text/highlights) to be dark enough. + // If brightness is too high (> 150), darken it. + while (brightness > 150) { + r = Math.floor(r * 0.9); + g = Math.floor(g * 0.9); + b = Math.floor(b * 0.9); + brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000; + } + } else { + // In dark mode, the background is dark. + // We need the color to be light enough. + // If brightness is too low (< 80), lighten it. + while (brightness < 80) { + r = Math.min(255, Math.floor(r * 1.15)); + g = Math.min(255, Math.floor(g * 1.15)); + b = Math.min(255, Math.floor(b * 1.15)); + brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000; + // Break if we hit white or can't get brighter to avoid infinite loop + if (r >= 255 && g >= 255 && b >= 255) break; + } + } + + const adjustedColor = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`; - // Calculate contrast text color - const hex = color.replace('#', ''); - const r = parseInt(hex.substr(0, 2), 16); - const g = parseInt(hex.substr(2, 2), 16); - const b = parseInt(hex.substr(4, 2), 16); - const brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000; + // Calculate contrast text color for buttons (text on top of the vibrant color) const foreground = brightness > 128 ? '#000000' : '#ffffff'; // Set global CSS variables - root.style.setProperty('--primary', color); + root.style.setProperty('--primary', adjustedColor); root.style.setProperty('--primary-foreground', foreground); - root.style.setProperty('--highlight', color); + root.style.setProperty('--highlight', adjustedColor); root.style.setProperty('--highlight-rgb', `${r}, ${g}, ${b}`); - root.style.setProperty('--active-highlight', color); - root.style.setProperty('--ring', color); + root.style.setProperty('--active-highlight', adjustedColor); + root.style.setProperty('--ring', adjustedColor); - // Calculate a safe hover color (darken if too light) + // Calculate a safe hover color let hoverColor; if (brightness > 200) { const dr = Math.floor(r * 0.85);