refactor: update toggle theme function for better structure and a11y

Move theme switch js codes in Layout.astro file to external js file (toggle-theme.js). Update
.prettierignore to exclude the new toggle-theme.js file.  Update base.css for new data-theme
attribute.
This commit is contained in:
satnaing
2022-11-26 23:43:27 +06:30
parent 5a67afc6b2
commit 0eeed8e870
4 changed files with 61 additions and 44 deletions
+1
View File
@@ -3,6 +3,7 @@
# Except these files & folders
!/src
!/public
!/.github
!tsconfig.json
!astro.config.mjs
+52
View File
@@ -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();
});
+1 -39
View File
@@ -61,45 +61,7 @@ const socialImageURL = new URL(
onload="this.onload=null;this.rel='stylesheet'"
/>
<script is:inline>
const primaryColorScheme = "none"; // "light" | "dark" | "none"
const darkModeMediaQuery = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
// Get theme data from local storage
const currentTheme = localStorage.getItem("theme");
let theme;
// Set theme to 'theme-dark' if currentTheme is 'dark'
if (currentTheme) {
theme = currentTheme === "dark" ? "theme-dark" : "";
} else {
// If primary color scheme is dark
// or primary color scheme is not set and prefers-color-scheme is dark
// choose dark mode
if (
primaryColorScheme === "dark" ||
(primaryColorScheme === "none" && darkModeMediaQuery)
) {
theme = "theme-dark";
}
// If primary color scheme is light
// choose light mode
else if (primaryColorScheme === "light") {
theme = "";
}
// fallback to prefers-color-scheme
else {
theme = darkModeMediaQuery ? "theme-dark" : "";
}
}
// Put dark class on html tag to enable dark mode
document.querySelector("html").className = theme;
</script>
<script is:inline src="/toggle-theme.js"></script>
</head>
<body>
<slot />
+7 -5
View File
@@ -3,7 +3,8 @@
@tailwind utilities;
@layer base {
:root {
:root,
html[data-theme="light"] {
--color-fill: 251, 254, 251;
--color-text-base: 40, 39, 40;
--color-accent: 0, 108, 172;
@@ -11,7 +12,7 @@
--color-card-muted: 205, 205, 205;
--color-border: 236, 233, 233;
}
.theme-dark {
html[data-theme="dark"] {
--color-fill: 47, 55, 65;
--color-text-base: 230, 230, 230;
--color-accent: 26, 217, 217;
@@ -20,11 +21,11 @@
--color-border: 59, 70, 85;
}
#sun-svg,
.theme-dark #moon-svg {
html[data-theme="dark"] #moon-svg {
display: none;
}
#moon-svg,
.theme-dark #sun-svg {
html[data-theme="dark"] #sun-svg {
display: block;
}
body {
@@ -36,7 +37,8 @@
@apply max-w-3xl mx-auto px-4;
}
a {
@apply outline-offset-1 outline-skin-fill outline-2 focus-visible:outline-dashed focus-visible:no-underline;
@apply outline-offset-1 outline-skin-fill outline-2
focus-visible:outline-dashed focus-visible:no-underline;
}
svg {
@apply w-6 h-6 inline-block fill-skin-base group-hover:fill-skin-accent;