MediaWiki:Common.js: Difference between revisions
No edit summary Tag: Reverted |
No edit summary Tag: Reverted |
||
| Line 9: | Line 9: | ||
var STORAGE_KEY = 'minerva-night-mode'; | var STORAGE_KEY = 'minerva-night-mode'; | ||
var | |||
// SVG icons (24x24) | |||
var MOON_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>'; | |||
var SUN_SVG = '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>'; | |||
/** | /** | ||
| Line 34: | Line 37: | ||
/** | /** | ||
* Apply theme | * Apply theme via inline style injection (prevents FOUC) | ||
* This runs immediately, before DOM is ready | |||
*/ | */ | ||
function | function applyThemeImmediate(theme) { | ||
var | // Remove any existing theme style tag | ||
var existingStyle = document.getElementById('night-mode-immediate'); | |||
html.classList.remove( | if (existingStyle) { | ||
}); | existingStyle.parentNode.removeChild(existingStyle); | ||
} | |||
// Inject style tag into head immediately | |||
var style = document.createElement('style'); | |||
style.id = 'night-mode-immediate'; | |||
if (theme === 'night') { | |||
// Apply night mode class to html element | |||
style.textContent = 'html { color-scheme: dark; }'; | |||
document.documentElement.classList.remove('skin-theme-clientpref-day'); | |||
document.documentElement.classList.add('skin-theme-clientpref-night'); | |||
} else { | |||
style.textContent = 'html { color-scheme: light; }'; | |||
document.documentElement.classList.remove('skin-theme-clientpref-night'); | |||
document.documentElement.classList.add('skin-theme-clientpref-day'); | |||
} | |||
// Insert into head as early as possible | |||
var head = document.head || document.getElementsByTagName('head')[0]; | |||
if (head) { | |||
head.insertBefore(style, head.firstChild); | |||
} | |||
} | } | ||
| Line 49: | Line 74: | ||
function updateButtonState(button, theme) { | function updateButtonState(button, theme) { | ||
var icon = button.querySelector('.minerva-icon'); | var icon = button.querySelector('.minerva-icon'); | ||
var label = button.querySelector(' | var label = button.querySelector('.toggle-label'); | ||
if (theme === 'night') { | if (theme === 'night') { | ||
icon.innerHTML = SUN_SVG; | |||
icon.innerHTML = | if (label) label.textContent = 'Light mode'; | ||
label.textContent = 'Light mode'; | button.setAttribute('title', 'Switch to light mode'); | ||
} else { | } else { | ||
icon.innerHTML = MOON_SVG; | |||
icon.innerHTML = | if (label) label.textContent = 'Dark mode'; | ||
label.textContent = 'Dark mode'; | button.setAttribute('title', 'Switch to dark mode'); | ||
} | } | ||
} | } | ||
| Line 79: | Line 104: | ||
var icon = document.createElement('span'); | var icon = document.createElement('span'); | ||
icon.className = 'minerva-icon'; | icon.className = 'minerva-icon'; | ||
icon.style.display = 'flex'; | icon.style.display = 'flex'; | ||
icon.style.alignItems = 'center'; | icon.style.alignItems = 'center'; | ||
icon.style.justifyContent = 'center'; | icon.style.justifyContent = 'center'; | ||
icon.style.width = '20px'; | |||
icon.style.height = '20px'; | |||
var label = document.createElement('span'); | var label = document.createElement('span'); | ||
label.className = 'toggle-label'; | |||
// Visually hidden but accessible | |||
label.style.cssText = 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;'; | |||
button.appendChild(icon); | button.appendChild(icon); | ||
| Line 98: | Line 127: | ||
var newTheme = getSavedTheme() === 'night' ? 'day' : 'night'; | var newTheme = getSavedTheme() === 'night' ? 'day' : 'night'; | ||
saveTheme(newTheme); | saveTheme(newTheme); | ||
applyThemeImmediate(newTheme); | |||
updateButtonState(button, newTheme); | updateButtonState(button, newTheme); | ||
}); | }); | ||
return li; | return li; | ||
} | } | ||
| Line 144: | Line 157: | ||
} | } | ||
// Run | /** | ||
* Initialize | |||
*/ | |||
function init() { | |||
// Apply saved theme IMMEDIATELY (this is the key to preventing FOUC) | |||
applyThemeImmediate(getSavedTheme()); | |||
// Insert button when DOM is ready | |||
if (document.readyState === 'loading') { | |||
document.addEventListener('DOMContentLoaded', insertButton); | |||
} else { | |||
insertButton(); | |||
} | |||
} | |||
// Run immediately | |||
init(); | init(); | ||
})(); | })(); | ||