Skip to content

Commit b2a7b1d

Browse files
authored
feat: add auto dark mode (#259)
Add detection for theme preferences given by the browser. This works by replacing the "dark mode" setting with a new selector that defaults to "auto" (losing old settings, sorry). You can try this out by opening the dev console and using the dedicated button (Inspector > sun/moon -shaped in Firefox, Elements > paint brush -shaped in Chromium). I tried to match the project style but I'm not too good at frontend, I hope this is OK!
1 parent 896182b commit b2a7b1d

3 files changed

Lines changed: 39 additions & 20 deletions

File tree

src/App.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,35 @@ export default function App() {
146146
const [errorsDialog, setErrorsDialog] = React.useState(false);
147147
const dispatch = useDispatch();
148148
const etebase = useCredentials();
149-
const darkMode = useSelector((state: store.StoreState) => state.settings.darkMode);
149+
const darkModeUserSelection = useSelector((state: store.StoreState) => state.settings.darkModeUserSelection);
150150
const fetchCount = useSelector((state: store.StoreState) => state.fetchCount);
151151
const errors = useSelector((state: store.StoreState) => state.errors);
152152

153+
function shouldBeDark(userSelection: string, browserPreference: boolean): boolean {
154+
if (userSelection === "auto") {
155+
return browserPreference;
156+
} else if (userSelection === "dark") {
157+
return true;
158+
}
159+
return false;
160+
}
161+
162+
const [darkModeBrowserPreference, setDarkModeBrowserPreference] = React.useState(Boolean(window.matchMedia?.("(prefers-color-scheme: dark)").matches));
163+
const handleBrowserDarkModePreferenceChange = React.useCallback((e) => {
164+
setDarkModeBrowserPreference(e.matches);
165+
}, []);
166+
React.useEffect(() => {
167+
window.matchMedia?.("(prefers-color-scheme: dark)").addEventListener("change", handleBrowserDarkModePreferenceChange);
168+
return () => {
169+
window.matchMedia?.("(prefers-color-scheme: dark)").removeEventListener("change", handleBrowserDarkModePreferenceChange);
170+
};
171+
}, [handleBrowserDarkModePreferenceChange]);
172+
173+
const [darkMode, setDarkMode] = React.useState(() => shouldBeDark(darkModeUserSelection, darkModeBrowserPreference));
174+
React.useEffect(() => {
175+
setDarkMode(shouldBeDark(darkModeUserSelection, darkModeBrowserPreference));
176+
}, [darkModeUserSelection, darkModeBrowserPreference]);
177+
153178
async function refresh() {
154179
const syncManager = SyncManager.getManager(etebase!);
155180
const sync = syncManager.sync();

src/Settings/index.tsx

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ import { useSelector, useDispatch } from "react-redux";
88
import Select from "@material-ui/core/Select";
99
import MenuItem from "@material-ui/core/MenuItem";
1010
import FormControl from "@material-ui/core/FormControl";
11-
import FormControlLabel from "@material-ui/core/FormControlLabel";
12-
import FormGroup from "@material-ui/core/FormGroup";
13-
import Switch from "@material-ui/core/Switch";
1411
import InputLabel from "@material-ui/core/InputLabel";
1512

1613
import { StoreState } from "../store";
@@ -173,8 +170,6 @@ export default React.memo(function Settings() {
173170
const dispatch = useDispatch();
174171
const settings = useSelector((state: StoreState) => state.settings);
175172

176-
const darkMode = !!settings.darkMode;
177-
178173
function handleChange(event: React.ChangeEvent<any>) {
179174
const name = event.target.name;
180175
const value = event.target.value;
@@ -228,18 +223,17 @@ export default React.memo(function Settings() {
228223
</Select>
229224
</FormControl>
230225
<h2>Dark mode</h2>
231-
<FormGroup>
232-
<FormControlLabel
233-
control={
234-
<Switch
235-
color="primary"
236-
checked={darkMode}
237-
onChange={() => dispatch(setSettings({ ...settings, darkMode: !darkMode }))}
238-
/>
239-
}
240-
label="Dark mode"
241-
/>
242-
</FormGroup>
226+
<FormControl style={{ width: "15em" }}>
227+
<Select
228+
name="darkModeUserSelection"
229+
value={settings.darkModeUserSelection}
230+
onChange={handleChange}
231+
>
232+
<MenuItem value="auto">Auto</MenuItem>
233+
<MenuItem value="dark">Dark</MenuItem>
234+
<MenuItem value="light">Light</MenuItem>
235+
</Select>
236+
</FormControl>
243237
</Container>
244238
</>
245239
);

src/store/reducers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ export const messagesReducer = handleActions(
240240
// FIXME Move all the below (potentially the fetchCount ones too) to their own file
241241
export interface SettingsType {
242242
locale: string;
243-
darkMode?: boolean;
243+
darkModeUserSelection: string;
244244
taskSettings: {
245245
filterBy: string | null;
246246
sortBy: string;
@@ -255,7 +255,7 @@ export const settingsReducer = handleActions(
255255
},
256256
{
257257
locale: "en-gb",
258-
darkMode: false,
258+
darkModeUserSelection: "auto",
259259
taskSettings: {
260260
filterBy: null,
261261
sortBy: "smart",

0 commit comments

Comments
 (0)