6.7 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			6.7 KiB
		
	
	
	
	
	
	
	
Système de Théming ObsiViewer - Documentation
Vue d'ensemble
Système de théming double dimension : 7 thèmes × 2 modes = 14 combinaisons
- Modes : Light, Dark
 - Thèmes : Light (default), Dark (default), Obsidian, Nord, Notion, GitHub, Discord, Monokai
 
Architecture
1. Tokens CSS (src/styles/themes.css)
Tous les thèmes définissent un ensemble cohérent de tokens CSS :
/* Backgrounds */
--bg, --bg-main, --bg-muted
--card, --card-bg, --elevated
--sidebar-bg, --surface-1, --surface-2
/* Text */
--fg, --text-main, --text-muted, --muted
/* Borders */
--border
/* Brand & Accents */
--primary, --brand, --brand-700, --brand-800
--secondary, --accent
/* Status */
--success, --warning, --danger, --info
/* UI Elements */
--chip-bg, --link, --link-hover, --ring
/* Editor (CodeMirror 6) */
--editor-bg, --editor-fg, --editor-selection
--editor-gutter-bg, --editor-gutter-fg, --editor-cursor
/* Shadows */
--shadow-color, --scrollbar-thumb
2. Configuration Tailwind (tailwind.config.js)
Tous les tokens sont mappés dans Tailwind :
colors: {
  bg: 'var(--bg)',
  'bg-main': 'var(--bg-main)',
  fg: 'var(--fg)',
  surface1: 'var(--surface-1)',
  primary: 'var(--primary)',
  // ... etc
}
3. ThemeService (src/app/core/services/theme.service.ts)
Service central qui gère :
- Mode : 
'system' | 'light' | 'dark' - Thème : 
'light' | 'dark' | 'obsidian' | 'nord' | 'notion' | 'github' | 'discord' | 'monokai' - Application sur 
<html>: classe.dark+ attributdata-theme - Persistance dans localStorage
 - Observable 
onPrefs$pour réactivité 
4. CodeMirror 6 (src/app/core/codemirror-themes.ts)
Fonction cm6ThemeFor(themeId, mode) qui retourne les extensions CM6 appropriées pour chaque combinaison thème/mode.
5. Anti-FOUC (index.html)
Script inline qui lit les préférences et applique le thème avant le chargement d'Angular :
(function () {
  const prefs = JSON.parse(localStorage.getItem('obsiviewer.preferences.v1') || '{}');
  const isDark = prefs.mode === 'dark' || (prefs.mode === 'system' && prefersDark);
  html.classList.toggle('dark', isDark);
  html.setAttribute('data-theme', prefs.theme || 'light');
})();
Matrice des Thèmes
Light (Default)
- Light mode : Blanc pur, texte gris foncé, accents bleus
 - Dark mode : N/A (thème light uniquement)
 
Dark (Default)
- Light mode : N/A (thème dark uniquement)
 - Dark mode : Fond bleu-gris foncé, texte clair, accents bleus clairs
 
Obsidian
- Light mode : Beige chaud (#fafaf8), texte anthracite, accents terre
 - Dark mode : Gris très foncé (#1e1e1e), texte clair, accents beiges
 
Nord
- Light mode : Blanc neigeux (#eceff4), texte bleu-gris, palette nordique pastel
 - Dark mode : Bleu-gris arctique (#2e3440), texte givré, palette nordique
 
Notion
- Light mode : Blanc pur, texte charbon, minimaliste
 - Dark mode : Noir profond (#171717), texte ivoire, contraste élevé
 
GitHub
- Light mode : Blanc, texte GitHub (#24292f), palette GitHub
 - Dark mode : Dimmed dark (#0d1117), palette GitHub dark
 
Discord
- Light mode : Gris très clair (#f6f7f9), texte foncé, violet Discord
 - Dark mode : Gris Discord (#2b2d31), texte clair, violet Discord
 
Monokai
- Light mode : Crème (#fbfbf7), texte foncé, accents verts/oranges atténués
 - Dark mode : Vert-gris foncé (#272822), texte clair, palette Monokai classique
 
Utilisation dans les Composants
Classes Tailwind recommandées
<!-- Backgrounds -->
<div class="bg-card">Carte</div>
<div class="bg-surface1">Surface niveau 1</div>
<div class="bg-surface2">Surface niveau 2</div>
<!-- Text -->
<p class="text-main">Texte principal</p>
<p class="text-muted">Texte secondaire</p>
<!-- Borders -->
<div class="border border-border">Bordure</div>
<!-- Interactive -->
<button class="bg-primary text-white hover:bg-brand-700">
  Action
</button>
<!-- Links -->
<a class="text-link hover:text-link-hover">Lien</a>
⚠️ À ÉVITER
<!-- ❌ Couleurs hardcodées -->
<div class="bg-slate-100 text-gray-900">...</div>
<div class="dark:bg-gray-800">...</div>
<!-- ✅ Utiliser les tokens -->
<div class="bg-surface1 text-main">...</div>
Tests
Checklist de validation
Pour chaque combinaison (14 au total) :
- Sidebar : Fond, hover, items actifs, badges
 - Topbar : Barre de recherche, focus, placeholder
 - Liste des notes : Items, hover, selected, path muted
 - Page détail : Titres, liens, listes, blockquotes, code, tables
 - Mode édition : Inputs, buttons, toolbars, CodeMirror
 - Panneaux : TOC, propriétés, tags
 - Modales : Fond, bordure, overlay
 - Menus contextuels : Dropdown, tooltips
 - Toasts : Fond, bordure, barre de progression
 - Tables : Headers, zebra, hover
 - Chips/Tags : Fond, texte, bordure, hover, selected
 - Scrollbars : Thumb, track
 - Page Parameters : Contrôles mode/thème
 - Mobile : Bottom nav, sheets, drawers
 
Contraste
Tous les thèmes doivent respecter WCAG AA :
- Texte normal : ratio ≥ 4.5:1
 - Texte large : ratio ≥ 3:1
 
Refactoring effectué
Automatisé (script refactor-colors.mjs)
- ✅ 66 fichiers mis à jour automatiquement
 - ✅ Remplacement de 232+ occurrences de couleurs hardcodées
 - ✅ Gestion des variantes : hover, focus, dark
 
Restant (109 occurrences)
Cas complexes nécessitant révision manuelle :
- Composants avec logique conditionnelle
 - Styles inline dynamiques
 - Cas spécifiques métier
 
Commandes utiles
# Lancer le refactoring automatique
node scripts/refactor-colors.mjs
# Rechercher les couleurs hardcodées restantes
grep -r "bg-slate-\|bg-gray-\|text-slate-\|text-gray-" src/
# Lancer l'application en mode dev
npm run dev
# Tests E2E
npm run test:e2e
Prochaines étapes
- ✅ Créer themes.css avec 14 variantes
 - ✅ Configurer Tailwind
 - ✅ Mettre à jour codemirror-themes.ts
 - ✅ Refactoring automatisé (68% des couleurs)
 - 🔄 Refactoring manuel des 109 occurrences restantes
 - ⏳ Tests matrice complète
 - ⏳ Validation contrastes
 - ⏳ Documentation utilisateur
 
Notes techniques
- Persistance : 
localStoragecléobsiviewer.preferences.v1 - Réactivité : Observable 
ThemeService.onPrefs$ - SSR-safe : Vérifications 
typeof window !== 'undefined' - Performance : Transitions CSS 150ms
 - Accessibilité : 
color-schemeCSS pour scrollbars natives