|
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