aboutsummaryrefslogtreecommitdiff
path: root/www/assets/color-scheme.ts
diff options
context:
space:
mode:
Diffstat (limited to 'www/assets/color-scheme.ts')
-rw-r--r--www/assets/color-scheme.ts86
1 files changed, 53 insertions, 33 deletions
diff --git a/www/assets/color-scheme.ts b/www/assets/color-scheme.ts
index 62a1b5c..db6a3aa 100644
--- a/www/assets/color-scheme.ts
+++ b/www/assets/color-scheme.ts
@@ -1,7 +1,3 @@
-const key = "color-scheme"
-
-type scheme = "dark" | "light" | null
-
function createResetTimer(cleanup: () => void, timeout = 1) {
let tag = 0
return () => {
@@ -12,10 +8,6 @@ function createResetTimer(cleanup: () => void, timeout = 1) {
}
}
-let current = localStorage.getItem(key) as scheme
-
-let inited = false
-
function createToast(duration: number = 1): (text: string) => void {
const toast = document.createElement("div")
toast.className = "toast"
@@ -33,40 +25,69 @@ function createToast(duration: number = 1): (text: string) => void {
}
}
-const themeToast = createToast()
+const setToast = createToast()
+
+const key = "force-color-scheme"
+const dark = "dark"
+const light = "light"
+type Scheme = typeof dark | typeof light
+
+const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
+
+function fromMediaQuery(value: boolean | null): Scheme {
+ if (value == null) { value = mediaQuery.matches}
+ return value ? dark : light
+}
+
+function opposite(scheme: Scheme): Scheme {
+ return scheme === dark ? light : dark
+}
+
+function updateScheme(theme: Scheme | null): Scheme {
+ if (theme == null) { theme = fromMediaQuery(null) }
+ document.querySelector("html")!.dataset["theme"] = theme
+ return theme
+}
+
+mediaQuery.addEventListener("change", (e) => updateScheme(current || fromMediaQuery(e.matches)))
-function setTheme(value: scheme) {
- let message = ""
+let current: Scheme | null = null
+
+{
+ const saved = localStorage.getItem(key)
+ if ([null, dark, light].includes(saved)) {
+ current = saved as never
+ } else {
+ console.log(`invalid saved theme: ${saved}`)
+ localStorage.removeItem(key)
+ }
+}
+
+updateScheme(current)
+
+function saveScheme(value: Scheme | null) {
current = value
if (value == null) {
- const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches
- value = prefersDarkScheme ? "dark" : "light"
- message = `theme: system(${value})`
localStorage.removeItem(key)
} else {
- message = `theme: force(${value})`
localStorage.setItem(key, value)
}
- document.body.dataset["theme"] = value
-
- if (inited) {
- themeToast(message)
- }
+ const real = updateScheme(value)
+ setToast(`theme: ${current == null ? "system" : "force"}(${real})`)
}
-setTheme(current)
-inited = true
-
-function next(scheme: scheme): scheme {
- switch (scheme) {
- case "dark":
- return "light"
- case "light":
- return null
- default:
- return "dark"
+function next(): Scheme | null {
+ const sys = fromMediaQuery(null)
+ if (current == null) {
+ return opposite(sys)
+ } else {
+ if (current === sys) {
+ return null;
+ } else {
+ return opposite(current)
+ }
}
}
@@ -82,9 +103,8 @@ window.addEventListener("load", () => {
reset()
clicks += 1
if (clicks === 3) {
- setTheme(next(current))
+ saveScheme(next())
clicks = 0
}
})
})
-