Merged in feat/sw-187-footer-content-stack (pull request #565)

Feat/sw 187 footer content stack

Approved-by: Erik Tiekstra
Approved-by: Matilda Landström
This commit is contained in:
Pontus Dreij
2024-09-12 07:11:25 +00:00
63 changed files with 1350 additions and 521 deletions

View File

@@ -8,7 +8,7 @@ import Navigation from "./Navigation"
import styles from "./footer.module.css"
export default async function Footer() {
const footerData = await serverClient().contentstack.base.footer({
const footerData = await serverClient().contentstack.base.currentFooter({
lang: getLang(),
})
if (!footerData) {

View File

@@ -18,6 +18,7 @@ import LoginButton from "../LoginButton"
import styles from "./mainMenu.module.css"
import type { MainMenuProps } from "@/types/components/current/header/mainMenu"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
export function MainMenu({
frontpageLinkText,
@@ -61,12 +62,8 @@ export function MainMenu({
"/sv/current-content-page",
].includes(pathname)
const {
isHamburgerMenuOpen,
isMyPagesMobileMenuOpen,
toggleHamburgerMenu,
toggleMyPagesMobileMenu,
} = useDropdownStore()
const { toggleDropdown, isMyPagesMobileMenuOpen, isHamburgerMenuOpen } =
useDropdownStore()
function handleMyPagesMobileMenuClick() {
// Only track click when opening it
@@ -74,7 +71,7 @@ export function MainMenu({
trackClick("profile picture icon")
}
toggleMyPagesMobileMenu()
toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)
}
return (
@@ -89,7 +86,7 @@ export function MainMenu({
<button
aria-pressed="false"
className={`${styles.expanderBtn} ${isHamburgerMenuOpen ? styles.expanded : ""}`}
onClick={toggleHamburgerMenu}
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
type="button"
>
<span className={styles.iconBars}></span>

View File

@@ -13,6 +13,8 @@ import useLang from "@/hooks/useLang"
import styles from "./my-pages-mobile-dropdown.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
type Navigation = Awaited<ReturnType<(typeof navigationQueryRouter)["get"]>>
export default function MyPagesMobileDropdown({
@@ -22,8 +24,7 @@ export default function MyPagesMobileDropdown({
}) {
const { formatMessage } = useIntl()
const lang = useLang()
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
useDropdownStore()
const { toggleDropdown, isMyPagesMobileMenuOpen } = useDropdownStore()
if (!navigation) {
return null
@@ -51,7 +52,9 @@ export default function MyPagesMobileDropdown({
size={menuItem.display_sign_out_link ? "small" : "regular"}
variant="myPageMobileDropdown"
color="burgundy"
onClick={toggleMyPagesMobileMenu}
onClick={() =>
toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)
}
>
{link.linkText}
</Link>

View File

@@ -52,7 +52,7 @@
gap: var(--Spacing-x1);
}
@media screen and (min-width: 1367px) {
@media screen and (min-width: 767px) {
.details {
padding: var(--Spacing-x6) var(--Spacing-x5) var(--Spacing-x4);
}
@@ -65,5 +65,6 @@
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
gap: var(--Spacing-x4);
}
}

View File

@@ -1,14 +1,14 @@
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
import { getIconByIconName } from "@/components/Icons/get-icon-by-icon-name"
import Image from "@/components/Image"
import LanguageSwitcher from "@/components/LanguageSwitcher"
import Link from "@/components/TempDesignSystem/Link"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import { footer } from "../mockedData"
import styles from "./details.module.css"
import type { FooterDetailsProps } from "@/types/components/footer/navigation"
import type { SocialIconsProps } from "@/types/components/footer/socialIcons"
import { IconName } from "@/types/components/icon"
@@ -17,16 +17,15 @@ function SocialIcon({ iconName }: SocialIconsProps) {
return SocialIcon ? <SocialIcon color="white" /> : <span>{iconName}</span>
}
export default function FooterDetails() {
export default async function FooterDetails({
socialMedia,
tertiaryLinks,
languageUrls,
}: FooterDetailsProps) {
const lang = getLang()
const { formatMessage } = await getIntl()
const currentYear = new Date().getFullYear()
const {
socialMedia,
copyrightCompany,
copyrightInfo,
tertiaryLinks,
languageSwitcher,
} = footer
return (
<section className={styles.details}>
<div className={styles.topContainer}>
@@ -43,48 +42,51 @@ export default function FooterDetails() {
/>
</Link>
<nav className={styles.socialNav}>
{socialMedia.links.map((link) => (
<a
className={styles.socialLink}
color="white"
href={link.href}
key={link.id}
target="_blank"
aria-label={link.title}
>
<SocialIcon iconName={link.title} />
</a>
))}
{socialMedia?.links.map(
(link) =>
link.href && (
<a
className={styles.socialLink}
color="white"
href={link.href.href}
key={link.href.title}
target="_blank"
aria-label={link.href.title}
>
<SocialIcon iconName={link.href.title} />
</a>
)
)}
</nav>
</div>
<div className={styles.bottomContainer}>
<div className={styles.copyrightContainer}>
<Footnote textTransform="uppercase">
© {currentYear} {copyrightCompany}
</Footnote>
<Footnote textTransform="uppercase" color="peach50">
{copyrightInfo}
© {currentYear}{" "}
{formatMessage({ id: "Copyright all rights reserved" })}
</Footnote>
</div>
<div className={styles.navigationContainer}>
<nav className={styles.navigation}>
{tertiaryLinks.map((link) => (
<Footnote asChild textTransform="uppercase" key={link.id}>
<Link
className={styles.link}
color="peach50"
href={link.href}
target="_blank"
>
{link.title}
</Link>
</Footnote>
))}
{tertiaryLinks?.map(
(link) =>
link.url && (
<Footnote asChild textTransform="uppercase" key={link.title}>
<Link
className={styles.link}
color="peach50"
href={link.url}
target="_blank"
>
{link.title}
</Link>
</Footnote>
)
)}
</nav>
{
// This will be changed to the new LangueSwitcher that is done in the header branch, when implementing contentstack
}
<LanguageSwitcher urls={languageSwitcher.urls} />
{languageUrls && (
<LanguageSwitcher type="footer" urls={languageUrls} />
)}
</div>
</div>
</section>

View File

@@ -11,11 +11,11 @@ export default function FooterMainNav({ mainLinks }: FooterMainNavProps) {
<nav className={styles.mainNavigation}>
<ul className={styles.mainNavigationList}>
{mainLinks.map((link) => (
<li key={link.id} className={styles.mainNavigationItem}>
<li key={link.title} className={styles.mainNavigationItem}>
<Subtitle type="two" asChild>
<Link
color="burgundy"
href={link.href}
href={link.url}
className={styles.mainNavigationLink}
>
{link.title}

View File

@@ -1,60 +1,78 @@
import Image from "@/components/Image"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import { getLang } from "@/i18n/serverContext"
import styles from "./secondarynav.module.css"
import {
AppDownLoadLinks,
type FooterSecondaryNavProps,
} from "@/types/components/footer/navigation"
import { AppDownLoadLinks } from "@/types/components/footer/appDownloadIcons"
import { type FooterSecondaryNavProps } from "@/types/components/footer/navigation"
export default function FooterSecondaryNav({
secondaryLinks,
appDownloads,
}: FooterSecondaryNavProps) {
const lang = getLang()
return (
<div className={styles.secondaryNavigation}>
<nav className={styles.secondaryNavigationGroup}>
<Body color="peach80" textTransform="uppercase">
{appDownloads.title}
</Body>
<ul className={styles.secondaryNavigationList}>
{appDownloads.links.map((link) => (
<li key={link.id} className={styles.appDownloadItem}>
<a href={link.href} target="_blank" aria-label={link.title}>
<Image
src={
AppDownLoadLinks[link.id as keyof typeof AppDownLoadLinks]
}
alt={link.title}
width={125}
height={40}
/>
</a>
</li>
))}
</ul>
</nav>
{appDownloads && (
<nav className={styles.secondaryNavigationGroup}>
<Body color="peach80" textTransform="uppercase">
{appDownloads.title}
</Body>
<ul className={styles.secondaryNavigationList}>
{appDownloads.links.map(
(link) =>
link.href && (
<li key={link.type} className={styles.appDownloadItem}>
<a
href={link.href.href}
target="_blank"
aria-label={link.href.title}
>
<Image
src={
AppDownLoadLinks[
`${link.type}_${lang}` as keyof typeof AppDownLoadLinks
]
}
alt=""
width={125}
height={40}
/>
</a>
</li>
)
)}
</ul>
</nav>
)}
{secondaryLinks.map((link) => (
<nav className={styles.secondaryNavigationGroup} key={link.title}>
<Body color="peach80" textTransform="uppercase">
{link.title}
</Body>
<ul className={styles.secondaryNavigationList}>
{link.links.map((link) => (
<li key={link.id} className={styles.secondaryNavigationItem}>
{link?.links?.map((link) => (
<li key={link.title} className={styles.secondaryNavigationItem}>
{link.isExternal ? (
<a
href={link.href}
href={link.url}
key={link.title}
target={link.openInNewTab ? "_blank" : "_self"}
aria-label={link.title}
className={styles.secondaryNavigationLink}
>
{link.title}
</a>
) : (
<Link href={link.href} key={link.title}>
<Link
href={link.url}
key={link.title}
target={link.openInNewTab ? "_blank" : "_self"}
color="burgundy"
>
{link.title}
</Link>
)}

View File

@@ -25,10 +25,24 @@
margin: 0;
}
.secondaryNavigationLink {
color: var(--Base-Text-High-contrast);
font-weight: var(--typography-Body-Bold-fontWeight);
font-family: var(--typography-Body-Bold-fontFamily);
margin: 0;
text-decoration: none;
}
@media screen and (min-width: 767px) {
.secondaryNavigation {
margin-top: var(--Spacing-x4);
gap: 120px;
flex-direction: row;
}
}
@media screen and (min-width: 1367px) {
.secondaryNavigation {
margin-top: 0;
gap: 80px;
flex-direction: row;
}
}

View File

@@ -1,11 +1,15 @@
import { footer } from "../mockedData"
import FooterMainNav from "./MainNav"
import FooterSecondaryNav from "./SecondaryNav"
import styles from "./navigation.module.css"
export default function FooterNavigation() {
const { mainLinks, secondaryLinks, appDownloads } = footer
import type { FooterNavigationProps } from "@/types/components/footer/navigation"
export default function FooterNavigation({
mainLinks,
secondaryLinks,
appDownloads,
}: FooterNavigationProps) {
return (
<section className={styles.section}>
<div className={styles.maxWidth}>

View File

@@ -11,6 +11,12 @@
max-width: var(--max-width-content);
}
@media screen and (min-width: 767px) {
.section {
padding: var(--Spacing-x9) var(--Spacing-x5);
}
}
@media screen and (min-width: 1367px) {
.section {
padding: var(--Spacing-x9) 0;

View File

@@ -1,11 +1,27 @@
import { serverClient } from "@/lib/trpc/server"
import FooterDetails from "./Details"
import FooterNavigation from "./Navigation"
export default function Footer() {
export default async function Footer() {
const footerData = await serverClient().contentstack.base.footer()
const languages = await serverClient().contentstack.languageSwitcher.get()
if (!footerData || !languages) {
return <FooterDetails />
}
return (
<footer>
<FooterNavigation />
<FooterDetails />
<FooterNavigation
mainLinks={footerData.mainLinks}
secondaryLinks={footerData.secondaryLinks}
appDownloads={footerData.appDownloads}
/>
<FooterDetails
socialMedia={footerData.socialMedia}
tertiaryLinks={footerData.tertiaryLinks}
languageUrls={languages.urls}
/>
</footer>
)
}

View File

@@ -1,192 +0,0 @@
export const footer = {
mainLinks: [
{
title: "Travel guides",
href: "/travel-guides",
id: "travel-guides",
openInNewTab: false,
isExternal: false,
},
{
title: "New hotels",
href: "/new-hotels",
id: "new-hotels",
openInNewTab: false,
isExternal: false,
},
{
title: "Accessibililty",
href: "/accessibility",
id: "accessibility",
openInNewTab: false,
isExternal: false,
},
{
title: "Sustanability",
href: "/sustainability",
id: "sustainability",
openInNewTab: false,
isExternal: false,
},
],
appDownloads: {
title: "Scandic App",
links: [
{
title: "App Store",
href: "https://apps.apple.com/se/app/scandic-hotels/id1020208712",
id: "apple",
},
{
title: "Google Play",
href: "https://play.google.com/store/apps/details?id=com.scandichotels.scandichotels",
id: "google",
},
],
},
secondaryLinks: [
{
title: "Customer service",
links: [
{
title: "Contact us",
href: "/contact-us",
id: "contact-us",
openInNewTab: false,
isExternal: false,
},
{
title: "Frequntly asked questions",
href: "/frequently-asked-questions",
id: "frequently-asked-questions",
openInNewTab: false,
isExternal: false,
},
{
title: "Rates and policys",
href: "/rates-and-policies",
id: "rates-and-policies",
openInNewTab: false,
isExternal: false,
},
{
title: "Terms and conditions",
href: "/terms-and-conditions",
id: "terms-and-conditions",
openInNewTab: false,
isExternal: false,
},
],
},
{
title: "About Scandic Hotels",
links: [
{
title: "Scandic Group",
href: "/scandic-group",
id: "scandic-group",
openInNewTab: false,
isExternal: false,
},
{
title: "Investors",
href: "/investors",
id: "investors",
openInNewTab: false,
isExternal: false,
},
{
title: "Press",
href: "/press",
id: "press",
openInNewTab: false,
isExternal: false,
},
{
title: "Sponsors",
href: "/sponsors",
id: "sponsors",
openInNewTab: false,
isExternal: false,
},
{
title: "Partners",
href: "/partners",
id: "partners",
openInNewTab: false,
isExternal: false,
},
{
title: "Career",
href: "/career",
id: "career",
openInNewTab: false,
isExternal: false,
},
],
},
],
copyrightCompany: "Scandic AB",
copyrightInfo: "All rights reserved.",
socialMedia: {
links: [
{
title: "Facebook",
href: "https://www.facebook.com/scandichotels/",
id: "facebook",
},
{
title: "Instagram",
href: "https://www.instagram.com/scandichotels/",
id: "instagram",
},
{
title: "Tripadvisor",
href: "https://www.tripadvisor.com/Hotel_Review-g297628-d1020208712-Reviews-Scandic_Hotels-Stockholm_Sweden.html",
id: "tripadvisor",
},
],
},
tertiaryLinks: [
{
title: "Cookies",
href: "/cookies",
id: "cookies",
},
{
title: "Privacy policy",
href: "/privacy",
id: "privacy",
},
],
languageSwitcher: {
urls: {
da: {
url: "https://www.scandichotels.com/da",
isExternal: true,
},
de: {
url: "https://www.scandichotels.com/de",
isExternal: true,
},
en: {
url: "https://www.scandichotels.com/en",
isExternal: true,
},
fi: {
url: "https://www.scandichotels.com/fi",
isExternal: true,
},
no: {
url: "https://www.scandichotels.com/no",
isExternal: true,
},
sv: {
url: "https://www.scandichotels.com/sv",
isExternal: true,
},
},
},
}

View File

@@ -14,6 +14,7 @@ import NavigationMenu from "../NavigationMenu"
import styles from "./mobileMenu.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { MobileMenuProps } from "@/types/components/header/mobileMenu"
export default function MobileMenu({
@@ -23,37 +24,25 @@ export default function MobileMenu({
}: MobileMenuProps) {
const intl = useIntl()
const {
handleHamburgerClick,
toggleDropdown,
isHamburgerMenuOpen,
isMyPagesMobileMenuOpen,
isLanguageSwitcherOpen,
toggleHamburgerMenu,
toggleMyPagesMobileMenu,
toggleLanguageSwitcher,
isHeaderLanguageSwitcherMobileOpen,
isFooterLanguageSwitcherOpen,
} = useDropdownStore()
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isHamburgerMenuOpen) {
toggleHamburgerMenu()
toggleDropdown(DropdownTypeEnum.HamburgerMenu)
}
})
function handleHamburgerClick() {
if (isMyPagesMobileMenuOpen) {
toggleMyPagesMobileMenu()
} else {
if (isLanguageSwitcherOpen) {
toggleLanguageSwitcher()
}
toggleHamburgerMenu()
}
}
return (
<>
<button
type="button"
className={`${styles.hamburger} ${isHamburgerMenuOpen || isMyPagesMobileMenuOpen ? styles.isExpanded : ""}`}
className={`${styles.hamburger} ${isHamburgerMenuOpen || isMyPagesMobileMenuOpen || isFooterLanguageSwitcherOpen || isHeaderLanguageSwitcherMobileOpen ? styles.isExpanded : ""}`}
aria-label={intl.formatMessage({
id: isHamburgerMenuOpen ? "Close menu" : "Open menu",
})}
@@ -61,7 +50,10 @@ export default function MobileMenu({
>
<span className={styles.bar}></span>
</button>
<Modal className={styles.modal} isOpen={isHamburgerMenuOpen}>
<Modal
className={styles.modal}
isOpen={isHamburgerMenuOpen || isHeaderLanguageSwitcherMobileOpen}
>
<Dialog
className={styles.dialog}
aria-label={intl.formatMessage({ id: "Menu" })}

View File

@@ -7,7 +7,6 @@ import useDropdownStore from "@/stores/main-menu"
import { ChevronDownIcon } from "@/components/Icons"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
import useLang from "@/hooks/useLang"
import { getInitials } from "@/utils/user"
import Avatar from "../Avatar"
@@ -16,6 +15,7 @@ import MyPagesMenuContent from "../MyPagesMenuContent"
import styles from "./myPagesMenu.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { MyPagesMenuProps } from "@/types/components/header/myPagesMenu"
export default function MyPagesMenu({
@@ -24,18 +24,21 @@ export default function MyPagesMenu({
user,
}: MyPagesMenuProps) {
const intl = useIntl()
const lang = useLang()
const { toggleMyPagesMenu, isMyPagesMenuOpen } = useDropdownStore()
const { toggleDropdown, isMyPagesMenuOpen } = useDropdownStore()
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isMyPagesMenuOpen) {
toggleMyPagesMenu()
toggleDropdown(DropdownTypeEnum.MyPagesMenu)
}
})
return (
<div className={styles.myPagesMenu}>
<MainMenuButton className={styles.button} onClick={toggleMyPagesMenu}>
<MainMenuButton
className={styles.button}
onClick={() => toggleDropdown(DropdownTypeEnum.MyPagesMenu)}
>
<Avatar initials={getInitials(user.firstName, user.lastName)} />
<Subtitle type="two" className={styles.userName}>
{intl.formatMessage({ id: "Hi" })} {user.firstName}!
@@ -51,7 +54,9 @@ export default function MyPagesMenu({
navigation={navigation}
user={user}
membership={membership}
toggleOpenStateFn={toggleMyPagesMenu}
toggleOpenStateFn={() =>
toggleDropdown(DropdownTypeEnum.MyPagesMenu)
}
/>
</div>
) : null}

View File

@@ -14,6 +14,7 @@ import MyPagesMenuContent from "../MyPagesMenuContent"
import styles from "./myPagesMobileMenu.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { MyPagesMenuProps } from "@/types/components/header/myPagesMenu"
export default function MyPagesMobileMenu({
@@ -22,12 +23,11 @@ export default function MyPagesMobileMenu({
user,
}: MyPagesMenuProps) {
const intl = useIntl()
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
useDropdownStore()
const { isMyPagesMobileMenuOpen, toggleDropdown } = useDropdownStore()
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isMyPagesMobileMenuOpen) {
toggleMyPagesMobileMenu()
toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)
}
})
@@ -35,7 +35,7 @@ export default function MyPagesMobileMenu({
<div className={styles.myPagesMobileMenu}>
<MainMenuButton
className={styles.button}
onClick={toggleMyPagesMobileMenu}
onClick={() => toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)}
aria-label={intl.formatMessage({ id: "Open my pages menu" })}
>
<Avatar initials={getInitials(user.firstName, user.lastName)} />
@@ -49,7 +49,9 @@ export default function MyPagesMobileMenu({
membership={membership}
navigation={navigation}
user={user}
toggleOpenStateFn={toggleMyPagesMobileMenu}
toggleOpenStateFn={() =>
toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)
}
/>
</Dialog>
</Modal>

View File

@@ -13,6 +13,7 @@ import { useTrapFocus } from "@/hooks/useTrapFocus"
import styles from "./languageSwitcherContent.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { LanguageSwitcherProps } from "@/types/components/languageSwitcher/languageSwitcher"
export default function LanguageSwitcherContent({
@@ -21,9 +22,13 @@ export default function LanguageSwitcherContent({
}: LanguageSwitcherProps) {
const intl = useIntl()
const currentLanguage = useLang()
const { toggleLanguageSwitcher } = useDropdownStore()
const { toggleDropdown } = useDropdownStore()
const languageSwitcherRef = useTrapFocus()
const urlKeys = Object.keys(urls) as Lang[]
const position =
type === "footer"
? DropdownTypeEnum.FooterLanguageSwitcher
: DropdownTypeEnum.HamburgerMenu
return (
<div className={styles.languageSwitcherContent} ref={languageSwitcherRef}>
@@ -32,7 +37,7 @@ export default function LanguageSwitcherContent({
<button
type="button"
className={styles.backButton}
onClick={toggleLanguageSwitcher}
onClick={() => toggleDropdown(position)}
>
<ChevronLeftIcon color="red" />
<Subtitle type="one">Main Menu</Subtitle>

View File

@@ -10,9 +10,11 @@ import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
import useLang from "@/hooks/useLang"
import LanguageSwitcherContent from "./LanguageSwitcherContent"
import { languageSwitcherVariants } from "./variants"
import styles from "./languageSwitcher.module.css"
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
import type { LanguageSwitcherProps } from "@/types/components/languageSwitcher/languageSwitcher"
export default function LanguageSwitcher({
@@ -21,16 +23,37 @@ export default function LanguageSwitcher({
}: LanguageSwitcherProps) {
const intl = useIntl()
const currentLanguage = useLang()
const { toggleLanguageSwitcher, isLanguageSwitcherOpen } = useDropdownStore()
const {
toggleDropdown,
isFooterLanguageSwitcherOpen,
isHeaderLanguageSwitcherOpen,
isHeaderLanguageSwitcherMobileOpen,
} = useDropdownStore()
const position = type === "footer" ? "footer" : "header"
const color = type === "footer" ? "pale" : "burgundy"
const dropdownType = {
footer: DropdownTypeEnum.FooterLanguageSwitcher,
desktopHeader: DropdownTypeEnum.HeaderLanguageSwitcher,
mobileHeader: DropdownTypeEnum.HeaderLanguageSwitcherMobile,
}[type]
const isLanguageSwitcherOpen =
(type === "footer" && isFooterLanguageSwitcherOpen) ||
(type !== "footer" &&
(isHeaderLanguageSwitcherOpen || isHeaderLanguageSwitcherMobileOpen))
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isLanguageSwitcherOpen) {
toggleLanguageSwitcher()
toggleDropdown(dropdownType)
}
})
const classNames = languageSwitcherVariants({ color, position })
return (
<div className={styles.languageSwitcher}>
<div className={classNames}>
<button
type="button"
className={styles.button}
@@ -39,15 +62,15 @@ export default function LanguageSwitcher({
? "Close language menu"
: "Open language menu",
})}
onClick={toggleLanguageSwitcher}
onClick={() => toggleDropdown(dropdownType)}
>
<GlobeIcon width={20} height={20} color="burgundy" />
<GlobeIcon width={20} height={20} color={color} />
<span>{languages[currentLanguage]}</span>
<ChevronDownIcon
className={`${styles.chevron} ${isLanguageSwitcherOpen ? styles.isExpanded : ""}`}
width={20}
height={20}
color="burgundy"
color={color}
/>
</button>

View File

@@ -1,6 +1,5 @@
.button {
background-color: transparent;
color: var(--Base-Text-High-contrast);
font-family: var(--typography-Caption-Regular-fontFamily);
font-size: var(--typography-Caption-Regular-fontSize);
border-width: 0;
@@ -13,6 +12,14 @@
width: 100%;
}
.burgundy .button {
color: var(--Base-Text-High-contrast);
}
.pale .button {
color: var(--Primary-Dark-On-Surface-Text);
}
.chevron {
justify-self: end;
transition: transform 0.3s;
@@ -45,29 +52,43 @@
.dropdown {
position: absolute;
top: 2.25rem;
background-color: var(--Base-Surface-Primary-light-Normal);
border-radius: var(--Corner-radius-Large);
box-shadow: 0px 0px 14px 6px #0000001a;
display: none;
min-width: 12.5rem;
z-index: 1;
}
.top .dropdown {
top: 2.25rem;
bottom: auto;
}
/* Triangle above dropdown */
.top .dropdown::before {
top: -1.25rem;
transform: rotate(180deg);
}
/* Triangle dropdown */
.dropdown::before {
content: "";
position: absolute;
top: -1.25rem;
right: 2.4rem;
transform: rotate(180deg);
border-width: 0.75rem;
border-style: solid;
border-color: var(--Base-Surface-Primary-light-Normal) transparent
transparent transparent;
}
.bottom .dropdown {
top: auto;
bottom: 2.25rem;
}
.bottom .dropdown::before {
top: 100%;
}
.button {
grid-template-columns: repeat(3, max-content);
font-size: var(--typography-Body-Bold-fontSize);

View File

@@ -0,0 +1,20 @@
import { cva } from "class-variance-authority"
import styles from "./languageSwitcher.module.css"
export const languageSwitcherVariants = cva(styles.languageSwitcher, {
variants: {
color: {
burgundy: styles.burgundy,
pale: styles.pale,
},
position: {
header: styles.top,
footer: styles.bottom,
},
defaultVariants: {
color: "burgundy",
position: "top",
},
},
})