Skip to content

Commit f9dc423

Browse files
committed
Add dark theme and theme switcher
1 parent 38b9d1c commit f9dc423

File tree

3 files changed

+116
-29
lines changed

3 files changed

+116
-29
lines changed

web/css/styles.css

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,48 @@
33
--input-width: 20em;
44
}
55

6+
[data-theme="light"] {
7+
--colour-background: rgb(255, 252, 240);
8+
--colour-background-secondary: rgb(242, 240, 229);
9+
--colour-borders: rgb(230, 228, 217);
10+
--colour-borders-hovered: rgb(218, 216, 206);
11+
--colour-borders-active: rgb(206, 205, 195);
12+
--colour-text-faint: rgb(183, 181, 172);
13+
--colour-text-muted: rgb(111, 110, 105);
14+
--colour-text: rgb(16, 15, 15);
15+
--colour-error: rgb(175, 48, 41);
16+
--colour-warning: rgb(188, 82, 21);
17+
--colour-link: rgb(36, 131, 123);
18+
--colour-success: rgb(102, 128, 11);
19+
--item-hover-colour: rgba(0, 0, 0, 0.2);
20+
}
21+
22+
[data-theme="dark"] {
23+
--colour-background: rgb(16, 15, 15);
24+
--colour-background-secondary: rgb(28, 27, 26);
25+
--colour-borders: rgb(40, 39, 38);
26+
--colour-borders-hovered: rgb(52, 51, 49);
27+
--colour-borders-active: rgb(64, 62, 60);
28+
--colour-text-faint: rgb(87, 86, 83);
29+
--colour-text-muted: rgb(135, 133, 128);
30+
--colour-text: rgb(206, 205, 195);
31+
--colour-error: rgb(209, 77, 65);
32+
--colour-warning: rgb(218, 112, 44);
33+
--colour-link: rgb(58, 169, 159);
34+
--colour-success: rgb(135, 154, 57);
35+
--item-hover-colour: rgba(255, 255, 255, 0.2);
36+
}
37+
638
body {
739
font-family: monospace, sans-serif;
840
margin: 20px;
941
padding: 0;
10-
background-color: rgb(255, 252, 240);
11-
color: rgb(16, 15, 15);
42+
background-color: var(--colour-background);
43+
color: var(--colour-text);
1244
}
1345

1446
h1,
1547
h2 {
16-
color: rgb(16, 15, 15);
1748
user-select: none;
1849
cursor: pointer;
1950
font-weight: var(--heading-weight);
@@ -43,7 +74,7 @@ ul {
4374
}
4475

4576
li {
46-
background: rgb(242, 240, 229);
77+
background: var(--colour-background-secondary);
4778
margin: 0;
4879
padding: 10px;
4980
border-radius: 10px;
@@ -64,7 +95,7 @@ li a {
6495

6596
li:hover {
6697
transform: scale(1.01);
67-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
98+
box-shadow: 0 4px 8px var(--item-hover-colour);
6899
}
69100

70101
.collapsible {
@@ -101,8 +132,8 @@ li:hover {
101132

102133
.restart-button {
103134
background-color: transparent;
104-
color: rgb(111, 110, 105);
105-
border: 1px solid rgb(230, 228, 217);
135+
color: var(--colour-text-muted);
136+
border: 1px solid var(--colour-borders);
106137
border-radius: 3px;
107138
padding: 2px 6px;
108139
font-size: 12px;
@@ -111,14 +142,14 @@ li:hover {
111142
}
112143

113144
.restart-button:hover {
114-
background-color: rgb(188, 82, 21);
115-
color: rgb(255, 252, 240);
116-
border-color: rgb(188, 82, 21);
145+
background-color: var(--colour-warning);
146+
color: var(--colour-text);
147+
border-color: var(--colour-warning);
117148
}
118149

119150
.restart-button:active {
120-
background-color: rgb(175, 48, 41);
121-
border-color: rgb(175, 48, 41);
151+
background-color: var(--colour-error);
152+
border-color: var(--colour-error);
122153
}
123154

124155
#auth-modal {
@@ -135,7 +166,7 @@ li:hover {
135166
}
136167

137168
.auth-modal-content {
138-
background: rgb(255, 252, 240);
169+
background: var(--colour-background);
139170
padding: 20px;
140171
border-radius: 8px;
141172
width: 300px;
@@ -155,8 +186,9 @@ li:hover {
155186
.auth-input-container input {
156187
width: var(--input-width);
157188
padding: 8px;
158-
border: 1px solid rgb(230, 228, 217);
159-
background-color: rgb(242, 240, 229);
189+
border: 1px solid var(--colour-borders);
190+
background-color: var(--colour-background-secondary);
191+
color: var(--colour-text);
160192
border-radius: 4px;
161193
box-sizing: border-box;
162194
}
@@ -170,11 +202,12 @@ li:hover {
170202
border: none;
171203
cursor: pointer;
172204
font-size: 14px;
205+
color: var(--colour-text-muted);
173206
}
174207

175208
.auth-submit {
176-
background-color: rgb(102, 128, 11);
177-
color: rgb(255, 252, 240);
209+
background-color: var(--colour-success);
210+
color: var(--colour-background);
178211
padding: 10px 20px;
179212
border: none;
180213
border-radius: 4px;
@@ -183,8 +216,8 @@ li:hover {
183216
}
184217

185218
.auth-cancel {
186-
background-color: rgb(175, 48, 41);
187-
color: rgb(255, 252, 240);
219+
background-color: var(--colour-error);
220+
color: var(--colour-background);
188221
padding: 10px 20px;
189222
border: none;
190223
border-radius: 4px;
@@ -194,8 +227,8 @@ li:hover {
194227
}
195228

196229
button {
197-
background-color: rgb(242, 240, 229);
198-
color: rgb(16, 15, 15);
230+
background-color: var(--colour-background-secondary);
231+
color: var(--colour-text-muted);
199232
border: none;
200233
padding: 10px 20px;
201234
border-radius: 4px;
@@ -206,14 +239,14 @@ button {
206239
}
207240

208241
button:hover {
209-
background-color: rgb(36, 131, 123);
210-
color: rgb(255, 252, 240);
242+
background-color: var(--colour-link);
243+
color: var(--colour-text);
211244
}
212245

213246
footer {
214247
margin-top: 20px;
215248
text-align: center;
216-
color: rgb(111, 110, 105);
249+
color: var(--colour-text-muted);
217250
}
218251

219252
.footer-content {
@@ -224,7 +257,7 @@ footer {
224257

225258
.footer-content p a {
226259
text-decoration: none;
227-
color: rgb(16, 15, 15);
260+
color: var(--colour-text-muted);
228261
text-decoration: underline;
229262
margin: 0 5px;
230263
}

web/index.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="en">
2+
<html lang="en" data-theme="light">
33

44
<head>
55
<meta charset="UTF-8">
@@ -16,6 +16,9 @@ <h1>Nomad URLs</h1>
1616
<button id="refresh-urls-button">
1717
Refresh URLs
1818
</button>
19+
20+
<button type="button" data-theme-toggle aria-label="Change to light theme">Change to light theme (or icon
21+
here)</button>
1922
</div>
2023
<ul id="url-list"></ul>
2124

web/js/main.js

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,55 @@ document.addEventListener("DOMContentLoaded", () => {
2121
);
2222
});
2323

24+
function calculateSettingAsThemeString({
25+
localStorageTheme,
26+
systemSettingDark,
27+
}) {
28+
if (localStorageTheme !== null) {
29+
return localStorageTheme;
30+
}
31+
32+
if (systemSettingDark.matches) {
33+
return "dark";
34+
}
35+
36+
return "light";
37+
}
38+
39+
function updateButton({ buttonEl, isDark }) {
40+
const newCta = isDark ? "Change to light theme" : "Change to dark theme";
41+
// use an aria-label if you are omitting text on the button
42+
// and using a sun/moon icon, for example
43+
buttonEl.setAttribute("aria-label", newCta);
44+
buttonEl.innerText = newCta;
45+
}
46+
47+
function updateThemeOnHtmlEl({ theme }) {
48+
document.querySelector("html").setAttribute("data-theme", theme);
49+
}
50+
51+
const button = document.querySelector("[data-theme-toggle]");
52+
const localStorageTheme = localStorage.getItem("theme");
53+
const systemSettingDark = window.matchMedia("(prefers-color-scheme: dark)");
54+
55+
let currentThemeSetting = calculateSettingAsThemeString({
56+
localStorageTheme,
57+
systemSettingDark,
58+
});
59+
60+
updateButton({ buttonEl: button, isDark: currentThemeSetting === "dark" });
61+
updateThemeOnHtmlEl({ theme: currentThemeSetting });
62+
63+
button.addEventListener("click", () => {
64+
const newTheme = currentThemeSetting === "dark" ? "light" : "dark";
65+
66+
localStorage.setItem("theme", newTheme);
67+
updateButton({ buttonEl: button, isDark: newTheme === "dark" });
68+
updateThemeOnHtmlEl({ theme: newTheme });
69+
70+
currentThemeSetting = newTheme;
71+
});
72+
2473
// Function to fetch data and populate the list
2574
async function fetchData(endpoint, listElement, includeFavicon = false) {
2675
try {
@@ -291,11 +340,13 @@ function showRestartNotification(message, isError = false) {
291340
notification.style.position = "fixed";
292341
notification.style.bottom = "20px";
293342
notification.style.right = "20px";
294-
notification.style.backgroundColor = isError ? "#f44336" : "#4caf50"; // Red for errors, green for success
295-
notification.style.color = "#fff";
343+
notification.style.backgroundColor = isError
344+
? "var(--colour-error)"
345+
: "var(--colour-success)";
346+
notification.style.color = "var(--colour-text)";
296347
notification.style.padding = "10px 20px";
297348
notification.style.borderRadius = "5px";
298-
notification.style.boxShadow = "0 2px 5px rgba(0, 0, 0, 0.2)";
349+
notification.style.boxShadow = "0 2px 5px var(--item-hover-colour)";
299350
notification.style.zIndex = "1000";
300351
notification.style.fontSize = "14px";
301352

0 commit comments

Comments
 (0)