site.lyte.dev/static/theme.mjs

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
}
}