70 lines
1.7 KiB
JavaScript
70 lines
1.7 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`)
|
|
const toggler = document.getElementById("theme-toggler")
|
|
toggler.setAttribute("title", this.toggleTitle)
|
|
toggler.setAttribute("aria-label", "toggle theme")
|
|
}
|
|
|
|
get toggleTitle() {
|
|
return `toggle theme (current theme: ${this.theme})`
|
|
}
|
|
|
|
get theme() {
|
|
return this.#theme
|
|
}
|
|
}
|