fix(theme): map sentient css variables properly to avoid black boxes on light themes
All checks were successful
BotUI CI / build (push) Successful in 3m57s
All checks were successful
BotUI CI / build (push) Successful in 3m57s
This commit is contained in:
parent
6bbfa2989e
commit
0c2dd80f30
1 changed files with 135 additions and 39 deletions
|
|
@ -6,11 +6,11 @@ const ThemeManager = (() => {
|
||||||
// Bot ID to theme mapping (configured via config.csv theme-base field)
|
// Bot ID to theme mapping (configured via config.csv theme-base field)
|
||||||
const botThemeMap = {
|
const botThemeMap = {
|
||||||
// Default bot uses light theme with brown accents
|
// Default bot uses light theme with brown accents
|
||||||
"default": "light",
|
default: "light",
|
||||||
// Cristo bot uses typewriter theme (classic typewriter style)
|
// Cristo bot uses typewriter theme (classic typewriter style)
|
||||||
"cristo": "typewriter",
|
cristo: "typewriter",
|
||||||
// Salesianos bot uses light theme with blue accents
|
// Salesianos bot uses light theme with blue accents
|
||||||
"salesianos": "light",
|
salesianos: "light",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Detect current bot from URL path
|
// Detect current bot from URL path
|
||||||
|
|
@ -98,72 +98,170 @@ const ThemeManager = (() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Get the theme's colors from CSS variables
|
// Get the theme's colors from CSS variables
|
||||||
const rootStyle = getComputedStyle(document.documentElement);
|
const rootStyle = getComputedStyle(document.documentElement);
|
||||||
const primary = rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6";
|
const primary =
|
||||||
const background = rootStyle.getPropertyValue("--background")?.trim() || "0 0% 100%";
|
rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6";
|
||||||
const foreground = rootStyle.getPropertyValue("--foreground")?.trim() || "222 47% 11%";
|
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 card = rootStyle.getPropertyValue("--card")?.trim() || "0 0% 98%";
|
||||||
const border = rootStyle.getPropertyValue("--border")?.trim() || "214 32% 91%";
|
const border =
|
||||||
|
rootStyle.getPropertyValue("--border")?.trim() || "214 32% 91%";
|
||||||
|
|
||||||
// Convert HSL values to hex format for app compatibility
|
// Convert HSL values to hex format for app compatibility
|
||||||
const hslToHex = (h, s, l) => {
|
const hslToHex = (h, s, l) => {
|
||||||
l /= 100;
|
l /= 100;
|
||||||
const a = s * Math.min(l, 1 - l) / 100;
|
const a = (s * Math.min(l, 1 - l)) / 100;
|
||||||
const f = n => {
|
const f = (n) => {
|
||||||
const k = (n + h / 30) % 12;
|
const k = (n + h / 30) % 12;
|
||||||
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
|
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 Math.round(255 * color)
|
||||||
|
.toString(16)
|
||||||
|
.padStart(2, "0");
|
||||||
};
|
};
|
||||||
return `#${f(0)}${f(8)}${f(4)}`;
|
return `#${f(0)}${f(8)}${f(4)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseHsl = (hslStr) => {
|
const parseHsl = (hslStr) => {
|
||||||
const match = hslStr.match(/(\d+)\s+(\d+)%\s+(\d+)%/);
|
if (!hslStr) return null;
|
||||||
|
const match = hslStr
|
||||||
|
.trim()
|
||||||
|
.match(/([0-9.]+)\s+([0-9.]+)%\s+([0-9.]+)%/);
|
||||||
if (match) {
|
if (match) {
|
||||||
return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
|
return [
|
||||||
|
parseFloat(match[1]),
|
||||||
|
parseFloat(match[2]),
|
||||||
|
parseFloat(match[3]),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getContrastYIQ = (hexcolor) => {
|
||||||
|
if (!hexcolor) return "#ffffff";
|
||||||
|
hexcolor = hexcolor.replace("#", "");
|
||||||
|
if (hexcolor.length === 3) {
|
||||||
|
hexcolor = hexcolor
|
||||||
|
.split("")
|
||||||
|
.map((c) => c + c)
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
if (hexcolor.length !== 6) return "#ffffff";
|
||||||
|
var r = parseInt(hexcolor.substr(0, 2), 16);
|
||||||
|
var g = parseInt(hexcolor.substr(2, 2), 16);
|
||||||
|
var b = parseInt(hexcolor.substr(4, 2), 16);
|
||||||
|
var yiq = (r * 299 + g * 587 + b * 114) / 1000;
|
||||||
|
return yiq >= 128 ? "#000000" : "#ffffff";
|
||||||
|
};
|
||||||
|
|
||||||
const bgHsl = parseHsl(background);
|
const bgHsl = parseHsl(background);
|
||||||
const fgHsl = parseHsl(foreground);
|
const fgHsl = parseHsl(foreground);
|
||||||
const cardHsl = parseHsl(card);
|
const cardHsl = parseHsl(card);
|
||||||
const borderHsl = parseHsl(border);
|
const borderHsl = parseHsl(border);
|
||||||
|
|
||||||
// Update the app's CSS variables with the theme colors
|
let calculatedTextHex = "#ffffff";
|
||||||
// These inline styles override the theme-sentient.css values
|
|
||||||
if (bgHsl) {
|
if (bgHsl) {
|
||||||
const bgHex = hslToHex(...bgHsl);
|
const bgHex = hslToHex(...bgHsl);
|
||||||
document.documentElement.style.setProperty("--bg", bgHex);
|
document.documentElement.style.setProperty("--bg", bgHex);
|
||||||
document.documentElement.style.setProperty("--primary-bg", `hsl(${background})`);
|
document.documentElement.style.setProperty("--bg-secondary", bgHex);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--primary-bg",
|
||||||
|
`hsl(${background})`,
|
||||||
|
);
|
||||||
document.documentElement.style.setProperty("--header-bg", bgHex);
|
document.documentElement.style.setProperty("--header-bg", bgHex);
|
||||||
|
document.documentElement.style.setProperty("--glass-bg", bgHex);
|
||||||
|
document.documentElement.style.setProperty("--sidebar-bg", bgHex);
|
||||||
|
calculatedTextHex = getContrastYIQ(bgHex);
|
||||||
}
|
}
|
||||||
if (fgHsl) {
|
if (fgHsl) {
|
||||||
const textHex = hslToHex(...fgHsl);
|
const textHex = hslToHex(...fgHsl);
|
||||||
document.documentElement.style.setProperty("--text", textHex);
|
document.documentElement.style.setProperty("--text", textHex);
|
||||||
document.documentElement.style.setProperty("--primary-fg", `hsl(${foreground})`);
|
document.documentElement.style.setProperty("--text-primary", textHex);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--text-secondary",
|
||||||
|
textHex,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty("--text-muted", textHex);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--primary-fg",
|
||||||
|
`hsl(${foreground})`,
|
||||||
|
);
|
||||||
|
} else if (bgHsl) {
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--text",
|
||||||
|
calculatedTextHex,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--text-primary",
|
||||||
|
calculatedTextHex,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--text-secondary",
|
||||||
|
calculatedTextHex,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--text-muted",
|
||||||
|
calculatedTextHex,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (cardHsl) {
|
if (cardHsl) {
|
||||||
const surfaceHex = hslToHex(...cardHsl);
|
const surfaceHex = hslToHex(...cardHsl);
|
||||||
document.documentElement.style.setProperty("--surface", surfaceHex);
|
document.documentElement.style.setProperty("--surface", surfaceHex);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--surface-hover",
|
||||||
|
surfaceHex,
|
||||||
|
);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--surface-active",
|
||||||
|
surfaceHex,
|
||||||
|
);
|
||||||
document.documentElement.style.setProperty("--card-bg", surfaceHex);
|
document.documentElement.style.setProperty("--card-bg", surfaceHex);
|
||||||
}
|
}
|
||||||
if (borderHsl) {
|
if (borderHsl) {
|
||||||
const borderHex = hslToHex(...borderHsl);
|
const borderHex = hslToHex(...borderHsl);
|
||||||
document.documentElement.style.setProperty("--border", borderHex);
|
document.documentElement.style.setProperty("--border", borderHex);
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--border-light",
|
||||||
|
borderHex,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if config.csv already set the primary color, we shouldn't wipe it
|
// Check if config.csv already set the primary color, we shouldn't wipe it
|
||||||
// Only update color and suggestion variables if they aren't marked as bot-config
|
// Only update color and suggestion variables if they aren't marked as bot-config
|
||||||
if (document.documentElement.getAttribute("data-has-bot-colors") !== "true") {
|
if (
|
||||||
document.documentElement.style.setProperty("--chat-color1", `hsl(${primary})`);
|
document.documentElement.getAttribute("data-has-bot-colors") !==
|
||||||
document.documentElement.style.setProperty("--chat-color2", `hsl(${card})`);
|
"true"
|
||||||
document.documentElement.style.setProperty("--suggestion-color", `hsl(${primary})`);
|
) {
|
||||||
document.documentElement.style.setProperty("--suggestion-bg", `hsl(${card})`);
|
document.documentElement.style.setProperty(
|
||||||
document.documentElement.style.setProperty("--color1", `hsl(${primary})`);
|
"--chat-color1",
|
||||||
document.documentElement.style.setProperty("--color2", `hsl(${card})`);
|
`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 });
|
console.log("✓ Theme colors applied:", {
|
||||||
|
bg: background,
|
||||||
|
primary: primary,
|
||||||
|
});
|
||||||
updateDropdown();
|
updateDropdown();
|
||||||
subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name }));
|
subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name }));
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|
@ -218,7 +316,7 @@ const ThemeManager = (() => {
|
||||||
// Dropdown injection restored for the window manager
|
// Dropdown injection restored for the window manager
|
||||||
const container = document.getElementById("themeSelectorContainer");
|
const container = document.getElementById("themeSelectorContainer");
|
||||||
if (container) {
|
if (container) {
|
||||||
container.innerHTML = '';
|
container.innerHTML = "";
|
||||||
container.appendChild(createDropdown());
|
container.appendChild(createDropdown());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,24 +335,22 @@ const ThemeManager = (() => {
|
||||||
|
|
||||||
if (data.logo_url) {
|
if (data.logo_url) {
|
||||||
// For img elements - set src and show, hide SVG
|
// For img elements - set src and show, hide SVG
|
||||||
const logoImg = document.querySelector('.logo-icon-img');
|
const logoImg = document.querySelector(".logo-icon-img");
|
||||||
const logoSvg = document.querySelector('.logo-icon-svg');
|
const logoSvg = document.querySelector(".logo-icon-svg");
|
||||||
if (logoImg && logoSvg) {
|
if (logoImg && logoSvg) {
|
||||||
logoImg.src = data.logo_url;
|
logoImg.src = data.logo_url;
|
||||||
logoImg.alt = data.title || 'Logo';
|
logoImg.alt = data.title || "Logo";
|
||||||
logoImg.style.display = 'block';
|
logoImg.style.display = "block";
|
||||||
logoSvg.style.display = 'none';
|
logoSvg.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
// For elements that use background image
|
// For elements that use background image
|
||||||
document
|
document.querySelectorAll(".assistant-avatar").forEach((el) => {
|
||||||
.querySelectorAll(".assistant-avatar")
|
el.style.backgroundImage = `url("${data.logo_url}")`;
|
||||||
.forEach((el) => {
|
el.style.backgroundSize = "contain";
|
||||||
el.style.backgroundImage = `url("${data.logo_url}")`;
|
el.style.backgroundRepeat = "no-repeat";
|
||||||
el.style.backgroundSize = "contain";
|
el.style.backgroundPosition = "center";
|
||||||
el.style.backgroundRepeat = "no-repeat";
|
});
|
||||||
el.style.backgroundPosition = "center";
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (data.color1) {
|
if (data.color1) {
|
||||||
document.documentElement.style.setProperty("--color1", data.color1);
|
document.documentElement.style.setProperty("--color1", data.color1);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue