({ fromSystemChange = false } = {})
| 852 | |
| 853 | // -------- DARK MODE (persist + system fallback + a11y labels) -------- |
| 854 | function applyDarkMode({ fromSystemChange = false } = {}) { |
| 855 | let stored = null; |
| 856 | try { stored = localStorage.getItem('darkMode'); } catch (e) { } |
| 857 | |
| 858 | let isDark = (stored === null) |
| 859 | ? (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) |
| 860 | : (stored === '1' || stored === 'true'); |
| 861 | |
| 862 | const root = document.documentElement; |
| 863 | const body = document.body; |
| 864 | |
| 865 | [root, body].forEach(el => { |
| 866 | if (!el) return; |
| 867 | el.classList.toggle('dark-mode', isDark); |
| 868 | el.setAttribute('data-theme', isDark ? 'dark' : 'light'); |
| 869 | }); |
| 870 | |
| 871 | // keep UA chrome & bg consistent post-toggle |
| 872 | const customBg = resolveAppBackground(isDark); |
| 873 | const bg = customBg || (isDark ? '#121212' : '#ffffff'); |
| 874 | const isLoginView = body && body.classList.contains('fr-login-view'); |
| 875 | if (isLoginView) { |
| 876 | root.style.background = ''; |
| 877 | root.style.backgroundColor = ''; |
| 878 | if (body) { |
| 879 | body.style.background = ''; |
| 880 | body.style.backgroundColor = ''; |
| 881 | } |
| 882 | } else { |
| 883 | root.style.background = bg; |
| 884 | if (body) body.style.background = bg; |
| 885 | } |
| 886 | root.style.colorScheme = isDark ? 'dark' : 'light'; |
| 887 | if (body) body.style.colorScheme = isDark ? 'dark' : 'light'; |
| 888 | applyBrandingThemeColor(isDark); |
| 889 | const mcs = document.querySelector('meta[name="color-scheme"]'); |
| 890 | if (mcs) mcs.content = isDark ? 'dark light' : 'light dark'; |
| 891 | |
| 892 | const btn = document.getElementById('darkModeToggle'); |
| 893 | const icon = document.getElementById('darkModeIcon'); |
| 894 | if (icon) icon.textContent = isDark ? 'light_mode' : 'dark_mode'; |
| 895 | if (btn) { |
| 896 | const ttOn = (typeof t === 'function' ? t('switch_to_dark_mode') : 'Switch to dark mode'); |
| 897 | const ttOff = (typeof t === 'function' ? t('switch_to_light_mode') : 'Switch to light mode'); |
| 898 | const aria = (typeof t === 'function' ? (isDark ? t('light_mode') : t('dark_mode')) : (isDark ? 'Light mode' : 'Dark mode')); |
| 899 | btn.classList.toggle('active', isDark); |
| 900 | btn.setAttribute('aria-label', aria); |
| 901 | btn.setAttribute('title', isDark ? ttOff : ttOn); |
| 902 | } |
| 903 | } |
| 904 | |
| 905 | function bindDarkMode() { |
| 906 | const btn = document.getElementById('darkModeToggle'); |
no test coverage detected