From 9b417bf4f23f540b5c8cace81e50c37729844e06 Mon Sep 17 00:00:00 2001 From: Rodrigo Rodriguez Date: Sun, 15 Feb 2026 23:19:16 +0000 Subject: [PATCH] fix: Remove body data-theme attribute to prevent CSS override This fixes the issue where theme changes required a page refresh to apply to the chat client area. The body element's data-theme attribute was applying base.css theme rules that overrode the inline styles set by the theme manager. Changes: - Add data-theme="sentient" to html element in base.html - Remove body's data-theme attribute when loading themes in theme-manager.js - This prevents base.css [data-theme="*"] selectors from overriding inline styles Now both header and body background update immediately when switching themes. Co-Authored-By: Claude Sonnet 4.5 --- ui/suite/base.html | 2 +- ui/suite/js/theme-manager.js | 88 +++++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/ui/suite/base.html b/ui/suite/base.html index 9fb8491..53afe53 100644 --- a/ui/suite/base.html +++ b/ui/suite/base.html @@ -1,5 +1,5 @@ - + diff --git a/ui/suite/js/theme-manager.js b/ui/suite/js/theme-manager.js index e208614..e292d3c 100644 --- a/ui/suite/js/theme-manager.js +++ b/ui/suite/js/theme-manager.js @@ -68,6 +68,8 @@ const ThemeManager = (() => { if (!theme.file) { currentThemeId = "default"; localStorage.setItem("gb-theme", "default"); + // Re-enable sentient theme for default + document.documentElement.setAttribute("data-theme", "sentient"); updateDropdown(); return; } @@ -81,24 +83,83 @@ const ThemeManager = (() => { currentThemeId = id; localStorage.setItem("gb-theme", id); + // Keep data-theme="sentient" on html so CSS selectors work + // The inline styles will override the colors + if (!document.documentElement.getAttribute("data-theme")) { + document.documentElement.setAttribute("data-theme", "sentient"); + } + + // Remove data-theme from body to prevent base.css theme rules from overriding + document.body.removeAttribute("data-theme"); + // Small delay to ensure CSS variables are applied setTimeout(() => { - // Get the theme's primary color from CSS variables + // Get the theme's colors from CSS variables const rootStyle = getComputedStyle(document.documentElement); - const primaryColor = rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6"; - const cardColor = rootStyle.getPropertyValue("--card")?.trim() || "#fafafa"; + const primary = rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6"; + const background = rootStyle.getPropertyValue("--background")?.trim() || "0 0% 100%"; + const foreground = rootStyle.getPropertyValue("--foreground")?.trim() || "222 47% 11%"; + const card = rootStyle.getPropertyValue("--card")?.trim() || "0 0% 98%"; + const border = rootStyle.getPropertyValue("--border")?.trim() || "214 32% 91%"; + + // Convert HSL values to hex format for app compatibility + const hslToHex = (h, s, l) => { + l /= 100; + const a = s * Math.min(l, 1 - l) / 100; + const f = n => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + return Math.round(255 * color).toString(16).padStart(2, '0'); + }; + return `#${f(0)}${f(8)}${f(4)}`; + }; + + const parseHsl = (hslStr) => { + const match = hslStr.match(/(\d+)\s+(\d+)%\s+(\d+)%/); + if (match) { + return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])]; + } + return null; + }; + + const bgHsl = parseHsl(background); + const fgHsl = parseHsl(foreground); + const cardHsl = parseHsl(card); + const borderHsl = parseHsl(border); + + // Update the app's CSS variables with the theme colors + // These inline styles override the theme-sentient.css values + if (bgHsl) { + const bgHex = hslToHex(...bgHsl); + document.documentElement.style.setProperty("--bg", bgHex); + document.documentElement.style.setProperty("--primary-bg", `hsl(${background})`); + document.documentElement.style.setProperty("--header-bg", bgHex); + } + if (fgHsl) { + const textHex = hslToHex(...fgHsl); + document.documentElement.style.setProperty("--text", textHex); + document.documentElement.style.setProperty("--primary-fg", `hsl(${foreground})`); + } + if (cardHsl) { + const surfaceHex = hslToHex(...cardHsl); + document.documentElement.style.setProperty("--surface", surfaceHex); + document.documentElement.style.setProperty("--card-bg", surfaceHex); + } + if (borderHsl) { + const borderHex = hslToHex(...borderHsl); + document.documentElement.style.setProperty("--border", borderHex); + } // Update ALL color-related CSS variables to match the theme // This overrides any bot config colors - document.documentElement.style.setProperty("--chat-color1", primaryColor); - document.documentElement.style.setProperty("--chat-color2", cardColor); - document.documentElement.style.setProperty("--suggestion-color", primaryColor); - document.documentElement.style.setProperty("--suggestion-bg", cardColor); - document.documentElement.style.setProperty("--color1", primaryColor); - document.documentElement.style.setProperty("--color2", cardColor); - - console.log("✓ Chat colors updated to match theme:", { primary: primaryColor, card: cardColor }); + document.documentElement.style.setProperty("--chat-color1", `hsl(${primary})`); + document.documentElement.style.setProperty("--chat-color2", `hsl(${card})`); + document.documentElement.style.setProperty("--suggestion-color", `hsl(${primary})`); + document.documentElement.style.setProperty("--suggestion-bg", `hsl(${card})`); + document.documentElement.style.setProperty("--color1", `hsl(${primary})`); + document.documentElement.style.setProperty("--color2", `hsl(${card})`); + console.log("✓ Theme colors applied:", { bg: background, primary: primary }); updateDropdown(); subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name })); }, 50); @@ -128,6 +189,11 @@ const ThemeManager = (() => { } function init() { + // Ensure data-theme is set on html element so CSS selectors work + if (!document.documentElement.getAttribute("data-theme")) { + document.documentElement.setAttribute("data-theme", "sentient"); + } + // First, load saved bot theme from config.csv (if available) loadSavedTheme();