diff --git a/frontend/components/NewLayout/Header/Header.tsx b/frontend/components/NewLayout/Header/Header.tsx
index 05bd370cd..b0e5944a5 100644
--- a/frontend/components/NewLayout/Header/Header.tsx
+++ b/frontend/components/NewLayout/Header/Header.tsx
@@ -1,8 +1,12 @@
import { AppBar, Slide, Toolbar, useScrollTrigger } from "@mui/material"
import { styled } from "@mui/material/styles"
+import HyLogoIcon from "../Icons/HyLogo"
import { DesktopNavigationMenu, MobileNavigationMenu } from "../Navigation"
+import LanguageSwitch from "./LanguageSwitch"
import MoocLogo from "./MoocLogo"
+import { useTranslator } from "/hooks/useTranslator"
+import CommonTranslations from "/translations/common"
interface HideOnScrollProps {
window?: () => Window
@@ -19,31 +23,108 @@ function HideOnScroll({ window, children }: HideOnScrollProps) {
)
}
-const StyledToolbar = styled(Toolbar)`
+const HyToolbar = styled(Toolbar)(
+ ({ theme }) => `
+ background-color: ${theme.palette.common.grayscale.black};
+ border-bottom: 2px solid rgb(0, 0, 0, 0.7);
+ padding: 0;
+ margin: 0;
+ position: relative;
+ flex-wrap: wrap;
+ display: flex;
+ justify-content: space-between;
+`,
+)
+
+const GroupToolbar = styled(Toolbar)`
display: flex;
flex-direction: row;
flex-shrink: 0;
overflow: hidden;
`
-const MenuContainer = styled("div")`
+const HyLogo = styled(HyLogoIcon)(
+ ({ theme }) => `
+ fill: ${theme.palette.common.grayscale.white};
+ font-size: 32;
+ ${theme.breakpoints.up("lg")} {
+ font-size: 64;
+ }
+`,
+)
+
+const HyLabel = styled("span")(
+ ({ theme }) => `
+ font-size: 0.75rem;
+ line-height: 14px;
+ font-weight: 700;
+ color: ${theme.palette.common.grayscale.white};
+ letter-spacing: -0.7px;
+ margin-left: 8px;
+ max-width: 90px;
+ text-transform: uppercase;
+ ${theme.breakpoints.down("xs")} {
+ font-size: 0.75rem;
+ line-height: 14px;
+ letter-spacing: -0.6px;
+ margin-left: 3px;
+ }
+ ${theme.breakpoints.up("md")} {
+ font-size: 0.875rem;
+ }
+ ${theme.breakpoints.up("lg")} {
+ letter-spacing: -0.6px;
+ margin-left: 4px;
+ }
+ ${theme.breakpoints.up("xl")} {
+ font-size: 0.875rem;
+ margin-left: 8px;
+ }
+`,
+)
+
+const HyLogoContainer = styled("div")(
+ ({ theme }) => `
+ padding: 8px 0;
display: flex;
align-items: center;
- justify-content: flex-end;
- flex: 1;
-`
+ justify-content: space-between;
+ ${theme.breakpoints.down("xs")} {
+ min-width: min-content;
+ max-width: max-content;
+ white-space: nowrap;
+ }
+ ${theme.breakpoints.up("lg")} {
+ min-width: min-content;
+ max-width: 90px;
+ white-space: initial;
+ }
+ ${theme.breakpoints.up("xl")} {
+ min-width: min-content;
+ max-width: max-content;
+ white-space: nowrap;
+ }
+`,
+)
function Header() {
+ const t = useTranslator(CommonTranslations)
+
return (
-
-
+
+
+
+
+ {t("hy")}
+
+
+
+
-
-
-
-
-
+
+
+
)
diff --git a/frontend/components/NewLayout/Header/LanguageSwitch.tsx b/frontend/components/NewLayout/Header/LanguageSwitch.tsx
index 4c643bbc6..eba3e79b3 100644
--- a/frontend/components/NewLayout/Header/LanguageSwitch.tsx
+++ b/frontend/components/NewLayout/Header/LanguageSwitch.tsx
@@ -1,80 +1,238 @@
-import React from "react"
+import React, { useState } from "react"
+import Link from "next/link"
import { useRouter } from "next/router"
-import LanguageIcon from "@mui/icons-material/Language"
import {
Button,
- ButtonGroup,
- ButtonGroupProps,
- ButtonProps,
EnhancedButton,
+ EnhancedMenuItem,
+ Menu,
+ MenuItem,
} from "@mui/material"
import { styled } from "@mui/material/styles"
+import { useEventCallback } from "@mui/material/utils"
+import CaretDownIcon from "../Icons/CaretDown"
+import CaretUpIcon from "../Icons/CaretUp"
+import GlobeIcon from "../Icons/Globe"
import { useTranslator } from "/hooks/useTranslator"
import { KeyOfTranslationDictionary } from "/translations"
import CommonTranslations from "/translations/common"
-const LanguageSwitchButton = (buttonProps: ButtonProps<"div">) => (
-
-)
+const LanguageSwitchMenu = styled(Menu)(
+ ({ theme }) => `
+ justify-items: center;
+ text-transform: uppercase;
+ top: 11px;
+
+ .MuiPaper-root {
+ width: max-content;
+ padding: 10px;
+ border-radius: 0 0 5px 5px;
+ box-shadow: rgba(0, 0, 0, 0.2) 0px 10px 10px;
+ min-width: 160px;
+ right: -15px;
-const StyledButtonGroup = styled(ButtonGroup)`
- cursor: unset;
- max-height: 8vh;
-` as typeof ButtonGroup
-
-const LanguageSwitchContainer = (props: ButtonGroupProps & ButtonProps) => (
-
+ ${theme.breakpoints.up("xl")} {
+ left: -15px;
+ }
+ }
+
+ .MuiList-root {
+ margin: 0;
+ padding: 0;
+ display: grid;
+ gap: 4px;
+ }
+
+ .Mui-selected {
+ color: ${theme.palette.common.grayscale.black};
+ background-color: transparent;
+ border: 2px solid ${theme.palette.common.grayscale.black};
+
+ &:hover {
+ color: ${theme.palette.common.grayscale.black};
+ background-color: ${theme.palette.common.grayscale.backgroundBox};
+ }
+ }
+`,
)
-interface LanguageButtonProps {
- active: boolean
-}
-const Language = styled(Button, {
- shouldForwardProp: (prop) => prop !== "active",
-})`
- border: 0;
- text-decoration: none;
+/*
+ */
+const LanguageOption = styled(MenuItem)(
+ ({ theme }) => `
+ margin: 0;
+ padding: 0;
+ color: ${theme.palette.common.brand.light};
+
+ &:hover {
+ color: ${theme.palette.common.brand.main};
+ background-color: ${theme.palette.common.grayscale.backgroundBox};
+ }
+
+ &.Mui-selected {
+ color: ${theme.palette.common.grayscale.black};
+ background-color: transparent;
+ border: 2px solid ${theme.palette.common.grayscale.black};
+
+ &:hover {
+ color: ${theme.palette.common.grayscale.medium};
+ background-color: ${theme.palette.common.grayscale.backgroundBox};
+ }
+ }
+`,
+) as EnhancedMenuItem
+
+const LanguageOptionLink = styled(Link)`
+ font-size: 1rem;
+ line-height: 24px;
+ font-weight: 600;
+ letter-spacing: -0.5px;
+ margin: 0;
+ padding: 12px;
+ display: block;
color: inherit;
- font-weight: ${({ active }) => (active ? "600" : "300")};
+ text-decoration: none;
+`
+const LanguageSwitchContainer = styled("div")`
+ align-items: center;
+ display: flex;
+ height: 100%;
+`
+
+const LanguageButton = styled(Button)(
+ ({ theme }) => `
+ color: ${theme.palette.common.grayscale.white};
+ align-items: center;
+ background-color: transparent;
+ border: 0;
+ display: inline-grid;
+ gap: 4px;
+ grid-template-columns: repeat(2, auto);
+ letter-spacing: -0.7px;
+ margin: 0;
+ padding: 14px 10px;
+ text-transform: uppercase;
+ height: 100%;
+ position: relative;
+ font-weight: 600;
+ font-size: 1rem;
+
+ svg:first-of-type {
+ display: none !important;
+ }
+
+ ${theme.breakpoints.up("lg")} {
+ font-size: 0.75rem;
+ font-weight: 400;
+ letter-spacing: -0.5px;
+ grid-template-columns: repeat(3, auto);
+ padding: 0;
+
+ svg:first-of-type {
+ display: inline-block !important;
+ }
+ }
+
+ &::after {
+ border-bottom: 0;
+ }
&:hover {
+ color: ${theme.palette.common.grayscale.medium};
+ svg {
+ fill: ${theme.palette.common.grayscale.medium};
+ }
+ cursor: pointer;
border: 0;
}
-` as EnhancedButton<"button", LanguageButtonProps>
+`,
+) as EnhancedButton
-const LanguageSwitch = () => {
+const CaretUp = styled(CaretUpIcon)(
+ ({ theme }) => `
+ fill: ${theme.palette.common.grayscale.white};
+ font-size: 8px;
+`,
+)
+const CaretDown = styled(CaretDownIcon)(
+ ({ theme }) => `
+ fill: ${theme.palette.common.grayscale.white};
+ font-size: 8px;
+`,
+)
+const LanguageIcon = styled(GlobeIcon)(
+ ({ theme }) => `
+ fill: ${theme.palette.common.grayscale.white};
+ font-size: 14px;
+`,
+)
+
+type LanguageSwitchProps = {
+ mobile?: boolean
+}
+
+const LanguageSwitch = ({ mobile }: LanguageSwitchProps) => {
const t = useTranslator(CommonTranslations)
const { locale: currentLocale, locales, asPath } = useRouter()
+ const [anchorEl, setAnchorEl] = useState(null)
+ const open = Boolean(anchorEl)
+
+ const handleLanguageSwitchClick = useEventCallback(
+ (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget)
+ },
+ )
+ const handleClose = useEventCallback(() => {
+ setAnchorEl(null)
+ })
+
+ const menuName = mobile
+ ? "mobile-language-switch-menu"
+ : "language-switch-menu"
+ const name = mobile ? "mobile-language-switch" : "language-switch"
return (
-
- {locales?.map((locale) => (
- ,
- )}
- aria-label={t(
- locale as KeyOfTranslationDictionary,
- )}
- >
- {locale}
-
- ))}
+
+
+ {currentLocale}
+ {open ? : }
+
+
)
}
diff --git a/frontend/components/NewLayout/Header/MoocLogo.tsx b/frontend/components/NewLayout/Header/MoocLogo.tsx
index e43c29f51..9a95f2b16 100644
--- a/frontend/components/NewLayout/Header/MoocLogo.tsx
+++ b/frontend/components/NewLayout/Header/MoocLogo.tsx
@@ -7,32 +7,23 @@ import moocLogo from "/public/images/new/logos/moocfi.svg"
const MoocLogoText = styled(Typography)(
({ theme }) => `
+ font-weight: 600;
font-size: 1.75rem !important;
+ letter-spacing: -0.75px;
${theme.breakpoints.down("xs")} {
font-size: 1.5rem !important;
}
${theme.breakpoints.down("xxs")} {
display: none !important;
}
-
- margin-top: 1rem;
`,
)
-const MoocLogoAvatar = styled(Avatar)(
- ({ theme }) => `
- margin-top: 0.5rem;
- margin-bottom: 0.5rem;
- margin-left: 0px;
- margin-right: 0.5rem;
- height: 3em;
- width: 3em;
- ${theme.breakpoints.down("xs")} {
- height: 2.5em;
- width: 2.5em;
- }
-`,
-)
+const MoocLogoAvatar = styled(Avatar)`
+ height: 3rem;
+ width: 3rem;
+ margin-right: 0.5em;
+`
const MoocLogoLink = styled(Link)`
color: black;
diff --git a/frontend/components/NewLayout/Icons/CaretDown.tsx b/frontend/components/NewLayout/Icons/CaretDown.tsx
new file mode 100644
index 000000000..b100795b7
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/CaretDown.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const CaretDownIcon = createSvgIcon(
+ ,
+ "CaretDown",
+)
+
+export default CaretDownIcon
diff --git a/frontend/components/NewLayout/Icons/CaretUp.tsx b/frontend/components/NewLayout/Icons/CaretUp.tsx
new file mode 100644
index 000000000..ae82c9bc4
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/CaretUp.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const CaretUpIcon = createSvgIcon(
+ ,
+ "CaretUp",
+)
+
+export default CaretUpIcon
diff --git a/frontend/components/NewLayout/Icons/Globe.tsx b/frontend/components/NewLayout/Icons/Globe.tsx
new file mode 100644
index 000000000..3400047a3
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/Globe.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const GlobeIcon = createSvgIcon(
+ ,
+ "Globe",
+)
+
+export default GlobeIcon
diff --git a/frontend/components/NewLayout/Icons/Hamburger.tsx b/frontend/components/NewLayout/Icons/Hamburger.tsx
new file mode 100644
index 000000000..cce379428
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/Hamburger.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const HamburgerIcon = createSvgIcon(
+ ,
+ "Hamburger",
+)
+
+export default HamburgerIcon
diff --git a/frontend/components/NewLayout/Icons/HyLogo.tsx b/frontend/components/NewLayout/Icons/HyLogo.tsx
new file mode 100644
index 000000000..dff94360b
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/HyLogo.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const HyLogoIcon = createSvgIcon(
+ ,
+ "HyLogo",
+)
+
+export default HyLogoIcon
diff --git a/frontend/components/NewLayout/Icons/Remove.tsx b/frontend/components/NewLayout/Icons/Remove.tsx
new file mode 100644
index 000000000..88c5049ee
--- /dev/null
+++ b/frontend/components/NewLayout/Icons/Remove.tsx
@@ -0,0 +1,10 @@
+import { createSvgIcon } from "@mui/material/utils"
+
+const RemoveIcon = createSvgIcon(
+ ,
+ "Remove",
+)
+
+export default RemoveIcon
diff --git a/frontend/components/NewLayout/Navigation/DesktopNavigationMenu.tsx b/frontend/components/NewLayout/Navigation/DesktopNavigationMenu.tsx
index efaea451c..c564972e3 100644
--- a/frontend/components/NewLayout/Navigation/DesktopNavigationMenu.tsx
+++ b/frontend/components/NewLayout/Navigation/DesktopNavigationMenu.tsx
@@ -15,21 +15,13 @@ import {
import { styled, Theme } from "@mui/material/styles"
import { NavigationLinks } from "./NavigationLinks"
-import LanguageSwitch from "/components/NewLayout/Header/LanguageSwitch"
import { useLoginStateContext } from "/contexts/LoginStateContext"
import { useTranslator } from "/hooks/useTranslator"
import { signOut } from "/lib/authentication"
import CommonTranslations from "/translations/common"
-const NavigationMenuContainer = styled("nav")(
+const NavigationLinksContainer = styled("div")(
({ theme }) => `
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 0.5rem;
-
${theme.breakpoints.down("sm")} {
display: none;
}
@@ -37,24 +29,12 @@ const NavigationMenuContainer = styled("nav")(
)
const NavigationRightContainer = styled("div")`
- display: flex;
+ display: inline-grid;
+ gap: 4px;
+ grid-template-columns: repeat(3, auto);
justify-content: flex-end;
- gap: 0.5rem;
- flex-grow: 1;
- width: 100%;
`
-const NavigationLinksWrapper = styled("div")(
- ({ theme }) => `
- display: flex;
- flex-shrink: 1;
-
- ${theme.breakpoints.down("md")} {
- display: none;
- }
-`,
-)
-
interface MenuButtonProps {
Icon?: React.FunctionComponent
narrow?: boolean
@@ -154,15 +134,14 @@ const UserOptionsMenu = () => {
const DesktopNavigationMenu = () => {
return (
-
-
+ <>
+
-
+
-
-
+ >
)
}
diff --git a/frontend/components/NewLayout/Navigation/MobileNavigationMenu.tsx b/frontend/components/NewLayout/Navigation/MobileNavigationMenu.tsx
index 24432cf23..75c7d619a 100644
--- a/frontend/components/NewLayout/Navigation/MobileNavigationMenu.tsx
+++ b/frontend/components/NewLayout/Navigation/MobileNavigationMenu.tsx
@@ -1,39 +1,38 @@
-import React, {
- forwardRef,
- MouseEventHandler,
- useCallback,
- useEffect,
- useMemo,
- useState,
-} from "react"
-
-import { useApolloClient } from "@apollo/client"
+import React, { useState } from "react"
+
+import { useRouter } from "next/router"
+
+/*import { useApolloClient } from "@apollo/client"
import ChalkboardTeacher from "@fortawesome/fontawesome-free/svgs/solid/chalkboard-user.svg?icon"
import Dashboard from "@fortawesome/fontawesome-free/svgs/solid/gauge-high.svg?icon"
-import List from "@fortawesome/fontawesome-free/svgs/solid/list.svg?icon"
+import ListIcon from "@fortawesome/fontawesome-free/svgs/solid/list.svg?icon"
import SignOut from "@fortawesome/fontawesome-free/svgs/solid/right-from-bracket.svg?icon"
import SignIn from "@fortawesome/fontawesome-free/svgs/solid/right-to-bracket.svg?icon"
import Register from "@fortawesome/fontawesome-free/svgs/solid/user-plus.svg?icon"
-import User from "@fortawesome/fontawesome-free/svgs/solid/user.svg?icon"
-import MenuIcon from "@mui/icons-material/Menu"
+import User from "@fortawesome/fontawesome-free/svgs/solid/user.svg?icon"*/
import {
- Divider,
- EnhancedMenuItem,
- EnhancedMenuItemProps,
+ Button,
+ Collapse,
+ Drawer,
+ EnhancedListItemButton,
IconButton,
+ List,
+ ListItem,
+ ListItemButton,
ListItemIcon,
ListItemText,
- Menu,
- MenuItem as MUIMenuItem,
SvgIcon,
} from "@mui/material"
import { styled } from "@mui/material/styles"
import { useEventCallback } from "@mui/material/utils"
-import LanguageSwitch from "/components/NewLayout/Header/LanguageSwitch"
+import CaretDownIcon from "../Icons/CaretDown"
+import CaretUpIcon from "../Icons/CaretUp"
+import HamburgerIcon from "../Icons/Hamburger"
+import RemoveIcon from "../Icons/Remove"
import { useLoginStateContext } from "/contexts/LoginStateContext"
import { useTranslator } from "/hooks/useTranslator"
-import { signOut } from "/lib/authentication"
+// import { signOut } from "/lib/authentication"
import CommonTranslations from "/translations/common"
const MobileMenuContainer = styled("div")(
@@ -46,59 +45,135 @@ const MobileMenuContainer = styled("div")(
`,
)
+const MobileMenu = styled(Drawer)(
+ ({ theme }) => `
+ .MuiDrawer-paper {
+ display: block;
+ width: 90%;
+
+ ${theme.breakpoints.up("xs")} {
+ width: 400px;
+ }
+ }
+`,
+) as typeof Drawer
+
+const MobileMenuHeader = styled("section")`
+ display: grid;
+ grid-template-columns: 1fr auto;
+ padding: 12px 80px 12px 16px;
+ gap: 16px;
+ min-height: 68px;
+ align-items: center;
+`
+
+const MobileMenuList = styled(List)`
+ position: relative;
+` as typeof List
+
+const MobileMenuListItem = styled(ListItem)(
+ ({ theme }) => `
+ margin: 0 0 4px;
+ display: flex;
+ padding: 0;
+
+ .MuiListItemText-primary {
+ font-size: 1.3125rem;
+ line-height: 28px;
+ font-weight: 700;
+ color: ${theme.palette.common.brand.light};
+ letter-spacing: -0.42px;
+ padding: 16px 0 16px 16px;
+ }
+
+ &.Mui-selected {
+ background-color: transparent;
+ .MuiListItemText-primary {
+ color: ${theme.palette.common.grayscale.dark};
+ }
+ }
+`,
+)
+
+const MobileMenuListItemText = styled(ListItemText)(
+ ({ theme }) => `
+ /*.MuiListItemText-primary {
+ font-size: 1.3125rem;
+ font-weight: 700;
+ color: ${theme.palette.common.brand.light};
+ letter-spacing: -0.42px;
+ padding: 16px 0 16px 16px;
+ }*/
+`,
+) as typeof ListItemText
+
+const MobileMenuListItemButton = styled(ListItemButton)`
+ &:hover {
+ background: transparent;
+ }
+` as EnhancedListItemButton
+
+const MobileMenuListItemIcon = styled(ListItemIcon)`
+ /* */
+`
+
interface MobileMenuItemProps {
- Icon: typeof SvgIcon
+ Icon?: typeof SvgIcon
+ href?: string
text: string
- onClick?: React.MouseEventHandler
+ collapsable?: boolean
}
-const MenuItem = MUIMenuItem as EnhancedMenuItem<"a">
+const MobileMenuItem = ({
+ Icon,
+ href,
+ text,
+ collapsable,
+ children,
+}: React.PropsWithChildren) => {
+ const { pathname } = useRouter()
+ const [open, setOpen] = useState(false)
+
+ const onClick = useEventCallback(() => {
+ if (collapsable) {
+ setOpen((prevOpen) => !prevOpen)
+ }
+ })
-const MobileMenuItem = forwardRef<
- HTMLAnchorElement,
- EnhancedMenuItemProps<"a"> & MobileMenuItemProps
->(({ Icon, text, ...props }, ref) => {
return (
-
+
+
+ {Icon && (
+
+
+
+ )}
+
+ {collapsable && (open ? : )}
+
+ {collapsable && {children}}
+
)
-})
+}
-const MobileNavigationMenu = forwardRef(({}, ref) => {
- const [anchor, setAnchor] = useState<
- (EventTarget & HTMLAnchorElement) | null
- >(null)
- const open = Boolean(anchor)
+// const MobileNavigationMenu = forwardRef(({}, ref) => {
+const MobileNavigationMenu = () => {
+ const [open, setOpen] = useState(false)
const t = useTranslator(CommonTranslations)
- const { admin, loggedIn, logInOrOut, currentUser } = useLoginStateContext()
- const apollo = useApolloClient()
-
- const onClick: MouseEventHandler = useEventCallback(
- (event) => {
- setAnchor(event.currentTarget)
- },
- )
+ const { admin /*loggedIn, logInOrOut, currentUser*/ } = useLoginStateContext()
+ //const apollo = useApolloClient()
- const onClose: MouseEventHandler = useEventCallback(() => {
- setAnchor(null)
+ const onClick = useEventCallback(() => {
+ setOpen((prevOpen) => !prevOpen)
})
- useEffect(() => {
- const resizeListener = () => {
- setAnchor(null)
- }
- window?.addEventListener("resize", resizeListener)
-
- return () => window?.removeEventListener("resize", resizeListener)
- }, [])
+ const onClose = useEventCallback(() => {
+ setOpen(false)
+ })
- const onSignOut = useCallback(() => {
- setAnchor(null)
+ /*const onSignOut = useCallback(() => {
+ setOpen(false)
signOut(apollo, logInOrOut)
}, [apollo, signOut, logInOrOut])
@@ -110,14 +185,11 @@ const MobileNavigationMenu = forwardRef(({}, ref) => {
}
return name
- }, [currentUser, t])
+ }, [currentUser, t])*/
- const menuItems = useMemo(() => {
+ /*const menuItems = useMemo(() => {
const items = [
- ,
- (({}, ref) => {
title={t("courses")}
onClick={onClose}
/>,
- (({}, ref) => {
if (admin) {
items.push(
- (({}, ref) => {
}
if (loggedIn) {
items.push(
- (({}, ref) => {
title={t("myProfile")}
onClick={onClose}
/>,
- (({}, ref) => {
)
} else {
items.push(
- (({}, ref) => {
title={t("loginShort")}
>
{t("loginShort")}
- ,
- ,
+ (({}, ref) => {
title={t("signUp")}
>
{t("signUp")}
- ,
+ ,
)
}
return items
- }, [loggedIn, onClose, t, admin, MobileMenuItem])
+ }, [loggedIn, onClose, t, admin, MobileMenuItemOld])*/
return (
- }
- aria-hidden
- >
-
+
+
-
+
+
+
+
+
+
+
+ {admin && }
+
+
)
-})
+}
+//})
export default MobileNavigationMenu
diff --git a/frontend/components/NewLayout/Navigation/NavigationLinks.tsx b/frontend/components/NewLayout/Navigation/NavigationLinks.tsx
index b446f16fd..e179c97b6 100644
--- a/frontend/components/NewLayout/Navigation/NavigationLinks.tsx
+++ b/frontend/components/NewLayout/Navigation/NavigationLinks.tsx
@@ -1,5 +1,5 @@
import { EnhancedLink, Link } from "@mui/material"
-import { css, styled } from "@mui/material/styles"
+import { styled } from "@mui/material/styles"
import { useActiveTab } from "/components/NewLayout/Navigation"
import { useLoginStateContext } from "/contexts/LoginStateContext"
@@ -12,60 +12,90 @@ interface NavigationLinkProps {
const NavigationLink = styled(Link, {
shouldForwardProp: (prop) => prop !== "active",
-})`
+})(
+ ({ theme, active }) => `
+ font-size: 0.875rem;
+ line-height: 16px;
+ font-weight: 700;
+ background-color: transparent;
+ border: none;
+ color: ${theme.palette.common.brand.nearlyBlack};
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+ letter-spacing: -0.7px;
+ padding: 12px 10px 13px;
+ text-transform: uppercase;
text-decoration: none;
- color: inherit;
- font-size: 1rem;
- padding: 0.2rem;
- ${({ active }) =>
- active
- ? css`
- border-bottom: 2px solid rgba(200, 100, 0, 0.25);
- font-weight: 600;
- `
- : css`
- &:hover {
- text-shadow: 0px 0px 1px black;
- }
- `}
-
+ text-align: left;
+ align-items: flex-start;
transition: 0.1s;
-` as EnhancedLink<"a", NavigationLinkProps>
+ ${active && `border-bottom: 2px solid ${theme.palette.common.brand.active};`}
+ &:hover {
+ color: ${theme.palette.common.brand.main};
+ }
+`,
+) as EnhancedLink<"a", NavigationLinkProps>
-const NavigationLinkContainer = styled("div")`
+const NavigationContainer = styled("nav")`
display: flex;
- justify-content: space-between;
- gap: 2rem;
+ margin: 0 32px;
+ align-items: center;
+ flex-flow: row;
+ justify-content: center;
+ padding: 0;
+`
+
+const NavigationLinkList = styled("ul")`
+ display: flex;
+ height: 100%;
+ list-style: none;
+ margin: 0;
+ padding: 0;
width: 100%;
`
+const NavigationLinkItem = styled("li")`
+ list-style: none;
+ height: 100%;
+`
+
export const NavigationLinks = () => {
const { admin } = useLoginStateContext()
const t = useTranslator(CommonTranslations)
const active = useActiveTab()
return (
-
-
- {t("courses")}
-
+
+
+
+
+ {t("courses")}
+
+
-
- {t("modules")}
-
+
+
+ {t("modules")}
+
+
- {admin && (
-
- Admin
-
- )}
-
+ {admin && (
+
+
+ Admin
+
+
+ )}
+
+
)
}
diff --git a/frontend/components/NewLayout/Navigation/NavigationMenu.tsx b/frontend/components/NewLayout/Navigation/NavigationMenu.tsx
deleted file mode 100644
index 8f66591c1..000000000
--- a/frontend/components/NewLayout/Navigation/NavigationMenu.tsx
+++ /dev/null
@@ -1,275 +0,0 @@
-import React, {
- forwardRef,
- MouseEventHandler,
- useCallback,
- useEffect,
- useRef,
- useState,
-} from "react"
-
-import { useRouter } from "next/router"
-
-import { useApolloClient } from "@apollo/client"
-import ChalkboardTeacherIcon from "@fortawesome/fontawesome-free/svgs/solid/chalkboard-teacher.svg?icon"
-import DashboardIcon from "@fortawesome/fontawesome-free/svgs/solid/dashboard.svg?icon"
-import ListIcon from "@fortawesome/fontawesome-free/svgs/solid/list.svg?icon"
-import SignOutIcon from "@fortawesome/fontawesome-free/svgs/solid/sign-out.svg?icon"
-import UserIcon from "@fortawesome/fontawesome-free/svgs/solid/user.svg?icon"
-import MenuIcon from "@mui/icons-material/Menu"
-import {
- Button,
- Divider,
- EnhancedMenuItem,
- IconButton,
- ListItemIcon,
- ListItemText,
- Menu,
- MenuItemProps,
- MenuItem as MUIMenuItem,
-} from "@mui/material"
-import { styled } from "@mui/material/styles"
-import { useEventCallback } from "@mui/material/utils"
-
-import { NavigationLinks } from "./NavigationLinks"
-import LanguageSwitch from "/components/NewLayout/Header/LanguageSwitch"
-import { useLoginStateContext } from "/contexts/LoginStateContext"
-import { useTranslator } from "/hooks/useTranslator"
-import { signOut } from "/lib/authentication"
-import CommonTranslations from "/translations/common"
-
-const MenuItem = MUIMenuItem as EnhancedMenuItem
-
-const NavigationMenuContainer = styled("nav")(
- ({ theme }) => `
- width: 100%;
- height: 100%;
- display: flex;
- justify-content: space-between;
- align-items: center;
- gap: 0.5rem;
-
- ${theme.breakpoints.down("xs")} {
- display: none;
- }
-`,
-)
-
-const MobileMenuContainer = styled("div")(
- ({ theme }) => `
- display: flex;
- justify-content: flex-end;
-
- ${theme.breakpoints.down("xs")} {
- display: none;
- }
-`,
-)
-
-const NavigationRightContainer = styled("div")`
- display: flex;
- justify-content: flex-end;
- gap: 0.5rem;
- flex-grow: 1;
-`
-
-const NavigationLinksWrapper = styled("div")(
- ({ theme }) => `
- display: flex;
- flex-grow: 1;
-
- ${theme.breakpoints.down("sm")} {
- display: none;
- }
-`,
-)
-
-const MenuButton = styled(Button)`
- display: flex;
- max-height: 10vh;
- white-space: nowrap;
- font-size: clamp(12px, 1.5vw, 16px);
-`
-
-const UserOptionsMenu = () => {
- const apollo = useApolloClient()
- const { pathname } = useRouter()
- const { loggedIn, logInOrOut, currentUser } = useLoginStateContext()
- const t = useTranslator(CommonTranslations)
-
- const userDisplayName = currentUser?.first_name
- ? `${currentUser.first_name} ${currentUser.last_name}`
- : t("myProfile")
-
- const onLogOut = useCallback(
- () => signOut(apollo, logInOrOut),
- [apollo, logInOrOut],
- )
-
- if (loggedIn) {
- return (
- <>
- {userDisplayName}
-
- {t("logout")}
-
- >
- )
- }
- return (
- <>
- {t("loginShort")}
- {t("signUp")}
- >
- )
-}
-
-const DesktopNavigationMenu = () => {
- return (
-
-
-
-
-
-
-
-
-
- )
-}
-
-interface MobileMenuItemProps extends MenuItemProps {
- icon: React.ElementType
- text: string
- onClick?: React.MouseEventHandler
-}
-
-const Nop = () => {
- /* */
-}
-
-const MobileMenuItem = forwardRef(
- ({ icon: Icon, text, onClick = Nop, ...props }, ref) => {
- return (
-
- )
- },
-) as EnhancedMenuItem<"li", MobileMenuItemProps>
-
-const MobileNavigationMenu = forwardRef(({}, ref) => {
- const [isOpen, setIsOpen] = useState(false)
- const anchor = useRef<(EventTarget & HTMLButtonElement) | null>(null)
-
- const t = useTranslator(CommonTranslations)
- const { admin, loggedIn, logInOrOut, currentUser } = useLoginStateContext()
- const apollo = useApolloClient()
-
- const onClick: MouseEventHandler = useEventCallback(
- (event) => {
- setIsOpen((value) => !value)
- anchor.current = event.currentTarget
- },
- )
-
- const onClose = useEventCallback(() => {
- setIsOpen(false)
- anchor.current = null
- })
-
- useEffect(() => {
- const resizeListener = () => {
- setIsOpen(false)
- }
- window?.addEventListener("resize", resizeListener)
-
- return () => window?.removeEventListener("resize", resizeListener)
- }, [])
-
- const userDisplayName = currentUser?.first_name
- ? `${currentUser.first_name} ${currentUser.last_name}`
- : t("myProfile")
-
- const onLogOut = useCallback(
- () => signOut(apollo, logInOrOut),
- [apollo, logInOrOut],
- )
-
- return (
-
-
-
-
-
-
- )
-})
-
-export { DesktopNavigationMenu, MobileNavigationMenu }
diff --git a/frontend/next.config.js b/frontend/next.config.js
index 46d35f50b..57c838763 100644
--- a/frontend/next.config.js
+++ b/frontend/next.config.js
@@ -56,7 +56,7 @@ const nextConfiguration = (_phase) => ({
emotion: {
// would label things with [local] or something; will break styling if not set to never
// autoLabel: "never",
- autoLabel: "never",
+ // autoLabel: "never",
// labelFormat: "[dirname]--[filename]--[local]",
importMap: {
"@mui/system": {
diff --git a/frontend/src/newTheme/components.tsx b/frontend/src/newTheme/components.tsx
index 97f056f9c..652a5e52d 100644
--- a/frontend/src/newTheme/components.tsx
+++ b/frontend/src/newTheme/components.tsx
@@ -3,6 +3,7 @@ import {
ButtonProps,
EnhancedLinkProps,
FormControlProps,
+ ListItemButtonProps,
MenuItemProps,
TextFieldProps,
} from "@mui/material"
@@ -44,21 +45,179 @@ export const withComponents = (theme: Theme) =>
MuiMenuItem: {
defaultProps: {
LinkComponent: LinkBehavior,
+ disableRipple: true,
} as MenuItemProps,
},
+ MuiListItemButton: {
+ defaultProps: {
+ LinkComponent: LinkBehavior,
+ disableRipple: true,
+ } as ListItemButtonProps,
+ },
MuiButton: {
defaultProps: {
variant: "outlined",
color: "primary",
+ disableRipple: true,
LinkComponent: LinkBehavior,
} as ButtonProps,
styleOverrides: {
root: {
...bodyFontDeclaration,
- textTransform: "uppercase",
- borderRadius: "20px",
+ display: "flex",
+ alignItems: "center",
+ border: "none",
+ cursor: "pointer",
+ fontSize: "0.9375rem",
+ justifyContent: "center",
+ lineHeight: "0.9375rem",
+ margin: 0,
+ padding: 0,
+ transitionDuration: "0.1s",
+ transitionProperty: "all",
+ minHeight: "44px",
+ position: "relative",
+ textDecoration: "none",
+ },
+ contained: {
+ backgroundColor: theme.palette.common.brand.main,
+ color: theme.palette.common.grayscale.white,
+ "&::after": {
+ content: '""',
+ display: "block",
+ borderBottom: `2px solid ${theme.palette.common.additional.skyblue}`,
+ position: "absolute",
+ bottom: "-3.5px",
+ left: "3px",
+ right: "3px",
+ zIndex: 0,
+ },
+ "&:disabled": {
+ cursor: "not-allowed",
+ "&::after": {
+ borderBottom: `2px solid ${theme.palette.common.grayscale.mediumDark}`,
+ bottom: "-3.5px",
+ },
+ },
+ },
+ containedPrimary: {
+ backgroundColor: theme.palette.common.brand.main,
+ color: theme.palette.common.grayscale.white,
+ svg: {
+ fill: theme.palette.common.grayscale.white,
+ },
+ "&:hover": {
+ backgroundColor: theme.palette.common.brand.active,
+ },
+ "&:active": {
+ backgroundColor: theme.palette.common.brand.dark,
+ },
+ "&:disabled": {
+ backgroundColor: theme.palette.common.grayscale.medium,
+ color: theme.palette.common.grayscale.dark,
+ svg: {
+ fill: theme.palette.common.grayscale.dark,
+ },
+ "&::after": {
+ bottom: "-2px",
+ },
+ },
+ "&:focus": {
+ outline: `solid 2px ${theme.palette.common.additional.yellow.main}`,
+ outlineOffset: "2px",
+ },
+ "&::after": {
+ bottom: "-2px",
+ },
+ },
+ containedSecondary: {
+ backgroundColor: "transparent",
+ border: `solid 2px ${theme.palette.common.brand.main}`,
+ color: theme.palette.common.brand.main,
+ ".svg": {
+ fill: theme.palette.common.brand.main,
+ },
+ "&:hover": {
+ border: `solid 2px ${theme.palette.common.brand.active}`,
+ color: theme.palette.common.brand.active,
+ svg: {
+ fill: theme.palette.common.brand.active,
+ },
+ },
+ "&:active": {
+ border: `solid 2px ${theme.palette.common.brand.dark}`,
+ color: theme.palette.common.brand.dark,
+ svg: {
+ fill: theme.palette.common.brand.dark,
+ },
+ },
+ "&:disabled": {
+ border: `solid 2px ${theme.palette.common.grayscale.mediumDark}`,
+ color: theme.palette.common.grayscale.mediumDark,
+ svg: {
+ fill: theme.palette.common.grayscale.mediumDark,
+ },
+ },
+ },
+ text: {
+ textTransform: "none",
+ backgroundColor: "transparent",
+ fontSize: "1rem",
+ fontWeight: "700",
+ letterSpacing: "-0.3px",
+ padding: "16px",
+ position: "fixed",
+ right: "16px",
+ top: "12px",
+ marginLeft: "auto",
+ marginRight: "-16px",
+ alignItems: "center",
+ display: "inline-flex",
+
+ svg: {
+ marginLeft: "8px",
+ },
+ "&::after": {
+ border: "none",
+ },
+ "&:hover": {
+ backgroundColor: "transparent",
+ },
+ },
+ textPrimary: {
+ color: theme.palette.common.brand.main,
+ svg: {
+ fill: theme.palette.common.brand.main,
+ },
+ },
+ },
+ },
+ MuiAppBar: {
+ styleOverrides: {
+ root: {
+ backgroundColor: theme.palette.common.grayscale.white,
+ zIndex: 100,
+ borderBottom: `2px solid ${theme.palette.common.grayscale.dark}`,
+ transform: "none",
+ [theme.breakpoints.up("lg")]: {
+ borderBottom: `1px solid ${theme.palette.common.grayscale.black}`,
+ margin: "0 auto",
+ maxWidth: "1920px",
+ },
+ },
+ },
+ },
+ MuiToolbar: {
+ styleOverrides: {
+ root: {
+ padding: "0 8px",
+ display: "flex",
+ justifyContent: "space-between",
+ [theme.breakpoints.up("lg")]: {
+ padding: "0 32px",
+ },
},
},
},
},
- })
+ } as Partial)
diff --git a/frontend/src/newTheme/fonts.tsx b/frontend/src/newTheme/fonts.tsx
index b4847ea32..0cf483c70 100644
--- a/frontend/src/newTheme/fonts.tsx
+++ b/frontend/src/newTheme/fonts.tsx
@@ -11,7 +11,7 @@ export const headerFont = Open_Sans({
})
export const bodyFont = Open_Sans({
- weight: ["400", "700"],
+ weight: ["400", "600", "700"],
style: ["normal", "italic"],
fallback: ["Helvetica", "Arial", "sans-serif"],
display: "swap",
diff --git a/frontend/src/newTheme/index.tsx b/frontend/src/newTheme/index.tsx
index 68c7205ec..c38cb8ac5 100644
--- a/frontend/src/newTheme/index.tsx
+++ b/frontend/src/newTheme/index.tsx
@@ -16,7 +16,7 @@ let theme = createTheme({
xxs: 360,
xs: 480,
sm: 640,
- md: 900,
+ md: 960,
desktop: 1024,
lg: 1200,
xl: 1536,
diff --git a/frontend/src/newTheme/palette.tsx b/frontend/src/newTheme/palette.tsx
index 3f3c53685..51e14c853 100644
--- a/frontend/src/newTheme/palette.tsx
+++ b/frontend/src/newTheme/palette.tsx
@@ -1,4 +1,3 @@
-import { amber } from "@mui/material/colors"
import { createTheme, Theme } from "@mui/material/styles"
export const withPalette = (theme: Theme) =>
@@ -6,10 +5,60 @@ export const withPalette = (theme: Theme) =>
...theme,
palette: {
primary: {
- main: "#378170",
+ main: "#0e688b",
},
secondary: {
- main: amber[500],
+ main: "#fff",
+ },
+ common: {
+ brand: {
+ main: "#0e688b",
+ soft: "#b1e7ff",
+ bright: "#48c5f8",
+ light: "#107eab",
+ active: "#005379",
+ dark: "#003146",
+ nearlyBlack: "#000222",
+ },
+ grayscale: {
+ white: "#fff",
+ slightlyGray: "#fefefe",
+ light: "#f8f8f8",
+ medium: "#d2d2d2",
+ backgroundBox: "#f5f5f5",
+ tabsBorder: "#e6e6e6",
+ backgroundArrow: "#dfdfdf",
+ mediumDark: "#979797",
+ dark: "#555555",
+ darkText: "#222222",
+ black: "#000",
+ },
+ additional: {
+ red: {
+ light: "#e5053a",
+ dark: "#a31621",
+ },
+ purple: {
+ light: "#420039",
+ },
+ yellow: {
+ light: "#f9a21a",
+ main: "#c47f1b",
+ },
+ skyblue: "#48c5f8",
+ orange: "#d14600",
+ green: {
+ light: "#96ba3c",
+ dark: "#006400",
+ },
+ },
+ link: {
+ blue: "#0479a4",
+ disabled: "#767676",
+ },
+ hover: {
+ gray: "#eaeaea",
+ },
},
blue: {
light3: "#DAE3EB",
diff --git a/frontend/translations/common/en.ts b/frontend/translations/common/en.ts
index b6c3e605b..020eb316f 100644
--- a/frontend/translations/common/en.ts
+++ b/frontend/translations/common/en.ts
@@ -77,8 +77,8 @@ export default {
ukraineHyText:
"Support students and researchers affected by the invasion of Ukraine",
ukraineHyLinkText: "University of Helsinki Ukraine appeal",
- fi: "Suomeksi",
- en: "In English",
+ fi: "Suomi",
+ en: "English",
selectAll: "Select all",
unscheduled: "Indefinitely open",
showCourse: "Show course",
@@ -108,4 +108,5 @@ export default {
difficulty: "Difficulty",
module: "Module",
courseOtherLanguages: "Also available in",
+ hy: "University of Helsinki",
} as const
diff --git a/frontend/translations/common/fi.ts b/frontend/translations/common/fi.ts
index c311f6a6d..2ec9b0f2e 100644
--- a/frontend/translations/common/fi.ts
+++ b/frontend/translations/common/fi.ts
@@ -77,8 +77,8 @@ export default {
"https://www.helsinki.fi/fi/yhteistyo/lahjoittajille/ukraina-kerays",
ukraineHyLinkText:
"Lahjoita Ukraina‑keräykseen opiskelijoiden ja tutkijoiden tueksi",
- fi: "Suomeksi",
- en: "In English",
+ fi: "Suomi",
+ en: "English",
selectAll: "Valitse kaikki",
unscheduled: "Aikatauluton",
showCourse: "Näytä kurssi",
@@ -108,4 +108,5 @@ export default {
difficulty: "Vaikeustaso",
module: "Kokonaisuus",
courseOtherLanguages: "Saatavilla myös kielillä",
+ hy: "Helsingin yliopisto",
} as const
diff --git a/frontend/translations/common/se.ts b/frontend/translations/common/se.ts
index 28fec9484..0bac7ff54 100644
--- a/frontend/translations/common/se.ts
+++ b/frontend/translations/common/se.ts
@@ -109,4 +109,5 @@ export default {
difficulty: "Difficulty",
module: "Module",
courseOtherLanguages: "Also available in",
+ hy: "Helsingfors universitet",
} as const
diff --git a/frontend/types/mui.d.ts b/frontend/types/mui.d.ts
index 7cbbf5321..3940ebad3 100644
--- a/frontend/types/mui.d.ts
+++ b/frontend/types/mui.d.ts
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/ban-types */
import { LinkProps as NextLinkProps } from "next/link"
+import { ListItemButtonTypeMap } from "@mui/material"
import { ButtonTypeMap } from "@mui/material/Button"
import { ButtonBaseTypeMap, ExtendButtonBase } from "@mui/material/ButtonBase"
import { LinkTypeMap } from "@mui/material/Link"
@@ -84,6 +85,27 @@ declare module "@mui/material/MenuItem" {
>
}
+declare module "@mui/material/ListItemButton" {
+ export type EnhancedListItemButtonProps<
+ RootComponent extends
+ React.ElementType = ListItemButtonTypeMap["defaultComponent"],
+ AdditionalProps = {},
+ > = OverrideProps<
+ ListItemButtonTypeMap<
+ AdditionalProps & Partial,
+ RootComponent
+ >,
+ RootComponent
+ > & { component?: React.ElementType }
+ export type EnhancedListItemButton<
+ D extends React.ElementType = ButtonTypeMap["defaultComponent"],
+ P = {},
+ > = ExtendButtonBase, D>>
+ const ListItemButton: ExtendButtonBase<
+ ListItemButtonTypeMap>
+ >
+}
+
declare module "@mui/material/Typography" {
// add typography variants - also needs to be declared in "styles"
interface TypographyPropsVariantOverrides {
@@ -164,7 +186,6 @@ declare module "@mui/material/styles" {
dark2?: string
dark3?: string
}
-
//
interface ComponentNameToClassKey {
@@ -219,3 +240,56 @@ declare module "@mui/material/styles" {
}
}
}
+
+declare module "@mui/material/styles/createPalette" {
+ interface CommonColors {
+ brand: {
+ main: string
+ soft: string
+ bright: string
+ light: string
+ active: string
+ dark: string
+ nearlyBlack: string
+ }
+ link: {
+ blue: string
+ disabled: string
+ }
+ grayscale: {
+ white: string
+ slightlyGray: string
+ light: string
+ medium: string
+ backgroundBox: string
+ tabsBorder: string
+ backgroundArrow: string
+ mediumDark: string
+ dark: string
+ darkText: string
+ black: string
+ }
+ additional: {
+ red: {
+ light: string
+ dark: string
+ }
+ purple: {
+ light: string
+ }
+ yellow: {
+ light: string
+ main: string
+ }
+ skyblue: string
+ orange: string
+ green: {
+ light: string
+ dark: string
+ }
+ }
+ hover: {
+ gray: string
+ }
+ }
+}