From ca4521e4a13f4268fd9310cc898419512b3538c1 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Fri, 13 Sep 2024 09:37:00 +0200 Subject: [PATCH 1/3] feat(SW-378): Added close button to footer language switcher and made it slide up from below --- .../LanguageSwitcherContainer/index.tsx | 63 ++++++++++++++++ .../languageSwitcherContainer.module.css | 74 +++++++++++++++++++ .../LanguageSwitcherContent/index.tsx | 28 +------ .../languageSwitcherContent.module.css | 19 ----- components/LanguageSwitcher/index.tsx | 34 +++++++-- .../languageSwitcher.module.css | 34 +++++++-- i18n/dictionaries/da.json | 1 + i18n/dictionaries/de.json | 1 + i18n/dictionaries/en.json | 1 + i18n/dictionaries/fi.json | 1 + i18n/dictionaries/no.json | 1 + i18n/dictionaries/sv.json | 1 + .../languageSwitcher/languageSwitcher.ts | 21 +++++- 13 files changed, 223 insertions(+), 56 deletions(-) create mode 100644 components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx create mode 100644 components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx b/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx new file mode 100644 index 000000000..ada415172 --- /dev/null +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/index.tsx @@ -0,0 +1,63 @@ +import { useIntl } from "react-intl" + +import useDropdownStore from "@/stores/main-menu" + +import { ChevronLeftIcon } from "@/components/Icons" +import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" + +import styles from "./languageSwitcherContainer.module.css" + +import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown" +import { + type LanguageSwitcherContainerProps, + LanguageSwitcherTypesEnum, +} from "@/types/components/languageSwitcher/languageSwitcher" + +export default function LanguageSwitcherContainer({ + children, + type, +}: LanguageSwitcherContainerProps) { + const { toggleDropdown } = useDropdownStore() + const intl = useIntl() + const isFooter = type === LanguageSwitcherTypesEnum.Footer + const isMobileHeader = type === LanguageSwitcherTypesEnum.MobileHeader + const position = isFooter + ? DropdownTypeEnum.FooterLanguageSwitcher + : DropdownTypeEnum.HamburgerMenu + + return ( +
+ {isMobileHeader ? ( +
+ +
+ ) : null} + {isFooter ? ( +
+ +
+ ) : null} + {children} +
+ ) +} diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css new file mode 100644 index 000000000..1f8983efa --- /dev/null +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css @@ -0,0 +1,74 @@ +.backWrapper { + background-color: var(--Base-Surface-Secondary-light-Normal); + padding: var(--Spacing-x2); +} + +.backButton { + background-color: transparent; + border: none; + color: var(--Base-Text-High-contrast); + font-family: var(--typography-Subtitle-1-fontFamily); + font-weight: var(--typography-Subtitle-1-fontWeight); + font-size: var(--typography-Subtitle-1-Mobile-fontSize); + padding: 0; + cursor: pointer; + display: flex; + align-items: center; + gap: var(--Spacing-x1); +} + +.closeWrapper { + display: flex; + justify-content: flex-end; + padding: var(--Spacing-x2); + border-bottom: 1px solid var(--Base-Border-Subtle); +} + +.closeButton { + background-color: transparent; + border: none; + cursor: pointer; + justify-self: flex-start; + padding: 11px 8px 16px; + user-select: none; +} + +.bar, +.bar::after, +.bar::before { + background: var(--Base-Text-High-contrast); + border-radius: 2.3px; + display: inline-block; + height: 3px; + position: relative; + transition: all 0.3s; + width: 32px; +} + +.bar::after, +.bar::before { + content: ""; + left: 0; + position: absolute; + top: 0; + transform-origin: 50% 50%; + width: 32px; +} + +.bar { + background: transparent; +} + +.bar::after { + transform: rotate(-45deg); +} + +.bar::before { + transform: rotate(45deg); +} + +@media screen and (min-width: 768px) { + .closeWrapper { + display: none; + } +} diff --git a/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx b/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx index 9aebfa711..3533ecb93 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx +++ b/components/LanguageSwitcher/LanguageSwitcherContent/index.tsx @@ -3,9 +3,8 @@ import { useIntl } from "react-intl" import { Lang, languages } from "@/constants/languages" -import useDropdownStore from "@/stores/main-menu" -import { CheckIcon, ChevronLeftIcon } from "@/components/Icons" +import { CheckIcon } from "@/components/Icons" import Link from "@/components/TempDesignSystem/Link" import Subtitle from "@/components/TempDesignSystem/Text/Subtitle" import useLang from "@/hooks/useLang" @@ -13,38 +12,19 @@ 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" +import type { LanguageSwitcherContentProps } from "@/types/components/languageSwitcher/languageSwitcher" export default function LanguageSwitcherContent({ urls, - type, -}: LanguageSwitcherProps) { +}: LanguageSwitcherContentProps) { const intl = useIntl() const currentLanguage = useLang() - const { toggleDropdown } = useDropdownStore() + const languageSwitcherRef = useTrapFocus() const urlKeys = Object.keys(urls) as Lang[] - const position = - type === "footer" - ? DropdownTypeEnum.FooterLanguageSwitcher - : DropdownTypeEnum.HamburgerMenu return (
- {type === "mobileHeader" ? ( -
- -
- ) : null} -
{intl.formatMessage({ id: "Select your language" })} diff --git a/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css b/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css index 465b39c23..24e3febb8 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css +++ b/components/LanguageSwitcher/LanguageSwitcherContent/languageSwitcherContent.module.css @@ -1,22 +1,3 @@ -.backWrapper { - background-color: var(--Base-Surface-Secondary-light-Normal); - padding: var(--Spacing-x2); -} - -.backButton { - background-color: transparent; - border: none; - color: var(--Base-Text-High-contrast); - font-family: var(--typography-Subtitle-1-fontFamily); - font-weight: var(--typography-Subtitle-1-fontWeight); - font-size: var(--typography-Subtitle-1-Mobile-fontSize); - padding: 0; - cursor: pointer; - display: flex; - align-items: center; - gap: var(--Spacing-x1); -} - .languageWrapper { display: grid; gap: var(--Spacing-x3); diff --git a/components/LanguageSwitcher/index.tsx b/components/LanguageSwitcher/index.tsx index 65888d578..7a5ecb6b2 100644 --- a/components/LanguageSwitcher/index.tsx +++ b/components/LanguageSwitcher/index.tsx @@ -1,5 +1,6 @@ "use client" +import { useEffect } from "react" import { useIntl } from "react-intl" import { languages } from "@/constants/languages" @@ -9,13 +10,17 @@ import { ChevronDownIcon, GlobeIcon } from "@/components/Icons" import { useHandleKeyUp } from "@/hooks/useHandleKeyUp" import useLang from "@/hooks/useLang" +import LanguageSwitcherContainer from "./LanguageSwitcherContainer" 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" +import { + type LanguageSwitcherProps, + LanguageSwitcherTypesEnum, +} from "@/types/components/languageSwitcher/languageSwitcher" export default function LanguageSwitcher({ urls, @@ -30,8 +35,11 @@ export default function LanguageSwitcher({ isHeaderLanguageSwitcherMobileOpen, } = useDropdownStore() - const position = type === "footer" ? "footer" : "header" - const color = type === "footer" ? "pale" : "burgundy" + const isFooter = type === LanguageSwitcherTypesEnum.Footer + const isHeader = !isFooter + + const position = isFooter ? "footer" : "header" + const color = isFooter ? "pale" : "burgundy" const dropdownType = { footer: DropdownTypeEnum.FooterLanguageSwitcher, @@ -40,8 +48,8 @@ export default function LanguageSwitcher({ }[type] const isLanguageSwitcherOpen = - (type === "footer" && isFooterLanguageSwitcherOpen) || - (type !== "footer" && + (isFooter && isFooterLanguageSwitcherOpen) || + (isHeader && (isHeaderLanguageSwitcherOpen || isHeaderLanguageSwitcherMobileOpen)) useHandleKeyUp((event: KeyboardEvent) => { @@ -50,6 +58,18 @@ export default function LanguageSwitcher({ } }) + useEffect(() => { + if (isFooter && isFooterLanguageSwitcherOpen) { + document.body.style.overflow = "hidden" + } else { + document.body.style.overflow = "" + } + + return () => { + document.body.style.overflow = "" + } + }, [isFooter, isFooterLanguageSwitcherOpen]) + const classNames = languageSwitcherVariants({ color, position }) return ( @@ -78,7 +98,9 @@ export default function LanguageSwitcher({ className={`${styles.dropdown} ${isLanguageSwitcherOpen ? styles.isExpanded : ""}`} > {isLanguageSwitcherOpen ? ( - + + + ) : null}
diff --git a/components/LanguageSwitcher/languageSwitcher.module.css b/components/LanguageSwitcher/languageSwitcher.module.css index 6c85a22aa..4cde01f31 100644 --- a/components/LanguageSwitcher/languageSwitcher.module.css +++ b/components/LanguageSwitcher/languageSwitcher.module.css @@ -31,20 +31,36 @@ .dropdown { position: fixed; - top: var(--main-menu-mobile-height); - right: -100vw; - bottom: 0; width: 100%; background-color: var(--Base-Surface-Primary-light-Normal); - transition: right 0.3s; z-index: var(--menu-overlay-z-index); } -.dropdown.isExpanded { +.top .dropdown { + right: -100vw; + top: var(--main-menu-mobile-height); + bottom: 0; + transition: right 0.3s; +} + +.top .dropdown.isExpanded { display: block; right: 0; } +.bottom .dropdown { + transition: transform 0.3s; + width: 100%; + height: 100vh; + left: 0; + bottom: 0; + transform: translateY(100%); +} + +.bottom .dropdown.isExpanded { + transform: translateY(0); +} + @media screen and (min-width: 768px) { .languageSwitcher { position: relative; @@ -81,10 +97,16 @@ } .bottom .dropdown { - top: auto; + transition: none; + height: auto; + left: -100%; bottom: 2.25rem; } + .bottom .dropdown.isExpanded { + display: block; + } + .bottom .dropdown::before { top: 100%; } diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index fc8186ab8..c6f01ae24 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -97,6 +97,7 @@ "Log in here": "Log ind her", "Log in/Join": "Log på/Tilmeld dig", "Log out": "Log ud", + "Main menu": "Hovedmenu", "Manage preferences": "Administrer præferencer", "Meetings & Conferences": "Møder & Konferencer", "Member price": "Medlemspris", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 9092608b6..9e989bb54 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -95,6 +95,7 @@ "Log in here": "Hier einloggen", "Log in/Join": "Log in/Anmelden", "Log out": "Ausloggen", + "Main menu": "Hauptmenü", "Manage preferences": "Verwalten von Voreinstellungen", "Member price": "Mitgliederpreis", "Member price from": "Mitgliederpreis ab", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index d08f7fd8b..838d32580 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -101,6 +101,7 @@ "Log in here": "Log in here", "Log in/Join": "Log in/Join", "Log out": "Log out", + "Main menu": "Main menu", "Manage preferences": "Manage preferences", "Meetings & Conferences": "Meetings & Conferences", "Member price": "Member price", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index b1d91abe3..0b9072373 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -96,6 +96,7 @@ "Log in here": "Kirjaudu sisään", "Log in/Join": "Kirjaudu sisään/Liittyä", "Log out": "Kirjaudu ulos", + "Main menu": "Päävalikko", "Manage preferences": "Asetusten hallinta", "Meetings & Conferences": "Kokoukset & Konferenssit", "Member price": "Jäsenhinta", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index 9d66f5df8..bd0540e9d 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -96,6 +96,7 @@ "Log in here": "Logg inn her", "Log in/Join": "Logg på/Bli med", "Log out": "Logg ut", + "Main menu": "Hovedmeny", "Manage preferences": "Administrer preferanser", "Meetings & Conferences": "Møter & Konferanser", "Member price": "Medlemspris", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index be1e56601..60f1881cb 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -98,6 +98,7 @@ "Log in here": "Logga in här", "Log in/Join": "Logga in/Gå med", "Log out": "Logga ut", + "Main menu": "Huvudmeny", "Manage preferences": "Hantera inställningar", "Meetings & Conferences": "Möten & Konferenser", "Member price": "Medlemspris", diff --git a/types/components/languageSwitcher/languageSwitcher.ts b/types/components/languageSwitcher/languageSwitcher.ts index 6672fbe83..312d28712 100644 --- a/types/components/languageSwitcher/languageSwitcher.ts +++ b/types/components/languageSwitcher/languageSwitcher.ts @@ -1,6 +1,25 @@ +import { ReactElement } from "react" + import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher" +export enum LanguageSwitcherTypesEnum { + MobileHeader = "mobileHeader", + DesktopHeader = "desktopHeader", + Footer = "footer", +} + +export type LanguageSwitcherTypes = `${LanguageSwitcherTypesEnum}` + export interface LanguageSwitcherProps { - type: "mobileHeader" | "desktopHeader" | "footer" + type: LanguageSwitcherTypes urls: LanguageSwitcherData } + +export interface LanguageSwitcherContentProps { + urls: LanguageSwitcherData +} + +export interface LanguageSwitcherContainerProps { + type: LanguageSwitcherTypes + children: ReactElement +} From a8cef1c6c588697566451b47f953ab0d2fcf719b Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Fri, 13 Sep 2024 09:39:45 +0200 Subject: [PATCH 2/3] feat(SW-378): Updated styling --- .../languageSwitcherContainer.module.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css index 1f8983efa..1722db825 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css @@ -29,7 +29,7 @@ border: none; cursor: pointer; justify-self: flex-start; - padding: 11px 8px 16px; + padding: 11px var(--Spacing-x1) var(--Spacing-x2); user-select: none; } @@ -42,7 +42,7 @@ height: 3px; position: relative; transition: all 0.3s; - width: 32px; + width: var(--Spacing-x4); } .bar::after, @@ -52,7 +52,7 @@ position: absolute; top: 0; transform-origin: 50% 50%; - width: 32px; + width: var(--Spacing-x4); } .bar { From d555447467f83bad85f80c680c2a5e3ceb1b2164 Mon Sep 17 00:00:00 2001 From: Pontus Dreij Date: Fri, 13 Sep 2024 16:46:09 +0200 Subject: [PATCH 3/3] fix(SW-378): remove unused css --- .../languageSwitcherContainer.module.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css index 1722db825..e683a5e26 100644 --- a/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css +++ b/components/LanguageSwitcher/LanguageSwitcherContainer/languageSwitcherContainer.module.css @@ -6,10 +6,6 @@ .backButton { background-color: transparent; border: none; - color: var(--Base-Text-High-contrast); - font-family: var(--typography-Subtitle-1-fontFamily); - font-weight: var(--typography-Subtitle-1-fontWeight); - font-size: var(--typography-Subtitle-1-Mobile-fontSize); padding: 0; cursor: pointer; display: flex;