Rename UI_MODE to THEME

pull/792/head v2.6.0
binwiederhier 2023-06-28 13:30:51 -04:00
parent e9f170a197
commit 64ac111d55
5 changed files with 40 additions and 36 deletions

View File

@ -7,15 +7,22 @@ Released June 28, 2023
With this release, the ntfy web app now contains a **[progressive web app](https://docs.ntfy.sh/subscribe/pwa/) (PWA)
with Web Push support**, which means you'll be able to **install the ntfy web app on your desktop or phone** similar
to a native app (__even on iOS!__ 🥳), and get basic push notification support (without any battery drain).
to a native app (__even on iOS!__ 🥳). Installing the PWA gives ntfy web its own launcher, a standalone window,
push notifications, and an app badge with the unread notification count.
Installing the PWA gives ntfy web its own launcher (e.g. shortcut on Windows, app on macOS, launcher shortcut on Linux,
home screen icon on iOS, and launcher icon on Android), a standalone window, push notifications, and an app badge with
the unread notification count.
On top of that, this release also brings **dark mode** 🧛🌙 to the web app.
🙏 A huge thanks for this release goes to [@nimbleghost](https://github.com/nimbleghost), for basically implementing the
Web Push / PWA and dark mode feature by himself. I'm really grateful for your contributions.
❤️ If you like ntfy, **please consider sponsoring us** via [GitHub Sponsors](https://github.com/sponsors/binwiederhier)
and [Liberapay](https://en.liberapay.com/ntfy/), or buying a [paid plan via the web app](https://ntfy.sh/app) (20% off
if you use promo code `MYTOPIC`). ntfy will always remain open source.
**Features:**
* The web app now supports Web Push, and is installable as a [progressive web app (PWA)](https://docs.ntfy.sh/subscribe/pwa/) on Chrome, Edge, Android, and iOS ([#751](https://github.com/binwiederhier/ntfy/pull/751), thanks to [@nimbleghost](https://github.com/nimbleghost))
* Support for dark mode in the web app ([#206](https://github.com/binwiederhier/ntfy/issues/206), thanks to [@nimbleghost](https://github.com/nimbleghost))
**Bug fixes:**

View File

@ -338,10 +338,6 @@
"prefs_notifications_web_push_disabled_description": "Notification are received when the web app is running (via WebSocket)",
"prefs_notifications_web_push_enabled": "Enabled for {{server}}",
"prefs_notifications_web_push_disabled": "Disabled",
"prefs_ui_mode_title": "UI Mode",
"prefs_ui_mode_system": "System (default)",
"prefs_ui_mode_dark": "Dark",
"prefs_ui_mode_light": "Light",
"prefs_users_title": "Manage users",
"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.",
"prefs_users_description_no_sync": "Users and passwords are not synchronized to your account.",
@ -359,6 +355,10 @@
"prefs_users_dialog_password_label": "Password",
"prefs_appearance_title": "Appearance",
"prefs_appearance_language_title": "Language",
"prefs_appearance_theme_title": "Theme",
"prefs_appearance_theme_system": "System (default)",
"prefs_appearance_theme_dark": "Dark mode",
"prefs_appearance_theme_light": "Light mode",
"prefs_reservations_title": "Reserved topics",
"prefs_reservations_description": "You can reserve topic names for personal use here. Reserving a topic gives you ownership over the topic, and allows you to define access permissions for other users over the topic.",
"prefs_reservations_limit_reached": "You reached your reserved topics limit.",

View File

@ -1,6 +1,6 @@
import db from "./db";
export const UI_MODE = {
export const THEME = {
DARK: "dark",
LIGHT: "light",
SYSTEM: "system",
@ -47,13 +47,13 @@ class Prefs {
await this.db.prefs.put({ key: "webPushEnabled", value: enabled });
}
async uiMode() {
const uiMode = await this.db.prefs.get("uiMode");
return uiMode?.value ?? UI_MODE.SYSTEM;
async theme() {
const theme = await this.db.prefs.get("theme");
return theme?.value ?? THEME.SYSTEM;
}
async setUIMode(mode) {
await this.db.prefs.put({ key: "uiMode", value: mode });
async setTheme(mode) {
await this.db.prefs.put({ key: "theme", value: mode });
}
}

View File

@ -22,19 +22,19 @@ import Login from "./Login";
import Signup from "./Signup";
import Account from "./Account";
import "../app/i18n"; // Translations!
import prefs, { UI_MODE } from "../app/Prefs";
import prefs, { THEME } from "../app/Prefs";
export const AccountContext = createContext(null);
const darkModeEnabled = (prefersDarkMode, uiModePreference) => {
switch (uiModePreference) {
case UI_MODE.DARK:
const darkModeEnabled = (prefersDarkMode, themePreference) => {
switch (themePreference) {
case THEME.DARK:
return true;
case UI_MODE.LIGHT:
case THEME.LIGHT:
return false;
case UI_MODE.SYSTEM:
case THEME.SYSTEM:
default:
return prefersDarkMode;
}
@ -43,20 +43,17 @@ const darkModeEnabled = (prefersDarkMode, uiModePreference) => {
const App = () => {
const [account, setAccount] = useState(null);
const accountMemo = useMemo(() => ({ account, setAccount }), [account, setAccount]);
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const uiModePreference = useLiveQuery(() => prefs.uiMode());
const themePreference = useLiveQuery(() => prefs.theme());
const theme = React.useMemo(
() =>
createTheme({
...themeOptions,
palette: {
...(darkModeEnabled(prefersDarkMode, uiModePreference) ? darkPalette : lightPalette),
...(darkModeEnabled(prefersDarkMode, themePreference) ? darkPalette : lightPalette),
},
}),
[prefersDarkMode, uiModePreference]
[prefersDarkMode, themePreference]
);
return (

View File

@ -43,7 +43,7 @@ import accountApi, { Permission, Role } from "../app/AccountApi";
import { Pref, PrefGroup } from "./Pref";
import { AccountContext } from "./App";
import { Paragraph } from "./styles";
import prefs, { UI_MODE } from "../app/Prefs";
import prefs, { THEME } from "../app/Prefs";
import { PermissionDenyAll, PermissionRead, PermissionReadWrite, PermissionWrite } from "./ReserveIcons";
import { ReserveAddDialog, ReserveDeleteDialog, ReserveEditDialog } from "./ReserveDialogs";
import { UnauthorizedError } from "../app/errors";
@ -86,7 +86,6 @@ const Notifications = () => {
{t("prefs_notifications_title")}
</Typography>
<PrefGroup>
<UIMode />
<Sound />
<MinPriority />
<DeleteAfter />
@ -238,21 +237,21 @@ const DeleteAfter = () => {
);
};
const UIMode = () => {
const Theme = () => {
const { t } = useTranslation();
const labelId = "prefUIMode";
const enabled = useLiveQuery(async () => prefs.uiMode());
const labelId = "prefTheme";
const enabled = useLiveQuery(async () => prefs.theme());
const handleChange = async (ev) => {
await prefs.setUIMode(ev.target.value);
await prefs.setTheme(ev.target.value);
};
return (
<Pref labelId={labelId} title={t("prefs_ui_mode_title")}>
<Pref labelId={labelId} title={t("prefs_appearance_theme_title")}>
<FormControl fullWidth variant="standard" sx={{ m: 1 }}>
<Select value={enabled ?? false} onChange={handleChange} aria-labelledby={labelId}>
<MenuItem value={UI_MODE.SYSTEM}>{t("prefs_ui_mode_system")}</MenuItem>
<MenuItem value={UI_MODE.DARK}>{t("prefs_ui_mode_dark")}</MenuItem>
<MenuItem value={UI_MODE.LIGHT}>{t("prefs_ui_mode_light")}</MenuItem>
<MenuItem value={THEME.SYSTEM}>{t("prefs_appearance_theme_system")}</MenuItem>
<MenuItem value={THEME.DARK}>{t("prefs_appearance_theme_dark")}</MenuItem>
<MenuItem value={THEME.LIGHT}>{t("prefs_appearance_theme_light")}</MenuItem>
</Select>
</FormControl>
</Pref>
@ -511,6 +510,7 @@ const Appearance = () => {
{t("prefs_appearance_title")}
</Typography>
<PrefGroup>
<Theme />
<Language />
</PrefGroup>
</Card>