From 4c9e8601504f76dcc3c273ea8ad1862df432b7b4 Mon Sep 17 00:00:00 2001
From: Andrew <80933354+ndrooo@users.noreply.github.com>
Date: Sat, 24 Aug 2024 20:33:30 +0000
Subject: [PATCH] a11y(darkmode): use a button for the theme toggle (#1335)

---
 quartz/components/Darkmode.tsx               |   67 ++++++++++++++++-----------------
 quartz/components/scripts/darkmode.inline.ts |   13 ++----
 quartz/components/styles/darkmode.scss       |   24 +++++------
 3 files changed, 48 insertions(+), 56 deletions(-)

diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx
index 8ed7c99..f64aad6 100644
--- a/quartz/components/Darkmode.tsx
+++ b/quartz/components/Darkmode.tsx
@@ -9,41 +9,38 @@
 
 const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
   return (
-    <div class={classNames(displayClass, "darkmode")}>
-      <input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex={-1} />
-      <label id="toggle-label-light" for="darkmode-toggle" tabIndex={-1}>
-        <svg
-          xmlns="http://www.w3.org/2000/svg"
-          xmlnsXlink="http://www.w3.org/1999/xlink"
-          version="1.1"
-          id="dayIcon"
-          x="0px"
-          y="0px"
-          viewBox="0 0 35 35"
-          style="enable-background:new 0 0 35 35"
-          xmlSpace="preserve"
-        >
-          <title>{i18n(cfg.locale).components.themeToggle.darkMode}</title>
-          <path d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5    S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5    C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6    C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9    c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44    l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5    c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06    L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z     M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2    C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29    c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7    C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5    c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path>
-        </svg>
-      </label>
-      <label id="toggle-label-dark" for="darkmode-toggle" tabIndex={-1}>
-        <svg
-          xmlns="http://www.w3.org/2000/svg"
-          xmlnsXlink="http://www.w3.org/1999/xlink"
-          version="1.1"
-          id="nightIcon"
-          x="0px"
-          y="0px"
-          viewBox="0 0 100 100"
-          style="enable-background:new 0 0 100 100"
-          xmlSpace="preserve"
-        >
-          <title>{i18n(cfg.locale).components.themeToggle.lightMode}</title>
-          <path d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571  C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23  c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369  c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65  c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path>
-        </svg>
-      </label>
-    </div>
+    <button class={classNames(displayClass, "darkmode")} id="darkmode">
+      <svg
+        xmlns="http://www.w3.org/2000/svg"
+        xmlnsXlink="http://www.w3.org/1999/xlink"
+        version="1.1"
+        id="dayIcon"
+        x="0px"
+        y="0px"
+        viewBox="0 0 35 35"
+        style="enable-background:new 0 0 35 35"
+        xmlSpace="preserve"
+        aria-label={i18n(cfg.locale).components.themeToggle.darkMode}
+      >
+        <title>{i18n(cfg.locale).components.themeToggle.darkMode}</title>
+        <path d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5    S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5    C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6    C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9    c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44    l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5    c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06    L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z     M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2    C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29    c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7    C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5    c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path>
+      </svg>
+      <svg
+        xmlns="http://www.w3.org/2000/svg"
+        xmlnsXlink="http://www.w3.org/1999/xlink"
+        version="1.1"
+        id="nightIcon"
+        x="0px"
+        y="0px"
+        viewBox="0 0 100 100"
+        style="enable-background:new 0 0 100 100"
+        xmlSpace="preserve"
+        aria-label={i18n(cfg.locale).components.themeToggle.lightMode}
+      >
+        <title>{i18n(cfg.locale).components.themeToggle.lightMode}</title>
+        <path d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571  C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23  c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369  c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65  c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path>
+      </svg>
+    </button>
   )
 }
 
diff --git a/quartz/components/scripts/darkmode.inline.ts b/quartz/components/scripts/darkmode.inline.ts
index 48e0aa1..038ae0f 100644
--- a/quartz/components/scripts/darkmode.inline.ts
+++ b/quartz/components/scripts/darkmode.inline.ts
@@ -11,7 +11,8 @@
 
 document.addEventListener("nav", () => {
   const switchTheme = (e: Event) => {
-    const newTheme = (e.target as HTMLInputElement)?.checked ? "dark" : "light"
+    const newTheme =
+      document.documentElement.getAttribute("saved-theme") === "dark" ? "light" : "dark"
     document.documentElement.setAttribute("saved-theme", newTheme)
     localStorage.setItem("theme", newTheme)
     emitThemeChangeEvent(newTheme)
@@ -21,17 +22,13 @@
     const newTheme = e.matches ? "dark" : "light"
     document.documentElement.setAttribute("saved-theme", newTheme)
     localStorage.setItem("theme", newTheme)
-    toggleSwitch.checked = e.matches
     emitThemeChangeEvent(newTheme)
   }
 
   // Darkmode toggle
-  const toggleSwitch = document.querySelector("#darkmode-toggle") as HTMLInputElement
-  toggleSwitch.addEventListener("change", switchTheme)
-  window.addCleanup(() => toggleSwitch.removeEventListener("change", switchTheme))
-  if (currentTheme === "dark") {
-    toggleSwitch.checked = true
-  }
+  const themeButton = document.querySelector("#darkmode") as HTMLButtonElement
+  themeButton.addEventListener("click", switchTheme)
+  window.addCleanup(() => themeButton.removeEventListener("click", switchTheme))
 
   // Listen for changes in prefers-color-scheme
   const colorSchemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
diff --git a/quartz/components/styles/darkmode.scss b/quartz/components/styles/darkmode.scss
index 348c6f7..edf4e61 100644
--- a/quartz/components/styles/darkmode.scss
+++ b/quartz/components/styles/darkmode.scss
@@ -1,17 +1,15 @@
 .darkmode {
+  cursor: pointer;
+  padding: 0;
   position: relative;
+  background: none;
+  border: none;
   width: 20px;
   height: 20px;
   margin: 0 10px;
-
-  & > .toggle {
-    display: none;
-    box-sizing: border-box;
-  }
+  text-align: inherit;
 
   & svg {
-    cursor: pointer;
-    opacity: 0;
     position: absolute;
     width: 20px;
     height: 20px;
@@ -29,20 +27,20 @@
   color-scheme: light;
 }
 
-:root[saved-theme="dark"] .toggle ~ label {
+:root[saved-theme="dark"] .darkmode {
   & > #dayIcon {
-    opacity: 0;
+    display: none;
   }
   & > #nightIcon {
-    opacity: 1;
+    display: inline;
   }
 }
 
-:root .toggle ~ label {
+:root .darkmode {
   & > #dayIcon {
-    opacity: 1;
+    display: inline;
   }
   & > #nightIcon {
-    opacity: 0;
+    display: none;
   }
 }

--
Gitblit v1.10.0