From 8edf0cb7a15f5db14112c543ba9ecb9e2f37411f Mon Sep 17 00:00:00 2001 From: Jacob Sommer Date: Wed, 7 Feb 2024 20:52:36 -0800 Subject: [PATCH 1/5] Profile menu --- site/src/component/AppHeader/AppHeader.scss | 5 + site/src/component/AppHeader/AppHeader.tsx | 13 +- site/src/component/AppHeader/Profile.scss | 136 ++++++++++++++++ site/src/component/AppHeader/Profile.tsx | 164 ++++++++++++++++++++ site/src/component/SideBar/SideBar.tsx | 88 +++++++---- site/src/component/SideBar/Sidebar.scss | 39 +++-- 6 files changed, 398 insertions(+), 47 deletions(-) create mode 100644 site/src/component/AppHeader/Profile.scss create mode 100644 site/src/component/AppHeader/Profile.tsx diff --git a/site/src/component/AppHeader/AppHeader.scss b/site/src/component/AppHeader/AppHeader.scss index 44a09687..56eaea1f 100644 --- a/site/src/component/AppHeader/AppHeader.scss +++ b/site/src/component/AppHeader/AppHeader.scss @@ -18,6 +18,11 @@ } } +.school-term { + margin-bottom: 0; + margin-right: 0.75em; +} + .navbar { position: sticky; z-index: 300; diff --git a/site/src/component/AppHeader/AppHeader.tsx b/site/src/component/AppHeader/AppHeader.tsx index 782221b3..7de22344 100644 --- a/site/src/component/AppHeader/AppHeader.tsx +++ b/site/src/component/AppHeader/AppHeader.tsx @@ -11,6 +11,8 @@ import './AppHeader.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { setSidebarStatus } from '../../store/slices/uiSlice'; +import Profile from './Profile'; +import { isDesktop, isMobile } from 'react-device-detect'; const AppHeader: FC = () => { const dispatch = useAppDispatch(); @@ -43,9 +45,11 @@ const AppHeader: FC = () => {
{/* Hamburger Menu */} -
- -
+ {isMobile && ( +
+ +
+ )} {/* Toggle Course and Professor */} {(coursesActive || professorsActive) && ( @@ -82,7 +86,7 @@ const AppHeader: FC = () => {
{/* Week */} -
+
{

{week}

+ {isDesktop && }
diff --git a/site/src/component/AppHeader/Profile.scss b/site/src/component/AppHeader/Profile.scss new file mode 100644 index 00000000..54251255 --- /dev/null +++ b/site/src/component/AppHeader/Profile.scss @@ -0,0 +1,136 @@ +.navbar-profile { + height: 70%; +} + +.navbar-profile-pic { + height: 100%; + border-radius: 100%; + + &:hover { + cursor: pointer; + } +} + +#profile-popover, +#theme-popover { + font-size: 1rem; + padding: 1em; + background-color: var(--overlay1); + border-radius: var(--border-radius); + border: 1px solid var(--background); + max-width: 94vw; + + .arrow::before { + border-bottom-color: var(--background); + } + + h1 { + font-size: 1.5em; + } + + h2 { + font-size: 1em; + color: var(--text-light); + } +} + +.profile-popover__header { + display: flex; + min-height: 6vh; + margin-bottom: 0.75em; + + img { + margin-right: 0.75em; + height: 6vh; + border-radius: 100%; + } + + button { + border: none; + background: none; + font-size: 1.5em; + line-height: 1em; + padding: 0 0.5em; + border-radius: var(--border-radius); + } + + button:hover { + background-color: var(--overlay2); + } +} + +#theme-popover { + padding: 0.5em; + + ul { + list-style: none; + padding: 0; + margin: 0; + } + + li div { + display: inline; + } + + a { + color: var(--text); + } +} + +.profile-popover__links { + ul { + list-style: none; + padding: 0; + margin: 0; + } + + li div { + display: inline; + } + + a { + color: var(--text); + } + + button { + border: none; + background: none; + width: 100%; + } + + .divider-before::before { + display: block; + content: ''; + width: 100%; + height: 1px; + background-color: var(--overlay2); + margin: 0.25em 0; + } +} + +.profile-popover__link, +.theme-popover__link { + display: flex; + gap: 10px; + padding: 10px; + border-radius: var(--border-radius); + + &:hover { + background-color: var(--overlay2); + } +} + +.profile-popover__link.active, +.theme-popover__link.active { + color: var(--peterportal-primary-color-1); +} + +i.login-icon { + margin-right: 0.75em; +} + +.theme-button:hover, +.theme-popover__link:hover { + cursor: pointer; + text-decoration: underline; +} diff --git a/site/src/component/AppHeader/Profile.tsx b/site/src/component/AppHeader/Profile.tsx new file mode 100644 index 00000000..0f07c341 --- /dev/null +++ b/site/src/component/AppHeader/Profile.tsx @@ -0,0 +1,164 @@ +import { useCookies } from 'react-cookie'; +import { useContext, useEffect, useState } from 'react'; +import ThemeContext from '../../style/theme-context'; +import { Button, OverlayTrigger, Popover } from 'react-bootstrap'; +import { Icon } from 'semantic-ui-react'; +import './Profile.scss'; +import { NavLink } from 'react-router-dom'; +import { ArrowLeftCircleFill } from 'react-bootstrap-icons'; + +type ProfileMenuTab = 'default' | 'theme'; + +const Profile = () => { + const { darkMode, setTheme, usingSystemTheme } = useContext(ThemeContext); + const [cookies] = useCookies(['user']); + const [show, setShow] = useState(false); + const [tab, setTab] = useState('default'); + + const { name, email, picture }: { name: string; email: string; picture: string } = cookies?.user ?? {}; + const isLoggedIn: boolean = cookies.user; + + useEffect(() => { + if (!show) { + setTimeout(() => setTab('default'), 150); // popover transition time is 150ms + } + }, [show]); + + const DefaultTab = ( + <> +
+ {name} + +

{name}

+

{email}

+
+
+
+
    +
  • + 'profile-popover__link' + (isActive ? ' active' : '')} + to="/reviews" + onClick={() => setShow(false)} + > +
    + +
    + Your Reviews +
    +
  • +
  • + +
  • +
  • + +
    + +
    + Log Out +
    +
  • +
+
+ + ); + + const ThemeTab = ( + <> +
+ +
+
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+ + ); + + const ProfilePopover = ( + + {tab === 'default' && DefaultTab} + {tab === 'theme' && ThemeTab} + + ); + + return ( + <> + {isLoggedIn ? ( +
+ + {name} + +
+ ) : ( + + + + )} + + ); +}; + +export default Profile; diff --git a/site/src/component/SideBar/SideBar.tsx b/site/src/component/SideBar/SideBar.tsx index 16bcc5b5..2b27a015 100644 --- a/site/src/component/SideBar/SideBar.tsx +++ b/site/src/component/SideBar/SideBar.tsx @@ -6,7 +6,7 @@ import { useCookies } from 'react-cookie'; import './Sidebar.scss'; import defaultAvatarLight from '../../asset/default-avatar.png'; import defaultAvatarDark from '../../asset/default-avatar-dark.png'; -import { Button } from 'react-bootstrap'; +import { Button, Dropdown } from 'react-bootstrap'; import { useAppSelector, useAppDispatch } from '../..//store/hooks'; import { setSidebarStatus } from '../../store/slices/uiSlice'; @@ -20,7 +20,7 @@ const SideBar = () => { const [name, setName] = useState(''); const [picture, setPicture] = useState(''); const [isAdmin, setIsAdmin] = useState(false); - const { darkMode, setTheme } = useContext(ThemeContext); + const { darkMode, setTheme, usingSystemTheme } = useContext(ThemeContext); const defaultAvatar = darkMode ? defaultAvatarDark : defaultAvatarLight; const isLoggedIn = cookies.user !== undefined; @@ -29,20 +29,20 @@ const SideBar = () => { admin: boolean; } - const checkAdmin = async () => { - const res: AxiosResponse = await axios.get('/api/users/isAdmin'); - const admin = res.data.admin; - setIsAdmin(admin); - }; - useEffect(() => { // if the user is logged in if (isLoggedIn) { setName(cookies.user.name); setPicture(cookies.user.picture); + // useEffect's function is not allowed to be async, create async checkAdmin function within + const checkAdmin = async () => { + const res: AxiosResponse = await axios.get('/api/users/isAdmin'); + const admin = res.data.admin; + setIsAdmin(admin); + }; + checkAdmin(); } - checkAdmin(); - }); + }, [cookies.user, isLoggedIn]); const closeSidebar = () => dispatch(setSidebarStatus(false)); @@ -75,29 +75,55 @@ const SideBar = () => { Peter's Roadmap - {isLoggedIn && ( -
  • - (isActive ? 'sidebar-active' : '')} - onClick={closeSidebar} - > -
    - -
    - Reviews -
    -
  • - )} {showSidebar && ( -
  • - setTheme(darkMode ? 'light' : 'dark')}> -
    - + <> + {isLoggedIn && ( +
  • + (isActive ? 'sidebar-active' : '')} + onClick={closeSidebar} + > +
    + +
    + Reviews +
    +
  • + )} +
  • +
    +
    + +
    + + + Theme + + + setTheme('light')} + > + Light + + setTheme('dark')} + > + Dark + + setTheme('system')} + > + System + + +
    - Toggle Dark Mode -
    -
  • + + )} {isAdmin && ( <> diff --git a/site/src/component/SideBar/Sidebar.scss b/site/src/component/SideBar/Sidebar.scss index e2740d66..3b60fa11 100644 --- a/site/src/component/SideBar/Sidebar.scss +++ b/site/src/component/SideBar/Sidebar.scss @@ -60,10 +60,11 @@ .sidebar-links { min-width: 60%; - margin-bottom: 20vh; + margin-bottom: 2em; ul li { - a { + a, + .theme-button { color: var(--text); display: flex; grid-gap: 10px; @@ -77,7 +78,7 @@ } .sidebar-login { - margin-bottom: 5vh; + margin-bottom: 20vh; .sidebar-login-icon { margin-right: 0.4vw; @@ -85,6 +86,28 @@ } } +.theme-button .dropdown { + width: 100%; + + button { + background-color: transparent; + padding: 0; + width: 100%; + text-align: left; + border: none; + } + + .dropdown-item.active { + background-color: transparent; + color: var(--peterportal-primary-color-1); + } +} + +.theme-button .show.dropdown button { + outline: none; + background-color: transparent; +} + .sidebar.mini { position: static; width: 5vw; @@ -130,16 +153,8 @@ .sidebar { width: 100vw; z-index: 400; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; - - .sidebar-login { - margin-top: -20vh; - margin-bottom: 35vh; - } } + .sidebar.mini { display: none; } From 12724b9cb9c20e775912592286f5619c9258bc98 Mon Sep 17 00:00:00 2001 From: Jacob Sommer Date: Tue, 13 Feb 2024 23:05:00 -0800 Subject: [PATCH 2/5] Remove unused styles --- site/src/component/AppHeader/Profile.scss | 21 +-------------------- site/src/component/AppHeader/Profile.tsx | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/site/src/component/AppHeader/Profile.scss b/site/src/component/AppHeader/Profile.scss index 54251255..b842254e 100644 --- a/site/src/component/AppHeader/Profile.scss +++ b/site/src/component/AppHeader/Profile.scss @@ -11,8 +11,7 @@ } } -#profile-popover, -#theme-popover { +#profile-popover { font-size: 1rem; padding: 1em; background-color: var(--overlay1); @@ -59,24 +58,6 @@ } } -#theme-popover { - padding: 0.5em; - - ul { - list-style: none; - padding: 0; - margin: 0; - } - - li div { - display: inline; - } - - a { - color: var(--text); - } -} - .profile-popover__links { ul { list-style: none; diff --git a/site/src/component/AppHeader/Profile.tsx b/site/src/component/AppHeader/Profile.tsx index 0f07c341..e0a2c91e 100644 --- a/site/src/component/AppHeader/Profile.tsx +++ b/site/src/component/AppHeader/Profile.tsx @@ -101,7 +101,7 @@ const Profile = () => {
  • )} {/* Toggle Course and Professor */} diff --git a/site/src/component/SideBar/SideBar.tsx b/site/src/component/SideBar/SideBar.tsx index 2b27a015..65cf9898 100644 --- a/site/src/component/SideBar/SideBar.tsx +++ b/site/src/component/SideBar/SideBar.tsx @@ -163,9 +163,9 @@ const SideBar = () => { return (
    {/* Close Button */} -
    - -
    + {/* Profile Icon and Name */}
    diff --git a/site/src/component/SideBar/Sidebar.scss b/site/src/component/SideBar/Sidebar.scss index 3b60fa11..22348786 100644 --- a/site/src/component/SideBar/Sidebar.scss +++ b/site/src/component/SideBar/Sidebar.scss @@ -27,15 +27,10 @@ } .sidebar-close { - padding: 2vw; - width: 100%; - - .sidebar-close-icon { - width: 3vh; - height: 3vh; - float: right; - cursor: pointer; - } + padding: 1em; + margin-left: auto; + border: none; + background: none; } .sidebar-profile { From 65a39a75387f95f5859ee0617b4bf1eab61d985d Mon Sep 17 00:00:00 2001 From: Jacob Sommer Date: Tue, 13 Feb 2024 23:50:54 -0800 Subject: [PATCH 5/5] Use size prop for hamburger icon size --- site/src/component/AppHeader/AppHeader.scss | 5 ----- site/src/component/AppHeader/AppHeader.tsx | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/site/src/component/AppHeader/AppHeader.scss b/site/src/component/AppHeader/AppHeader.scss index 72f4a383..2caee222 100644 --- a/site/src/component/AppHeader/AppHeader.scss +++ b/site/src/component/AppHeader/AppHeader.scss @@ -58,11 +58,6 @@ align-items: center; border: none; background: none; - - .navbar-menu-icon { - width: 3vh; - height: 3vh; - } } .desktop-toggle { diff --git a/site/src/component/AppHeader/AppHeader.tsx b/site/src/component/AppHeader/AppHeader.tsx index c7066a0a..c9a42f1b 100644 --- a/site/src/component/AppHeader/AppHeader.tsx +++ b/site/src/component/AppHeader/AppHeader.tsx @@ -47,7 +47,7 @@ const AppHeader: FC = () => { {/* Hamburger Menu */} {isMobile && ( )}