| @@ -15,6 +15,13 @@ | |||
| user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ | |||
| --> | |||
| <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> | |||
| <link | |||
| style | |||
| rel="preload" | |||
| as="style" | |||
| href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" | |||
| onload="this.onload=null;this.rel='stylesheet';this.type='text/css'" | |||
| /> | |||
| <!-- | |||
| Notice the use of %PUBLIC_URL% in the tags above. | |||
| It will be replaced with the URL of the `public` folder during the build. | |||
| @@ -1,6 +1,9 @@ | |||
| .App { | |||
| text-align: center; | |||
| } | |||
| * { | |||
| box-sizing: border-box; | |||
| } | |||
| .App-logo { | |||
| height: 40vmin; | |||
| @@ -1,6 +1,17 @@ | |||
| import { Box } from "@mui/material"; | |||
| import { Box, IconButton } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const HeaderIconContainer = styled(IconButton)` | |||
| cursor: pointer; | |||
| min-width: 0; | |||
| border-radius: 100%; | |||
| &:hover { | |||
| background-color: ${(props) => props?.theme?.colors?.primaryLighter}; | |||
| } | |||
| & svg { | |||
| fill: ${(props) => props?.theme?.colors?.textColor}; | |||
| } | |||
| `; | |||
| export const HeaderContainer = styled(Box)` | |||
| display: flex; | |||
| justify-content: space-between; | |||
| @@ -7,7 +7,7 @@ export const HeaderNavigationItemIconTitle = styled(Box)` | |||
| font-size: 14px; | |||
| line-height: 20px; | |||
| font-weight: ${(props) => props?.$isActive && 600}; | |||
| color: white; | |||
| color: ${props => props?.theme?.colors?.textColor}; | |||
| font-weight: 500; | |||
| `; | |||
| @@ -1,10 +1,27 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { HeaderNotificationsContainer } from "./HeaderNotifications.styled"; | |||
| import NotificationsIcon from "@mui/icons-material/Notifications"; | |||
| import { HeaderIconContainer } from "components/Header/Header.styled"; | |||
| import PopoverComponent from "components/Popover/Popover"; | |||
| import HeaderNotificationsContent from "./HeaderNotificationsContent/HeaderNotificationsContent"; | |||
| const HeaderNotifications = () => { | |||
| return ( | |||
| <HeaderNotificationsContainer>notifications</HeaderNotificationsContainer> | |||
| <PopoverComponent | |||
| trigger={ | |||
| <HeaderIconContainer> | |||
| <NotificationsIcon /> | |||
| </HeaderIconContainer> | |||
| } | |||
| contentContainerStyles={{ borderRadius: "8px" }} | |||
| content={<HeaderNotificationsContent />} | |||
| popoverProps={{ | |||
| anchorOrigin: { | |||
| vertical: "bottom", | |||
| horizontal: "right", | |||
| }, | |||
| }} | |||
| /> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,37 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| HeaderLatestNotificationsContainer, | |||
| HeaderNotificationsContentContainer, | |||
| HeaderNotificationsContentHeader, | |||
| HeaderNotificationsContentHeaderSeeMore, | |||
| HeaderNotificationsContentHeaderTitle, | |||
| } from "./HeaderNotificationsContent.styled"; | |||
| import SingleNotification from "./SingleNotification/SingleNotification"; | |||
| const HeaderNotificationsContent = (props) => { | |||
| console.log(props); | |||
| return ( | |||
| <HeaderNotificationsContentContainer> | |||
| <HeaderNotificationsContentHeader> | |||
| <HeaderNotificationsContentHeaderTitle> | |||
| Notifications | |||
| </HeaderNotificationsContentHeaderTitle> | |||
| <HeaderNotificationsContentHeaderSeeMore> | |||
| See more | |||
| </HeaderNotificationsContentHeaderSeeMore> | |||
| </HeaderNotificationsContentHeader> | |||
| <HeaderLatestNotificationsContainer> | |||
| <SingleNotification /> | |||
| <SingleNotification /> | |||
| <SingleNotification /> | |||
| </HeaderLatestNotificationsContainer> | |||
| </HeaderNotificationsContentContainer> | |||
| ); | |||
| }; | |||
| HeaderNotificationsContent.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default HeaderNotificationsContent; | |||
| @@ -0,0 +1,32 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import { Link } from "react-router-dom"; | |||
| import styled from "styled-components"; | |||
| export const HeaderNotificationsContentContainer = styled(Box)` | |||
| width: 350px; | |||
| padding: 0 8px; | |||
| padding-bottom: 8px; | |||
| cursor: default; | |||
| background-color: ${(props) => props?.theme?.colors?.primaryDark}; | |||
| border-radius: 6px; | |||
| `; | |||
| export const HeaderNotificationsContentHeader = styled(Box)` | |||
| display: flex; | |||
| padding: 0 8px; | |||
| justify-content: space-between; | |||
| height: 60px; | |||
| align-items: center; | |||
| `; | |||
| export const HeaderNotificationsContentHeaderTitle = styled(Typography)` | |||
| font-size: 18px; | |||
| font-weight: 700; | |||
| font-family: Inter; | |||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||
| `; | |||
| export const HeaderNotificationsContentHeaderSeeMore = styled(Link)` | |||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||
| `; | |||
| export const HeaderLatestNotificationsContainer = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| `; | |||
| @@ -0,0 +1,39 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| SingleNotificationContainer, | |||
| SingleNotificationContent, | |||
| SingleNotificationDate, | |||
| SingleNotificationDetails, | |||
| SingleNotificationProfile, | |||
| SingleNotificationUnseen, | |||
| } from "./SingleNotification.styled"; | |||
| import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |||
| const SingleNotification = () => { | |||
| return ( | |||
| <SingleNotificationContainer> | |||
| <SingleNotificationProfile> | |||
| <AccountCircleIcon /> | |||
| </SingleNotificationProfile> | |||
| <SingleNotificationDetails> | |||
| <SingleNotificationContent> | |||
| <p> | |||
| <i>Olivia Saturday</i> commented on your | |||
| post. | |||
| </p> | |||
| </SingleNotificationContent> | |||
| <SingleNotificationDate> | |||
| 12 hours ago | |||
| </SingleNotificationDate> | |||
| </SingleNotificationDetails> | |||
| <SingleNotificationUnseen /> | |||
| </SingleNotificationContainer> | |||
| ); | |||
| }; | |||
| SingleNotification.propTypes = { | |||
| children: PropTypes.node, | |||
| }; | |||
| export default SingleNotification; | |||
| @@ -0,0 +1,41 @@ | |||
| import { Box, Typography } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const SingleNotificationContainer = styled(Box)` | |||
| display: flex; | |||
| gap: 8px; | |||
| align-items: center; | |||
| border-top: 1px solid ${(props) => props?.theme?.colors?.secondaryDark}; | |||
| padding: 6px 0px; | |||
| cursor: pointer; | |||
| &:hover { | |||
| background-color: ${props => props?.theme?.colors?.secondaryDark}; | |||
| border-radius: 8px; | |||
| } | |||
| `; | |||
| export const SingleNotificationProfile = styled(Box)``; | |||
| export const SingleNotificationDetails = styled(Box)` | |||
| display: flex; | |||
| flex-direction: column; | |||
| gap: 8px; | |||
| `; | |||
| export const SingleNotificationContent = styled(Typography)` | |||
| font-family: Inter; | |||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||
| & * { | |||
| margin: 0; | |||
| } | |||
| `; | |||
| export const SingleNotificationDate = styled(Typography)` | |||
| font-family: Inter; | |||
| font-size: 12px; | |||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||
| `; | |||
| export const SingleNotificationUnseen = styled(Box)` | |||
| width: 8px; | |||
| min-width: 8px; | |||
| height: 8px; | |||
| min-height: 8px; | |||
| background-color: ${(props) => props?.theme?.colors?.primaryLighter}; | |||
| border-radius: 100%; | |||
| `; | |||
| @@ -1,7 +1,9 @@ | |||
| /*eslint-disable*/ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { HeaderProfileContainer } from "./HeaderProfile.styled"; | |||
| import PersonIcon from "@mui/icons-material/Person"; | |||
| import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |||
| const HeaderProfile = () => { | |||
| return <HeaderProfileContainer>profile</HeaderProfileContainer>; | |||
| }; | |||
| @@ -1,10 +1,10 @@ | |||
| import React, { useContext } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { HeaderThemeChooserContainer } from "./HeaderThemeChooser.styled"; | |||
| import DarkModeIcon from "@mui/icons-material/DarkMode"; | |||
| import LightModeIcon from "@mui/icons-material/LightMode"; | |||
| import { ColorModeContext } from "context/ColorModeContext"; | |||
| import { DARK_THEME } from "constants/themeConstants"; | |||
| import { HeaderIconContainer } from "components/Header/Header.styled"; | |||
| const HeaderThemeChooser = () => { | |||
| const themeCtx = useContext(ColorModeContext); | |||
| @@ -12,11 +12,14 @@ const HeaderThemeChooser = () => { | |||
| const handleChangeTheme = () => { | |||
| themeCtx?.changeTheme?.(); | |||
| }; | |||
| console.log(themeCtx) | |||
| return ( | |||
| <HeaderThemeChooserContainer onClick={handleChangeTheme}> | |||
| {themeCtx?.currentTheme === DARK_THEME ? <LightModeIcon /> : <DarkModeIcon />} | |||
| </HeaderThemeChooserContainer> | |||
| <HeaderIconContainer onClick={handleChangeTheme}> | |||
| {themeCtx?.currentTheme === DARK_THEME ? ( | |||
| <LightModeIcon /> | |||
| ) : ( | |||
| <DarkModeIcon /> | |||
| )} | |||
| </HeaderIconContainer> | |||
| ); | |||
| }; | |||
| @@ -1,8 +1 @@ | |||
| import { IconButton } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const HeaderThemeChooserContainer = styled(IconButton)` | |||
| cursor: pointer; | |||
| min-width: 0; | |||
| border-radius: 100%; | |||
| `; | |||
| @@ -3,5 +3,6 @@ import styled from "styled-components"; | |||
| export const LogoContainer = styled.div` | |||
| text-decoration: none; | |||
| cursor: pointer; | |||
| color: white; | |||
| font-size: 14px; | |||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||
| `; | |||
| @@ -2,7 +2,7 @@ import React, { useState } from "react"; | |||
| import { Button, Divider, Paper, Typography } from "@mui/material"; | |||
| import DialogComponent from "../Dialog/DialogComponent"; | |||
| import DrawerComponent from "../Drawer/DrawerComponent"; | |||
| import PopoverComponent from "../Popover/PopoverComponent"; | |||
| import PopoverComponent from "../Popover/Popover"; | |||
| const Modals = () => { | |||
| const [dialogOpen, setDialogOpen] = useState(false); | |||
| @@ -0,0 +1,50 @@ | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Popover } from "@mui/material"; | |||
| import { PopoverContainer, PopoverTrigger } from "./Popover.styled"; | |||
| const PopoverComponent = (props) => { | |||
| const [isOpened, setIsOpened] = useState(false); | |||
| const [anchorEl, setAnchorEl] = useState(null); | |||
| const togglePopover = (event) => { | |||
| setIsOpened((prevState) => !prevState); | |||
| setAnchorEl(event?.currentTarget); | |||
| }; | |||
| return ( | |||
| <PopoverContainer> | |||
| <PopoverTrigger | |||
| onClick={togglePopover} | |||
| style={props?.triggerContainerStyles} | |||
| > | |||
| {props?.trigger} | |||
| </PopoverTrigger> | |||
| <Popover | |||
| style={props?.contentContainerStyles} | |||
| open={isOpened} | |||
| anchorEl={anchorEl} | |||
| onClose={togglePopover} | |||
| anchorOrigin={{ | |||
| vertical: "bottom", | |||
| horizontal: "left", | |||
| }} | |||
| {...props?.popoverProps} | |||
| > | |||
| {props?.content} | |||
| </Popover> | |||
| </PopoverContainer> | |||
| ); | |||
| }; | |||
| PopoverComponent.propTypes = { | |||
| anchorEl: PropTypes.object, | |||
| onClose: PropTypes.func.isRequired, | |||
| isOpened: PropTypes.bool, | |||
| popoverProps: PropTypes.object, | |||
| trigger: PropTypes.oneOfType([PropTypes.element, PropTypes.node]), | |||
| content: PropTypes.oneOfType([PropTypes.element, PropTypes.node]), | |||
| triggerContainerStyles: PropTypes.object, | |||
| contentContainerStyles: PropTypes.object, | |||
| }; | |||
| export default PopoverComponent; | |||
| @@ -0,0 +1,5 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const PopoverContainer = styled(Box)`` | |||
| export const PopoverTrigger = styled(Box)`` | |||
| @@ -1,35 +0,0 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { Box, Popover } from "@mui/material"; | |||
| const PopoverComponent = ({ open, anchorEl, onClose, content }) => { | |||
| const handleClose = () => { | |||
| onClose(); | |||
| }; | |||
| return ( | |||
| <Box component="div"> | |||
| <Popover | |||
| sx={{ p: 5 }} | |||
| open={open} | |||
| anchorEl={anchorEl} | |||
| onClose={handleClose} | |||
| anchorOrigin={{ | |||
| vertical: "bottom", | |||
| horizontal: "left", | |||
| }} | |||
| > | |||
| {content} | |||
| </Popover> | |||
| </Box> | |||
| ); | |||
| }; | |||
| PopoverComponent.propTypes = { | |||
| anchorEl: PropTypes.object, | |||
| open: PropTypes.bool, | |||
| onClose: PropTypes.func.isRequired, | |||
| content: PropTypes.any, | |||
| }; | |||
| export default PopoverComponent; | |||
| @@ -1,14 +1,26 @@ | |||
| import React from "react"; | |||
| import { DarkMode, LightMode } from "@mui/icons-material"; | |||
| export const DARK_THEME = "dark"; | |||
| export const LIGHT_THEME = "light"; | |||
| export const themes = [DARK_THEME, LIGHT_THEME]; | |||
| export const themes = [ | |||
| { | |||
| name: DARK_THEME, | |||
| icon: <DarkMode />, | |||
| }, | |||
| { | |||
| name: LIGHT_THEME, | |||
| icon: <LightMode />, | |||
| }, | |||
| ]; | |||
| export const getNextTheme = (currentTheme) => { | |||
| const currentThemeIndex = | |||
| themes?.findIndex?.((singleTheme) => singleTheme === currentTheme) || 0; | |||
| themes?.findIndex?.((singleTheme) => singleTheme?.name === currentTheme) || 0; | |||
| const nextThemeIndex = | |||
| currentThemeIndex === themes?.length - 1 ? 0 : currentThemeIndex + 1; | |||
| return themes[nextThemeIndex]; | |||
| return themes[nextThemeIndex]?.name; | |||
| }; | |||
| export const themeStorageKey = "colorMode"; | |||
| @@ -12,7 +12,7 @@ import { | |||
| const useTheme = () => { | |||
| const currentColorMode = | |||
| authScopeStringGetHelper(themeStorageKey) || themes[0]; | |||
| authScopeStringGetHelper(themeStorageKey) || themes[0]?.name; | |||
| const [currentTheme, setCurrentTheme] = useState(currentColorMode); | |||
| const changeTheme = (newTheme) => { | |||
| @@ -11,3 +11,6 @@ code { | |||
| font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', | |||
| monospace; | |||
| } | |||
| * { | |||
| box-sizing: border-box; | |||
| } | |||
| @@ -1,11 +1,11 @@ | |||
| import { authScopeStringGetHelper } from "util/authScopeHelpers"; | |||
| import primary from "./primaryTheme/primaryTheme"; | |||
| import secondary from "./secondaryTheme/secondaryTheme"; | |||
| import { LIGHT_THEME } from "constants/themeConstants"; | |||
| import { DARK_THEME } from "constants/themeConstants"; | |||
| export let getTheme = () => { | |||
| let selectedThemeStorage = authScopeStringGetHelper("colorMode"); | |||
| if (selectedThemeStorage === LIGHT_THEME) { | |||
| if (selectedThemeStorage === DARK_THEME) { | |||
| return { ...primary }; | |||
| } | |||
| return { ...secondary }; | |||
| @@ -1,5 +1,7 @@ | |||
| export const primaryThemeColors = { | |||
| primaryDark: "#673ab7", | |||
| primaryLighter: "#845ccb", | |||
| secondaryDark: "#212121", | |||
| primaryDark: "#393646", | |||
| secondaryDark: "#4F4557", | |||
| secondaryLighter: "#6D5D6E", | |||
| primaryLighter: "#836E80", | |||
| textColor: "#C4DFDF" | |||
| }; | |||
| @@ -1,4 +1,7 @@ | |||
| export const secondaryThemeColors = { | |||
| primaryDark: "#009688", | |||
| secondaryDark: "#f5f5f5", | |||
| primaryDark: "#C4DFDF", | |||
| secondaryDark: "#D2E9E9", | |||
| primaryLighter: "#F8F6F4", | |||
| secondaryLighter: "#E3F4F4", | |||
| textColor: "#393646", | |||
| }; | |||