Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 710d88e

Browse files
committed
Support dark mode and theme switching
1 parent adc3fc1 commit 710d88e

File tree

8 files changed

+621
-96
lines changed

8 files changed

+621
-96
lines changed

.node/package-lock.json

Lines changed: 340 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.node/package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
"not dead"
66
],
77
"scripts": {
8-
"watch": "postcss -w ../Assets/**/*.css -o ../Resources/all.min.css --config ./postcss.config.js"
8+
"watch": "concurrently \"postcss -w ../Assets/**/*.css -o ../Resources/all.min.css --config ./postcss.config.js\" \"tsc -w\"",
9+
"build": "tsc && postcss ../Assets/**/*.css -o ../Resources/all.min.css --config ./postcss.config.js"
910
},
10-
"dependencies": {
11+
"devDependencies": {
12+
"concurrently": "^5.2.0",
1113
"cssnano": "^4.1.10",
1214
"postcss-cli": "^7.1.0",
13-
"postcss-preset-env": "^6.7.0"
15+
"postcss-preset-env": "^6.7.0",
16+
"typescript": "~3.9.7"
1417
}
1518
}

.node/tsconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"files": ["../Assets/ts/theme-switching.ts"],
3+
"compilerOptions": {
4+
"outFile": "../Resources/all.js"
5+
}
6+
}

Assets/css/all.css

Lines changed: 109 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -74,92 +74,89 @@
7474
}
7575
}
7676

77-
/*
78-
@media (prefers-color-scheme: dark) {
79-
:root {
80-
--system-red: rgb(255, 69, 58);
81-
--system-orange: rgb(255, 159, 10);
82-
--system-yellow: rgb(255, 214, 10);
83-
--system-green: rgb(48, 209, 88);
84-
--system-teal: rgb(100, 210, 255);
85-
--system-blue: rgb(10, 132, 255);
86-
--system-indigo: rgb(94, 92, 230);
87-
--system-purple: rgb(191, 90, 242);
88-
--system-pink: rgb(255, 55, 95);
89-
--system-gray: rgb(142, 142, 147);
90-
--system-gray2: rgb(99, 99, 102);
91-
--system-gray3: rgb(72, 72, 74);
92-
--system-gray4: rgb(58, 58, 60);
93-
--system-gray5: rgb(44, 44, 46);
94-
--system-gray6: rgb(28, 28, 30);
95-
96-
--label: rgb(255, 255, 255);
97-
--secondary-label: rgb(235, 235, 245);
98-
--tertiary-label: rgb(235, 235, 245);
99-
--quaternary-label: rgb(235, 235, 245);
100-
--placeholder-text: rgb(235, 235, 245);
101-
--link: rgb(9, 132, 255);
102-
--separator: rgb(44, 44, 46);
103-
--opaque-separator: rgb(56, 56, 58);
104-
--system-fill: rgb(120, 120, 128);
105-
--secondary-system-fill: rgb(120, 120, 128);
106-
--tertiary-system-fill: rgb(118, 118, 128);
107-
--quaternary-system-fill: rgb(118, 118, 128);
108-
--system-background: rgb(0, 0, 0);
109-
--secondary-system-background: rgb(28, 28, 30);
110-
--tertiary-system-background: rgb(44, 44, 46);
111-
--system-grouped-background: rgb(0, 0, 0);
112-
--secondary-system-grouped-background: rgb(28, 28, 30);
113-
--tertiary-system-grouped-background: rgb(44, 44, 46);
114-
}
77+
.dark-theme {
78+
--system-red: rgb(255, 69, 58);
79+
--system-orange: rgb(255, 159, 10);
80+
--system-yellow: rgb(255, 214, 10);
81+
--system-green: rgb(48, 209, 88);
82+
--system-teal: rgb(100, 210, 255);
83+
--system-blue: rgb(10, 132, 255);
84+
--system-indigo: rgb(94, 92, 230);
85+
--system-purple: rgb(191, 90, 242);
86+
--system-pink: rgb(255, 55, 95);
87+
--system-gray: rgb(142, 142, 147);
88+
--system-gray2: rgb(99, 99, 102);
89+
--system-gray3: rgb(72, 72, 74);
90+
--system-gray4: rgb(58, 58, 60);
91+
--system-gray5: rgb(44, 44, 46);
92+
--system-gray6: rgb(28, 28, 30);
93+
94+
--label: rgb(255, 255, 255);
95+
--secondary-label: rgb(235, 235, 245);
96+
--tertiary-label: rgb(235, 235, 245);
97+
--quaternary-label: rgb(235, 235, 245);
98+
--placeholder-text: rgb(235, 235, 245);
99+
--link: rgb(9, 132, 255);
100+
--separator: rgb(44, 44, 46);
101+
--opaque-separator: rgb(56, 56, 58);
102+
--system-fill: rgb(120, 120, 128);
103+
--secondary-system-fill: rgb(120, 120, 128);
104+
--tertiary-system-fill: rgb(118, 118, 128);
105+
--quaternary-system-fill: rgb(118, 118, 128);
106+
--system-background: rgb(0, 0, 0);
107+
--secondary-system-background: rgb(28, 28, 30);
108+
--tertiary-system-background: rgb(44, 44, 46);
109+
--system-grouped-background: rgb(0, 0, 0);
110+
--secondary-system-grouped-background: rgb(28, 28, 30);
111+
--tertiary-system-grouped-background: rgb(44, 44, 46);
112+
}
115113

116-
@supports (color: color(display-p3 1 1 1)) {
117-
:root {
118-
--system-red: color(display-p3 1 0.4118 0.3804);
119-
--system-orange: color(display-p3 1 0.702 0.251);
120-
--system-yellow: color(display-p3 1 0.8314 0.149);
121-
--system-green: color(display-p3 0.1882 0.8588 0.3569);
122-
--system-teal: color(display-p3 0.4392 0.8431 1);
123-
--system-blue: color(display-p3 0.251 0.6118 1);
124-
--system-indigo: color(display-p3 0.4902 0.4784 1);
125-
--system-purple: color(display-p3 0.8549 0.5608 1);
126-
--system-pink: color(display-p3 1 0.3922 0.5098);
127-
--system-gray: color(display-p3 0.6824 0.6824 0.698);
128-
--system-gray2: color(display-p3 0.4863 0.4863 0.502);
129-
--system-gray3: color(display-p3 0.3294 0.3294 0.3373);
130-
--system-gray4: color(display-p3 0.2667 0.2667 0.2745);
131-
--system-gray5: color(display-p3 0.2118 0.2118 0.2196);
132-
--system-gray6: color(display-p3 0.1412 0.1412 0.149);
133-
134-
--label: color(display-p3 1 1 1);
135-
--secondary-label: color(display-p3 0.9216 0.9216 0.9608);
136-
--tertiary-label: color(display-p3 0.9216 0.9216 0.9608);
137-
--quaternary-label: color(display-p3 0.9216 0.9216 0.9608);
138-
--placeholder-text: color(display-p3 0.9216 0.9216 0.9608);
139-
--link: color(display-p3 0.03529 0.5176 1);
140-
--separator: color(display-p3 0.2118 0.2118 0.2196);
141-
--opaque-separator: color(display-p3 0.2196 0.2196 0.2275);
142-
--system-fill: color(display-p3 0.4706 0.4706 0.502);
143-
--secondary-system-fill: color(display-p3 0.4706 0.4706 0.502);
144-
--tertiary-system-fill: color(display-p3 0.4627 0.4627 0.502);
145-
--quaternary-system-fill: color(display-p3 0.4627 0.4627 0.502);
146-
--system-background: color(display-p3 0 0 0);
147-
--secondary-system-background: color(
148-
display-p3 0.1412 0.1412 0.149
149-
);
150-
--tertiary-system-background: color(
151-
display-p3 0.2118 0.2118 0.2196
152-
);
153-
--system-grouped-background: color(display-p3 0 0 0);
154-
--secondary-system-grouped-background: color(
155-
display-p3 0.1412 0.1412 0.149
156-
);
157-
--tertiary-system-grouped-background: color(
158-
display-p3 0.2118 0.2118 0.2196
159-
);
160-
}
161-
}
162-
} */
114+
@supports (color: color(display-p3 1 1 1)) {
115+
.dark-theme {
116+
--system-red: color(display-p3 1 0.4118 0.3804);
117+
--system-orange: color(display-p3 1 0.702 0.251);
118+
--system-yellow: color(display-p3 1 0.8314 0.149);
119+
--system-green: color(display-p3 0.1882 0.8588 0.3569);
120+
--system-teal: color(display-p3 0.4392 0.8431 1);
121+
--system-blue: color(display-p3 0.251 0.6118 1);
122+
--system-indigo: color(display-p3 0.4902 0.4784 1);
123+
--system-purple: color(display-p3 0.8549 0.5608 1);
124+
--system-pink: color(display-p3 1 0.3922 0.5098);
125+
--system-gray: color(display-p3 0.6824 0.6824 0.698);
126+
--system-gray2: color(display-p3 0.4863 0.4863 0.502);
127+
--system-gray3: color(display-p3 0.3294 0.3294 0.3373);
128+
--system-gray4: color(display-p3 0.2667 0.2667 0.2745);
129+
--system-gray5: color(display-p3 0.2118 0.2118 0.2196);
130+
--system-gray6: color(display-p3 0.1412 0.1412 0.149);
131+
132+
--label: color(display-p3 1 1 1);
133+
--secondary-label: color(display-p3 0.9216 0.9216 0.9608);
134+
--tertiary-label: color(display-p3 0.9216 0.9216 0.9608);
135+
--quaternary-label: color(display-p3 0.9216 0.9216 0.9608);
136+
--placeholder-text: color(display-p3 0.9216 0.9216 0.9608);
137+
--link: color(display-p3 0.03529 0.5176 1);
138+
--separator: color(display-p3 0.2118 0.2118 0.2196);
139+
--opaque-separator: color(display-p3 0.2196 0.2196 0.2275);
140+
--system-fill: color(display-p3 0.4706 0.4706 0.502);
141+
--secondary-system-fill: color(display-p3 0.4706 0.4706 0.502);
142+
--tertiary-system-fill: color(display-p3 0.4627 0.4627 0.502);
143+
--quaternary-system-fill: color(display-p3 0.4627 0.4627 0.502);
144+
--system-background: color(display-p3 0 0 0);
145+
--secondary-system-background: color(
146+
display-p3 0.1412 0.1412 0.149
147+
);
148+
--tertiary-system-background: color(
149+
display-p3 0.2118 0.2118 0.2196
150+
);
151+
--system-grouped-background: color(display-p3 0 0 0);
152+
--secondary-system-grouped-background: color(
153+
display-p3 0.1412 0.1412 0.149
154+
);
155+
--tertiary-system-grouped-background: color(
156+
display-p3 0.2118 0.2118 0.2196
157+
);
158+
}
159+
}
163160

164161
:root {
165162
--large-title: 600 32pt / 39pt sans-serif;
@@ -674,6 +671,8 @@ body {
674671
& > header {
675672
font: var(--title-1);
676673
padding: 0.5em 0;
674+
display: flex;
675+
align-items: center;
677676

678677
& a {
679678
color: var(--label);
@@ -690,6 +689,31 @@ body {
690689
color: var(--secondary-label);
691690
letter-spacing: 0.1ch;
692691
}
692+
& label {
693+
padding-bottom: 4px;
694+
font: var(--caption-1);
695+
}
696+
& .theme-select-container {
697+
display: flex;
698+
flex-direction: column;
699+
}
700+
& select {
701+
color: var(--secondary-label);
702+
font: var(--caption-1);
703+
width: auto;
704+
border: 1px solid var(--label);
705+
706+
/* Simple down-pointing rectangle positioned on the right side of the input */
707+
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%238a8a8a%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
708+
background-repeat: no-repeat, repeat;
709+
background-position: right .7em top 50%, 0 0;
710+
background-size: .65em auto, 100%;
711+
padding-right: 1.8em;
712+
}
713+
& .spacer {
714+
flex-grow: 1;
715+
}
716+
693717
}
694718

695719
& > footer {

Assets/ts/theme-switching.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
type ThemeChoice = "light" | "dark" | "auto";
2+
const themeQuery = window.matchMedia('(prefers-color-scheme: dark)');
3+
const localStorageKey = "picked-theme";
4+
let autoTheme = false;
5+
6+
// load initial theme before load event to prevent flashing of background color on navigation
7+
let initialTheme = window.localStorage.getItem(localStorageKey) ?? "auto";
8+
setPickedTheme(initialTheme as ThemeChoice);
9+
10+
window.addEventListener("load", () => {
11+
const themeSwitcher = window.document.getElementById("theme-switcher") as HTMLSelectElement;
12+
13+
themeSwitcher.addEventListener("change", (themePickedEvent: Event) => {
14+
const newValue = (themePickedEvent.target as HTMLSelectElement).value
15+
setPickedTheme(newValue as ThemeChoice);
16+
});
17+
18+
themeQuery.addEventListener("change", (systemThemeChangeEvent) => {
19+
const systemTheme = systemThemeChangeEvent.matches ? "dark" : "light";
20+
updateDropdownLabel(systemTheme);
21+
if (autoTheme) {
22+
applyTheme(systemTheme);
23+
}
24+
})
25+
26+
setInitialTheme(themeSwitcher);
27+
})
28+
29+
/**
30+
* Sets the correct theme based on what's in storage, and updates the theme switcher dropdown with the correct initial value.
31+
*/
32+
function setInitialTheme(themeSwitcher: HTMLSelectElement) {
33+
let initialTheme = window.localStorage.getItem(localStorageKey) ?? "auto";
34+
themeSwitcher.value = initialTheme;
35+
setPickedTheme(initialTheme as ThemeChoice);
36+
const systemTheme = themeQuery.matches ? "dark" : "light";
37+
updateDropdownLabel(systemTheme);
38+
}
39+
40+
/**
41+
* Updates the styles of the page to reflect a new theme
42+
*/
43+
function applyTheme(newTheme: "light" | "dark") {
44+
const otherTheme = newTheme == "light" ? "dark" : "light";
45+
window.document.documentElement.classList.remove(`${otherTheme}-theme`);
46+
window.document.documentElement.classList.add(`${newTheme}-theme`);
47+
}
48+
49+
/**
50+
* Saves a newly picked theme to storage and applies the theme.
51+
* If the new theme is "auto", the correct theme will be applied based on the system settings.
52+
*/
53+
function setPickedTheme(newTheme: ThemeChoice) {
54+
window.localStorage.setItem(localStorageKey, newTheme);
55+
autoTheme = newTheme === "auto";
56+
if (newTheme === "auto") {
57+
const systemTheme = themeQuery.matches ? "dark" : "light";
58+
applyTheme(systemTheme);
59+
} else {
60+
applyTheme(newTheme);
61+
}
62+
}
63+
64+
/**
65+
* Updates the "Auto" choice of the theme dropdown to reflect the current system theme - either "Auto (light)" or "Auto (dark)"
66+
*/
67+
function updateDropdownLabel(systemTheme: "light" | "dark") {
68+
window.document.getElementById('theme-option-auto').innerText = `Auto (${systemTheme})`;
69+
}

Resources/all.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
var _a;
2+
var themeQuery = window.matchMedia('(prefers-color-scheme: dark)');
3+
var localStorageKey = "picked-theme";
4+
var autoTheme = false; // hello
5+
// load initial theme before load event to prevent flashing of background color on navigation
6+
var initialTheme = (_a = window.localStorage.getItem(localStorageKey)) !== null && _a !== void 0 ? _a : "auto";
7+
setPickedTheme(initialTheme);
8+
window.addEventListener("load", function () {
9+
var themeSwitcher = window.document.getElementById("theme-switcher");
10+
themeSwitcher.addEventListener("change", function (themePickedEvent) {
11+
var newValue = themePickedEvent.target.value;
12+
setPickedTheme(newValue);
13+
});
14+
themeQuery.addEventListener("change", function (systemThemeChangeEvent) {
15+
var systemTheme = systemThemeChangeEvent.matches ? "dark" : "light";
16+
updateDropdownLabel(systemTheme);
17+
if (autoTheme) {
18+
applyTheme(systemTheme);
19+
}
20+
});
21+
setInitialTheme(themeSwitcher);
22+
});
23+
/**
24+
* Sets the correct theme based on what's in storage, and updates the theme switcher dropdown with the correct initial value.
25+
*/
26+
function setInitialTheme(themeSwitcher) {
27+
var _a;
28+
var initialTheme = (_a = window.localStorage.getItem(localStorageKey)) !== null && _a !== void 0 ? _a : "auto";
29+
themeSwitcher.value = initialTheme;
30+
setPickedTheme(initialTheme);
31+
var systemTheme = themeQuery.matches ? "dark" : "light";
32+
updateDropdownLabel(systemTheme);
33+
}
34+
/**
35+
* Updates the styles of the page to reflect a new theme
36+
*/
37+
function applyTheme(newTheme) {
38+
var otherTheme = newTheme == "light" ? "dark" : "light";
39+
window.document.documentElement.classList.remove(otherTheme + "-theme");
40+
window.document.documentElement.classList.add(newTheme + "-theme");
41+
}
42+
/**
43+
* Saves a newly picked theme to storage and applies the theme.
44+
* If the new theme is "auto", the correct theme will be applied based on the system settings.
45+
*/
46+
function setPickedTheme(newTheme) {
47+
window.localStorage.setItem(localStorageKey, newTheme);
48+
autoTheme = newTheme === "auto";
49+
if (newTheme === "auto") {
50+
var systemTheme = themeQuery.matches ? "dark" : "light";
51+
applyTheme(systemTheme);
52+
}
53+
else {
54+
applyTheme(newTheme);
55+
}
56+
}
57+
/**
58+
* Updates the "Auto" choice of the theme dropdown to reflect the current system theme - either "Auto (light)" or "Auto (dark)"
59+
*/
60+
function updateDropdownLabel(systemTheme) {
61+
window.document.getElementById('theme-option-auto').innerText = "Auto (" + systemTheme + ")";
62+
}

0 commit comments

Comments
 (0)