Spaces:
Running
Running
// ===== KIMI APPEARANCE MANAGER ===== | |
class KimiAppearanceManager extends KimiBaseManager { | |
constructor(database) { | |
super(); | |
this.db = database; | |
this.currentTheme = "purple"; | |
this.interfaceOpacity = 0.8; | |
this.animationsEnabled = true; | |
} | |
async init() { | |
try { | |
await this.loadAppearanceSettings(); | |
this.applyTheme(this.currentTheme); | |
this.applyInterfaceOpacity(this.interfaceOpacity); | |
this.applyAnimationSettings(this.animationsEnabled); | |
this.setupAppearanceControls(); | |
this.syncAnimationToggleState(); | |
} catch (error) { | |
console.error("KimiAppearanceManager initialization error:", error); | |
} | |
} | |
syncAnimationToggleState() { | |
const animationsToggle = document.getElementById("animations-toggle"); | |
if (animationsToggle) { | |
animationsToggle.classList.toggle("active", this.animationsEnabled); | |
animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); | |
} | |
} | |
async loadAppearanceSettings() { | |
if (!this.db) return; | |
try { | |
this.currentTheme = await this.db.getPreference("colorTheme", "purple"); | |
this.interfaceOpacity = await this.db.getPreference("interfaceOpacity", 0.8); | |
this.animationsEnabled = await this.db.getPreference("animationsEnabled", true); | |
} catch (error) { | |
console.error("Error loading appearance settings:", error); | |
} | |
} | |
setupAppearanceControls() { | |
try { | |
this.setupThemeSelector(); | |
this.setupOpacitySlider(); | |
this.setupAnimationsToggle(); | |
} catch (error) { | |
console.error("Error setting up appearance controls:", error); | |
} | |
} | |
setupThemeSelector() { | |
const themeSelector = document.getElementById("color-theme"); | |
if (!themeSelector) return; | |
themeSelector.value = this.currentTheme; | |
themeSelector.addEventListener("change", async e => { | |
try { | |
await this.changeTheme(e.target.value); | |
} catch (error) { | |
console.error("Error changing theme:", error); | |
} | |
}); | |
} | |
setupOpacitySlider() { | |
const opacitySlider = document.getElementById("interface-opacity"); | |
const opacityValue = document.getElementById("interface-opacity-value"); | |
if (!opacitySlider || !opacityValue) return; | |
opacitySlider.value = this.interfaceOpacity; | |
opacityValue.textContent = this.interfaceOpacity; | |
opacitySlider.addEventListener("input", async e => { | |
try { | |
const value = parseFloat(e.target.value); | |
opacityValue.textContent = value; | |
await this.changeInterfaceOpacity(value); | |
} catch (error) { | |
console.error("Error changing opacity:", error); | |
} | |
}); | |
} | |
setupAnimationsToggle() { | |
const animationsToggle = document.getElementById("animations-toggle"); | |
if (!animationsToggle) return; | |
animationsToggle.classList.toggle("active", this.animationsEnabled); | |
animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); | |
// Remove any existing listener to prevent conflicts | |
if (this._animationsClickHandler) { | |
animationsToggle.removeEventListener("click", this._animationsClickHandler); | |
} | |
this._animationsClickHandler = async () => { | |
try { | |
this.animationsEnabled = !this.animationsEnabled; | |
animationsToggle.classList.toggle("active", this.animationsEnabled); | |
animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); | |
await this.toggleAnimations(this.animationsEnabled); | |
} catch (error) { | |
console.error("Error toggling animations:", error); | |
} | |
}; | |
animationsToggle.addEventListener("click", this._animationsClickHandler); | |
} | |
async changeTheme(theme) { | |
try { | |
this.currentTheme = theme; | |
this.applyTheme(theme); | |
if (this.db) { | |
await this.db.setPreference("colorTheme", theme); | |
} | |
} catch (error) { | |
console.error("Error changing theme:", error); | |
} | |
} | |
async changeInterfaceOpacity(opacity) { | |
try { | |
const validatedOpacity = window.KimiValidationUtils?.validateRange(opacity, "interfaceOpacity"); | |
const finalOpacity = validatedOpacity?.valid ? validatedOpacity.value : opacity; | |
this.interfaceOpacity = finalOpacity; | |
this.applyInterfaceOpacity(finalOpacity); | |
if (this.db) { | |
await this.db.setPreference("interfaceOpacity", finalOpacity); | |
} | |
} catch (error) { | |
console.error("Error changing interface opacity:", error); | |
} | |
} | |
async toggleAnimations(enabled) { | |
try { | |
this.animationsEnabled = enabled; | |
this.applyAnimationSettings(enabled); | |
if (this.db) { | |
await this.db.setPreference("animationsEnabled", enabled); | |
} | |
} catch (error) { | |
console.error("Error toggling animations:", error); | |
} | |
} | |
applyTheme(theme) { | |
document.documentElement.setAttribute("data-theme", theme); | |
} | |
applyInterfaceOpacity(opacity) { | |
document.documentElement.style.setProperty("--interface-opacity", opacity); | |
} | |
applyAnimationSettings(enabled) { | |
document.documentElement.setAttribute("data-animations", enabled ? "true" : "false"); | |
document.documentElement.style.setProperty("--animations-enabled", enabled ? "1" : "0"); | |
// Ensure body class reflects animation state | |
if (enabled) { | |
document.body.classList.remove("no-animations"); | |
document.body.classList.add("animations-enabled"); | |
} else { | |
document.body.classList.remove("animations-enabled"); | |
document.body.classList.add("no-animations"); | |
} | |
} | |
cleanup() { | |
const animationsToggle = document.getElementById("animations-toggle"); | |
if (animationsToggle && this._animationsClickHandler) { | |
animationsToggle.removeEventListener("click", this._animationsClickHandler); | |
this._animationsClickHandler = null; | |
} | |
} | |
getThemeName(theme) { | |
const themeNames = { | |
dark: "Dark Night", | |
default: "Passionate Pink", | |
blue: "Ocean Blue", | |
purple: "Mystic Purple", | |
green: "Emerald Forest" | |
}; | |
return themeNames[theme] || "Unknown"; | |
} | |
forceSyncUIState() { | |
// Force synchronization of UI state to prevent inconsistencies | |
const animationsToggle = document.getElementById("animations-toggle"); | |
if (animationsToggle) { | |
// Remove any conflicting classes or states | |
animationsToggle.classList.remove("active"); | |
// Re-apply correct state | |
animationsToggle.classList.toggle("active", this.animationsEnabled); | |
animationsToggle.setAttribute("aria-checked", this.animationsEnabled ? "true" : "false"); | |
// Ensure CSS custom properties are in sync | |
this.applyAnimationSettings(this.animationsEnabled); | |
} | |
} | |
} | |
window.KimiAppearanceManager = KimiAppearanceManager; | |