summaryrefslogtreecommitdiff
path: root/src/components/ThemeProvider.astro
diff options
context:
space:
mode:
authorDawid Rycerz <dawid@rycerz.xyz>2025-07-03 10:56:21 +0300
committerDawid Rycerz <dawid@rycerz.xyz>2025-07-03 10:56:21 +0300
commit456cf011b36de91c9936994b1fa45703adcd309b (patch)
tree8e60daf998f731ac50d100fa490eaecae1168042 /src/components/ThemeProvider.astro
Initial fork of chrismwilliams/astro-theme-cactus theme
Diffstat (limited to 'src/components/ThemeProvider.astro')
-rw-r--r--src/components/ThemeProvider.astro44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/components/ThemeProvider.astro b/src/components/ThemeProvider.astro
new file mode 100644
index 0000000..5f0723d
--- /dev/null
+++ b/src/components/ThemeProvider.astro
@@ -0,0 +1,44 @@
+{/* Inlined to avoid FOUC. This is a parser blocking script. */}
+<script is:inline>
+ const lightModePref = window.matchMedia("(prefers-color-scheme: light)");
+
+ function getUserPref() {
+ const storedTheme = typeof localStorage !== "undefined" && localStorage.getItem("theme");
+ return storedTheme || (lightModePref.matches ? "light" : "dark");
+ }
+
+ function setTheme(newTheme) {
+ if (newTheme !== "light" && newTheme !== "dark") {
+ return console.warn(
+ `Invalid theme value '${newTheme}' received. Expected 'light' or 'dark'.`,
+ );
+ }
+
+ const root = document.documentElement;
+
+ // root already set to newTheme, exit early
+ if (newTheme === root.getAttribute("data-theme")) {
+ return;
+ }
+
+ root.setAttribute("data-theme", newTheme);
+
+ if (typeof localStorage !== "undefined") {
+ localStorage.setItem("theme", newTheme);
+ }
+ }
+
+ // initial setup
+ setTheme(getUserPref());
+
+ // View Transitions hook to restore theme
+ document.addEventListener("astro:after-swap", () => setTheme(getUserPref()));
+
+ // listen for theme-change custom event, fired in src/components/ThemeToggle.astro
+ document.addEventListener("theme-change", (e) => {
+ setTheme(e.detail.theme);
+ });
+
+ // listen for prefers-color-scheme change.
+ lightModePref.addEventListener("change", (e) => setTheme(e.matches ? "light" : "dark"));
+</script>