63 lines
1.5 KiB
JavaScript
63 lines
1.5 KiB
JavaScript
|
const DARK = "dark"
|
||
|
const LIGHT = "light"
|
||
|
const SYSTEM = "system"
|
||
|
|
||
|
const DEFAULT_THEME = SYSTEM
|
||
|
|
||
|
const parseTheme = (themeName) => {
|
||
|
const s = (typeof (themeName) === 'string') ? themeName.toLowerCase().trim() : themeName
|
||
|
if (s == "light" || s == LIGHT) return LIGHT
|
||
|
else if (s == "dark" || s == DARK) return DARK
|
||
|
else return SYSTEM
|
||
|
}
|
||
|
|
||
|
const oppositeOf = (theme) => {
|
||
|
if (theme == LIGHT) return DARK
|
||
|
else if (theme == DARK) return LIGHT
|
||
|
else return null
|
||
|
}
|
||
|
|
||
|
export class Theme {
|
||
|
#theme = DEFAULT_THEME
|
||
|
#defaultPreference = LIGHT
|
||
|
|
||
|
constructor(initialThemeName = undefined) {
|
||
|
if (!initialThemeName) initialThemeName = localStorage.getItem("theme")
|
||
|
this.#defaultPreference = window.matchMedia("(prefers-color-scheme: light)").matches ? LIGHT : DARK
|
||
|
this.theme = parseTheme(initialThemeName)
|
||
|
}
|
||
|
|
||
|
cycle() {
|
||
|
this.theme = this.getNext()
|
||
|
}
|
||
|
|
||
|
getNext() {
|
||
|
if (this.theme == SYSTEM) {
|
||
|
return oppositeOf(this.#defaultPreference)
|
||
|
} else {
|
||
|
if (this.theme == this.#defaultPreference) {
|
||
|
return SYSTEM
|
||
|
} else {
|
||
|
return oppositeOf(this.#theme)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
toggle() {
|
||
|
// unused on this page
|
||
|
}
|
||
|
|
||
|
set theme(themeName) {
|
||
|
localStorage.setItem("theme", themeName)
|
||
|
this.#theme = parseTheme(themeName)
|
||
|
document.body.classList.remove(`light-theme`)
|
||
|
document.body.classList.remove(`dark-theme`)
|
||
|
document.body.classList.remove(`system-theme`)
|
||
|
document.body.classList.add(`${this.#theme}-theme`)
|
||
|
}
|
||
|
|
||
|
get theme() {
|
||
|
return this.#theme
|
||
|
}
|
||
|
}
|