start theme implementation

This commit is contained in:
Thibaut Valentin 2024-02-03 16:24:12 +01:00
parent b4e0d0fa3d
commit c553ff14da
3 changed files with 89 additions and 23 deletions

View File

@ -10,6 +10,7 @@ import {ToastContainer} from "react-toastify";
import './App.css'
import 'react-toastify/dist/ReactToastify.css';
import {ThemeProvider} from "./hooks/useTheme.jsx";
const router = createBrowserRouter([
{
@ -82,7 +83,9 @@ function App() {
console.log('render')
return <KeycloakContextProvider>
<RouterProvider router={router}/>
<ThemeProvider>
<RouterProvider router={router}/>
</ThemeProvider>
</KeycloakContextProvider>;
}

View File

@ -1,38 +1,53 @@
import LogoIcon from '../assets/FFSSAF-bord-blanc-fond-transparent.webp'
import './Nav.css'
// import './Nav.css'
import {NavLink} from "react-router-dom";
import {useAuth} from "../hooks/useAuth.jsx";
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() {
const {theme} = useTheme();
return <nav className="navbar navbar-light navbar-expand-md bg-body-tertiary " id="main-navbar">
<div className="container-fluid">
<a className="navbar-brand" href="/">
<img className="logo" src={LogoIcon} alt="logo"/>
FFSAF Intra
</a>
return <>
<ThemeCss path="./nav"/>
<nav className={"navbar navbar-" + theme + " navbar-expand-md bg-body-tertiary bg-" + theme}
id="main-navbar">
<div className="container-fluid">
<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"
data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavDropdown">
<div className="collapse-item">
<ul className="navbar-nav">
<li className="nav-item"><NavLink className="nav-link" to="/">Accueil</NavLink></li>
<AdminMenu/>
<LoginMenu/>
</ul>
<button className="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarNavDropdown" aria-controls="navbarNavDropdown"
aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
<div className={"collapse navbar-collapse bg-" + theme} id="navbarNavDropdown">
<div className="collapse-item">
<ul className="navbar-nav">
<li className="nav-item"><NavLink className="nav-link" to="/">Accueil</NavLink></li>
<AdminMenu/>
<LoginMenu/>
<li className="nav-item"><ThemeSwitcher/></li>
</ul>
</div>
</div>
</div>
</div>
</nav>
</nav>
</>
}
function AdminMenu() {
const {is_authenticated, userinfo} = useAuth()
const {theme} = useTheme();
if (!is_authenticated || !userinfo?.roles?.includes("federation_admin"))
return <></>
@ -41,7 +56,7 @@ function AdminMenu() {
<div className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Administration
</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/b">B</NavLink></li>
</ul>
@ -58,4 +73,10 @@ function LoginMenu() {
<div className="nav-link" onClick={() => logout()}>Déconnexion</div>
)}
</li>
}
function ThemeSwitcher() {
const {isLight, toggleTheme} = useTheme()
return <div className="nav-link" onClick={toggleTheme}>{isLight ? <FontAwesomeIcon icon={faSun}/> :
<FontAwesomeIcon icon={faMoon}/>}</div>
}

View 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>
}