| user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ | 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 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. | Notice the use of %PUBLIC_URL% in the tags above. | ||||
| It will be replaced with the URL of the `public` folder during the build. | It will be replaced with the URL of the `public` folder during the build. |
| .App { | .App { | ||||
| text-align: center; | text-align: center; | ||||
| } | } | ||||
| * { | |||||
| box-sizing: border-box; | |||||
| } | |||||
| .App-logo { | .App-logo { | ||||
| height: 40vmin; | height: 40vmin; |
| import { Box } from "@mui/material"; | |||||
| import { Box, IconButton } from "@mui/material"; | |||||
| import styled from "styled-components"; | 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)` | export const HeaderContainer = styled(Box)` | ||||
| display: flex; | display: flex; | ||||
| justify-content: space-between; | justify-content: space-between; |
| font-size: 14px; | font-size: 14px; | ||||
| line-height: 20px; | line-height: 20px; | ||||
| font-weight: ${(props) => props?.$isActive && 600}; | font-weight: ${(props) => props?.$isActive && 600}; | ||||
| color: white; | |||||
| color: ${props => props?.theme?.colors?.textColor}; | |||||
| font-weight: 500; | font-weight: 500; | ||||
| `; | `; | ||||
| import React from "react"; | import React from "react"; | ||||
| import PropTypes from "prop-types"; | 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 = () => { | const HeaderNotifications = () => { | ||||
| return ( | return ( | ||||
| <HeaderNotificationsContainer>notifications</HeaderNotificationsContainer> | |||||
| <PopoverComponent | |||||
| trigger={ | |||||
| <HeaderIconContainer> | |||||
| <NotificationsIcon /> | |||||
| </HeaderIconContainer> | |||||
| } | |||||
| contentContainerStyles={{ borderRadius: "8px" }} | |||||
| content={<HeaderNotificationsContent />} | |||||
| popoverProps={{ | |||||
| anchorOrigin: { | |||||
| vertical: "bottom", | |||||
| horizontal: "right", | |||||
| }, | |||||
| }} | |||||
| /> | |||||
| ); | ); | ||||
| }; | }; | ||||
| 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; |
| 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; | |||||
| `; |
| 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; |
| 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%; | |||||
| `; |
| /*eslint-disable*/ | |||||
| import React from "react"; | import React from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { HeaderProfileContainer } from "./HeaderProfile.styled"; | import { HeaderProfileContainer } from "./HeaderProfile.styled"; | ||||
| import PersonIcon from "@mui/icons-material/Person"; | |||||
| import AccountCircleIcon from "@mui/icons-material/AccountCircle"; | |||||
| const HeaderProfile = () => { | const HeaderProfile = () => { | ||||
| return <HeaderProfileContainer>profile</HeaderProfileContainer>; | return <HeaderProfileContainer>profile</HeaderProfileContainer>; | ||||
| }; | }; |
| import React, { useContext } from "react"; | import React, { useContext } from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { HeaderThemeChooserContainer } from "./HeaderThemeChooser.styled"; | |||||
| import DarkModeIcon from "@mui/icons-material/DarkMode"; | import DarkModeIcon from "@mui/icons-material/DarkMode"; | ||||
| import LightModeIcon from "@mui/icons-material/LightMode"; | import LightModeIcon from "@mui/icons-material/LightMode"; | ||||
| import { ColorModeContext } from "context/ColorModeContext"; | import { ColorModeContext } from "context/ColorModeContext"; | ||||
| import { DARK_THEME } from "constants/themeConstants"; | import { DARK_THEME } from "constants/themeConstants"; | ||||
| import { HeaderIconContainer } from "components/Header/Header.styled"; | |||||
| const HeaderThemeChooser = () => { | const HeaderThemeChooser = () => { | ||||
| const themeCtx = useContext(ColorModeContext); | const themeCtx = useContext(ColorModeContext); | ||||
| const handleChangeTheme = () => { | const handleChangeTheme = () => { | ||||
| themeCtx?.changeTheme?.(); | themeCtx?.changeTheme?.(); | ||||
| }; | }; | ||||
| console.log(themeCtx) | |||||
| return ( | return ( | ||||
| <HeaderThemeChooserContainer onClick={handleChangeTheme}> | |||||
| {themeCtx?.currentTheme === DARK_THEME ? <LightModeIcon /> : <DarkModeIcon />} | |||||
| </HeaderThemeChooserContainer> | |||||
| <HeaderIconContainer onClick={handleChangeTheme}> | |||||
| {themeCtx?.currentTheme === DARK_THEME ? ( | |||||
| <LightModeIcon /> | |||||
| ) : ( | |||||
| <DarkModeIcon /> | |||||
| )} | |||||
| </HeaderIconContainer> | |||||
| ); | ); | ||||
| }; | }; | ||||
| import { IconButton } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const HeaderThemeChooserContainer = styled(IconButton)` | |||||
| cursor: pointer; | |||||
| min-width: 0; | |||||
| border-radius: 100%; | |||||
| `; |
| export const LogoContainer = styled.div` | export const LogoContainer = styled.div` | ||||
| text-decoration: none; | text-decoration: none; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| color: white; | |||||
| font-size: 14px; | |||||
| color: ${(props) => props?.theme?.colors?.textColor}; | |||||
| `; | `; |
| import { Button, Divider, Paper, Typography } from "@mui/material"; | import { Button, Divider, Paper, Typography } from "@mui/material"; | ||||
| import DialogComponent from "../Dialog/DialogComponent"; | import DialogComponent from "../Dialog/DialogComponent"; | ||||
| import DrawerComponent from "../Drawer/DrawerComponent"; | import DrawerComponent from "../Drawer/DrawerComponent"; | ||||
| import PopoverComponent from "../Popover/PopoverComponent"; | |||||
| import PopoverComponent from "../Popover/Popover"; | |||||
| const Modals = () => { | const Modals = () => { | ||||
| const [dialogOpen, setDialogOpen] = useState(false); | const [dialogOpen, setDialogOpen] = useState(false); |
| 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; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const PopoverContainer = styled(Box)`` | |||||
| export const PopoverTrigger = styled(Box)`` |
| 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; |
| import React from "react"; | |||||
| import { DarkMode, LightMode } from "@mui/icons-material"; | |||||
| export const DARK_THEME = "dark"; | export const DARK_THEME = "dark"; | ||||
| export const LIGHT_THEME = "light"; | 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) => { | export const getNextTheme = (currentTheme) => { | ||||
| const currentThemeIndex = | const currentThemeIndex = | ||||
| themes?.findIndex?.((singleTheme) => singleTheme === currentTheme) || 0; | |||||
| themes?.findIndex?.((singleTheme) => singleTheme?.name === currentTheme) || 0; | |||||
| const nextThemeIndex = | const nextThemeIndex = | ||||
| currentThemeIndex === themes?.length - 1 ? 0 : currentThemeIndex + 1; | currentThemeIndex === themes?.length - 1 ? 0 : currentThemeIndex + 1; | ||||
| return themes[nextThemeIndex]; | |||||
| return themes[nextThemeIndex]?.name; | |||||
| }; | }; | ||||
| export const themeStorageKey = "colorMode"; | export const themeStorageKey = "colorMode"; |
| const useTheme = () => { | const useTheme = () => { | ||||
| const currentColorMode = | const currentColorMode = | ||||
| authScopeStringGetHelper(themeStorageKey) || themes[0]; | |||||
| authScopeStringGetHelper(themeStorageKey) || themes[0]?.name; | |||||
| const [currentTheme, setCurrentTheme] = useState(currentColorMode); | const [currentTheme, setCurrentTheme] = useState(currentColorMode); | ||||
| const changeTheme = (newTheme) => { | const changeTheme = (newTheme) => { |
| font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', | ||||
| monospace; | monospace; | ||||
| } | } | ||||
| * { | |||||
| box-sizing: border-box; | |||||
| } |
| import { authScopeStringGetHelper } from "util/authScopeHelpers"; | import { authScopeStringGetHelper } from "util/authScopeHelpers"; | ||||
| import primary from "./primaryTheme/primaryTheme"; | import primary from "./primaryTheme/primaryTheme"; | ||||
| import secondary from "./secondaryTheme/secondaryTheme"; | import secondary from "./secondaryTheme/secondaryTheme"; | ||||
| import { LIGHT_THEME } from "constants/themeConstants"; | |||||
| import { DARK_THEME } from "constants/themeConstants"; | |||||
| export let getTheme = () => { | export let getTheme = () => { | ||||
| let selectedThemeStorage = authScopeStringGetHelper("colorMode"); | let selectedThemeStorage = authScopeStringGetHelper("colorMode"); | ||||
| if (selectedThemeStorage === LIGHT_THEME) { | |||||
| if (selectedThemeStorage === DARK_THEME) { | |||||
| return { ...primary }; | return { ...primary }; | ||||
| } | } | ||||
| return { ...secondary }; | return { ...secondary }; |
| export const primaryThemeColors = { | export const primaryThemeColors = { | ||||
| primaryDark: "#673ab7", | |||||
| primaryLighter: "#845ccb", | |||||
| secondaryDark: "#212121", | |||||
| primaryDark: "#393646", | |||||
| secondaryDark: "#4F4557", | |||||
| secondaryLighter: "#6D5D6E", | |||||
| primaryLighter: "#836E80", | |||||
| textColor: "#C4DFDF" | |||||
| }; | }; |
| export const secondaryThemeColors = { | export const secondaryThemeColors = { | ||||
| primaryDark: "#009688", | |||||
| secondaryDark: "#f5f5f5", | |||||
| primaryDark: "#C4DFDF", | |||||
| secondaryDark: "#D2E9E9", | |||||
| primaryLighter: "#F8F6F4", | |||||
| secondaryLighter: "#E3F4F4", | |||||
| textColor: "#393646", | |||||
| }; | }; |