// Unified Theme Manager - Dropdown only, no light/dark toggle const ThemeManager = (() => { let currentThemeId = "default"; let subscribers = []; // Bot ID to theme mapping (configured via config.csv theme-base field) const botThemeMap = { // Default bot uses light theme with brown accents "default": "light", // Cristo bot uses mellowgold theme with earth tones "cristo": "mellowgold", // Salesianos bot uses light theme with blue accents "salesianos": "light", }; // Detect current bot from URL path function getCurrentBotId() { const path = window.location.pathname; // Match patterns like /bot/cristo, /cristo, etc. const match = path.match(/(?:\/bot\/)?([a-z0-9-]+)/i); if (match && match[1]) { return match[1].toLowerCase(); } return "default"; } const themes = [ { id: "default", name: "🎨 Default", file: "light.css" }, { id: "light", name: "â˜€ī¸ Light", file: "light.css" }, { id: "orange", name: "🍊 Orange", file: "orange.css" }, { id: "cyberpunk", name: "🌃 Cyberpunk", file: "cyberpunk.css" }, { id: "retrowave", name: "🌴 Retrowave", file: "retrowave.css" }, { id: "vapordream", name: "💭 Vapor Dream", file: "vapordream.css" }, { id: "y2kglow", name: "✨ Y2K", file: "y2kglow.css" }, { id: "3dbevel", name: "🔲 3D Bevel", file: "3dbevel.css" }, { id: "arcadeflash", name: "đŸ•šī¸ Arcade", file: "arcadeflash.css" }, { id: "discofever", name: "đŸĒŠ Disco", file: "discofever.css" }, { id: "grungeera", name: "🎸 Grunge", file: "grungeera.css" }, { id: "jazzage", name: "đŸŽē Jazz", file: "jazzage.css" }, { id: "mellowgold", name: "đŸŒģ Mellow", file: "mellowgold.css" }, { id: "midcenturymod", name: "🏠 Mid Century", file: "midcenturymod.css" }, { id: "polaroidmemories", name: "📷 Polaroid", file: "polaroidmemories.css", }, { id: "saturdaycartoons", name: "đŸ“ē Cartoons", file: "saturdaycartoons.css", }, { id: "seasidepostcard", name: "đŸ–ī¸ Seaside", file: "seasidepostcard.css" }, { id: "typewriter", name: "âŒ¨ī¸ Typewriter", file: "typewriter.css" }, { id: "xeroxui", name: "📠 Xerox", file: "xeroxui.css" }, { id: "xtreegold", name: "📁 XTree", file: "xtreegold.css" }, ]; function loadTheme(id) { const theme = themes.find((t) => t.id === id); if (!theme) { console.warn("Theme not found:", id); return; } const old = document.getElementById("theme-css"); if (old) old.remove(); if (!theme.file) { currentThemeId = "default"; localStorage.setItem("gb-theme", "default"); updateDropdown(); return; } const link = document.createElement("link"); link.id = "theme-css"; link.rel = "stylesheet"; link.href = `/suite/public/themes/${theme.file}`; link.onload = () => { console.log("✓ Theme loaded:", theme.name); currentThemeId = id; localStorage.setItem("gb-theme", id); // Get the theme's primary color from CSS variables const rootStyle = getComputedStyle(document.documentElement); const primaryColor = rootStyle.getPropertyValue("--primary")?.trim() || "#3b82f6"; const cardColor = rootStyle.getPropertyValue("--card")?.trim() || "#fafafa"; // Update chat-specific CSS variables to match the theme 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); console.log("✓ Chat colors updated to match theme:", { primary: primaryColor, card: cardColor }); updateDropdown(); subscribers.forEach((cb) => cb({ themeId: id, themeName: theme.name })); }; link.onerror = () => console.error("✗ Failed:", theme.name); document.head.appendChild(link); } function updateDropdown() { const dd = document.getElementById("themeDropdown"); if (dd) dd.value = currentThemeId; } function createDropdown() { const select = document.createElement("select"); select.id = "themeDropdown"; select.className = "theme-dropdown"; themes.forEach((t) => { const opt = document.createElement("option"); opt.value = t.id; opt.textContent = t.name; select.appendChild(opt); }); select.value = currentThemeId; select.onchange = (e) => loadTheme(e.target.value); return select; } function init() { // First, load saved bot theme from config.csv (if available) loadSavedTheme(); // Then load the UI theme (CSS theme) // Priority: 1) localStorage user preference, 2) bot-specific theme, 3) default let saved = localStorage.getItem("gb-theme"); if (!saved || !themes.find((t) => t.id === saved)) { // No user preference, try bot-specific theme const botId = getCurrentBotId(); saved = botThemeMap[botId] || "light"; // Save to localStorage so it persists localStorage.setItem("gb-theme", saved); } if (!themes.find((t) => t.id === saved)) saved = "default"; currentThemeId = saved; loadTheme(saved); const container = document.getElementById("themeSelectorContainer"); if (container) container.appendChild(createDropdown()); console.log("✓ Theme Manager initialized"); } function setThemeFromServer(data) { // Save theme to localStorage for persistence across page loads localStorage.setItem("gb-theme-data", JSON.stringify(data)); // Load base theme if specified if (data.theme_base) { loadTheme(data.theme_base); } if (data.logo_url) { // For img elements - set src and show, hide SVG const logoImg = document.querySelector('.logo-icon-img'); const logoSvg = document.querySelector('.logo-icon-svg'); if (logoImg && logoSvg) { logoImg.src = data.logo_url; logoImg.alt = data.title || 'Logo'; logoImg.style.display = 'block'; logoSvg.style.display = 'none'; } // For elements that use background image document .querySelectorAll(".assistant-avatar") .forEach((el) => { el.style.backgroundImage = `url("${data.logo_url}")`; el.style.backgroundSize = "contain"; el.style.backgroundRepeat = "no-repeat"; el.style.backgroundPosition = "center"; }); } if (data.color1) { document.documentElement.style.setProperty("--color1", data.color1); } if (data.color2) { document.documentElement.style.setProperty("--color2", data.color2); } if (data.title) document.title = data.title; if (data.logo_text) { document.querySelectorAll(".logo span, .logo-text").forEach((el) => { el.textContent = data.logo_text; }); } } // Load saved theme from localStorage on page load function loadSavedTheme() { const savedTheme = localStorage.getItem("gb-theme-data"); if (savedTheme) { try { const data = JSON.parse(savedTheme); setThemeFromServer(data); console.log("✓ Theme loaded from localStorage"); } catch (e) { console.warn("Failed to load saved theme:", e); } } } function applyCustomizations() { // Called by modules if needed } function subscribe(cb) { subscribers.push(cb); } return { init, loadTheme, setThemeFromServer, loadSavedTheme, applyCustomizations, subscribe, getAvailableThemes: () => themes, }; })(); window.ThemeManager = ThemeManager;