feat(SW-187): Fixed LanguageSwitcher for footer

This commit is contained in:
Pontus Dreij
2024-09-05 14:30:33 +02:00
parent 05ee4d1717
commit 6d55ee7595
13 changed files with 136 additions and 54 deletions

View File

@@ -65,5 +65,6 @@
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
gap: var(--Spacing-x4);
}
}

View File

@@ -6,8 +6,6 @@ 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"
@@ -22,11 +20,12 @@ function SocialIcon({ iconName }: SocialIconsProps) {
export default async function FooterDetails({
socialMedia,
tertiaryLinks,
languageUrls,
}: FooterDetailsProps) {
const lang = getLang()
const { formatMessage } = await getIntl()
const currentYear = new Date().getFullYear()
const { languageSwitcher } = footer
return (
<section className={styles.details}>
<div className={styles.topContainer}>
@@ -85,7 +84,9 @@ export default async function FooterDetails({
)
)}
</nav>
<LanguageSwitcher type="desktopFooter" urls={languageSwitcher.urls} />
{languageUrls && (
<LanguageSwitcher type="footer" urls={languageUrls} />
)}
</div>
</div>
</section>

View File

@@ -22,7 +22,7 @@
justify-content: space-between;
}
@media screen and (min-width: 767px) {
@media screen and (min-width: 1367px) {
.mainNavigation {
max-width: 360px;
}

View File

@@ -27,8 +27,14 @@
@media screen and (min-width: 767px) {
.secondaryNavigation {
margin-top: 0;
gap: 80px;
margin-top: var(--Spacing-x4);
gap: 120px;
flex-direction: row;
}
}
@media screen and (min-width: 1367px) {
.secondaryNavigation {
margin-top: 0;
gap: 80px;
}
}

View File

@@ -13,10 +13,7 @@
@media screen and (min-width: 767px) {
.section {
padding: var(--Spacing-x9) var(--Spacing-x6);
}
.maxWidth {
flex-direction: row;
padding: var(--Spacing-x9) var(--Spacing-x5);
}
}
@@ -24,4 +21,7 @@
.section {
padding: var(--Spacing-x9) 0;
}
.maxWidth {
flex-direction: row;
}
}

View File

@@ -9,7 +9,9 @@ export default async function Footer() {
const footerData = await serverClient().contentstack.base.footer({
lang: getLang(),
})
if (!footerData) {
const languages = await serverClient().contentstack.languageSwitcher.get()
if (!footerData || !languages) {
return <FooterDetails />
}
return (
@@ -22,6 +24,7 @@ export default async function Footer() {
<FooterDetails
socialMedia={footerData.socialMedia}
tertiaryLinks={footerData.tertiaryLinks}
languageUrls={languages.urls}
/>
</footer>
)

View File

@@ -25,7 +25,7 @@ export default function MobileMenu({
const {
isHamburgerMenuOpen,
isMyPagesMobileMenuOpen,
isLanguageSwitcherOpen,
isHeaderLanguageSwitcherOpen,
toggleHamburgerMenu,
toggleMyPagesMobileMenu,
toggleLanguageSwitcher,
@@ -41,8 +41,8 @@ export default function MobileMenu({
if (isMyPagesMobileMenuOpen) {
toggleMyPagesMobileMenu()
} else {
if (isLanguageSwitcherOpen) {
toggleLanguageSwitcher()
if (isHeaderLanguageSwitcherOpen) {
toggleLanguageSwitcher("header")
}
toggleHamburgerMenu()

View File

@@ -24,6 +24,7 @@ export default function LanguageSwitcherContent({
const { toggleLanguageSwitcher } = useDropdownStore()
const languageSwitcherRef = useTrapFocus()
const urlKeys = Object.keys(urls) as Lang[]
const position = type === "footer" ? "footer" : "header"
return (
<div className={styles.languageSwitcherContent} ref={languageSwitcherRef}>
@@ -32,7 +33,7 @@ export default function LanguageSwitcherContent({
<button
type="button"
className={styles.backButton}
onClick={toggleLanguageSwitcher}
onClick={() => toggleLanguageSwitcher(position)}
>
<ChevronLeftIcon color="red" />
<Subtitle type="one">Main Menu</Subtitle>

View File

@@ -10,6 +10,7 @@ import { useHandleKeyUp } from "@/hooks/useHandleKeyUp"
import useLang from "@/hooks/useLang"
import LanguageSwitcherContent from "./LanguageSwitcherContent"
import { languageSwitcherVariants } from "./variants"
import styles from "./languageSwitcher.module.css"
@@ -21,16 +22,29 @@ export default function LanguageSwitcher({
}: LanguageSwitcherProps) {
const intl = useIntl()
const currentLanguage = useLang()
const { toggleLanguageSwitcher, isLanguageSwitcherOpen } = useDropdownStore()
const {
toggleLanguageSwitcher,
isHeaderLanguageSwitcherOpen,
isFooterLanguageSwitcherOpen,
} = useDropdownStore()
const position = type === "footer" ? "footer" : "header"
const color = type === "footer" ? "pale" : "burgundy"
const isLanguageSwitcherOpen =
type === "footer"
? isFooterLanguageSwitcherOpen
: isHeaderLanguageSwitcherOpen
useHandleKeyUp((event: KeyboardEvent) => {
if (event.key === "Escape" && isLanguageSwitcherOpen) {
toggleLanguageSwitcher()
toggleLanguageSwitcher(position)
}
})
const classNames = languageSwitcherVariants({ color, position })
return (
<div className={styles.languageSwitcher}>
<div className={classNames}>
<button
type="button"
className={styles.button}
@@ -39,15 +53,15 @@ export default function LanguageSwitcher({
? "Close language menu"
: "Open language menu",
})}
onClick={toggleLanguageSwitcher}
onClick={() => toggleLanguageSwitcher(position)}
>
<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",
},
},
})

View File

@@ -6,18 +6,20 @@ interface DropdownState {
isHamburgerMenuOpen: boolean
isMyPagesMobileMenuOpen: boolean
isMyPagesMenuOpen: boolean
isLanguageSwitcherOpen: boolean
isHeaderLanguageSwitcherOpen: boolean
isFooterLanguageSwitcherOpen: boolean
toggleHamburgerMenu: () => void
toggleMyPagesMobileMenu: () => void
toggleMyPagesMenu: () => void
toggleLanguageSwitcher: () => void
toggleLanguageSwitcher: (location: "header" | "footer") => void
}
const useDropdownStore = create<DropdownState>((set) => ({
isHamburgerMenuOpen: false,
isMyPagesMobileMenuOpen: false,
isMyPagesMenuOpen: false,
isLanguageSwitcherOpen: false,
isHeaderLanguageSwitcherOpen: false,
isFooterLanguageSwitcherOpen: false,
toggleHamburgerMenu: () =>
set(
({ isHamburgerMenuOpen, isMyPagesMenuOpen, isMyPagesMobileMenuOpen }) => {
@@ -39,7 +41,8 @@ const useDropdownStore = create<DropdownState>((set) => ({
isMyPagesMenuOpen,
isMyPagesMobileMenuOpen,
isHamburgerMenuOpen,
isLanguageSwitcherOpen,
isHeaderLanguageSwitcherOpen,
isFooterLanguageSwitcherOpen,
}) => {
// Close the other dropdowns if they're open
if (!isMyPagesMobileMenuOpen) {
@@ -49,8 +52,11 @@ const useDropdownStore = create<DropdownState>((set) => ({
if (isHamburgerMenuOpen) {
set({ isHamburgerMenuOpen: false })
}
if (isLanguageSwitcherOpen) {
set({ isLanguageSwitcherOpen: false })
if (isHeaderLanguageSwitcherOpen) {
set({ isHeaderLanguageSwitcherOpen: false })
}
if (isFooterLanguageSwitcherOpen) {
set({ isFooterLanguageSwitcherOpen: false })
}
}
return { isMyPagesMobileMenuOpen: !isMyPagesMobileMenuOpen }
@@ -60,7 +66,8 @@ const useDropdownStore = create<DropdownState>((set) => ({
set(
({
isHamburgerMenuOpen,
isLanguageSwitcherOpen,
isHeaderLanguageSwitcherOpen,
isFooterLanguageSwitcherOpen,
isMyPagesMenuOpen,
isMyPagesMobileMenuOpen,
}) => {
@@ -72,32 +79,40 @@ const useDropdownStore = create<DropdownState>((set) => ({
if (isMyPagesMobileMenuOpen) {
set({ isMyPagesMobileMenuOpen: false })
}
if (isLanguageSwitcherOpen) {
set({ isLanguageSwitcherOpen: false })
if (isHeaderLanguageSwitcherOpen) {
set({ isHeaderLanguageSwitcherOpen: false })
}
if (isFooterLanguageSwitcherOpen) {
set({ isFooterLanguageSwitcherOpen: false })
}
}
return { isMyPagesMenuOpen: !isMyPagesMenuOpen }
}
),
toggleLanguageSwitcher: () =>
set(
({
isLanguageSwitcherOpen,
isMyPagesMenuOpen,
isMyPagesMobileMenuOpen,
}) => {
// Close the other dropdowns if they're open
if (!isLanguageSwitcherOpen) {
if (isMyPagesMenuOpen) {
set({ isMyPagesMenuOpen: false })
}
if (isMyPagesMobileMenuOpen) {
set({ isMyPagesMobileMenuOpen: false })
}
toggleLanguageSwitcher: (location: "header" | "footer") =>
set((state) => {
const isCurrentlyOpen =
location === "header"
? state.isHeaderLanguageSwitcherOpen
: state.isFooterLanguageSwitcherOpen
if (!isCurrentlyOpen) {
return {
isHeaderLanguageSwitcherOpen: location === "header",
isFooterLanguageSwitcherOpen: location === "footer",
isMyPagesMenuOpen: false,
isMyPagesMobileMenuOpen: false,
isHamburgerMenuOpen: false,
}
return { isLanguageSwitcherOpen: !isLanguageSwitcherOpen }
}
),
return {
isHeaderLanguageSwitcherOpen:
location === "header" ? false : state.isHeaderLanguageSwitcherOpen,
isFooterLanguageSwitcherOpen:
location === "footer" ? false : state.isFooterLanguageSwitcherOpen,
}
}),
}))
export default useDropdownStore

View File

@@ -1,6 +1,6 @@
import { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
export interface LanguageSwitcherProps {
type: "mobileHeader" | "mobileFooter" | "desktopHeader" | "desktopFooter"
type: "mobileHeader" | "desktopHeader" | "footer"
urls: LanguageSwitcherData
}