fix(BOOK-325): Added refetch options to user.name query and refactored header
Approved-by: Linus Flood Approved-by: Matilda Landström
This commit is contained in:
@@ -3,16 +3,8 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--Space-x1);
|
gap: var(--Space-x1);
|
||||||
color: var(--Text-Interactive-Secondary);
|
color: var(--Text-Interactive-Secondary);
|
||||||
}
|
|
||||||
|
|
||||||
.headerLink:hover {
|
&:hover {
|
||||||
color: var(--Text-Interactive-Default);
|
color: var(--Text-Interactive-Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.headerLink .icon * {
|
|
||||||
fill: var(--Icon-Interactive-Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerLink:hover .icon * {
|
|
||||||
fill: var(--Icon-Interactive-Secondary);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import Link from "next/link"
|
import NextLink from "next/link"
|
||||||
|
|
||||||
import { IconByIconName } from "@scandic-hotels/design-system/Icons/IconByIconName"
|
import { IconByIconName } from "@scandic-hotels/design-system/Icons/IconByIconName"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
@@ -14,11 +14,11 @@ export default function HeaderLink({
|
|||||||
href,
|
href,
|
||||||
iconName,
|
iconName,
|
||||||
iconSize = 20,
|
iconSize = 20,
|
||||||
onClick = () => undefined,
|
onClick,
|
||||||
}: HeaderLinkProps) {
|
}: HeaderLinkProps) {
|
||||||
return (
|
return (
|
||||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
<Link href={href} className={styles.headerLink} onClick={onClick}>
|
<NextLink href={href} className={styles.headerLink} onClick={onClick}>
|
||||||
{iconName ? (
|
{iconName ? (
|
||||||
<IconByIconName
|
<IconByIconName
|
||||||
iconName={iconName}
|
iconName={iconName}
|
||||||
@@ -28,7 +28,7 @@ export default function HeaderLink({
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
{children}
|
{children}
|
||||||
</Link>
|
</NextLink>
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,30 @@
|
|||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import { Button as ButtonRAC } from "react-aria-components"
|
||||||
|
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import styles from "./menuButton.module.css"
|
import styles from "./menuButton.module.css"
|
||||||
|
|
||||||
import type { MainMenuButtonProps } from "@/types/components/header/mainMenuButton"
|
import type { ComponentProps } from "react"
|
||||||
|
|
||||||
|
interface MainMenuButtonProps extends ComponentProps<typeof ButtonRAC> {
|
||||||
|
isLoading?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export default function MainMenuButton({
|
export default function MainMenuButton({
|
||||||
className = "",
|
className,
|
||||||
|
isLoading,
|
||||||
...props
|
...props
|
||||||
}: MainMenuButtonProps) {
|
}: MainMenuButtonProps) {
|
||||||
return (
|
return (
|
||||||
<button
|
<Typography variant="Body/Paragraph/mdBold">
|
||||||
type="button"
|
<ButtonRAC
|
||||||
className={`${styles.menuButton} ${className}`}
|
type="button"
|
||||||
{...props}
|
className={cx(styles.menuButton, className, {
|
||||||
/>
|
[styles.loading]: isLoading,
|
||||||
|
})}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
.menuButton {
|
.menuButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--Space-x05);
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: var(--Base-Text-High-contrast);
|
color: var(--Text-Interactive-Default);
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
padding: var(--Space-x05) 0;
|
padding: var(--Space-x05) 0;
|
||||||
cursor: pointer;
|
|
||||||
font-family: var(--typography-Body-Bold-fontFamily);
|
&:focus-visible {
|
||||||
font-weight: 500; /* Should be fixed when variables starts working: var(--typography-Body-Bold-fontWeight); */
|
outline: 2px auto -webkit-focus-ring-color;
|
||||||
font-size: var(--typography-Body-Bold-fontSize);
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading {
|
||||||
|
cursor: progress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import NextLink from "next/link"
|
||||||
|
|
||||||
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
|
import styles from "./menuLink.module.css"
|
||||||
|
|
||||||
|
import type { ComponentProps } from "react"
|
||||||
|
|
||||||
|
export function MenuLink({
|
||||||
|
className,
|
||||||
|
children,
|
||||||
|
...props
|
||||||
|
}: ComponentProps<typeof NextLink>) {
|
||||||
|
return (
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
<NextLink className={cx(styles.menuLink, className)} {...props}>
|
||||||
|
{children}
|
||||||
|
<MaterialIcon
|
||||||
|
icon="arrow_forward"
|
||||||
|
color="CurrentColor"
|
||||||
|
className={styles.arrowIcon}
|
||||||
|
/>
|
||||||
|
</NextLink>
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
.menuLink {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--Space-x1);
|
||||||
|
gap: var(--Space-x15);
|
||||||
|
border-radius: var(--Corner-radius-md);
|
||||||
|
color: var(--Text-Interactive-Default);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--Surface-Primary-Hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px auto -webkit-focus-ring-color;
|
||||||
|
outline-offset: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:hover) .arrowIcon {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.arrowIcon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
import { Dialog, Modal } from "react-aria-components"
|
import { Button as ButtonRAC, Dialog, Modal } from "react-aria-components"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
import { useMediaQuery } from "usehooks-ts"
|
import { useMediaQuery } from "usehooks-ts"
|
||||||
|
|
||||||
@@ -75,16 +76,21 @@ export default function MobileMenu({
|
|||||||
|
|
||||||
const findMyBookingUrl = findMyBookingRoutes[lang]
|
const findMyBookingUrl = findMyBookingRoutes[lang]
|
||||||
|
|
||||||
|
function handleLinkClick() {
|
||||||
|
toggleDropdown(DropdownTypeEnum.HamburgerMenu)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
<ButtonRAC
|
||||||
type="button"
|
className={cx(styles.hamburger, {
|
||||||
className={`${styles.hamburger} ${isHamburgerExtended ? styles.isExpanded : ""}`}
|
[styles.isExpanded]: isHamburgerExtended,
|
||||||
|
})}
|
||||||
aria-label={isHamburgerExtended ? closeMsg : openMsg}
|
aria-label={isHamburgerExtended ? closeMsg : openMsg}
|
||||||
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
|
onPress={handleLinkClick}
|
||||||
>
|
>
|
||||||
<span className={styles.bar} />
|
<span className={styles.bar} />
|
||||||
</button>
|
</ButtonRAC>
|
||||||
<Modal className={styles.modal} isOpen={isHamburgerMenuOpen}>
|
<Modal className={styles.modal} isOpen={isHamburgerMenuOpen}>
|
||||||
<Dialog
|
<Dialog
|
||||||
className={styles.dialog}
|
className={styles.dialog}
|
||||||
@@ -98,17 +104,23 @@ export default function MobileMenu({
|
|||||||
<HeaderLink
|
<HeaderLink
|
||||||
href={findMyBookingUrl}
|
href={findMyBookingUrl}
|
||||||
iconName={IconName.Search}
|
iconName={IconName.Search}
|
||||||
onClick={() => toggleDropdown(DropdownTypeEnum.HamburgerMenu)}
|
onClick={handleLinkClick}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
id: "booking.findBooking",
|
id: "booking.findBooking",
|
||||||
defaultMessage: "Find booking",
|
defaultMessage: "Find booking",
|
||||||
})}
|
})}
|
||||||
</HeaderLink>
|
</HeaderLink>
|
||||||
<TopLink isLoggedIn={isLoggedIn} topLink={topLink} iconSize={20} />
|
<TopLink
|
||||||
|
isLoggedIn={isLoggedIn}
|
||||||
|
topLink={topLink}
|
||||||
|
iconSize={20}
|
||||||
|
onClick={handleLinkClick}
|
||||||
|
/>
|
||||||
<HeaderLink
|
<HeaderLink
|
||||||
href={customerService[lang]}
|
href={customerService[lang]}
|
||||||
iconName={IconName.Service}
|
iconName={IconName.Service}
|
||||||
|
onClick={handleLinkClick}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
id: "common.customerService",
|
id: "common.customerService",
|
||||||
|
|||||||
@@ -1,13 +1,3 @@
|
|||||||
@keyframes slide-in {
|
|
||||||
from {
|
|
||||||
right: -100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hamburger {
|
.hamburger {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -20,7 +10,7 @@
|
|||||||
.bar,
|
.bar,
|
||||||
.bar::after,
|
.bar::after,
|
||||||
.bar::before {
|
.bar::before {
|
||||||
background: var(--Base-Text-High-contrast);
|
background: var(--Icon-Interactive-Default);
|
||||||
border-radius: 2.3px;
|
border-radius: 2.3px;
|
||||||
display: block;
|
display: block;
|
||||||
height: 3px;
|
height: 3px;
|
||||||
@@ -70,7 +60,7 @@
|
|||||||
right: auto;
|
right: auto;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Surface-Primary-Default);
|
||||||
transition: right 0.3s;
|
transition: right 0.3s;
|
||||||
z-index: var(--menu-overlay-z-index);
|
z-index: var(--menu-overlay-z-index);
|
||||||
}
|
}
|
||||||
@@ -90,7 +80,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
background-color: var(--Surface-Secondary-Default);
|
||||||
padding: var(--Space-x4) var(--Space-x2);
|
padding: var(--Space-x4) var(--Space-x2);
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x2);
|
gap: var(--Space-x2);
|
||||||
@@ -102,3 +92,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
right: -100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
import { useRef } from "react"
|
import { useRef } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { Avatar } from "@scandic-hotels/design-system/Avatar"
|
import { Avatar } from "@scandic-hotels/design-system/Avatar"
|
||||||
import Body from "@scandic-hotels/design-system/Body"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
|
|
||||||
@@ -56,24 +56,24 @@ export default function MyPagesMenu({
|
|||||||
return (
|
return (
|
||||||
<div className={styles.myPagesMenu} ref={myPagesMenuRef}>
|
<div className={styles.myPagesMenu} ref={myPagesMenuRef}>
|
||||||
<MainMenuButton
|
<MainMenuButton
|
||||||
onClick={() => toggleDropdown(DropdownTypeEnum.MyPagesMenu)}
|
onPress={() => toggleDropdown(DropdownTypeEnum.MyPagesMenu)}
|
||||||
>
|
>
|
||||||
<Avatar initials={getInitials(user.firstName, user.lastName)} />
|
<Avatar initials={getInitials(user.firstName, user.lastName)} />
|
||||||
<Body textTransform="bold" color="baseTextHighContrast" asChild>
|
<span data-hj-suppress>
|
||||||
<span data-hj-suppress>
|
{intl.formatMessage(
|
||||||
{intl.formatMessage(
|
{
|
||||||
{
|
id: "myPages.hiFirstName",
|
||||||
id: "myPages.hiFirstName",
|
defaultMessage: "Hi {firstName}!",
|
||||||
defaultMessage: "Hi {firstName}!",
|
},
|
||||||
},
|
{ firstName: user.firstName }
|
||||||
{ firstName: user.firstName }
|
)}
|
||||||
)}
|
</span>
|
||||||
</span>
|
|
||||||
</Body>
|
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="keyboard_arrow_down"
|
icon="keyboard_arrow_down"
|
||||||
size={20}
|
size={20}
|
||||||
className={`${styles.chevron} ${isMyPagesMenuOpen ? styles.isExpanded : ""}`}
|
className={cx(styles.chevron, {
|
||||||
|
[styles.isExpanded]: isMyPagesMenuOpen,
|
||||||
|
})}
|
||||||
color="CurrentColor"
|
color="CurrentColor"
|
||||||
/>
|
/>
|
||||||
</MainMenuButton>
|
</MainMenuButton>
|
||||||
@@ -96,7 +96,7 @@ export default function MyPagesMenu({
|
|||||||
export function MyPagesMenuSkeleton() {
|
export function MyPagesMenuSkeleton() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.myPagesMenu}>
|
<div className={styles.myPagesMenu}>
|
||||||
<MainMenuButton>
|
<MainMenuButton isLoading>
|
||||||
<Avatar />
|
<Avatar />
|
||||||
<SkeletonShimmer width="10ch" />
|
<SkeletonShimmer width="10ch" />
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
.myPagesMenu {
|
.chevron {
|
||||||
display: none;
|
transition: transform 0.3s;
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
&.isExpanded {
|
||||||
.myPagesMenu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chevron {
|
|
||||||
transition: transform 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chevron.isExpanded {
|
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(
|
top: calc(
|
||||||
3.5rem - 2px
|
3.5rem - 2px
|
||||||
); /* 3.5rem is the height of the main menu + bottom padding. */
|
); /* 3.5rem is the height of the main menu + bottom padding. */
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Surface-Primary-Default);
|
||||||
border-radius: var(--Corner-radius-lg);
|
border-radius: var(--Corner-radius-lg);
|
||||||
box-shadow: 0 0 0.875rem 0.375rem rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 0.875rem 0.375rem rgba(0, 0, 0, 0.1);
|
||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
z-index: var(--menu-overlay-z-index);
|
z-index: var(--menu-overlay-z-index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
.myPagesMenu {
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
import FocusLock from "react-focus-lock"
|
import FocusLock from "react-focus-lock"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { logout } from "@scandic-hotels/common/constants/routes/handleAuth"
|
import { logout } from "@scandic-hotels/common/constants/routes/handleAuth"
|
||||||
import Caption from "@scandic-hotels/design-system/Caption"
|
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
import { trpc } from "@scandic-hotels/trpc/client"
|
import { trpc } from "@scandic-hotels/trpc/client"
|
||||||
|
|
||||||
import useLang from "@/hooks/useLang"
|
import useLang from "@/hooks/useLang"
|
||||||
|
|
||||||
|
import { MenuLink } from "../MenuLink"
|
||||||
|
|
||||||
import styles from "./myPagesMenuContent.module.css"
|
import styles from "./myPagesMenuContent.module.css"
|
||||||
|
|
||||||
import type { MyPagesLinkKey } from "@scandic-hotels/trpc/routers/navigation/mypages/MyPagesLink"
|
import type { MyPagesLinkKey } from "@scandic-hotels/trpc/routers/navigation/mypages/MyPagesLink"
|
||||||
@@ -34,10 +34,7 @@ export default function MyPagesMenuContent({
|
|||||||
const secondaryLinks = myPagesNavigation?.secondaryLinks ?? []
|
const secondaryLinks = myPagesNavigation?.secondaryLinks ?? []
|
||||||
|
|
||||||
const membershipPoints = membership?.currentPoints
|
const membershipPoints = membership?.currentPoints
|
||||||
const introClassName =
|
const showMembershipInfo = membershipLevel && membershipPoints !== undefined
|
||||||
membershipLevel && membershipPoints
|
|
||||||
? `${styles.intro}`
|
|
||||||
: `${styles.intro} ${styles.noMembership}`
|
|
||||||
|
|
||||||
if (primaryLinks.length === 0 && secondaryLinks.length === 0) {
|
if (primaryLinks.length === 0 && secondaryLinks.length === 0) {
|
||||||
return null
|
return null
|
||||||
@@ -46,7 +43,11 @@ export default function MyPagesMenuContent({
|
|||||||
return (
|
return (
|
||||||
<FocusLock returnFocus={true}>
|
<FocusLock returnFocus={true}>
|
||||||
<nav className={styles.myPagesMenuContent}>
|
<nav className={styles.myPagesMenuContent}>
|
||||||
<div className={introClassName}>
|
<div
|
||||||
|
className={cx(styles.intro, {
|
||||||
|
[styles.noMembership]: !showMembershipInfo,
|
||||||
|
})}
|
||||||
|
>
|
||||||
<Typography variant="Title/Subtitle/md" className={styles.userName}>
|
<Typography variant="Title/Subtitle/md" className={styles.userName}>
|
||||||
<p data-hj-suppress>
|
<p data-hj-suppress>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
@@ -58,32 +59,32 @@ export default function MyPagesMenuContent({
|
|||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
{membershipLevel && membershipPoints ? (
|
{showMembershipInfo ? (
|
||||||
<Caption className={styles.friendTypeWrapper}>
|
<div className={styles.friendTypeWrapper}>
|
||||||
<span className={styles.friendType}>{membershipLevel.name}</span>
|
<Typography variant="Title/Overline/sm">
|
||||||
<span>
|
<span className={styles.friendType}>
|
||||||
{intl.formatMessage(
|
{membershipLevel.name}
|
||||||
{
|
</span>
|
||||||
id: "common.pointsAmountPoints",
|
</Typography>
|
||||||
defaultMessage: "{pointsAmount, number} points",
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
},
|
<span>
|
||||||
{ pointsAmount: membershipPoints }
|
{intl.formatMessage(
|
||||||
)}
|
{
|
||||||
</span>
|
id: "common.pointsAmountPoints",
|
||||||
</Caption>
|
defaultMessage: "{pointsAmount, number} points",
|
||||||
|
},
|
||||||
|
{ pointsAmount: membershipPoints }
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
<Divider className={styles.divider} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className={styles.groups}>
|
<PrimaryLinks toggleOpenStateFn={toggleOpenStateFn} />
|
||||||
<li>
|
<Divider className={styles.divider} />
|
||||||
<Divider className={styles.divider} />
|
<SecondaryLinks toggleOpenStateFn={toggleOpenStateFn} />
|
||||||
|
|
||||||
<PrimaryLinks toggleOpenStateFn={toggleOpenStateFn} />
|
|
||||||
|
|
||||||
<Divider className={styles.divider} />
|
|
||||||
<SecondaryLinks toggleOpenStateFn={toggleOpenStateFn} />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
</nav>
|
||||||
</FocusLock>
|
</FocusLock>
|
||||||
)
|
)
|
||||||
@@ -100,22 +101,11 @@ function PrimaryLinks({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className={styles.menuItems}>
|
<ul className={styles.menuItems}>
|
||||||
{primaryLinks.map((link, i) => (
|
{primaryLinks.map(({ text, href }) => (
|
||||||
<li key={link.href + i}>
|
<li key={`${text}-${href}`}>
|
||||||
<Link
|
<MenuLink href={href} onClick={toggleOpenStateFn}>
|
||||||
href={link.href}
|
{text}
|
||||||
onClick={toggleOpenStateFn}
|
</MenuLink>
|
||||||
variant="menu"
|
|
||||||
weight="bold"
|
|
||||||
className={styles.link}
|
|
||||||
>
|
|
||||||
{link.text}
|
|
||||||
<MaterialIcon
|
|
||||||
icon="arrow_forward"
|
|
||||||
className={styles.arrow}
|
|
||||||
color="CurrentColor"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -135,35 +125,20 @@ function SecondaryLinks({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className={styles.menuItems}>
|
<ul className={styles.menuItems}>
|
||||||
{secondaryLinks.map((link, i) => (
|
{secondaryLinks.map(({ text, href }) => (
|
||||||
<li key={link.href + i}>
|
<li key={`${text}-${href}`}>
|
||||||
<Link
|
<MenuLink href={href} onClick={toggleOpenStateFn}>
|
||||||
href={link.href}
|
{text}
|
||||||
onClick={toggleOpenStateFn}
|
</MenuLink>
|
||||||
variant="menu"
|
|
||||||
className={styles.link}
|
|
||||||
>
|
|
||||||
{link.text}
|
|
||||||
<MaterialIcon
|
|
||||||
icon="arrow_forward"
|
|
||||||
className={styles.arrow}
|
|
||||||
color="Icon/Interactive/Default"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li>
|
<li>
|
||||||
<Link
|
<MenuLink href={logout[lang]} prefetch={false}>
|
||||||
href={logout[lang]}
|
|
||||||
prefetch={false}
|
|
||||||
variant="menu"
|
|
||||||
className={styles.link}
|
|
||||||
>
|
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
id: "common.logOut",
|
id: "common.logOut",
|
||||||
defaultMessage: "Log out",
|
defaultMessage: "Log out",
|
||||||
})}
|
})}
|
||||||
</Link>
|
</MenuLink>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,44 +6,29 @@
|
|||||||
padding: 0 var(--Space-x1);
|
padding: 0 var(--Space-x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.myPagesMenuContent .friendTypeWrapper {
|
.friendTypeWrapper {
|
||||||
color: var(--UI-Text-Medium-contrast);
|
color: var(--Text-Secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
margin: var(--Space-x2) 0;
|
margin: var(--Space-x2) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.friendType {
|
|
||||||
font-family: var(--typography-Title-5-fontFamily);
|
|
||||||
letter-spacing: var(--typography-Title-5-letterSpacing);
|
|
||||||
font-size: var(--typography-Caption-Bold-fontSize);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.friendType::after {
|
.friendType::after {
|
||||||
content: " · ";
|
content: " · ";
|
||||||
display: inline;
|
display: inline;
|
||||||
padding: 0 var(--Space-x05);
|
padding: 0 var(--Space-x05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.groups,
|
|
||||||
.menuItems {
|
.menuItems {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:not(:hover) .arrow {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
.myPagesMenuContent {
|
.myPagesMenuContent {
|
||||||
padding: var(--Space-x2) var(--Space-x4);
|
padding: var(--Space-x2) var(--Space-x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.intro.noMembership,
|
.intro.noMembership,
|
||||||
.userName {
|
.userName {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
@@ -28,7 +28,13 @@ export default function MyPagesMenuWrapper() {
|
|||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
const isUserLoggedIn = isValidSession(session)
|
const isUserLoggedIn = isValidSession(session)
|
||||||
|
|
||||||
const { data: user, isLoading: isLoadingUser } = trpc.user.name.useQuery()
|
const { data: user, isLoading: isLoadingUser } = trpc.user.name.useQuery(
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
refetchOnWindowFocus: true,
|
||||||
|
refetchInterval: 300_000,
|
||||||
|
}
|
||||||
|
)
|
||||||
const { data: membership, isLoading: isLoadingMembership } =
|
const { data: membership, isLoading: isLoadingMembership } =
|
||||||
trpc.user.safeMembershipLevel.useQuery()
|
trpc.user.safeMembershipLevel.useQuery()
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,7 @@ export default function MyPagesMobileMenu({
|
|||||||
return (
|
return (
|
||||||
<div className={styles.myPagesMobileMenu}>
|
<div className={styles.myPagesMobileMenu}>
|
||||||
<MainMenuButton
|
<MainMenuButton
|
||||||
className={styles.button}
|
onPress={() => toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)}
|
||||||
onClick={() => toggleDropdown(DropdownTypeEnum.MyPagesMobileMenu)}
|
|
||||||
aria-label={intl.formatMessage({
|
aria-label={intl.formatMessage({
|
||||||
id: "header.openMyPagesMenu",
|
id: "header.openMyPagesMenu",
|
||||||
defaultMessage: "Open my pages menu",
|
defaultMessage: "Open my pages menu",
|
||||||
@@ -85,7 +84,7 @@ export default function MyPagesMobileMenu({
|
|||||||
export function MyPagesMobileMenuSkeleton() {
|
export function MyPagesMobileMenuSkeleton() {
|
||||||
return (
|
return (
|
||||||
<div className={styles.myPagesMobileMenu}>
|
<div className={styles.myPagesMobileMenu}>
|
||||||
<MainMenuButton className={styles.button}>
|
<MainMenuButton isLoading>
|
||||||
<Avatar />
|
<Avatar />
|
||||||
</MainMenuButton>
|
</MainMenuButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,13 +1,3 @@
|
|||||||
@keyframes slide-in {
|
|
||||||
from {
|
|
||||||
right: -100vw;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: calc(var(--main-menu-mobile-height) + var(--alert-and-banner-height));
|
top: calc(var(--main-menu-mobile-height) + var(--alert-and-banner-height));
|
||||||
@@ -16,13 +6,14 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
z-index: var(--menu-overlay-z-index);
|
z-index: var(--menu-overlay-z-index);
|
||||||
}
|
|
||||||
|
|
||||||
.modal[data-entering] {
|
&[data-entering] {
|
||||||
animation: slide-in 0.3s;
|
animation: slide-in 0.3s;
|
||||||
}
|
}
|
||||||
.modal[data-exiting] {
|
|
||||||
animation: slide-in 0.3s reverse;
|
&[data-exiting] {
|
||||||
|
animation: slide-in 0.3s reverse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog {
|
.dialog {
|
||||||
@@ -36,3 +27,13 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in {
|
||||||
|
from {
|
||||||
|
right: -100vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import { Button as ButtonRAC } from "react-aria-components"
|
||||||
import FocusLock from "react-focus-lock"
|
import FocusLock from "react-focus-lock"
|
||||||
|
|
||||||
|
import ButtonLink from "@scandic-hotels/design-system/ButtonLink"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import useDropdownStore from "@/stores/main-menu"
|
import useDropdownStore from "@/stores/main-menu"
|
||||||
|
|
||||||
import Card from "@/components/TempDesignSystem/Card"
|
import Card from "@/components/TempDesignSystem/Card"
|
||||||
|
|
||||||
|
import { MenuLink } from "../../MenuLink"
|
||||||
|
|
||||||
import styles from "./megaMenu.module.css"
|
import styles from "./megaMenu.module.css"
|
||||||
|
|
||||||
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
|
import { DropdownTypeEnum } from "@/types/components/dropdown/dropdown"
|
||||||
@@ -35,14 +39,13 @@ export default function MegaMenu({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FocusLock disabled={!isOpen} returnFocus={true}>
|
<FocusLock disabled={!isOpen} returnFocus={true}>
|
||||||
<nav className={`${styles.megaMenu} ${isOpen ? styles.active : ""}`}>
|
<nav className={cx(styles.megaMenu, { [styles.active]: isOpen })}>
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<div className={styles.backWrapper}>
|
<div className={styles.backWrapper}>
|
||||||
<Typography variant="Title/Subtitle/lg" className={styles.text}>
|
<Typography variant="Title/Subtitle/lg">
|
||||||
<button
|
<ButtonRAC
|
||||||
type="button"
|
|
||||||
className={styles.backButton}
|
className={styles.backButton}
|
||||||
onClick={() => toggleMegaMenu(false)}
|
onPress={() => toggleMegaMenu(false)}
|
||||||
>
|
>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="arrow_back_ios"
|
icon="arrow_back_ios"
|
||||||
@@ -50,22 +53,27 @@ export default function MegaMenu({
|
|||||||
color="CurrentColor"
|
color="CurrentColor"
|
||||||
/>
|
/>
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
</button>
|
</ButtonRAC>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<div className={styles.megaMenuContent}>
|
<div className={styles.megaMenuContent}>
|
||||||
<div className={styles.seeAllLink}>
|
<div className={styles.seeAllLinkWrapper}>
|
||||||
{seeAllLink?.url ? (
|
{seeAllLink?.url ? (
|
||||||
<Link
|
<ButtonLink
|
||||||
href={seeAllLink.url}
|
href={seeAllLink.url}
|
||||||
variant="icon"
|
variant="Text"
|
||||||
weight="bold"
|
typography="Body/Paragraph/mdBold"
|
||||||
onClick={handleNavigate}
|
onClick={handleNavigate}
|
||||||
|
wrapping={false}
|
||||||
>
|
>
|
||||||
{seeAllLink.title}
|
{seeAllLink.title}
|
||||||
<MaterialIcon icon="arrow_forward" color="CurrentColor" />
|
<MaterialIcon
|
||||||
</Link>
|
icon="arrow_forward"
|
||||||
|
color="CurrentColor"
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
|
</ButtonLink>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<ul className={styles.submenus}>
|
<ul className={styles.submenus}>
|
||||||
@@ -77,20 +85,10 @@ export default function MegaMenu({
|
|||||||
<ul className={styles.submenu}>
|
<ul className={styles.submenu}>
|
||||||
{item.links.map(({ title, url }) =>
|
{item.links.map(({ title, url }) =>
|
||||||
url ? (
|
url ? (
|
||||||
<li key={title} className={styles.submenuItem}>
|
<li key={title}>
|
||||||
<Link
|
<MenuLink href={url} onClick={handleNavigate}>
|
||||||
href={url}
|
|
||||||
variant="menu"
|
|
||||||
className={styles.link}
|
|
||||||
onClick={handleNavigate}
|
|
||||||
>
|
|
||||||
{title}
|
{title}
|
||||||
<MaterialIcon
|
</MenuLink>
|
||||||
icon="arrow_forward"
|
|
||||||
color="Icon/Interactive/Default"
|
|
||||||
className={styles.arrow}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</li>
|
</li>
|
||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,64 +1,47 @@
|
|||||||
.megaMenu:not(.active) {
|
.megaMenu {
|
||||||
display: none;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&:not(.active) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.megaMenuContent {
|
.megaMenuContent {
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.seeAllLink {
|
.seeAllLinkWrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: var(--Space-x2) var(--Space-x3);
|
padding: var(--Space-x2) var(--Space-x3);
|
||||||
align-items: center;
|
background-color: var(--Surface-Primary-OnSurface-Default);
|
||||||
gap: var(--Space-x1);
|
|
||||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenus {
|
.submenus {
|
||||||
list-style: none;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
|
||||||
|
|
||||||
.submenuTitle {
|
|
||||||
padding-left: var(--Space-x1);
|
|
||||||
color: var(--Text-Tertiary);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submenu {
|
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenuItem {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.submenusItem {
|
.submenusItem {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x1);
|
gap: var(--Space-x1);
|
||||||
align-content: start;
|
align-content: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkIcon {
|
.submenuTitle {
|
||||||
display: none;
|
padding-left: var(--Space-x1);
|
||||||
|
color: var(--Text-Tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link:not(:hover) .arrow {
|
.submenu {
|
||||||
opacity: 0;
|
list-style: none;
|
||||||
}
|
|
||||||
|
|
||||||
.arrow {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.backWrapper {
|
.backWrapper {
|
||||||
padding: var(--Space-x2);
|
padding: var(--Space-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
|
||||||
color: var(--Text-Interactive-Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
.backButton {
|
.backButton {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -68,39 +51,40 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--Space-x1);
|
gap: var(--Space-x1);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
color: var(--Text-Interactive-Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
.megaMenu {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
.megaMenuContent {
|
.megaMenuContent {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
grid-template-rows: max-content 1fr;
|
grid-template-rows: max-content 1fr;
|
||||||
gap: var(--Space-x2);
|
gap: var(--Space-x2);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
|
||||||
.megaMenuContent:has(.cardWrapper) {
|
&:has(.cardWrapper) {
|
||||||
grid-template-rows: max-content 1fr max-content;
|
grid-template-rows: max-content 1fr max-content;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenus {
|
.submenus {
|
||||||
padding: var(--Space-x2);
|
padding: var(--Space-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenusItem:first-child {
|
.submenusItem {
|
||||||
padding-bottom: var(--Space-x2);
|
&:first-child {
|
||||||
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
padding-bottom: var(--Space-x2);
|
||||||
}
|
border-bottom: 1px solid var(--Border-Divider-Subtle);
|
||||||
.submenusItem:last-child {
|
}
|
||||||
padding-top: var(--Space-x3);
|
|
||||||
|
&:last-child {
|
||||||
|
padding-top: var(--Space-x3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardWrapper {
|
.cardWrapper {
|
||||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
padding: var(--Space-x4) var(--Space-x2);
|
padding: var(--Space-x4) var(--Space-x2);
|
||||||
|
height: 320px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,17 +96,17 @@
|
|||||||
"submenus";
|
"submenus";
|
||||||
width: 600px;
|
width: 600px;
|
||||||
max-width: calc(100vw - var(--Space-x4));
|
max-width: calc(100vw - var(--Space-x4));
|
||||||
|
|
||||||
|
&:has(.cardWrapper) {
|
||||||
|
width: 900px;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
grid-template-areas:
|
||||||
|
"seeAllLink seeAllLink card"
|
||||||
|
"submenus submenus card";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.megaMenuContent:has(.cardWrapper) {
|
.seeAllLinkWrapper {
|
||||||
width: 900px;
|
|
||||||
grid-template-columns: repeat(3, 1fr);
|
|
||||||
grid-template-areas:
|
|
||||||
"seeAllLink seeAllLink card"
|
|
||||||
"submenus submenus card";
|
|
||||||
}
|
|
||||||
|
|
||||||
.seeAllLink {
|
|
||||||
grid-area: seeAllLink;
|
grid-area: seeAllLink;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +116,15 @@
|
|||||||
padding: var(--Space-x2) var(--Space-x3);
|
padding: var(--Space-x2) var(--Space-x3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.submenusItem:first-child {
|
.submenusItem {
|
||||||
padding-right: var(--Space-x5);
|
&:first-child {
|
||||||
border-right: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
padding-right: var(--Space-x5);
|
||||||
}
|
border-right: 1px solid var(--Border-Divider-Subtle);
|
||||||
.submenusItem:last-child {
|
}
|
||||||
padding-left: var(--Space-x5);
|
|
||||||
|
&:last-child {
|
||||||
|
padding-left: var(--Space-x5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.cardWrapper {
|
.cardWrapper {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
|
import NextLink from "next/link"
|
||||||
import { useRef } from "react"
|
import { useRef } from "react"
|
||||||
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import useDropdownStore from "@/stores/main-menu"
|
import useDropdownStore from "@/stores/main-menu"
|
||||||
|
|
||||||
@@ -46,29 +48,40 @@ export default function MenuItem({ item, isMobile }: NavigationMenuItemProps) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MainMenuButton
|
<MainMenuButton
|
||||||
onClick={() => toggleMegaMenu(megaMenuTitle)}
|
onPress={() => toggleMegaMenu(megaMenuTitle)}
|
||||||
className={`${styles.navigationMenuItem} ${isMobile ? styles.mobile : ""}`}
|
className={styles.navigationMenuItem}
|
||||||
>
|
>
|
||||||
{title}
|
|
||||||
{isMobile ? (
|
{isMobile ? (
|
||||||
<MaterialIcon
|
<>
|
||||||
icon="arrow_forward_ios"
|
<Typography variant="Title/Subtitle/lg">
|
||||||
size={20}
|
<span>{title}</span>
|
||||||
className={`${styles.chevron}`}
|
</Typography>
|
||||||
color="CurrentColor"
|
<MaterialIcon
|
||||||
/>
|
icon="arrow_forward_ios"
|
||||||
|
size={20}
|
||||||
|
className={styles.chevron}
|
||||||
|
color="CurrentColor"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
) : (
|
) : (
|
||||||
<MaterialIcon
|
<>
|
||||||
icon="keyboard_arrow_down"
|
<span>{title}</span>
|
||||||
size={20}
|
<MaterialIcon
|
||||||
className={`${styles.chevron} ${isMegaMenuOpen ? styles.isExpanded : ""}`}
|
icon="keyboard_arrow_down"
|
||||||
color="CurrentColor"
|
size={20}
|
||||||
/>
|
className={cx(styles.chevron, {
|
||||||
|
[styles.isExpanded]: isMegaMenuOpen,
|
||||||
|
})}
|
||||||
|
color="CurrentColor"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</MainMenuButton>
|
</MainMenuButton>
|
||||||
<div
|
<div
|
||||||
ref={megaMenuRef}
|
ref={megaMenuRef}
|
||||||
className={`${styles.dropdown} ${isMegaMenuOpen ? styles.isExpanded : ""}`}
|
className={cx(styles.dropdown, {
|
||||||
|
[styles.isExpanded]: isMegaMenuOpen,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
<MegaMenu
|
<MegaMenu
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
@@ -83,15 +96,17 @@ export default function MenuItem({ item, isMobile }: NavigationMenuItemProps) {
|
|||||||
)
|
)
|
||||||
} else if (link?.url) {
|
} else if (link?.url) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Typography
|
||||||
className={`${styles.navigationMenuItem} ${isMobile ? styles.mobile : ""}`}
|
variant={isMobile ? "Title/Subtitle/lg" : "Body/Paragraph/mdBold"}
|
||||||
variant="navigation"
|
|
||||||
weight="bold"
|
|
||||||
onClick={handleNavigate}
|
|
||||||
href={link.url}
|
|
||||||
>
|
>
|
||||||
{title}
|
<NextLink
|
||||||
</Link>
|
className={cx(styles.navigationMenuItem, styles.link)}
|
||||||
|
onClick={handleNavigate}
|
||||||
|
href={link.url}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</NextLink>
|
||||||
|
</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,28 @@
|
|||||||
.navigationMenuItem {
|
.navigationMenuItem {
|
||||||
font-weight: 500; /* Should be fixed when variables starts working: var(--typography-Body-Bold-fontWeight); */
|
color: var(--Text-Interactive-Default);
|
||||||
}
|
|
||||||
|
|
||||||
.navigationMenuItem.mobile {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: var(--Space-x2) 0;
|
|
||||||
font-size: var(--typography-Subtitle-1-Mobile-fontSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chevron {
|
.chevron {
|
||||||
transition: transform 0.3s;
|
transition: transform 0.3s;
|
||||||
}
|
|
||||||
|
|
||||||
.chevron.isExpanded {
|
&.isExpanded {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Surface-Primary-Default);
|
||||||
z-index: var(--menu-overlay-z-index);
|
z-index: var(--menu-overlay-z-index);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 767px) {
|
@media screen and (max-width: 767px) {
|
||||||
|
.navigationMenuItem {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: var(--Space-x2) 0;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -34,13 +33,18 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
transition: right 0.3s;
|
transition: right 0.3s;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
|
||||||
.dropdown.isExpanded {
|
&.isExpanded {
|
||||||
right: 0;
|
right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
|
.navigationMenuItem.link {
|
||||||
|
padding: var(--Space-x05) 0;
|
||||||
|
}
|
||||||
|
|
||||||
.dropdown {
|
.dropdown {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -51,8 +55,9 @@
|
|||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
border-radius: var(--Corner-radius-lg);
|
border-radius: var(--Corner-radius-lg);
|
||||||
box-shadow: var(--popup-box-shadow);
|
box-shadow: var(--popup-box-shadow);
|
||||||
}
|
|
||||||
.dropdown.isExpanded {
|
&.isExpanded {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ export default function NavigationMenuList({
|
|||||||
}: NavigationMenuListProps) {
|
}: NavigationMenuListProps) {
|
||||||
return (
|
return (
|
||||||
<ul
|
<ul
|
||||||
className={`${styles.navigationMenu} ${isMobile ? styles.mobile : styles.desktop}`}
|
className={cx(
|
||||||
|
styles.navigationMenu,
|
||||||
|
isMobile ? styles.mobile : styles.desktop
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{items.map((item) => (
|
{items.map((item) => (
|
||||||
<li key={item.title} className={styles.item}>
|
<li key={item.title} className={styles.item}>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
.mainMenu {
|
.mainMenu {
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Surface-Primary-Default);
|
||||||
padding: var(--Space-x2) 0;
|
padding: var(--Space-x2) 0;
|
||||||
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
border-bottom: 1px solid var(--Border-Divider-Subtle);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav {
|
.nav {
|
||||||
|
|||||||
@@ -4,12 +4,24 @@ import HeaderLink from "../HeaderLink"
|
|||||||
|
|
||||||
import styles from "./topLink.module.css"
|
import styles from "./topLink.module.css"
|
||||||
|
|
||||||
import type { TopLinkProps } from "@/types/components/header/topLink"
|
import type { Header } from "@scandic-hotels/trpc/types/header"
|
||||||
|
import type { ComponentProps } from "react"
|
||||||
|
|
||||||
|
export interface TopLinkProps
|
||||||
|
extends Omit<
|
||||||
|
ComponentProps<typeof HeaderLink>,
|
||||||
|
"href" | "iconName" | "children"
|
||||||
|
> {
|
||||||
|
isLoggedIn: boolean
|
||||||
|
topLink: Header["header"]["topLink"]
|
||||||
|
iconSize?: number
|
||||||
|
}
|
||||||
|
|
||||||
export default function TopLink({
|
export default function TopLink({
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
topLink,
|
topLink,
|
||||||
iconSize = 16,
|
iconSize = 16,
|
||||||
|
...props
|
||||||
}: TopLinkProps) {
|
}: TopLinkProps) {
|
||||||
const linkData = isLoggedIn ? topLink.logged_in : topLink.logged_out
|
const linkData = isLoggedIn ? topLink.logged_in : topLink.logged_out
|
||||||
|
|
||||||
@@ -22,6 +34,7 @@ export default function TopLink({
|
|||||||
href={linkData.url}
|
href={linkData.url}
|
||||||
iconName={linkData.icon || IconName.Gift}
|
iconName={linkData.icon || IconName.Gift}
|
||||||
iconSize={iconSize}
|
iconSize={iconSize}
|
||||||
|
{...props}
|
||||||
>
|
>
|
||||||
<span className={styles.topLink}>{linkData.title}</span>
|
<span className={styles.topLink}>{linkData.title}</span>
|
||||||
</HeaderLink>
|
</HeaderLink>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.topMenu {
|
.topMenu {
|
||||||
display: none;
|
display: none;
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
background-color: var(--Surface-Secondary-Default);
|
||||||
padding: var(--Space-x2) 0;
|
padding: var(--Space-x2) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
.header {
|
|
||||||
font-family: var(--typography-Body-Regular-fontFamily);
|
|
||||||
color: var(--Base-Text-High-contrast);
|
|
||||||
}
|
|
||||||
@@ -5,13 +5,11 @@ import { getHeader } from "@/lib/trpc/memoizedRequests"
|
|||||||
import MainMenu from "./MainMenu"
|
import MainMenu from "./MainMenu"
|
||||||
import TopMenu, { TopMenuSkeleton } from "./TopMenu"
|
import TopMenu, { TopMenuSkeleton } from "./TopMenu"
|
||||||
|
|
||||||
import styles from "./header.module.css"
|
|
||||||
|
|
||||||
export default async function Header() {
|
export default async function Header() {
|
||||||
void getHeader()
|
void getHeader()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={styles.header}>
|
<header>
|
||||||
<Suspense fallback={<TopMenuSkeleton />}>
|
<Suspense fallback={<TopMenuSkeleton />}>
|
||||||
<TopMenu />
|
<TopMenu />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
export interface MainMenuButtonProps
|
|
||||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
import type { Header } from "@scandic-hotels/trpc/types/header"
|
|
||||||
|
|
||||||
export interface TopLinkProps {
|
|
||||||
isLoggedIn: boolean
|
|
||||||
topLink: Header["header"]["topLink"]
|
|
||||||
iconSize?: number
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user