63 lines
1.7 KiB
Plaintext
63 lines
1.7 KiB
Plaintext
---
|
|
type Props = {
|
|
defaultTheme?: "auto" | "dark" | "light" | undefined;
|
|
};
|
|
|
|
const { defaultTheme = "auto" } = Astro.props;
|
|
---
|
|
|
|
<script is:inline data-default-theme={defaultTheme}>
|
|
window.theme ??= (() => {
|
|
const defaultTheme =
|
|
document.currentScript.getAttribute("data-default-theme");
|
|
const storageKey = "theme";
|
|
const store =
|
|
typeof localStorage !== "undefined"
|
|
? localStorage
|
|
: { getItem: () => null, setItem: () => {} };
|
|
|
|
const mediaMatcher = window.matchMedia("(prefers-color-scheme: light)");
|
|
let systemTheme = mediaMatcher.matches ? "light" : "dark";
|
|
mediaMatcher.addEventListener("change", (event) => {
|
|
systemTheme = event.matches ? "light" : "dark";
|
|
applyTheme(getTheme());
|
|
});
|
|
|
|
function applyTheme(theme) {
|
|
const resolvedTheme = theme === "auto" ? systemTheme : theme;
|
|
document.documentElement.dataset.theme = resolvedTheme;
|
|
document.documentElement.style.colorScheme = resolvedTheme;
|
|
document.dispatchEvent(
|
|
new CustomEvent("theme-changed", {
|
|
detail: { theme, systemTheme, defaultTheme }
|
|
})
|
|
);
|
|
}
|
|
|
|
function setTheme(theme = defaultTheme) {
|
|
store.setItem(storageKey, theme);
|
|
applyTheme(theme);
|
|
}
|
|
|
|
function getTheme() {
|
|
return store.getItem(storageKey) || defaultTheme;
|
|
}
|
|
|
|
function getSystemTheme() {
|
|
return systemTheme;
|
|
}
|
|
|
|
function getDefaultTheme() {
|
|
return defaultTheme;
|
|
}
|
|
|
|
return { setTheme, getTheme, getSystemTheme, getDefaultTheme };
|
|
})();
|
|
theme.setTheme(theme.getTheme());
|
|
</script>
|
|
<script>
|
|
document.addEventListener("astro:after-swap", () =>
|
|
window.theme.setTheme(window.theme.getTheme())
|
|
);
|
|
</script>
|