import React, { ReactNode, useState, useEffect } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { useTranslation } from "next-i18next"; import { useSession } from "next-auth/react"; import { Affix, Box, Button, ColorSchemeProvider, Group, MediaQuery, Menu, Transition, } from "@mantine/core"; import { NotificationsProvider } from "@mantine/notifications"; import { useWindowScroll } from "@mantine/hooks"; import { Icon, ICONS } from "vseth-canine-ui"; import { ApolloProvider } from "@apollo/client"; import apolloClient from "../lib/apollo"; import { makeVsethTheme, useConfig, VSETHExternalApp, VSETHThemeProvider, } from "vseth-canine-ui"; import hasAccess from "../utilities/hasAccess"; import LoginButton from "../components/loginButton"; import ThemeSwitcher from "../components/themeSwitcher"; export default function Navbar(props) { const router = useRouter(); const { locale, pathname, asPath, query } = router; const { t } = useTranslation("common"); const { data: session } = useSession(); const theme = makeVsethTheme(); const [selectedLanguage, setSelectedLanguage] = React.useState(locale); const [colorScheme, setColorScheme] = useState("light"); const toggleColorScheme = (value) => setColorScheme(value || (colorScheme === "dark" ? "light" : "dark")); theme.colorScheme = colorScheme; const [scroll, scrollTo] = useWindowScroll(); /* * VSETH Colors: See https://s.aschoch.ch/canine-colors * theme.colors.vsethMain[7] is #009fe3 (cyan) */ theme.colors.vsethMain[7] = "#244471"; theme.colors.vsethMain[0] = "#dee5ef"; // light color theme.colors.vsethMain[1] = "#b7cae5"; // light color theme.colors.vsethMain[8] = "#4f6d96"; // light color theme.colors.orange = [ "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", "#f28a20", ]; theme.fontSizes = { md: 17, }; // NOTE: This is a hack, as colors are hardcoded in vseth-canine useEffect(() => { const footerDiv = document.querySelector("footer>div"); const footerLogo = document.querySelector("footer img"); const selectItems = document.querySelector("header a"); if (colorScheme == "dark") { footerDiv.classList.add("vseth-footer-dark"); footerLogo.classList.add("vseth-logo-dark"); if (selectItems) selectItems.classList.add("vseth-text-dark"); } else { footerDiv.classList.remove("vseth-footer-dark"); footerLogo.classList.remove("vseth-logo-dark"); if (selectItems) selectItems.classList.remove("vseth-text-dark"); } }, [colorScheme]); const { data } = useConfig( "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/config.json" ); const customDemoNav = [ { title: t("bashGuide"), href: "/bash" }, { title: t("installGuide"), href: "/install" }, { title: t("courses"), href: "https://gitlab.ethz.ch/thealternative/courses", }, ]; const customNav = [ { title: ( <> <MediaQuery smallerThan="md" styles={{ display: "none" }}> <Menu shadow="md" width={200}> <Menu.Target> <Group> <span style={{ color: "#f28a20" }}>{t("guides")}</span> <Icon icon={ICONS.DOWN} color="#f28a20" /> </Group> </Menu.Target> <Menu.Dropdown> <Menu.Item> <Link style={{ textDecoration: "none" }} href="/bash"> {t("bashGuide")} </Link> </Menu.Item> <Menu.Item> <Link style={{ textDecoration: "none" }} href="/install"> {t("installGuide")} </Link> </Menu.Item> </Menu.Dropdown> </Menu> </MediaQuery> <MediaQuery largerThan="md" styles={{ display: "none" }}> <span style={{ color: "white" }}> <Link style={{ textDecoration: "none" }} href="/bash"> {t("bashGuide")} </Link> • <Link style={{ textDecoration: "none" }} href="/install"> {t("installGuide")} </Link> </span> </MediaQuery> </> ), href: "", }, { title: ( <a style={{ textDecoration: "none" }} target="_blank" href="https://gitlab.ethz.ch/thealternative/courses" > {t("courses")} </a> ), href: "", }, ]; return ( <React.StrictMode> <ColorSchemeProvider colorScheme={colorScheme} toggleColorScheme={toggleColorScheme} > <VSETHThemeProvider theme={theme}> <Box sx={(theme) => ({ main: { backgroundColor: theme.colorScheme === "dark" ? theme.colors.dark[8] : "white", }, })} > <VSETHExternalApp selectedLanguage={selectedLanguage} onLanguageSelect={(lang) => { setSelectedLanguage(lang); router.push({ pathname, query }, asPath, { locale: lang }); }} languages={data?.languages} title={ <> <MediaQuery largerThan="md" styles={{ display: "none" }}> <Link href="/"> <img style={{ maxWidth: "250px" }} src={ "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/logo-inv.svg" } /> </Link> </MediaQuery> <MediaQuery smallerThan="md" styles={{ display: "none" }}> <Link href="/"> <img style={{ maxWidth: "250px" }} src={ theme.colorScheme === "dark" ? "https://static.vseth.ethz.ch/assets/vseth-0522-thealt/logo-inv.svg" : "/images/logo.svg" } /> </Link> </MediaQuery> </> } appNav={customNav} organizationNav={data.externalNav} makeWrapper={(url, child) => <span>{child}</span>} privacyPolicy={data?.privacy} disclaimer={data?.copyright} //activeHref is the current active url path. Required to style the active page in the Nav activeHref={"/"} socialMedia={data?.socialMedia} logo={"/images/vseth_inv_nobyline.svg"} loginButton={ <Group> <ThemeSwitcher /> <LoginButton /> </Group> } signet={"/images/empty.svg"} size="xl" > <ApolloProvider client={apolloClient}> <NotificationsProvider>{props.children}</NotificationsProvider> </ApolloProvider> </VSETHExternalApp> </Box> <Affix position={{ bottom: 20, right: 20 }}> <Transition transition="slide-up" mounted={scroll.y > 0}> {(transitionStyles) => ( <Button leftIcon={<Icon icon={ICONS.UP} size={20} color="#f28a20" />} style={{ ...transitionStyles, color: "#f28a20" }} onClick={() => scrollTo({ y: 0 })} > {t("scrollToTop")} </Button> )} </Transition> </Affix> </VSETHThemeProvider> </ColorSchemeProvider> </React.StrictMode> ); }