62 lines
1.4 KiB
JavaScript
62 lines
1.4 KiB
JavaScript
const storageKey = 'theme-preference'
|
|
|
|
const onClick = () => {
|
|
// flip current value
|
|
theme.value = theme.value === 'light'
|
|
? 'dark'
|
|
: 'light';
|
|
|
|
document
|
|
.querySelector('.theme-toggle')
|
|
.classList.toggle('theme-toggle--toggled');
|
|
|
|
setPreference()
|
|
}
|
|
|
|
const getColorPreference = () => {
|
|
if (localStorage.getItem(storageKey))
|
|
return localStorage.getItem(storageKey)
|
|
else
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
? 'dark'
|
|
: 'light'
|
|
}
|
|
|
|
const setPreference = () => {
|
|
localStorage.setItem(storageKey, theme.value)
|
|
reflectPreference()
|
|
}
|
|
|
|
const reflectPreference = () => {
|
|
document.firstElementChild
|
|
.setAttribute('data-theme', theme.value)
|
|
|
|
document
|
|
.querySelector('#theme-toggle')
|
|
?.setAttribute('aria-label', theme.value)
|
|
}
|
|
|
|
const theme = {
|
|
value: getColorPreference(),
|
|
}
|
|
|
|
// set early so no page flashes / CSS is made aware
|
|
reflectPreference()
|
|
|
|
window.onload = () => {
|
|
// set on load so screen readers can see latest value on the button
|
|
reflectPreference()
|
|
|
|
// now this script can find and listen for clicks on the control
|
|
document
|
|
.querySelector('.theme-toggle')
|
|
.addEventListener('click', onClick)
|
|
}
|
|
|
|
// sync with system changes
|
|
window
|
|
.matchMedia('(prefers-color-scheme: dark)')
|
|
.addEventListener('change', ({matches:isDark}) => {
|
|
theme.value = isDark ? 'dark' : 'light'
|
|
setPreference()
|
|
}) |