Merged in feat/mypages-mobile-dropdown (pull request #256)
Feat/mypages mobile dropdown Approved-by: Michael Zetterberg
This commit is contained in:
committed by
Michael Zetterberg
commit
5af198613a
@@ -0,0 +1,14 @@
|
||||
import { logout } from "@/constants/routes/handleAuth"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
if (!navigation) return null
|
||||
return <MyPagesMobileDropdown navigation={navigation} lang={params.lang} />
|
||||
}
|
||||
@@ -5,8 +5,15 @@ import { LangParams, PageArgs } from "@/types/params"
|
||||
export default function HeaderLayout({
|
||||
params,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
}: PageArgs<LangParams> & {
|
||||
languageSwitcher: React.ReactNode
|
||||
}) {
|
||||
return <Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
||||
} & { myPagesMobileDropdown: React.ReactNode }) {
|
||||
return (
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { baseUrls } from "@/constants/routes/baseUrls"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import Header from "@/components/Current/Header"
|
||||
import LanguageSwitcher from "@/components/Current/Header/LanguageSwitcher"
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function HeaderPage({ params }: PageArgs<LangParams>) {
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
return (
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={
|
||||
<MyPagesMobileDropdown navigation={navigation} lang={params.lang} />
|
||||
}
|
||||
languageSwitcher={<LanguageSwitcher urls={baseUrls} lang={params.lang} />}
|
||||
/>
|
||||
)
|
||||
|
||||
15
app/[lang]/(live-current)/@myPagesMobileDropdown/page.tsx
Normal file
15
app/[lang]/(live-current)/@myPagesMobileDropdown/page.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
|
||||
import MyPagesMobileDropdown from "@/components/Current/Header/MyPagesMobileDropdown"
|
||||
|
||||
import { LangParams, PageArgs } from "@/types/params"
|
||||
|
||||
export default async function MyPagesMobileDropdownPage({
|
||||
params,
|
||||
}: PageArgs<LangParams>) {
|
||||
const navigation = await serverClient().contentstack.myPages.navigation.get()
|
||||
if (!navigation) {
|
||||
return null
|
||||
}
|
||||
return <MyPagesMobileDropdown navigation={navigation} lang={params.lang} />
|
||||
}
|
||||
@@ -24,8 +24,11 @@ export default async function RootLayout({
|
||||
children,
|
||||
params,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
}: React.PropsWithChildren<
|
||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode }
|
||||
LayoutArgs<LangParams> & { languageSwitcher: React.ReactNode } & {
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}
|
||||
>) {
|
||||
const { defaultLocale, locale, messages } = await getIntl()
|
||||
return (
|
||||
@@ -82,7 +85,11 @@ export default async function RootLayout({
|
||||
<LangPopup lang={params.lang} />
|
||||
<SkipToMainContent />
|
||||
<ServerIntlProvider intl={{ defaultLocale, locale, messages }}>
|
||||
<Header lang={params.lang} languageSwitcher={languageSwitcher} />
|
||||
<Header
|
||||
lang={params.lang}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
languageSwitcher={languageSwitcher}
|
||||
/>
|
||||
{children}
|
||||
<Footer lang={params.lang} />
|
||||
</ServerIntlProvider>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 950px) {
|
||||
@media screen and (min-width: 1367px) {
|
||||
.button {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
|
||||
@@ -4,8 +4,10 @@ import { useIntl } from "react-intl"
|
||||
|
||||
import { login } from "@/constants/routes/handleAuth"
|
||||
import { myPages } from "@/constants/routes/myPages"
|
||||
import useDropdownStore from "@/stores/main-menu"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
import Avatar from "@/components/MyPages/Avatar"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
|
||||
import BookingButton from "../BookingButton"
|
||||
@@ -21,16 +23,19 @@ export function MainMenu({
|
||||
logo,
|
||||
topMenuMobileLinks,
|
||||
languageSwitcher,
|
||||
myPagesMobileDropdown,
|
||||
bookingHref,
|
||||
isLoggedIn,
|
||||
user,
|
||||
lang,
|
||||
}: MainMenuProps) {
|
||||
const intl = useIntl()
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
function toogleIsOpen() {
|
||||
setIsOpen((prevIsOpen) => !prevIsOpen)
|
||||
}
|
||||
const {
|
||||
isHamburgerMenuOpen,
|
||||
isMyPagesMobileMenuOpen,
|
||||
toggleHamburgerMenu,
|
||||
toggleMyPagesMobileMenu,
|
||||
} = useDropdownStore()
|
||||
|
||||
return (
|
||||
<div className={styles.mainMenu}>
|
||||
@@ -43,8 +48,8 @@ export function MainMenu({
|
||||
<nav className={styles.navBar}>
|
||||
<button
|
||||
aria-pressed="false"
|
||||
className={`${styles.expanderBtn} ${isOpen ? styles.expanded : ""}`}
|
||||
onClick={toogleIsOpen}
|
||||
className={`${styles.expanderBtn} ${isHamburgerMenuOpen ? styles.expanded : ""}`}
|
||||
onClick={toggleHamburgerMenu}
|
||||
type="button"
|
||||
>
|
||||
<span className={styles.iconBars}></span>
|
||||
@@ -66,13 +71,16 @@ export function MainMenu({
|
||||
</a>
|
||||
|
||||
<ul
|
||||
className={`${styles.listWrapper} ${isOpen ? styles.isOpen : ""}`}
|
||||
className={`${styles.listWrapper} ${isHamburgerMenuOpen ? styles.isOpen : ""}`}
|
||||
>
|
||||
<ul className={styles.linkRow}>
|
||||
{isLoggedIn ? (
|
||||
{!!user ? (
|
||||
<>
|
||||
<li>
|
||||
<div className={styles.loggedInLogo} />
|
||||
<li className={styles.avatarWrapper}>
|
||||
<Avatar
|
||||
firstName={user.firstName}
|
||||
lastName={user.lastName}
|
||||
/>
|
||||
</li>
|
||||
<li className={styles.mobileLinkRow}>
|
||||
<Link
|
||||
@@ -139,8 +147,23 @@ export function MainMenu({
|
||||
) : null}
|
||||
</ul>
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.myPagesDesktopLink}>
|
||||
<Link className={styles.link} href={myPages[lang]}>
|
||||
{intl.formatMessage({ id: "My pages" })}
|
||||
</Link>
|
||||
</div>
|
||||
<BookingButton href={bookingHref} />
|
||||
{myPagesMobileDropdown && user ? (
|
||||
<div
|
||||
role="button"
|
||||
onClick={() => toggleMyPagesMobileMenu()}
|
||||
className={styles.avatarButton}
|
||||
>
|
||||
<Avatar firstName={user.firstName} lastName={user.lastName} />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
{isMyPagesMobileMenuOpen ? myPagesMobileDropdown : null}
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
.mainMenu {
|
||||
background-color: #fff;
|
||||
background-color: var(--Main-Grey-White);
|
||||
background-image: none;
|
||||
box-shadow: 0 0 7px rgba(0, 0, 0, 0.75);
|
||||
box-shadow: 0px 1.001px 1.001px 0px rgba(0, 0, 0, 0.05);
|
||||
max-height: 100%;
|
||||
overflow: visible;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 99999;
|
||||
height: 52.39px;
|
||||
height: 70.047px;
|
||||
}
|
||||
|
||||
.container {
|
||||
box-sizing: content-box;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
max-width: 1200px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@@ -26,8 +25,11 @@
|
||||
.navBar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 80px 1fr;
|
||||
grid-template-columns: auto auto 1fr auto;
|
||||
grid-template-areas: "expanderBtn logoLink . buttonContainer";
|
||||
grid-template-rows: 100%;
|
||||
height: 100%;
|
||||
padding: 0 var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.expanderBtn {
|
||||
@@ -46,7 +48,7 @@
|
||||
background: #757575;
|
||||
border-radius: 2.3px;
|
||||
display: inline-block;
|
||||
height: 5px;
|
||||
height: 3px;
|
||||
position: relative;
|
||||
transition: 0.3s;
|
||||
width: 32px;
|
||||
@@ -98,16 +100,19 @@
|
||||
}
|
||||
|
||||
.logoLink {
|
||||
display: inline;
|
||||
/*padding: 16px 0 8px;*/
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 80px;
|
||||
padding: 16px 0 8px;
|
||||
padding-left: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
object-fit: fill;
|
||||
}
|
||||
|
||||
.listWrapper {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #e3e0db;
|
||||
@@ -175,13 +180,8 @@
|
||||
padding: 15px 15px 15px 5px;
|
||||
}
|
||||
|
||||
.loggedInLogo {
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
border-radius: 50px;
|
||||
background-color: #000;
|
||||
.avatarWrapper {
|
||||
margin-right: 4px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.mobileLinkButton {
|
||||
@@ -228,50 +228,56 @@
|
||||
}
|
||||
|
||||
.buttonContainer {
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-right: 8px;
|
||||
gap: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 950px) {
|
||||
.myPagesDesktopLink {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: 1367px) {
|
||||
.navBar {
|
||||
grid-template-columns: 140px auto 1fr;
|
||||
height: 82.4px;
|
||||
align-content: center;
|
||||
padding: 0px 0px var(--Spacing-x-quarter) 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.logoLink {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 27px 30px 26px 0;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mainMenu {
|
||||
box-shadow: none;
|
||||
background-color: hsla(0, 0%, 100%, 0.95);
|
||||
position: relative;
|
||||
z-index: unset;
|
||||
height: 85.09px;
|
||||
height: 82.4px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 0px 30px;
|
||||
padding: 0 var(--Spacing-x5) 0 120px;
|
||||
}
|
||||
|
||||
.mainLinks {
|
||||
padding-top: 2.5px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.navBar {
|
||||
grid-template-columns: 132.18px 1fr auto;
|
||||
align-content: center;
|
||||
padding-bottom: 2px;
|
||||
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.expanderBtn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.logoLink {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
padding: 30px 10px 30px 15px;
|
||||
width: auto;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 102.17px;
|
||||
height: 100%;
|
||||
@@ -282,9 +288,11 @@
|
||||
border-top: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
position: static;
|
||||
width: 100%;
|
||||
padding-bottom: 0px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.listWrapper.isOpen {
|
||||
@@ -292,7 +300,7 @@
|
||||
}
|
||||
|
||||
.li {
|
||||
display: table-cell;
|
||||
display: inline-grid;
|
||||
float: none;
|
||||
vertical-align: middle;
|
||||
line-height: 1.15;
|
||||
@@ -300,10 +308,16 @@
|
||||
|
||||
.link {
|
||||
background-image: none;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-weight: 700;
|
||||
line-height: 1.15;
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
font-size: var(--typography-Body-Regular-fontSize);
|
||||
font-feature-settings:
|
||||
"clig" off,
|
||||
"liga" off;
|
||||
font-weight: 600;
|
||||
line-height: 125%;
|
||||
padding: 30px 15px;
|
||||
text-transform: uppercase;
|
||||
color: var(--text-black); /* Design system should return #404040 */
|
||||
}
|
||||
|
||||
.linkRow {
|
||||
@@ -322,25 +336,11 @@
|
||||
.buttonContainer {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.mainMenu {
|
||||
height: 82.4px;
|
||||
.avatarButton {
|
||||
display: none;
|
||||
}
|
||||
.navBar {
|
||||
grid-template-columns: 140px auto 1fr;
|
||||
height: 82.4px;
|
||||
}
|
||||
|
||||
.logoLink {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
padding: 27px 30px 26px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.listWrapper {
|
||||
padding-top: 0;
|
||||
.myPagesDesktopLink {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
80
components/Current/Header/MyPagesMobileDropdown/index.tsx
Normal file
80
components/Current/Header/MyPagesMobileDropdown/index.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
"use client"
|
||||
import { Fragment } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { logout } from "@/constants/routes/handleAuth"
|
||||
import { navigationQueryRouter } from "@/server/routers/contentstack/myPages/navigation/query"
|
||||
import useDropdownStore from "@/stores/main-menu"
|
||||
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Link from "@/components/TempDesignSystem/Link"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
|
||||
import styles from "./my-pages-mobile-dropdown.module.css"
|
||||
|
||||
type Navigation = Awaited<ReturnType<(typeof navigationQueryRouter)["get"]>>
|
||||
|
||||
export default function MyPagesMobileDropdown({
|
||||
navigation,
|
||||
lang,
|
||||
}: {
|
||||
navigation: Navigation
|
||||
lang: Lang | null
|
||||
}) {
|
||||
const { formatMessage } = useIntl()
|
||||
const { toggleMyPagesMobileMenu, isMyPagesMobileMenuOpen } =
|
||||
useDropdownStore()
|
||||
|
||||
if (!navigation) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<nav
|
||||
className={`${styles.navigationMenu} ${isMyPagesMobileMenuOpen ? styles.navigationMenuIsOpen : ""}`}
|
||||
>
|
||||
<Title className={styles.heading} textTransform="capitalize" level="h5">
|
||||
{navigation.title}
|
||||
</Title>
|
||||
{navigation.menuItems.map((menuItem, idx) => (
|
||||
<Fragment key={`${menuItem.display_sign_out_link}-${idx}`}>
|
||||
<div className={styles.dividerWrapper}>
|
||||
<Divider color="subtle" />
|
||||
</div>
|
||||
<ul className={styles.dropdownWrapper}>
|
||||
<ul className={styles.dropdownLinks}>
|
||||
{menuItem.links.map((link) => (
|
||||
<li key={link.uid}>
|
||||
<Link
|
||||
href={link.originalUrl || link.url}
|
||||
partialMatch
|
||||
size={menuItem.display_sign_out_link ? "small" : "regular"}
|
||||
variant="myPageMobileDropdown"
|
||||
color="burgundy"
|
||||
onClick={toggleMyPagesMobileMenu}
|
||||
>
|
||||
{link.linkText}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
{menuItem.display_sign_out_link && lang ? (
|
||||
<li>
|
||||
<Link
|
||||
color="burgundy"
|
||||
href={logout[lang]}
|
||||
prefetch={false}
|
||||
size="small"
|
||||
variant="sidebar"
|
||||
>
|
||||
{formatMessage({ id: "Log out" })}
|
||||
</Link>
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
</ul>
|
||||
</Fragment>
|
||||
))}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
.navigationMenu {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #e3e0db;
|
||||
display: none;
|
||||
list-style: none;
|
||||
overflow-y: visible;
|
||||
margin: 0;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
|
||||
.navigationMenu.navigationMenuIsOpen {
|
||||
display: block;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
.dropdownWrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 20px var(--Spacing-x2);
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
background-color: var(--Main-Grey-White);
|
||||
box-shadow:
|
||||
0px 276px 77px 0px rgba(0, 0, 0, 0),
|
||||
0px 177px 71px 0px rgba(0, 0, 0, 0.01),
|
||||
0px 99px 60px 0px rgba(0, 0, 0, 0.05),
|
||||
0px 44px 44px 0px rgba(0, 0, 0, 0.09),
|
||||
0px 11px 24px 0px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.dividerWrapper {
|
||||
background-color: var(--Main-Grey-White);
|
||||
padding: 0 var(--Spacing-x2);
|
||||
margin: auto;
|
||||
place-content: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.heading {
|
||||
padding: 20px var(--Spacing-x2);
|
||||
}
|
||||
|
||||
.dropdownLinks {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--Spacing-x-half);
|
||||
width: 100%;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.navigationMenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navigationMenu.navigationMenuIsOpen {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
display: grid;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 950px) {
|
||||
@media screen and (max-width: 1366px) {
|
||||
.header {
|
||||
height: 50px;
|
||||
height: 70.047px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,18 @@ import { LangParams } from "@/types/params"
|
||||
export default async function Header({
|
||||
lang,
|
||||
languageSwitcher,
|
||||
}: LangParams & { languageSwitcher: React.ReactNode }) {
|
||||
const data = await serverClient().contentstack.base.header({
|
||||
lang,
|
||||
})
|
||||
const session = await auth()
|
||||
myPagesMobileDropdown,
|
||||
}: LangParams & { languageSwitcher: React.ReactNode } & {
|
||||
myPagesMobileDropdown: React.ReactNode
|
||||
}) {
|
||||
const [data, session] = await Promise.all([
|
||||
serverClient().contentstack.base.header({
|
||||
lang,
|
||||
}),
|
||||
auth(),
|
||||
])
|
||||
|
||||
const user = !!session ? await serverClient().user.get() : null
|
||||
|
||||
if (!data) {
|
||||
return null
|
||||
@@ -49,8 +56,9 @@ export default async function Header({
|
||||
logo={logo}
|
||||
topMenuMobileLinks={topMenuMobileLinks}
|
||||
languageSwitcher={languageSwitcher}
|
||||
myPagesMobileDropdown={myPagesMobileDropdown}
|
||||
bookingHref={homeHref}
|
||||
isLoggedIn={!!session}
|
||||
user={user}
|
||||
lang={lang}
|
||||
/>
|
||||
</header>
|
||||
|
||||
27
components/MyPages/Avatar/avatar.module.css
Normal file
27
components/MyPages/Avatar/avatar.module.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.avatar {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.avatarInitialsText {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--Theme-Primary-Dark-Surface-Normal);
|
||||
color: var(--Theme-Primary-Dark-On-Surface-Text);
|
||||
font-size: var(--typography-Caption-Bold-fontSize);
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
font-weight: var(--typography-Caption-Bold-fontWeight);
|
||||
line-height: 150%;
|
||||
letter-spacing: 0.096px;
|
||||
}
|
||||
20
components/MyPages/Avatar/index.tsx
Normal file
20
components/MyPages/Avatar/index.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { getInitials } from "@/utils/user"
|
||||
|
||||
import styles from "./avatar.module.css"
|
||||
|
||||
import { User } from "@/types/user"
|
||||
|
||||
export default function Avatar({
|
||||
firstName,
|
||||
lastName,
|
||||
}: {
|
||||
firstName: User["firstName"]
|
||||
lastName: User["lastName"]
|
||||
}) {
|
||||
const initials = getInitials(firstName, lastName)
|
||||
return (
|
||||
<span className={styles.avatar}>
|
||||
<span className={styles.avatarInitialsText}>{initials}</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -17,6 +17,10 @@
|
||||
border-bottom-color: var(--Theme-Primary-Light-On-Surface-Divider);
|
||||
}
|
||||
|
||||
.subtle {
|
||||
border-bottom-color: var(--Base-Border-Subtle);
|
||||
}
|
||||
|
||||
.opacity100 {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export const dividerVariants = cva(styles.divider, {
|
||||
color: {
|
||||
burgundy: styles.burgundy,
|
||||
peach: styles.peach,
|
||||
subtle: styles.subtle,
|
||||
},
|
||||
opacity: {
|
||||
100: styles.opacity100,
|
||||
|
||||
@@ -29,6 +29,33 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.myPageMobileDropdown {
|
||||
color: var(--Scandic-Brand-Burgundy);
|
||||
font-family: var(--typography-Body-Regular-fontFamily);
|
||||
font-size: var(--typography-Body-Regular-fontSize);
|
||||
line-height: var(--typography-Body-Regular-lineHeight);
|
||||
letter-spacing: 0.096px;
|
||||
padding: var(--Spacing-x1) var(--Spacing-x1) var(--Spacing-x1)
|
||||
var(--Spacing-x-one-and-half);
|
||||
width: 100%;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
gap: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
.myPageMobileDropdown.active {
|
||||
background-color: var(--Scandic-Brand-Pale-Peach);
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
font-family: var(--typography-Body-Underlined-fontFamily);
|
||||
font-size: var(--typography-Body-Underlined-fontSize);
|
||||
font-weight: var(--typography-Body-Underlined-fontWeight);
|
||||
letter-spacing: var(--typography-Body-Underlined-letterSpacing);
|
||||
line-height: var(--typography-Body-Underlined-lineHeight);
|
||||
}
|
||||
|
||||
.shortcut {
|
||||
align-items: center;
|
||||
border-bottom: 0.5px solid var(--Scandic-Beige-20);
|
||||
|
||||
@@ -23,6 +23,7 @@ export const linkVariants = cva(styles.link, {
|
||||
default: styles.default,
|
||||
icon: styles.icon,
|
||||
myPage: styles.myPage,
|
||||
myPageMobileDropdown: styles.myPageMobileDropdown,
|
||||
shortcut: styles.shortcut,
|
||||
sidebar: styles.sidebar,
|
||||
},
|
||||
|
||||
@@ -68,6 +68,10 @@
|
||||
text-decoration: var(--typography-Title-5-textDecoration);
|
||||
}
|
||||
|
||||
.capitalize {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.regular {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ const config = {
|
||||
left: styles.left,
|
||||
},
|
||||
textTransform: {
|
||||
capitalize: styles.capitalize,
|
||||
regular: styles.regular,
|
||||
uppercase: styles.uppercase,
|
||||
},
|
||||
|
||||
31
stores/main-menu.ts
Normal file
31
stores/main-menu.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { create } from "zustand"
|
||||
|
||||
interface DropdownState {
|
||||
isHamburgerMenuOpen: boolean
|
||||
isMyPagesMobileMenuOpen: boolean
|
||||
toggleHamburgerMenu: () => void
|
||||
toggleMyPagesMobileMenu: () => void
|
||||
}
|
||||
|
||||
const useDropdownStore = create<DropdownState>((set) => ({
|
||||
isHamburgerMenuOpen: false,
|
||||
isMyPagesMobileMenuOpen: false,
|
||||
toggleHamburgerMenu: () =>
|
||||
set((state) => {
|
||||
// Close the other dropdown if it's open
|
||||
if (!state.isHamburgerMenuOpen && state.isMyPagesMobileMenuOpen) {
|
||||
set({ isMyPagesMobileMenuOpen: false })
|
||||
}
|
||||
return { isHamburgerMenuOpen: !state.isHamburgerMenuOpen }
|
||||
}),
|
||||
toggleMyPagesMobileMenu: () =>
|
||||
set((state) => {
|
||||
// Close the other dropdown if it's open
|
||||
if (!state.isMyPagesMobileMenuOpen && state.isHamburgerMenuOpen) {
|
||||
set({ isHamburgerMenuOpen: false })
|
||||
}
|
||||
return { isMyPagesMobileMenuOpen: !state.isMyPagesMobileMenuOpen }
|
||||
}),
|
||||
}))
|
||||
|
||||
export default useDropdownStore
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
CurrentHeaderLink,
|
||||
TopMenuHeaderLink,
|
||||
} from "@/types/requests/currentHeader"
|
||||
import { User } from "@/types/user"
|
||||
|
||||
export type MainMenuProps = {
|
||||
frontpageLinkText: string
|
||||
@@ -13,7 +14,8 @@ export type MainMenuProps = {
|
||||
logo: Image
|
||||
topMenuMobileLinks: TopMenuHeaderLink[]
|
||||
languageSwitcher: React.ReactNode | null
|
||||
myPagesMobileDropdown: React.ReactNode | null
|
||||
bookingHref: string
|
||||
isLoggedIn: boolean
|
||||
user: User | null
|
||||
lang: Lang
|
||||
}
|
||||
|
||||
@@ -6,3 +6,13 @@ export function getMembership(memberships: User["memberships"]) {
|
||||
membership.membershipType.toLowerCase() === "guestpr" || "scandicfriend's"
|
||||
)
|
||||
}
|
||||
|
||||
export function getInitials(
|
||||
firstName: User["firstName"],
|
||||
lastName: User["lastName"]
|
||||
) {
|
||||
if (!firstName || !lastName) return null
|
||||
const firstInitial = firstName.charAt(0).toUpperCase()
|
||||
const lastInitial = lastName.charAt(0).toUpperCase()
|
||||
return `${firstInitial}${lastInitial}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user