Skip to content

Commit 4828e3a

Browse files
committed
Add preference
1 parent e607944 commit 4828e3a

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

web/public/static/langs/en.json

+4
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@
338338
"prefs_notifications_web_push_disabled_description": "Notification are received when the web app is running (via WebSocket)",
339339
"prefs_notifications_web_push_enabled": "Enabled for {{server}}",
340340
"prefs_notifications_web_push_disabled": "Disabled",
341+
"prefs_ui_mode_title": "UI Mode",
342+
"prefs_ui_mode_system": "System (default)",
343+
"prefs_ui_mode_dark": "Dark",
344+
"prefs_ui_mode_light": "Light",
341345
"prefs_users_title": "Manage users",
342346
"prefs_users_description": "Add/remove users for your protected topics here. Please note that username and password are stored in the browser's local storage.",
343347
"prefs_users_description_no_sync": "Users and passwords are not synchronized to your account.",

web/src/app/Prefs.js

+15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import db from "./db";
22

3+
export const UI_MODE = {
4+
DARK: "dark",
5+
LIGHT: "light",
6+
SYSTEM: "system",
7+
};
8+
39
class Prefs {
410
constructor(dbImpl) {
511
this.db = dbImpl;
@@ -40,6 +46,15 @@ class Prefs {
4046
async setWebPushEnabled(enabled) {
4147
await this.db.prefs.put({ key: "webPushEnabled", value: enabled });
4248
}
49+
50+
async uiMode() {
51+
const uiMode = await this.db.prefs.get("uiMode");
52+
return uiMode?.value ?? UI_MODE.SYSTEM;
53+
}
54+
55+
async setUIMode(mode) {
56+
await this.db.prefs.put({ key: "uiMode", value: mode });
57+
}
4358
}
4459

4560
const prefs = new Prefs(db());

web/src/components/App.jsx

+19-2
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,41 @@ import Login from "./Login";
2222
import Signup from "./Signup";
2323
import Account from "./Account";
2424
import "../app/i18n"; // Translations!
25+
import prefs, { UI_MODE } from "../app/Prefs";
2526

2627
export const AccountContext = createContext(null);
2728

29+
const darkModeEnabled = (prefersDarkMode, uiModePreference) => {
30+
switch (uiModePreference) {
31+
case UI_MODE.DARK:
32+
return true;
33+
34+
case UI_MODE.LIGHT:
35+
return false;
36+
37+
case UI_MODE.SYSTEM:
38+
default:
39+
return prefersDarkMode;
40+
}
41+
};
42+
2843
const App = () => {
2944
const [account, setAccount] = useState(null);
3045
const accountMemo = useMemo(() => ({ account, setAccount }), [account, setAccount]);
3146

3247
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
3348

49+
const uiModePreference = useLiveQuery(() => prefs.uiMode());
50+
3451
const theme = React.useMemo(
3552
() =>
3653
createTheme({
3754
...themeOptions,
3855
palette: {
39-
...(prefersDarkMode ? darkPalette : lightPalette),
56+
...(darkModeEnabled(prefersDarkMode, uiModePreference) ? darkPalette : lightPalette),
4057
},
4158
}),
42-
[prefersDarkMode]
59+
[prefersDarkMode, uiModePreference]
4360
);
4461

4562
return (

web/src/components/Preferences.jsx

+23-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import accountApi, { Permission, Role } from "../app/AccountApi";
4343
import { Pref, PrefGroup } from "./Pref";
4444
import { AccountContext } from "./App";
4545
import { Paragraph } from "./styles";
46-
import prefs from "../app/Prefs";
46+
import prefs, { UI_MODE } from "../app/Prefs";
4747
import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons";
4848
import { ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog } from "./ReserveDialogs";
4949
import { UnauthorizedError } from "../app/errors";
@@ -86,6 +86,7 @@ const Notifications = () => {
8686
{t("prefs_notifications_title")}
8787
</Typography>
8888
<PrefGroup>
89+
<UIMode />
8990
<Sound />
9091
<MinPriority />
9192
<DeleteAfter />
@@ -237,6 +238,27 @@ const DeleteAfter = () => {
237238
);
238239
};
239240

241+
const UIMode = () => {
242+
const { t } = useTranslation();
243+
const labelId = "prefUIMode";
244+
const enabled = useLiveQuery(async () => prefs.uiMode());
245+
const handleChange = async (ev) => {
246+
await prefs.setUIMode(ev.target.value);
247+
};
248+
249+
return (
250+
<Pref labelId={labelId} title={t("prefs_ui_mode_title")}>
251+
<FormControl fullWidth variant="standard" sx={{ m: 1 }}>
252+
<Select value={enabled ?? false} onChange={handleChange} aria-labelledby={labelId}>
253+
<MenuItem value={UI_MODE.SYSTEM}>{t("prefs_ui_mode_system")}</MenuItem>
254+
<MenuItem value={UI_MODE.DARK}>{t("prefs_ui_mode_dark")}</MenuItem>
255+
<MenuItem value={UI_MODE.LIGHT}>{t("prefs_ui_mode_light")}</MenuItem>
256+
</Select>
257+
</FormControl>
258+
</Pref>
259+
);
260+
};
261+
240262
const WebPushEnabled = () => {
241263
const { t } = useTranslation();
242264
const labelId = "prefWebPushEnabled";

0 commit comments

Comments
 (0)