Skip to content

Commit a984ef0

Browse files
committed
Refactor header
1 parent c20b900 commit a984ef0

2 files changed

Lines changed: 34 additions & 12 deletions

File tree

src/components/page/header.astro

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -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>

src/lib/store.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export default class Store<T extends string> {
2+
#key: string;
3+
4+
constructor(key: string) {
5+
this.#key = key;
6+
}
7+
8+
get(): T | null {
9+
return localStorage.getItem(this.#key) as T | null;
10+
}
11+
12+
set(value: T) {
13+
localStorage.setItem(this.#key, value);
14+
}
15+
}

0 commit comments

Comments
 (0)