/** * MYP Platform Dark Mode Handler * Version: 6.0.0 */ // Sofort ausführen, um FOUC zu vermeiden (Flash of Unstyled Content) (function() { "use strict"; // Speicherort für Dark Mode-Einstellung const STORAGE_KEY = 'myp-dark-mode'; // DOM-Elemente let darkModeToggle; const html = document.documentElement; // Initialisierung beim Laden der Seite document.addEventListener('DOMContentLoaded', initialize); // Prüft System-Präferenz und gespeicherte Einstellung function shouldUseDarkMode() { // Lokale Speichereinstellung prüfen const savedMode = localStorage.getItem(STORAGE_KEY); // Prüfen ob es eine gespeicherte Einstellung gibt if (savedMode !== null) { return savedMode === 'true'; } // Ansonsten Systemeinstellung verwenden return window.matchMedia('(prefers-color-scheme: dark)').matches; } // Setzt Dark/Light Mode function setDarkMode(enable) { // Deaktiviere Übergänge temporär, um Flackern zu vermeiden html.classList.add('disable-transitions'); // Dark Mode Klasse am HTML-Element setzen if (enable) { html.classList.add('dark'); html.setAttribute('data-theme', 'dark'); html.style.colorScheme = 'dark'; } else { html.classList.remove('dark'); html.setAttribute('data-theme', 'light'); html.style.colorScheme = 'light'; } // Speichern in LocalStorage localStorage.setItem(STORAGE_KEY, enable); // Update ThemeColor Meta-Tag updateMetaThemeColor(enable); // Wenn Toggle existiert, aktualisiere Icon if (darkModeToggle) { updateDarkModeToggle(enable); } // Event für andere Komponenten window.dispatchEvent(new CustomEvent('darkModeChanged', { detail: { isDark: enable, source: 'dark-mode-toggle', timestamp: new Date().toISOString() } })); // Event auch als eigenen Event-Typ versenden (rückwärtskompatibel) const eventName = enable ? 'darkModeEnabled' : 'darkModeDisabled'; window.dispatchEvent(new CustomEvent(eventName, { detail: { timestamp: new Date().toISOString() } })); // Übergänge nach kurzer Verzögerung wieder aktivieren setTimeout(function() { html.classList.remove('disable-transitions'); }, 100); // Erfolgsmeldung in die Konsole console.log(`Dark Mode ${enable ? 'aktiviert' : 'deaktiviert'}`); } // Aktualisiert das Theme-Color Meta-Tag function updateMetaThemeColor(isDark) { // Alle Theme-Color Meta-Tags aktualisieren const metaTags = [ document.getElementById('metaThemeColor'), document.querySelector('meta[name="theme-color"]'), document.querySelector('meta[name="theme-color"][media="(prefers-color-scheme: light)"]'), document.querySelector('meta[name="theme-color"][media="(prefers-color-scheme: dark)"]') ]; // CSS-Variablen für konsistente Farben verwenden const darkColor = getComputedStyle(document.documentElement).getPropertyValue('--color-bg') || '#0f172a'; const lightColor = getComputedStyle(document.documentElement).getPropertyValue('--color-bg') || '#ffffff'; metaTags.forEach(tag => { if (tag) { // Für Media-spezifische Tags die entsprechende Farbe setzen if (tag.getAttribute('media') === '(prefers-color-scheme: dark)') { tag.setAttribute('content', darkColor); } else if (tag.getAttribute('media') === '(prefers-color-scheme: light)') { tag.setAttribute('content', lightColor); } else { // Für nicht-Media-spezifische Tags die aktuelle Farbe setzen tag.setAttribute('content', isDark ? darkColor : lightColor); } } }); } // Aktualisiert das Aussehen des Toggle-Buttons function updateDarkModeToggle(isDark) { // Aria-Attribute für Barrierefreiheit darkModeToggle.setAttribute('aria-pressed', isDark.toString()); darkModeToggle.title = isDark ? "Light Mode aktivieren" : "Dark Mode aktivieren"; // Stile aktualisieren mit Tailwind-Klassen if (isDark) { darkModeToggle.classList.remove('bg-indigo-600', 'hover:bg-indigo-700'); darkModeToggle.classList.add('bg-slate-800', 'hover:bg-slate-700', 'text-amber-400'); darkModeToggle.setAttribute('data-tooltip', 'Light Mode aktivieren'); } else { darkModeToggle.classList.remove('bg-slate-800', 'hover:bg-slate-700', 'text-amber-400'); darkModeToggle.classList.add('bg-indigo-600', 'hover:bg-indigo-700'); darkModeToggle.setAttribute('data-tooltip', 'Dark Mode aktivieren'); } // Icon aktualisieren - ohne innerHTML für CSP-Kompatibilität const icon = darkModeToggle.querySelector('svg'); if (icon) { // Animationsklasse hinzufügen icon.classList.add('animate-spin-once'); // Nach Animation wieder entfernen setTimeout(() => { icon.classList.remove('animate-spin-once'); }, 300); const pathElement = icon.querySelector('path'); if (pathElement) { // Sonnen- oder Mond-Symbol if (isDark) { pathElement.setAttribute("d", "M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"); } else { pathElement.setAttribute("d", "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"); } } } } // Initialisierungsfunktion function initialize() { // Toggle-Button finden darkModeToggle = document.getElementById('darkModeToggle'); // Wenn kein Toggle existiert, erstelle einen if (!darkModeToggle) { createDarkModeToggle(); } // Event-Listener für Dark Mode Toggle if (darkModeToggle) { darkModeToggle.addEventListener('click', function() { const isDark = !shouldUseDarkMode(); setDarkMode(isDark); }); } // Tastenkombination: Strg+Shift+D document.addEventListener('keydown', function(e) { if (e.ctrlKey && e.shiftKey && e.key === 'D') { const isDark = !shouldUseDarkMode(); setDarkMode(isDark); e.preventDefault(); } }); // Auf Systemeinstellungsänderungen reagieren const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); // Moderne Event-API verwenden try { darkModeMediaQuery.addEventListener('change', function(e) { // Nur anwenden, wenn keine benutzerdefinierte Einstellung gespeichert ist if (localStorage.getItem(STORAGE_KEY) === null) { setDarkMode(e.matches); } }); } catch (error) { // Fallback für ältere Browser darkModeMediaQuery.addListener(function(e) { if (localStorage.getItem(STORAGE_KEY) === null) { setDarkMode(e.matches); } }); } // Initialer Zustand setDarkMode(shouldUseDarkMode()); // Animation für den korrekten Modus hinzufügen const animClass = shouldUseDarkMode() ? 'dark-mode-transition' : 'light-mode-transition'; document.body.classList.add(animClass); // Animation entfernen nach Abschluss setTimeout(() => { document.body.classList.remove(animClass); }, 300); } // Erstellt ein Toggle-Element, falls keines existiert function createDarkModeToggle() { // Bestehende Header-Elemente finden const header = document.querySelector('header'); const nav = document.querySelector('nav'); const container = document.querySelector('.dark-mode-container') || header || nav; if (!container) return; // Toggle-Button erstellen darkModeToggle = document.createElement('button'); darkModeToggle.id = 'darkModeToggle'; darkModeToggle.className = 'p-2 sm:p-3 rounded-full bg-indigo-600 text-white transition-all duration-300'; darkModeToggle.setAttribute('aria-label', 'Dark Mode umschalten'); darkModeToggle.setAttribute('title', 'Dark Mode aktivieren'); darkModeToggle.setAttribute('data-tooltip', 'Dark Mode aktivieren'); // SVG-Icon erstellen (ohne innerHTML für Content Security Policy) const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("class", "w-4 h-4 sm:w-5 sm:h-5"); svg.setAttribute("fill", "none"); svg.setAttribute("stroke", "currentColor"); svg.setAttribute("viewBox", "0 0 24 24"); // Path für das Icon const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("stroke-linecap", "round"); path.setAttribute("stroke-linejoin", "round"); path.setAttribute("stroke-width", "2"); path.setAttribute("d", "M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"); // Elemente zusammenfügen svg.appendChild(path); darkModeToggle.appendChild(svg); // Screenreader-Text hinzufügen const srText = document.createElement('span'); srText.className = 'sr-only'; srText.textContent = 'Dark Mode umschalten'; darkModeToggle.appendChild(srText); // Zum Container hinzufügen container.appendChild(darkModeToggle); } // Sofort Dark/Light Mode anwenden (vor DOMContentLoaded) const isDark = shouldUseDarkMode(); setDarkMode(isDark); })(); // Animationen für Spin-Effekt if (!document.querySelector('style#dark-mode-animations')) { const styleTag = document.createElement('style'); styleTag.id = 'dark-mode-animations'; styleTag.textContent = ` @keyframes spin-once { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } .animate-spin-once { animation: spin-once 0.3s ease-in-out; } `; document.head.appendChild(styleTag); }