212 lines
6.5 KiB
JavaScript
212 lines
6.5 KiB
JavaScript
import { debug, debugError } from './debug.js';
|
|
/**
|
|
* ThemeManager - Gère le système de thèmes de l'application
|
|
* Permet de changer entre différents thèmes et persiste le choix dans localStorage
|
|
*/
|
|
class ThemeManager {
|
|
constructor() {
|
|
this.themes = [
|
|
{
|
|
id: 'material-dark',
|
|
name: 'Material Dark',
|
|
icon: '🌙',
|
|
description: 'Thème professionnel inspiré de Material Design'
|
|
},
|
|
{
|
|
id: 'monokai-dark',
|
|
name: 'Monokai Dark',
|
|
icon: '🎨',
|
|
description: 'Palette Monokai classique pour les développeurs'
|
|
},
|
|
{
|
|
id: 'dracula',
|
|
name: 'Dracula',
|
|
icon: '🧛',
|
|
description: 'Thème sombre élégant avec des accents violets et cyan'
|
|
},
|
|
{
|
|
id: 'one-dark',
|
|
name: 'One Dark',
|
|
icon: '⚡',
|
|
description: 'Thème populaire d\'Atom avec des couleurs douces'
|
|
},
|
|
{
|
|
id: 'solarized-dark',
|
|
name: 'Solarized Dark',
|
|
icon: '☀️',
|
|
description: 'Palette scientifiquement optimisée pour réduire la fatigue oculaire'
|
|
},
|
|
{
|
|
id: 'nord',
|
|
name: 'Nord',
|
|
icon: '❄️',
|
|
description: 'Palette arctique apaisante avec des tons bleus froids'
|
|
},
|
|
{
|
|
id: 'catppuccin',
|
|
name: 'Catppuccin',
|
|
icon: '🌸',
|
|
description: 'Thème pastel doux et chaleureux avec des accents roses et bleus'
|
|
},
|
|
{
|
|
id: 'everforest',
|
|
name: 'Everforest',
|
|
icon: '🌲',
|
|
description: 'Palette naturelle inspirée de la forêt avec des tons verts et beiges'
|
|
}
|
|
];
|
|
|
|
this.currentTheme = this.loadTheme();
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
// Appliquer le thème sauvegardé
|
|
this.applyTheme(this.currentTheme);
|
|
|
|
// Écouter les événements HTMX pour réinitialiser les listeners
|
|
document.body.addEventListener('htmx:afterSwap', (event) => {
|
|
if (event.detail.target.id === 'sidebar' || event.detail.target.closest('#sidebar')) {
|
|
this.attachModalListeners();
|
|
}
|
|
});
|
|
|
|
debug('ThemeManager initialized with theme:', this.currentTheme);
|
|
}
|
|
|
|
loadTheme() {
|
|
// Charger le thème depuis localStorage, par défaut 'material-dark'
|
|
return localStorage.getItem('app-theme') || 'material-dark';
|
|
}
|
|
|
|
saveTheme(themeId) {
|
|
localStorage.setItem('app-theme', themeId);
|
|
}
|
|
|
|
applyTheme(themeId) {
|
|
// Appliquer le thème sur l'élément racine
|
|
document.documentElement.setAttribute('data-theme', themeId);
|
|
this.currentTheme = themeId;
|
|
this.saveTheme(themeId);
|
|
|
|
// Mettre à jour les cartes de thème si la modale est ouverte
|
|
this.updateThemeCards();
|
|
|
|
debug('Theme applied:', themeId);
|
|
}
|
|
|
|
openThemeModal() {
|
|
const modal = document.getElementById('theme-modal');
|
|
if (modal) {
|
|
modal.style.display = 'flex';
|
|
this.updateThemeCards();
|
|
}
|
|
}
|
|
|
|
closeThemeModal() {
|
|
const modal = document.getElementById('theme-modal');
|
|
if (modal) {
|
|
modal.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
updateThemeCards() {
|
|
// Mettre à jour l'état actif des cartes de thème
|
|
const cards = document.querySelectorAll('.theme-card');
|
|
cards.forEach(card => {
|
|
const themeId = card.dataset.theme;
|
|
if (themeId === this.currentTheme) {
|
|
card.classList.add('active');
|
|
} else {
|
|
card.classList.remove('active');
|
|
}
|
|
});
|
|
}
|
|
|
|
attachModalListeners() {
|
|
// Ré-attacher les listeners après un swap HTMX
|
|
const settingsBtn = document.getElementById('theme-settings-btn');
|
|
if (settingsBtn) {
|
|
settingsBtn.replaceWith(settingsBtn.cloneNode(true));
|
|
const newBtn = document.getElementById('theme-settings-btn');
|
|
newBtn.addEventListener('click', () => this.openThemeModal());
|
|
}
|
|
}
|
|
|
|
getThemes() {
|
|
return this.themes;
|
|
}
|
|
|
|
getCurrentTheme() {
|
|
return this.currentTheme;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Fonctions globales pour les boutons
|
|
*/
|
|
window.openThemeModal = function() {
|
|
if (window.themeManager) {
|
|
window.themeManager.openThemeModal();
|
|
}
|
|
};
|
|
|
|
window.closeThemeModal = function() {
|
|
if (window.themeManager) {
|
|
window.themeManager.closeThemeModal();
|
|
}
|
|
};
|
|
|
|
window.selectTheme = function(themeId) {
|
|
if (window.themeManager) {
|
|
window.themeManager.applyTheme(themeId);
|
|
}
|
|
};
|
|
|
|
window.switchSettingsTab = function(tabName) {
|
|
debug('Switching to tab:', tabName);
|
|
|
|
// Désactiver tous les onglets
|
|
const tabs = document.querySelectorAll('.settings-tab');
|
|
tabs.forEach(tab => tab.classList.remove('active'));
|
|
|
|
// Cacher toutes les sections
|
|
document.getElementById('themes-section').style.display = 'none';
|
|
document.getElementById('fonts-section').style.display = 'none';
|
|
document.getElementById('editor-section').style.display = 'none';
|
|
const otherSection = document.getElementById('other-section');
|
|
if (otherSection) {
|
|
otherSection.style.display = 'none';
|
|
}
|
|
|
|
// Activer l'onglet cliqué
|
|
const activeTab = Array.from(tabs).find(tab => {
|
|
const text = tab.textContent.toLowerCase();
|
|
if (tabName === 'themes') return text.includes('thème');
|
|
if (tabName === 'fonts') return text.includes('police');
|
|
if (tabName === 'editor') return text.includes('éditeur');
|
|
if (tabName === 'other') return text.includes('autre');
|
|
return false;
|
|
});
|
|
if (activeTab) {
|
|
activeTab.classList.add('active');
|
|
}
|
|
|
|
// Afficher la section correspondante
|
|
const sectionId = tabName + '-section';
|
|
const section = document.getElementById(sectionId);
|
|
if (section) {
|
|
section.style.display = 'block';
|
|
debug('Showing section:', sectionId);
|
|
} else {
|
|
console.error('Section not found:', sectionId);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Initialisation automatique
|
|
*/
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.themeManager = new ThemeManager();
|
|
});
|