start theme implementation
This commit is contained in:
parent
b4e0d0fa3d
commit
c553ff14da
@ -10,6 +10,7 @@ import {ToastContainer} from "react-toastify";
|
|||||||
|
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import 'react-toastify/dist/ReactToastify.css';
|
import 'react-toastify/dist/ReactToastify.css';
|
||||||
|
import {ThemeProvider} from "./hooks/useTheme.jsx";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@ -82,7 +83,9 @@ function App() {
|
|||||||
console.log('render')
|
console.log('render')
|
||||||
|
|
||||||
return <KeycloakContextProvider>
|
return <KeycloakContextProvider>
|
||||||
<RouterProvider router={router}/>
|
<ThemeProvider>
|
||||||
|
<RouterProvider router={router}/>
|
||||||
|
</ThemeProvider>
|
||||||
</KeycloakContextProvider>;
|
</KeycloakContextProvider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,38 +1,53 @@
|
|||||||
import LogoIcon from '../assets/FFSSAF-bord-blanc-fond-transparent.webp'
|
import LogoIcon from '../assets/FFSSAF-bord-blanc-fond-transparent.webp'
|
||||||
import './Nav.css'
|
// import './Nav.css'
|
||||||
import {NavLink} from "react-router-dom";
|
import {NavLink} from "react-router-dom";
|
||||||
import {useAuth} from "../hooks/useAuth.jsx";
|
import {useAuth} from "../hooks/useAuth.jsx";
|
||||||
import {login, logout} from "../utils/auth.js";
|
import {login, logout} from "../utils/auth.js";
|
||||||
|
import {ThemeCss, useTheme} from "../hooks/useTheme.jsx";
|
||||||
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
||||||
|
import {faMoon, faSun} from "@fortawesome/free-regular-svg-icons";
|
||||||
|
|
||||||
|
const themeSwitcherVariant = {
|
||||||
|
light: "outline-primary bg-light",
|
||||||
|
dark: "outline-light bg-dark"
|
||||||
|
};
|
||||||
|
|
||||||
export function Nav() {
|
export function Nav() {
|
||||||
|
const {theme} = useTheme();
|
||||||
|
|
||||||
return <nav className="navbar navbar-light navbar-expand-md bg-body-tertiary " id="main-navbar">
|
return <>
|
||||||
<div className="container-fluid">
|
<ThemeCss path="./nav"/>
|
||||||
<a className="navbar-brand" href="/">
|
<nav className={"navbar navbar-" + theme + " navbar-expand-md bg-body-tertiary bg-" + theme}
|
||||||
<img className="logo" src={LogoIcon} alt="logo"/>
|
id="main-navbar">
|
||||||
FFSAF Intra
|
<div className="container-fluid">
|
||||||
</a>
|
<a className="navbar-brand" href="/">
|
||||||
|
<img className="logo" src={LogoIcon} alt="logo"/>
|
||||||
|
FFSAF Intra
|
||||||
|
</a>
|
||||||
|
|
||||||
<button className="navbar-toggler" type="button" data-bs-toggle="collapse"
|
<button className="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||||
data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
|
data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
|
||||||
aria-expanded="false" aria-label="Toggle navigation">
|
aria-expanded="false" aria-label="Toggle navigation">
|
||||||
<span className="navbar-toggler-icon"></span>
|
<span className="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div className="collapse navbar-collapse" id="navbarNavDropdown">
|
<div className={"collapse navbar-collapse bg-" + theme} id="navbarNavDropdown">
|
||||||
<div className="collapse-item">
|
<div className="collapse-item">
|
||||||
<ul className="navbar-nav">
|
<ul className="navbar-nav">
|
||||||
<li className="nav-item"><NavLink className="nav-link" to="/">Accueil</NavLink></li>
|
<li className="nav-item"><NavLink className="nav-link" to="/">Accueil</NavLink></li>
|
||||||
<AdminMenu/>
|
<AdminMenu/>
|
||||||
<LoginMenu/>
|
<LoginMenu/>
|
||||||
</ul>
|
<li className="nav-item"><ThemeSwitcher/></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</nav>
|
||||||
</nav>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function AdminMenu() {
|
function AdminMenu() {
|
||||||
const {is_authenticated, userinfo} = useAuth()
|
const {is_authenticated, userinfo} = useAuth()
|
||||||
|
const {theme} = useTheme();
|
||||||
|
|
||||||
if (!is_authenticated || !userinfo?.roles?.includes("federation_admin"))
|
if (!is_authenticated || !userinfo?.roles?.includes("federation_admin"))
|
||||||
return <></>
|
return <></>
|
||||||
@ -41,7 +56,7 @@ function AdminMenu() {
|
|||||||
<div className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
<div className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
Administration
|
Administration
|
||||||
</div>
|
</div>
|
||||||
<ul className="dropdown-menu">
|
<ul className={"dropdown-menu " + themeSwitcherVariant[theme]}>
|
||||||
<li className="nav-item"><NavLink className="nav-link" to="/admin/member">Member</NavLink></li>
|
<li className="nav-item"><NavLink className="nav-link" to="/admin/member">Member</NavLink></li>
|
||||||
<li className="nav-item"><NavLink className="nav-link" to="/admin/b">B</NavLink></li>
|
<li className="nav-item"><NavLink className="nav-link" to="/admin/b">B</NavLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -58,4 +73,10 @@ function LoginMenu() {
|
|||||||
<div className="nav-link" onClick={() => logout()}>Déconnexion</div>
|
<div className="nav-link" onClick={() => logout()}>Déconnexion</div>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
}
|
||||||
|
|
||||||
|
function ThemeSwitcher() {
|
||||||
|
const {isLight, toggleTheme} = useTheme()
|
||||||
|
return <div className="nav-link" onClick={toggleTheme}>{isLight ? <FontAwesomeIcon icon={faSun}/> :
|
||||||
|
<FontAwesomeIcon icon={faMoon}/>}</div>
|
||||||
}
|
}
|
||||||
42
src/main/webapp/src/hooks/useTheme.jsx
Normal file
42
src/main/webapp/src/hooks/useTheme.jsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import React, {createContext, useContext, useLayoutEffect, useState} from "react";
|
||||||
|
|
||||||
|
export const ThemeContext = createContext({
|
||||||
|
theme: 'light',
|
||||||
|
toggleTheme: () => {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useTheme() {
|
||||||
|
const {theme, toggleTheme} = useContext(ThemeContext);
|
||||||
|
return {
|
||||||
|
isLight: theme === 'light',
|
||||||
|
isDark: theme === 'dark',
|
||||||
|
theme,
|
||||||
|
toggleTheme
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ThemeCss({path}) {
|
||||||
|
const {theme} = useTheme();
|
||||||
|
|
||||||
|
const Light = React.lazy(() => import(path + ".css"));
|
||||||
|
const Dark = React.lazy(() => import(path + ".dark.css"));
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<React.Suspense fallback={<></>}>
|
||||||
|
{theme === "light" && <Light />}
|
||||||
|
{theme === "dark" && <Dark />}
|
||||||
|
</React.Suspense>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ThemeProvider({children}) {
|
||||||
|
const [theme, setTheme] = useState('light');
|
||||||
|
const toggleTheme = () => {
|
||||||
|
setTheme(theme === 'light' ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
|
||||||
|
return <ThemeContext.Provider value={{theme, toggleTheme}}>
|
||||||
|
{children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user