@@ -105,6 +105,7 @@ import {
105105 navId,
106106 navListId
107107 } from "@components/page/header.ids";
108+ import Store from "@lib/store.ts";
108109 import { colors } from "@styles/data/colors.json";
109110
110111 const header = document.getElementById(headerId) as HTMLElement;
@@ -127,18 +128,22 @@ import {
127128 modeButton.classList.toggle("open-nav");
128129 });
129130
130- type Mode = "light" | "dark";
131-
132131 const darkModeMedia = matchMedia("(prefers-color-scheme: dark)");
133132 const rootStyle = document.documentElement.style;
134133 const modeTitle = document.getElementById(modeTitleId) as HTMLTitleElement & {
135- textContent: "Light mode" | "Dark mode" | null;
134+ // This type is a bit inaccurate because it could also be 'null', but either
135+ // 'setModeTitleBasedOnMedia' or 'setMode' are called right away at page
136+ // load, so this type is accurate enough.
137+ textContent: "Light mode" | "Dark mode";
136138 };
137139 const modeMoon = document.getElementById(
138140 modeMoonId
139141 ) as unknown as SVGGElement;
140142 const modeSun = document.getElementById(modeSunId) as unknown as SVGGElement;
141143
144+ type Mode = "light" | "dark";
145+ const modeStore = new Store<Mode>("mode");
146+
142147 darkModeMedia.addEventListener("change", setModeTitleBasedOnMedia);
143148 function setModeTitleBasedOnMedia() {
144149 if (darkModeMedia.matches) {
@@ -168,7 +173,7 @@ import {
168173 }
169174
170175 modeTitle.textContent = "Dark mode";
171- localStorage.setItem("mode", "light");
176+ modeStore.set( "light");
172177 break;
173178 }
174179 case "dark": {
@@ -185,7 +190,7 @@ import {
185190 }
186191
187192 modeTitle.textContent = "Light mode";
188- localStorage.setItem("mode", "dark");
193+ modeStore.set( "dark");
189194 break;
190195 }
191196 }
@@ -198,7 +203,7 @@ import {
198203 // Mode moon and sun animations end at the same time so put 'animationend'
199204 // handling on only one of them.
200205 modeMoon.addEventListener("animationend", () => {
201- const storedMode = localStorage.getItem("mode") as Mode | null ;
206+ const storedMode = modeStore.get() ;
202207
203208 if (storedMode === null) {
204209 return;
@@ -208,29 +213,31 @@ import {
208213 case "light": {
209214 modeMoon.style.opacity = "1";
210215 modeSun.style.opacity = "0";
216+
217+ modeMoon.classList.remove("rotate-appear");
218+ modeSun.classList.remove("rotate-vanish");
211219 break;
212220 }
213221 case "dark": {
214222 modeMoon.style.opacity = "0";
215223 modeSun.style.opacity = "1";
224+
225+ modeMoon.classList.remove("rotate-vanish");
226+ modeSun.classList.remove("rotate-appear");
216227 break;
217228 }
218229 }
219-
220- modeMoon.classList.remove("rotate-appear");
221- modeMoon.classList.remove("rotate-vanish");
222- modeSun.classList.remove("rotate-appear");
223- modeSun.classList.remove("rotate-vanish");
224230 });
225231
226232 addEventListener("DOMContentLoaded", () => {
227- const storedMode = localStorage.getItem("mode") as Mode | null ;
233+ const storedMode = modeStore.get() ;
228234
229235 if (storedMode === null) {
230236 setModeTitleBasedOnMedia();
231237 return;
232238 }
233239
240+ // Mode SVG should not animate at initial page load.
234241 setMode(storedMode, false);
235242 });
236243</script >
0 commit comments