|
1 | | -import { useState, useContext } from 'react'; |
| 1 | +import {useState, useContext, useEffect} from 'react'; |
2 | 2 | import PropTypes from 'prop-types'; |
3 | 3 |
|
4 | 4 | import {Button, Nav, Navbar, NavDropdown} from 'react-bootstrap'; |
5 | 5 | import {NavLink as ReactNavLink} from 'react-router-dom'; |
6 | 6 |
|
7 | 7 | import UserContext from '../data/UserContext'; |
8 | 8 |
|
| 9 | +function scrollListener() { |
| 10 | + const nav = document.querySelector('nav'); |
| 11 | + |
| 12 | + if (nav) { |
| 13 | + if (window.scrollY > 0 && window.scrollY < 26) { |
| 14 | + nav.classList.add('shadow-sm'); |
| 15 | + nav.classList.remove('shadow'); |
| 16 | + } else if (window.scrollY > 25) { |
| 17 | + nav.classList.add('shadow'); |
| 18 | + nav.classList.remove('shadow-sm'); |
| 19 | + } else { |
| 20 | + nav.classList.remove('shadow'); |
| 21 | + nav.classList.remove('shadow-sm'); |
| 22 | + } |
| 23 | + } |
| 24 | +} |
| 25 | + |
9 | 26 | function NavBar(props) { |
10 | 27 | const [isExpanded, setIsExpanded] = useState(false); |
11 | 28 | const user = useContext(UserContext); |
12 | 29 |
|
| 30 | + const [lightOrDark, setLightOrDark] = useState(window.localStorage.getItem('theme')); |
| 31 | + let lightDarkAutoClass = 'bi-circle-half'; |
| 32 | + |
| 33 | + if (lightOrDark === 'dark') { |
| 34 | + lightDarkAutoClass = 'bi-moon-fill'; |
| 35 | + } else if (lightOrDark === 'light') { |
| 36 | + lightDarkAutoClass = 'bi-sun-fill'; |
| 37 | + } |
| 38 | + |
13 | 39 | function closeNavbar() { |
14 | 40 | setIsExpanded(false); |
15 | 41 | } |
16 | 42 |
|
| 43 | + function switchTheme(e) { |
| 44 | + const newTheme = e.target.getAttribute('data-theme-set'); |
| 45 | + |
| 46 | + setLightOrDark(newTheme); |
| 47 | + window.localStorage.setItem('theme', newTheme); |
| 48 | + |
| 49 | + tellBootstrapAboutTheme(newTheme); |
| 50 | + } |
| 51 | + |
| 52 | + function tellBootstrapAboutTheme(newTheme) { |
| 53 | + if (newTheme === 'light' || newTheme === 'dark') { |
| 54 | + document.documentElement.setAttribute('data-bs-theme', newTheme); |
| 55 | + } else { |
| 56 | + document.documentElement.setAttribute('data-bs-theme', window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + function themeListener() { |
| 61 | + tellBootstrapAboutTheme(lightOrDark); |
| 62 | + } |
| 63 | + |
| 64 | + useEffect(() => { |
| 65 | + window.addEventListener('scroll', scrollListener); |
| 66 | + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', themeListener); |
| 67 | + |
| 68 | + // If we don't do this, and the page loads with "auto" and the user wants it dark, it won't change. |
| 69 | + tellBootstrapAboutTheme(lightOrDark); |
| 70 | + |
| 71 | + return () => { |
| 72 | + window.removeEventListener('scroll', scrollListener); |
| 73 | + window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', themeListener); |
| 74 | + }; |
| 75 | + }); |
| 76 | + |
17 | 77 | return ( |
18 | 78 | <Navbar |
19 | | - bg="dark" |
20 | | - variant="dark" |
| 79 | + bg="body-tertiary" |
21 | 80 | expand="sm" |
22 | 81 | sticky="top" |
23 | | - className="mb-3 ps-3 pe-3" |
| 82 | + className="mb-3 ps-3 pe-3 border-bottom" |
24 | 83 | expanded={isExpanded} |
25 | 84 | onToggle={() => setIsExpanded(!isExpanded)} |
26 | 85 | > |
27 | 86 | <Navbar.Brand>{appConfig.appName}</Navbar.Brand> |
28 | 87 | <Navbar.Toggle aria-controls="basic-navbar-nav" /> |
29 | 88 | <Navbar.Collapse id="basic-navbar-nav"> |
30 | | - <Nav className="me-auto"> |
| 89 | + <Nav className="me-auto" navbarScroll> |
31 | 90 | <Nav.Link as={ReactNavLink} to="/admin/dashboard" onClick={closeNavbar}>Home</Nav.Link> |
32 | 91 | { |
33 | 92 | (user.info.role === 'admin') |
34 | 93 | ? <Nav.Link as={ReactNavLink} to="/admin/users" onClick={closeNavbar}>Users</Nav.Link> |
35 | 94 | : null |
36 | 95 | } |
37 | 96 | <Nav.Link as={ReactNavLink} to="/admin/404" onClick={closeNavbar}>404 Page</Nav.Link> |
38 | | - <NavDropdown title="Settings" id="basic-nav-dropdown" menuVariant="dark"> |
39 | | - <NavDropdown.Item className="ps-3 pe-3" as={ReactNavLink} to="/admin/settings/profile" onClick={closeNavbar}>Profile</NavDropdown.Item> |
40 | | - <NavDropdown.Item className="ps-3 pe-3" as={ReactNavLink} to="/admin/settings/security" onClick={closeNavbar}>Security</NavDropdown.Item> |
| 97 | + <NavDropdown title="Settings" id="basic-nav-dropdown"> |
| 98 | + <NavDropdown.Item className="ps-3 pe-3" as={ReactNavLink} to="/admin/settings/profile" onClick={closeNavbar}><i className="bi bi-person-fill" /> Profile</NavDropdown.Item> |
| 99 | + <NavDropdown.Item className="ps-3 pe-3" as={ReactNavLink} to="/admin/settings/security" onClick={closeNavbar}><i className="bi bi-shield-lock-fill" /> Security</NavDropdown.Item> |
41 | 100 | </NavDropdown> |
42 | 101 | </Nav> |
43 | 102 |
|
44 | 103 | { |
45 | 104 | user.isLoggedIn ? |
46 | 105 | <> |
47 | | - <span className="text-white d-none d-md-block">Welcome, {user.info.firstName} </span> |
| 106 | + <Navbar.Text>Welcome, {user.info.firstName} </Navbar.Text> |
48 | 107 | <Button variant="danger" onClick={() => props.handleLogout()} size="sm" className="mt-2 mt-sm-0 mb-2 mb-sm-0">Logout</Button> |
49 | 108 | </> |
50 | 109 | : null |
51 | 110 | } |
| 111 | + |
| 112 | + <NavDropdown title={<i className={'bi ' + lightDarkAutoClass}/>} id="light-or-dark-toggle" className="ms-3 right-align-menu"> |
| 113 | + <NavDropdown.Item className="bi bi-sun-fill" active={lightOrDark === 'light'} data-theme-set="light" onClick={switchTheme}>Light</NavDropdown.Item> |
| 114 | + <NavDropdown.Item className="bi bi-moon-fill" active={lightOrDark === 'dark'} data-theme-set="dark" onClick={switchTheme}>Dark</NavDropdown.Item> |
| 115 | + <NavDropdown.Item className="bi bi-circle-half" active={lightOrDark !== 'light' && lightOrDark !== 'dark'} data-theme-set="auto" onClick={switchTheme}>Auto</NavDropdown.Item> |
| 116 | + </NavDropdown> |
52 | 117 | </Navbar.Collapse> |
53 | 118 | </Navbar> |
54 | 119 | ); |
|
0 commit comments