Can toggle dark theme
This commit is contained in:
parent
f93bc704a5
commit
099e517688
@ -1,4 +1,3 @@
|
|||||||
import { ThemeProvider, createTheme } from "@mui/material/styles";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Route, Routes } from "react-router-dom";
|
import { Route, Routes } from "react-router-dom";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
@ -24,12 +23,6 @@ interface AuthContext {
|
|||||||
|
|
||||||
const AuthContextK = React.createContext<AuthContext | null>(null);
|
const AuthContextK = React.createContext<AuthContext | null>(null);
|
||||||
|
|
||||||
const darkTheme = createTheme({
|
|
||||||
palette: {
|
|
||||||
mode: "dark", // TODO : switch back to light
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core app
|
* Core app
|
||||||
*/
|
*/
|
||||||
@ -42,37 +35,35 @@ export function App(): React.ReactElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ThemeProvider theme={darkTheme}>
|
<AuthContextK.Provider value={context}>
|
||||||
<AuthContextK.Provider value={context}>
|
<Routes>
|
||||||
<Routes>
|
<Route path="delete_account" element={<DeleteAccountRoute />} />
|
||||||
<Route path="delete_account" element={<DeleteAccountRoute />} />
|
|
||||||
|
|
||||||
{signedIn ? (
|
{signedIn ? (
|
||||||
<Route path="*" element={<BaseAuthenticatedPage />}>
|
<Route path="*" element={<BaseAuthenticatedPage />}>
|
||||||
<Route path="" element={<FamiliesListRoute />} />
|
<Route path="" element={<FamiliesListRoute />} />
|
||||||
<Route path="profile" element={<ProfileRoute />} />
|
<Route path="profile" element={<ProfileRoute />} />
|
||||||
<Route path="family/:familyId/*" element={<BaseFamilyRoute />}>
|
<Route path="family/:familyId/*" element={<BaseFamilyRoute />}>
|
||||||
<Route path="" element={<FamilyHomeRoute />} />
|
<Route path="" element={<FamilyHomeRoute />} />
|
||||||
<Route path="*" element={<NotFoundRoute />} />
|
|
||||||
</Route>
|
|
||||||
<Route path="*" element={<NotFoundRoute />} />
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
</Route>
|
</Route>
|
||||||
) : (
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
<Route path="*" element={<BaseLoginPage />}>
|
</Route>
|
||||||
<Route path="" element={<LoginRoute />} />
|
) : (
|
||||||
<Route path="oidc_cb" element={<OIDCCbRoute />} />
|
<Route path="*" element={<BaseLoginPage />}>
|
||||||
<Route path="new-account" element={<NewAccountRoute />} />
|
<Route path="" element={<LoginRoute />} />
|
||||||
<Route
|
<Route path="oidc_cb" element={<OIDCCbRoute />} />
|
||||||
path="password_forgotten"
|
<Route path="new-account" element={<NewAccountRoute />} />
|
||||||
element={<PasswordForgottenRoute />}
|
<Route
|
||||||
/>
|
path="password_forgotten"
|
||||||
<Route path="reset_password" element={<ResetPasswordRoute />} />
|
element={<PasswordForgottenRoute />}
|
||||||
<Route path="*" element={<NotFoundRoute />} />
|
/>
|
||||||
</Route>
|
<Route path="reset_password" element={<ResetPasswordRoute />} />
|
||||||
)}
|
<Route path="*" element={<NotFoundRoute />} />
|
||||||
</Routes>
|
</Route>
|
||||||
</AuthContextK.Provider>
|
)}
|
||||||
</ThemeProvider>
|
</Routes>
|
||||||
|
</AuthContextK.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
geneit_app/src/context_providers/DarkThemeProvider.tsx
Normal file
50
geneit_app/src/context_providers/DarkThemeProvider.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { ThemeProvider, createTheme } from "@mui/material/styles";
|
||||||
|
import React from "react";
|
||||||
|
import { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
const localStorageKey = "dark-theme";
|
||||||
|
|
||||||
|
const darkTheme = createTheme({
|
||||||
|
palette: {
|
||||||
|
mode: "dark",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const lightTheme = createTheme({
|
||||||
|
palette: {
|
||||||
|
mode: "light",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
interface DarkThemeContext {
|
||||||
|
enabled: boolean;
|
||||||
|
setEnabled: (enabled: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DarkThemeContextK = React.createContext<DarkThemeContext | null>(null);
|
||||||
|
|
||||||
|
export function DarkThemeProvider(p: PropsWithChildren): React.ReactElement {
|
||||||
|
const [enabled, setEnabled] = React.useState(
|
||||||
|
localStorage.getItem(localStorageKey) === "true"
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DarkThemeContextK.Provider
|
||||||
|
value={{
|
||||||
|
enabled: enabled,
|
||||||
|
setEnabled(enabled) {
|
||||||
|
localStorage.setItem(localStorageKey, enabled ? "true" : "false");
|
||||||
|
setEnabled(enabled);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ThemeProvider theme={enabled ? darkTheme : lightTheme}>
|
||||||
|
{p.children}
|
||||||
|
</ThemeProvider>
|
||||||
|
</DarkThemeContextK.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDarkTheme(): DarkThemeContext {
|
||||||
|
return React.useContext(DarkThemeContextK)!;
|
||||||
|
}
|
@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import { TextInputDialog } from "./TextInputDialog";
|
import { TextInputDialog } from "./TextInputDialog";
|
||||||
import { ServerApi } from "../api/ServerApi";
|
import { ServerApi } from "../api/ServerApi";
|
||||||
import { FamilyApi } from "../api/FamilyApi";
|
import { FamilyApi } from "../api/FamilyApi";
|
||||||
import { useAlert } from "../widgets/AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
|
|
||||||
export function CreateFamilyDialog(p: {
|
export function CreateFamilyDialog(p: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import { TextInputDialog } from "./TextInputDialog";
|
import { TextInputDialog } from "./TextInputDialog";
|
||||||
import { ServerApi } from "../api/ServerApi";
|
import { ServerApi } from "../api/ServerApi";
|
||||||
import { FamilyApi, JoinFamilyResult } from "../api/FamilyApi";
|
import { FamilyApi, JoinFamilyResult } from "../api/FamilyApi";
|
||||||
import { useAlert } from "../widgets/AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
|
|
||||||
export function JoinFamilyDialog(p: {
|
export function JoinFamilyDialog(p: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
|
@ -11,10 +11,11 @@ import "@fontsource/roboto/400.css";
|
|||||||
import "@fontsource/roboto/500.css";
|
import "@fontsource/roboto/500.css";
|
||||||
import "@fontsource/roboto/700.css";
|
import "@fontsource/roboto/700.css";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { ConfirmDialogProvider } from "./widgets/ConfirmDialogProvider";
|
import { ConfirmDialogProvider } from "./context_providers/ConfirmDialogProvider";
|
||||||
import { AlertDialogProvider } from "./widgets/AlertDialogProvider";
|
import { AlertDialogProvider } from "./context_providers/AlertDialogProvider";
|
||||||
import { AsyncWidget } from "./widgets/AsyncWidget";
|
import { AsyncWidget } from "./widgets/AsyncWidget";
|
||||||
import { SnackbarProvider } from "./widgets/SnackbarProvider";
|
import { SnackbarProvider } from "./context_providers/SnackbarProvider";
|
||||||
|
import { DarkThemeProvider } from "./context_providers/DarkThemeProvider";
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
@ -25,20 +26,22 @@ async function init() {
|
|||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<AlertDialogProvider>
|
<DarkThemeProvider>
|
||||||
<ConfirmDialogProvider>
|
<AlertDialogProvider>
|
||||||
<SnackbarProvider>
|
<ConfirmDialogProvider>
|
||||||
<div style={{ height: "100vh" }}>
|
<SnackbarProvider>
|
||||||
<AsyncWidget
|
<div style={{ height: "100vh" }}>
|
||||||
loadKey={1}
|
<AsyncWidget
|
||||||
load={async () => await ServerApi.LoadConfig()}
|
loadKey={1}
|
||||||
errMsg="Echec de la connexion au serveur pour la récupération de la configuration statique !"
|
load={async () => await ServerApi.LoadConfig()}
|
||||||
build={() => <App />}
|
errMsg="Echec de la connexion au serveur pour la récupération de la configuration statique !"
|
||||||
/>
|
build={() => <App />}
|
||||||
</div>
|
/>
|
||||||
</SnackbarProvider>
|
</div>
|
||||||
</ConfirmDialogProvider>
|
</SnackbarProvider>
|
||||||
</AlertDialogProvider>
|
</ConfirmDialogProvider>
|
||||||
|
</AlertDialogProvider>
|
||||||
|
</DarkThemeProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
@ -3,9 +3,9 @@ import React from "react";
|
|||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { AuthApi } from "../api/AuthApi";
|
import { AuthApi } from "../api/AuthApi";
|
||||||
import { DeleteAccountTokenInfo, UserApi } from "../api/UserApi";
|
import { DeleteAccountTokenInfo, UserApi } from "../api/UserApi";
|
||||||
import { useAlert } from "../widgets/AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { useConfirm } from "../widgets/ConfirmDialogProvider";
|
import { useConfirm } from "../context_providers/ConfirmDialogProvider";
|
||||||
|
|
||||||
export function DeleteAccountRoute(): React.ReactElement {
|
export function DeleteAccountRoute(): React.ReactElement {
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
|
@ -14,9 +14,9 @@ import React from "react";
|
|||||||
import { Family, FamilyApi } from "../api/FamilyApi";
|
import { Family, FamilyApi } from "../api/FamilyApi";
|
||||||
import { CreateFamilyDialog } from "../dialogs/CreateFamilyDialog";
|
import { CreateFamilyDialog } from "../dialogs/CreateFamilyDialog";
|
||||||
import { JoinFamilyDialog } from "../dialogs/JoinFamilyDialog";
|
import { JoinFamilyDialog } from "../dialogs/JoinFamilyDialog";
|
||||||
import { useAlert } from "../widgets/AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
import { useConfirm } from "../widgets/ConfirmDialogProvider";
|
import { useConfirm } from "../context_providers/ConfirmDialogProvider";
|
||||||
import { RouterLink } from "../widgets/RouterLink";
|
import { RouterLink } from "../widgets/RouterLink";
|
||||||
import { TimeWidget } from "../widgets/TimeWidget";
|
import { TimeWidget } from "../widgets/TimeWidget";
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ import {
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { ServerApi } from "../api/ServerApi";
|
import { ServerApi } from "../api/ServerApi";
|
||||||
import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi";
|
import { ReplacePasswordResponse, User, UserApi } from "../api/UserApi";
|
||||||
import { useAlert } from "../widgets/AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
import { useUser } from "../widgets/BaseAuthenticatedPage";
|
import { useUser } from "../widgets/BaseAuthenticatedPage";
|
||||||
import { useConfirm } from "../widgets/ConfirmDialogProvider";
|
import { useConfirm } from "../context_providers/ConfirmDialogProvider";
|
||||||
import { PasswordInput } from "../widgets/PasswordInput";
|
import { PasswordInput } from "../widgets/PasswordInput";
|
||||||
import { formatDate } from "../widgets/TimeWidget";
|
import { formatDate } from "../widgets/TimeWidget";
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import { AuthApi } from "../api/AuthApi";
|
|||||||
import { User, UserApi } from "../api/UserApi";
|
import { User, UserApi } from "../api/UserApi";
|
||||||
import { AsyncWidget } from "./AsyncWidget";
|
import { AsyncWidget } from "./AsyncWidget";
|
||||||
import { RouterLink } from "./RouterLink";
|
import { RouterLink } from "./RouterLink";
|
||||||
|
import { DarkThemeButton } from "./DarkThemeButton";
|
||||||
|
|
||||||
interface UserContext {
|
interface UserContext {
|
||||||
user: User;
|
user: User;
|
||||||
@ -90,6 +91,8 @@ export function BaseAuthenticatedPage(): React.ReactElement {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<DarkThemeButton />
|
||||||
|
|
||||||
<Button size="large" color="inherit">
|
<Button size="large" color="inherit">
|
||||||
{user!.name}
|
{user!.name}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -27,9 +27,9 @@ import { Outlet, useLocation, useParams } from "react-router-dom";
|
|||||||
import { Family, FamilyApi } from "../api/FamilyApi";
|
import { Family, FamilyApi } from "../api/FamilyApi";
|
||||||
import { AsyncWidget } from "./AsyncWidget";
|
import { AsyncWidget } from "./AsyncWidget";
|
||||||
import { RouterLink } from "./RouterLink";
|
import { RouterLink } from "./RouterLink";
|
||||||
import { useSnackbar } from "./SnackbarProvider";
|
import { useSnackbar } from "../context_providers/SnackbarProvider";
|
||||||
import { useConfirm } from "./ConfirmDialogProvider";
|
import { useConfirm } from "../context_providers/ConfirmDialogProvider";
|
||||||
import { useAlert } from "./AlertDialogProvider";
|
import { useAlert } from "../context_providers/AlertDialogProvider";
|
||||||
|
|
||||||
interface FamilyContext {
|
interface FamilyContext {
|
||||||
family: Family;
|
family: Family;
|
||||||
|
@ -8,6 +8,7 @@ import Paper from "@mui/material/Paper";
|
|||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Link, Outlet } from "react-router-dom";
|
import { Link, Outlet } from "react-router-dom";
|
||||||
|
import { DarkThemeButton } from "./DarkThemeButton";
|
||||||
|
|
||||||
function Copyright(props: any) {
|
function Copyright(props: any) {
|
||||||
return (
|
return (
|
||||||
@ -64,6 +65,10 @@ export function BaseLoginPage() {
|
|||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<div style={{ position: "absolute", right: "10px", top: "5px" }}>
|
||||||
|
<DarkThemeButton />
|
||||||
|
</div>
|
||||||
|
|
||||||
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
|
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
|
||||||
<Icon path={mdiFamilyTree} size={1} />
|
<Icon path={mdiFamilyTree} size={1} />
|
||||||
</Avatar>
|
</Avatar>
|
||||||
|
19
geneit_app/src/widgets/DarkThemeButton.tsx
Normal file
19
geneit_app/src/widgets/DarkThemeButton.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import Brightness7Icon from "@mui/icons-material/Brightness7";
|
||||||
|
import DarkModeIcon from "@mui/icons-material/DarkMode";
|
||||||
|
import { IconButton, Tooltip } from "@mui/material";
|
||||||
|
import { useDarkTheme } from "../context_providers/DarkThemeProvider";
|
||||||
|
|
||||||
|
export function DarkThemeButton(): React.ReactElement {
|
||||||
|
const darkTheme = useDarkTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip title="Activer / désactiver le mode sombre">
|
||||||
|
<IconButton
|
||||||
|
onClick={() => darkTheme.setEnabled(!darkTheme.enabled)}
|
||||||
|
style={{ color: "inherit" }}
|
||||||
|
>
|
||||||
|
{!darkTheme.enabled ? <DarkModeIcon /> : <Brightness7Icon />}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user