diff --git a/.prettierignore b/.prettierignore index 6056347..d84f1a6 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ # Except these files & folders !/src +!/public !/.github !tsconfig.json !astro.config.mjs diff --git a/public/toggle-theme.js b/public/toggle-theme.js new file mode 100644 index 0000000..7baaa00 --- /dev/null +++ b/public/toggle-theme.js @@ -0,0 +1,52 @@ +const primaryColorScheme = ""; // "light" | "dark" + +// Get theme data from local storage +const currentTheme = localStorage.getItem("theme"); + +function getPreferTheme() { + // return theme value in local storage if it is set + if (currentTheme) return currentTheme; + + // return primary color scheme if it is set + if (primaryColorScheme) return primaryColorScheme; + + // return user device's prefer color scheme + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; +} + +let themeValue = getPreferTheme(); + +function setPreference() { + localStorage.setItem("theme", themeValue); + reflectPreference(); +} + +function reflectPreference() { + document.firstElementChild.setAttribute("data-theme", themeValue); + + document.querySelector("#theme-btn")?.setAttribute("aria-label", themeValue); +} + +// set early so no page flashes / CSS is made aware +reflectPreference(); + +window.onload = () => { + // set on load so screen readers can get the latest value on the button + reflectPreference(); + + // now this script can find and listen for clicks on the control + document.querySelector("#theme-btn").addEventListener("click", () => { + themeValue = themeValue === "light" ? "dark" : "light"; + setPreference(); + }); +}; + +// sync with system changes +window + .matchMedia("(prefers-color-scheme: dark)") + .addEventListener("change", ({ matches: isDark }) => { + themeValue = isDark ? "dark" : "light"; + setPreference(); + }); diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 2e7dfd6..3b5dca7 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -61,45 +61,7 @@ const socialImageURL = new URL( onload="this.onload=null;this.rel='stylesheet'" /> - +