Merge branch 'main' of github.com:binwiederhier/ntfy
commit
9146e439d2
|
@ -19,11 +19,14 @@ import Navigation from "./Navigation";
|
||||||
import accountApi from "../app/AccountApi";
|
import accountApi from "../app/AccountApi";
|
||||||
import PopupMenu from "./PopupMenu";
|
import PopupMenu from "./PopupMenu";
|
||||||
import { SubscriptionPopup } from "./SubscriptionPopup";
|
import { SubscriptionPopup } from "./SubscriptionPopup";
|
||||||
|
import { useIsLaunchedPWA } from "./hooks";
|
||||||
|
|
||||||
const ActionBar = (props) => {
|
const ActionBar = (props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const isLaunchedPWA = useIsLaunchedPWA();
|
||||||
|
|
||||||
let title = "ntfy";
|
let title = "ntfy";
|
||||||
if (props.selected) {
|
if (props.selected) {
|
||||||
title = topicDisplayName(props.selected);
|
title = topicDisplayName(props.selected);
|
||||||
|
@ -32,6 +35,22 @@ const ActionBar = (props) => {
|
||||||
} else if (location.pathname === routes.account) {
|
} else if (location.pathname === routes.account) {
|
||||||
title = t("action_bar_account");
|
title = t("action_bar_account");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getActionBarBackground = () => {
|
||||||
|
if (isLaunchedPWA) {
|
||||||
|
return "#317f6f";
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (theme.palette.mode) {
|
||||||
|
case "dark":
|
||||||
|
return "linear-gradient(150deg, #203631 0%, #2a6e60 100%)";
|
||||||
|
|
||||||
|
case "light":
|
||||||
|
default:
|
||||||
|
return "linear-gradient(150deg, #338574 0%, #56bda8 100%)";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar
|
<AppBar
|
||||||
position="fixed"
|
position="fixed"
|
||||||
|
@ -44,7 +63,7 @@ const ActionBar = (props) => {
|
||||||
<Toolbar
|
<Toolbar
|
||||||
sx={{
|
sx={{
|
||||||
pr: "24px",
|
pr: "24px",
|
||||||
background: theme.palette.actionBarBackground,
|
background: getActionBarBackground(),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { ThemeProvider, createTheme } from "@mui/material/styles";
|
||||||
import { useLiveQuery } from "dexie-react-hooks";
|
import { useLiveQuery } from "dexie-react-hooks";
|
||||||
import { BrowserRouter, Outlet, Route, Routes, useParams } from "react-router-dom";
|
import { BrowserRouter, Outlet, Route, Routes, useParams } from "react-router-dom";
|
||||||
import { AllSubscriptions, SingleSubscription } from "./Notifications";
|
import { AllSubscriptions, SingleSubscription } from "./Notifications";
|
||||||
import themeOptions, { darkPalette, lightPalette } from "./theme";
|
import { darkTheme, lightTheme } from "./theme";
|
||||||
import Navigation from "./Navigation";
|
import Navigation from "./Navigation";
|
||||||
import ActionBar from "./ActionBar";
|
import ActionBar from "./ActionBar";
|
||||||
import notifier from "../app/Notifier";
|
import notifier from "../app/Notifier";
|
||||||
|
@ -46,13 +46,7 @@ const App = () => {
|
||||||
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
|
||||||
const themePreference = useLiveQuery(() => prefs.theme());
|
const themePreference = useLiveQuery(() => prefs.theme());
|
||||||
const theme = React.useMemo(
|
const theme = React.useMemo(
|
||||||
() =>
|
() => createTheme(darkModeEnabled(prefersDarkMode, themePreference) ? darkTheme : lightTheme),
|
||||||
createTheme({
|
|
||||||
...themeOptions,
|
|
||||||
palette: {
|
|
||||||
...(darkModeEnabled(prefersDarkMode, themePreference) ? darkPalette : lightPalette),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[prefersDarkMode, themePreference]
|
[prefersDarkMode, themePreference]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
Box,
|
Box,
|
||||||
IconButton,
|
IconButton,
|
||||||
Button,
|
Button,
|
||||||
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
|
@ -82,6 +83,7 @@ const Navigation = (props) => {
|
||||||
Navigation.width = navWidth;
|
Navigation.width = navWidth;
|
||||||
|
|
||||||
const NavList = (props) => {
|
const NavList = (props) => {
|
||||||
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -130,7 +132,7 @@ const NavList = (props) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Toolbar sx={{ display: { xs: "none", sm: "block" } }} />
|
<Toolbar sx={{ display: { xs: "none", sm: "block" } }} />
|
||||||
<List component="nav" sx={{ paddingTop: alertVisible ? "0" : "" }}>
|
<List component="nav" sx={{ paddingTop: { xs: 0, sm: alertVisible ? 0 : "" } }}>
|
||||||
{showNotificationPermissionRequired && <NotificationPermissionRequired refreshPermissions={refreshPermissions} />}
|
{showNotificationPermissionRequired && <NotificationPermissionRequired refreshPermissions={refreshPermissions} />}
|
||||||
{showNotificationPermissionDenied && <NotificationPermissionDeniedAlert />}
|
{showNotificationPermissionDenied && <NotificationPermissionDeniedAlert />}
|
||||||
{showNotificationBrowserNotSupportedBox && <NotificationBrowserNotSupportedAlert />}
|
{showNotificationBrowserNotSupportedBox && <NotificationBrowserNotSupportedAlert />}
|
||||||
|
@ -190,7 +192,11 @@ const NavList = (props) => {
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("nav_button_subscribe")} />
|
<ListItemText primary={t("nav_button_subscribe")} />
|
||||||
</ListItemButton>
|
</ListItemButton>
|
||||||
{showUpgradeBanner && <UpgradeBanner />}
|
{showUpgradeBanner && (
|
||||||
|
// The text background gradient didn't seem to do well with switching between light/dark mode,
|
||||||
|
// So adding a `key` forces React to replace the entire component when the theme changes
|
||||||
|
<UpgradeBanner key={`upgrade-banner-${theme.palette.mode}`} mode={theme.palette.mode} />
|
||||||
|
)}
|
||||||
</List>
|
</List>
|
||||||
<SubscribeDialog
|
<SubscribeDialog
|
||||||
key={`subscribeDialog${subscribeDialogKey}`} // Resets dialog when canceled/closed
|
key={`subscribeDialog${subscribeDialogKey}`} // Resets dialog when canceled/closed
|
||||||
|
@ -203,7 +209,7 @@ const NavList = (props) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const UpgradeBanner = () => {
|
const UpgradeBanner = ({ mode }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [dialogKey, setDialogKey] = useState(0);
|
const [dialogKey, setDialogKey] = useState(0);
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
|
@ -220,13 +226,16 @@ const UpgradeBanner = () => {
|
||||||
width: `${Navigation.width - 1}px`,
|
width: `${Navigation.width - 1}px`,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
mt: "auto",
|
mt: "auto",
|
||||||
background: "linear-gradient(150deg, rgba(196, 228, 221, 0.46) 0%, rgb(255, 255, 255) 100%)",
|
background:
|
||||||
|
mode === "light"
|
||||||
|
? "linear-gradient(150deg, rgba(196, 228, 221, 0.46) 0%, rgb(255, 255, 255) 100%)"
|
||||||
|
: "linear-gradient(150deg, #203631 0%, #2a6e60 100%)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Divider />
|
<Divider />
|
||||||
<ListItemButton onClick={handleClick} sx={{ pt: 2, pb: 2 }}>
|
<ListItemButton onClick={handleClick} sx={{ pt: 2, pb: 2 }}>
|
||||||
<ListItemIcon>
|
<ListItemIcon>
|
||||||
<CelebrationIcon sx={{ color: "#55b86e" }} fontSize="large" />
|
<CelebrationIcon sx={{ color: mode === "light" ? "#55b86e" : "#00ff95" }} fontSize="large" />
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
sx={{ ml: 1 }}
|
sx={{ ml: 1 }}
|
||||||
|
@ -236,7 +245,10 @@ const UpgradeBanner = () => {
|
||||||
style: {
|
style: {
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
fontSize: "1.1rem",
|
fontSize: "1.1rem",
|
||||||
background: "-webkit-linear-gradient(45deg, #09009f, #00ff95 80%)",
|
background:
|
||||||
|
mode === "light"
|
||||||
|
? "-webkit-linear-gradient(45deg, #09009f, #00ff95 80%)"
|
||||||
|
: "-webkit-linear-gradient(45deg,rgb(255, 255, 255), #00ff95 80%)",
|
||||||
WebkitBackgroundClip: "text",
|
WebkitBackgroundClip: "text",
|
||||||
WebkitTextFillColor: "transparent",
|
WebkitTextFillColor: "transparent",
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/** @type {import("@mui/material").ThemeOptions} */
|
/** @type {import("@mui/material").ThemeOptions} */
|
||||||
const themeOptions = {
|
const baseThemeOptions = {
|
||||||
components: {
|
components: {
|
||||||
MuiListItemIcon: {
|
MuiListItemIcon: {
|
||||||
styleOverrides: {
|
styleOverrides: {
|
||||||
|
@ -22,37 +22,53 @@ const themeOptions = {
|
||||||
|
|
||||||
// https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/colors.xml
|
// https://github.com/binwiederhier/ntfy-android/blob/main/app/src/main/res/values/colors.xml
|
||||||
|
|
||||||
/** @type {import("@mui/material").ThemeOptions['palette']} */
|
/** @type {import("@mui/material").ThemeOptions} */
|
||||||
export const lightPalette = {
|
export const lightTheme = {
|
||||||
mode: "light",
|
...baseThemeOptions,
|
||||||
primary: {
|
components: {
|
||||||
main: "#338574",
|
...baseThemeOptions.components,
|
||||||
},
|
},
|
||||||
secondary: {
|
palette: {
|
||||||
main: "#6cead0",
|
mode: "light",
|
||||||
|
primary: {
|
||||||
|
main: "#338574",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: "#6cead0",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
main: "#c30000",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
error: {
|
|
||||||
main: "#c30000",
|
|
||||||
},
|
|
||||||
actionBarBackground: "linear-gradient(150deg, #338574 0%, #56bda8 100%)",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @type {import("@mui/material").ThemeOptions['palette']} */
|
/** @type {import("@mui/material").ThemeOptions} */
|
||||||
export const darkPalette = {
|
export const darkTheme = {
|
||||||
mode: "dark",
|
...baseThemeOptions,
|
||||||
background: {
|
components: {
|
||||||
paper: "#1b2124",
|
...baseThemeOptions.components,
|
||||||
|
MuiSnackbarContent: {
|
||||||
|
styleOverrides: {
|
||||||
|
root: {
|
||||||
|
color: "#000",
|
||||||
|
backgroundColor: "#aeaeae",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
primary: {
|
palette: {
|
||||||
main: "#65b5a3",
|
mode: "dark",
|
||||||
|
background: {
|
||||||
|
paper: "#1b2124",
|
||||||
|
},
|
||||||
|
primary: {
|
||||||
|
main: "#65b5a3",
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
main: "#6cead0",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
main: "#fe4d2e",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
secondary: {
|
|
||||||
main: "#6cead0",
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
main: "#fe4d2e",
|
|
||||||
},
|
|
||||||
actionBarBackground: "linear-gradient(150deg, #203631 0%, #2a6e60 100%)",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default themeOptions;
|
|
||||||
|
|
Loading…
Reference in New Issue