Feat/BOOK-63 hotel subpages branding
* feat(BOOK-63): Replaced css variables and components to apply hotel branding on subpages * feat(BOOK-63): Replaced css variables and components to apply hotel branding on hotel page map view Approved-by: Christel Westerberg Approved-by: Matilda Landström
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
|||||||
DEFAULT_THEME,
|
DEFAULT_THEME,
|
||||||
getThemeByHotel,
|
getThemeByHotel,
|
||||||
} from "@scandic-hotels/common/utils/theme"
|
} from "@scandic-hotels/common/utils/theme"
|
||||||
|
import { setTheme } from "@scandic-hotels/common/utils/theme/serverContext"
|
||||||
|
|
||||||
import { env } from "@/env/server"
|
import { env } from "@/env/server"
|
||||||
import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests"
|
import { getHotel, getHotelPage } from "@/lib/trpc/memoizedRequests"
|
||||||
@@ -44,6 +45,8 @@ export default async function HotelPagePage(
|
|||||||
? getThemeByHotel(hotelPageData.hotel_page_id, hotelData.hotel.hotelType)
|
? getThemeByHotel(hotelPageData.hotel_page_id, hotelData.hotel.hotelType)
|
||||||
: DEFAULT_THEME
|
: DEFAULT_THEME
|
||||||
|
|
||||||
|
setTheme(hotelTheme)
|
||||||
|
|
||||||
if (searchParams.subpage) {
|
if (searchParams.subpage) {
|
||||||
return (
|
return (
|
||||||
<div className={hotelTheme}>
|
<div className={hotelTheme}>
|
||||||
@@ -59,11 +62,7 @@ export default async function HotelPagePage(
|
|||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.hotelPage, hotelTheme)}>
|
<div className={cx(styles.hotelPage, hotelTheme)}>
|
||||||
<HotelPage
|
<HotelPage hotelData={hotelData} hotelPageData={hotelPageData} />
|
||||||
theme={hotelTheme}
|
|
||||||
hotelData={hotelData}
|
|
||||||
hotelPageData={hotelPageData}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { SessionProvider } from "next-auth/react"
|
|||||||
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
import StorageCleaner from "@scandic-hotels/booking-flow/components/EnterDetails/StorageCleaner"
|
||||||
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
import { NuqsAdapter } from "@scandic-hotels/booking-flow/utils/nuqs"
|
||||||
import { Lang } from "@scandic-hotels/common/constants/language"
|
import { Lang } from "@scandic-hotels/common/constants/language"
|
||||||
|
import { DEFAULT_THEME } from "@scandic-hotels/common/utils/theme"
|
||||||
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
import { ToastHandler } from "@scandic-hotels/design-system/ToastHandler"
|
||||||
|
|
||||||
import TrpcProvider from "@/lib/trpc/Provider"
|
import TrpcProvider from "@/lib/trpc/Provider"
|
||||||
@@ -63,7 +64,7 @@ export default async function RootLayout(
|
|||||||
window.dataLayer = window.dataLayer || []
|
window.dataLayer = window.dataLayer || []
|
||||||
`}</Script>
|
`}</Script>
|
||||||
</head>
|
</head>
|
||||||
<body className="scandic">
|
<body className={DEFAULT_THEME}>
|
||||||
<div className="root">
|
<div className="root">
|
||||||
<SessionProvider basePath="/api/web/auth">
|
<SessionProvider basePath="/api/web/auth">
|
||||||
<ClientIntlProvider
|
<ClientIntlProvider
|
||||||
|
|||||||
@@ -94,9 +94,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.usp li:before {
|
.usp li:before {
|
||||||
content: url("/_static/icons/heart.svg");
|
content: "";
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 3px;
|
top: 3px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-image: url("/_static/icons/heart.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.primaryButton {
|
.primaryButton {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.activeCard {
|
.activeCard {
|
||||||
border: 1px solid var(--Border-Interactive-Selected);
|
border: 1px solid var(--Border-Interactive-Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.sidebar {
|
.sidebar {
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
grid-template-columns: 1fr max-content;
|
grid-template-columns: 1fr max-content;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--Space-x2);
|
gap: var(--Space-x2);
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
color: var(--Text-Default);
|
color: var(--Text-Default);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -86,11 +86,12 @@
|
|||||||
.sidebarToggle {
|
.sidebarToggle {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--Text-Secondary);
|
color: var(--Text-Secondary);
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
margin: var(--Space-x2) 0;
|
margin: var(--Space-x2) 0;
|
||||||
padding: var(--Space-x2);
|
padding: var(--Space-x2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarToggle::before {
|
.sidebarToggle::before {
|
||||||
@@ -124,7 +125,7 @@
|
|||||||
width: 40vw;
|
width: 40vw;
|
||||||
min-width: 10rem;
|
min-width: 10rem;
|
||||||
max-width: 26.25rem;
|
max-width: 26.25rem;
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarToggle {
|
.sidebarToggle {
|
||||||
|
|||||||
@@ -5,13 +5,11 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
height: var(--hotel-map-height);
|
height: var(--hotel-map-height);
|
||||||
width: 100dvw;
|
width: 100dvw;
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Background-Default);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.closeButton {
|
.closeButton {
|
||||||
box-shadow: var(--button-box-shadow);
|
box-shadow: var(--button-box-shadow);
|
||||||
color: var(--Component-Button-Inverted-On-fill-Default);
|
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
gap: var(--Space-x05);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,21 @@
|
|||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heartList > li::before {
|
.heartList > li {
|
||||||
content: url("/_static/icons/heart.svg");
|
display: flex;
|
||||||
position: relative;
|
gap: var(--Space-x1);
|
||||||
height: 8px;
|
|
||||||
top: 3px;
|
&::before {
|
||||||
margin-right: var(--Space-x1);
|
content: "";
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-image: url("/_static/icons/heart.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { Suspense } from "react"
|
|||||||
|
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
import { safeTry } from "@scandic-hotels/common/utils/safeTry"
|
||||||
import { DEFAULT_THEME, type Theme } from "@scandic-hotels/common/utils/theme"
|
import { DEFAULT_THEME } from "@scandic-hotels/common/utils/theme"
|
||||||
|
import { getTheme } from "@scandic-hotels/common/utils/theme/serverContext"
|
||||||
import { Alert } from "@scandic-hotels/design-system/Alert"
|
import { Alert } from "@scandic-hotels/design-system/Alert"
|
||||||
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
|
||||||
import { type HotelPageData } from "@scandic-hotels/trpc/types/hotelPage"
|
import { type HotelPageData } from "@scandic-hotels/trpc/types/hotelPage"
|
||||||
@@ -58,16 +59,15 @@ import { HotelHashValues } from "@/types/enums/hotelPage"
|
|||||||
interface HotelPageProps {
|
interface HotelPageProps {
|
||||||
hotelData: HotelData
|
hotelData: HotelData
|
||||||
hotelPageData: HotelPageData
|
hotelPageData: HotelPageData
|
||||||
theme: Theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function HotelPage({
|
export default async function HotelPage({
|
||||||
hotelData,
|
hotelData,
|
||||||
hotelPageData,
|
hotelPageData,
|
||||||
theme,
|
|
||||||
}: HotelPageProps) {
|
}: HotelPageProps) {
|
||||||
const lang = await getLang()
|
const lang = await getLang()
|
||||||
const intl = await getIntl()
|
const intl = await getIntl()
|
||||||
|
const hotelTheme = getTheme()
|
||||||
|
|
||||||
const [meetingRoomsData] = await safeTry(
|
const [meetingRoomsData] = await safeTry(
|
||||||
getMeetingRooms({ hotelId: hotelData.hotel.operaId, language: lang })
|
getMeetingRooms({ hotelId: hotelData.hotel.operaId, language: lang })
|
||||||
@@ -146,7 +146,7 @@ export default async function HotelPage({
|
|||||||
)
|
)
|
||||||
const trackingHotelData = getTrackingHotelData(hotelData.hotel)
|
const trackingHotelData = getTrackingHotelData(hotelData.hotel)
|
||||||
|
|
||||||
const isThemed = theme !== DEFAULT_THEME
|
const isThemed = hotelTheme !== DEFAULT_THEME
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.pageContainer}>
|
<div className={styles.pageContainer}>
|
||||||
@@ -226,7 +226,7 @@ export default async function HotelPage({
|
|||||||
healthAndWellness={healthAndWellness ?? null}
|
healthAndWellness={healthAndWellness ?? null}
|
||||||
pageSections={pageSections}
|
pageSections={pageSections}
|
||||||
activities={activities}
|
activities={activities}
|
||||||
hotelTheme={theme}
|
hotelTheme={hotelTheme}
|
||||||
/>
|
/>
|
||||||
{campaignsBlock ? (
|
{campaignsBlock ? (
|
||||||
<HotelCampaigns
|
<HotelCampaigns
|
||||||
|
|||||||
@@ -46,12 +46,23 @@
|
|||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listItem::before {
|
.listItem {
|
||||||
content: url("/_static/icons/heart.svg");
|
display: flex;
|
||||||
position: relative;
|
gap: var(--Space-x1);
|
||||||
height: 8px;
|
|
||||||
top: 3px;
|
&::before {
|
||||||
margin-right: var(--Space-x1);
|
content: "";
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-image: url("/_static/icons/heart.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1367px) {
|
@media screen and (min-width: 1367px) {
|
||||||
|
|||||||
@@ -72,21 +72,18 @@ export default async function AccessibilitySubpage({
|
|||||||
<Typography variant="Title/Subtitle/md">
|
<Typography variant="Title/Subtitle/md">
|
||||||
<h2>{accessibilityGroup.name}</h2>
|
<h2>{accessibilityGroup.name}</h2>
|
||||||
</Typography>
|
</Typography>
|
||||||
<ul className={styles.list}>
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
{accessibilityGroup.specialNeeds.map((groupItem) => (
|
<ul className={styles.list}>
|
||||||
<Typography
|
{accessibilityGroup.specialNeeds.map((groupItem) => (
|
||||||
key={groupItem.name}
|
<li key={groupItem.name} className={styles.listItem}>
|
||||||
variant="Body/Paragraph/mdRegular"
|
|
||||||
>
|
|
||||||
<li className={styles.listItem}>
|
|
||||||
{groupItem.details
|
{groupItem.details
|
||||||
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||||
`${groupItem.name}: ${groupItem.details}`
|
`${groupItem.name}: ${groupItem.details}`
|
||||||
: groupItem.name}
|
: groupItem.name}
|
||||||
</li>
|
</li>
|
||||||
</Typography>
|
))}
|
||||||
))}
|
</ul>
|
||||||
</ul>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
.header {
|
.header {
|
||||||
display: grid;
|
display: grid;
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
background-color: var(--Background-Primary);
|
||||||
padding-bottom: var(--Space-x4);
|
padding-bottom: var(--Space-x4);
|
||||||
|
|
||||||
|
&.isThemed {
|
||||||
|
gap: var(--Space-x3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.heroWrapper {
|
.heroWrapper {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
import { cx } from "class-variance-authority"
|
||||||
import { Suspense } from "react"
|
import { Suspense } from "react"
|
||||||
|
|
||||||
|
import { DEFAULT_THEME } from "@scandic-hotels/common/utils/theme"
|
||||||
|
import { getTheme } from "@scandic-hotels/common/utils/theme/serverContext"
|
||||||
|
|
||||||
import Breadcrumbs from "@/components/Breadcrumbs"
|
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||||
import Hero from "@/components/Hero"
|
import Hero from "@/components/Hero"
|
||||||
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||||
@@ -17,10 +21,16 @@ export default async function HeroHeader({
|
|||||||
breadcrumbsTitle,
|
breadcrumbsTitle,
|
||||||
heroImage,
|
heroImage,
|
||||||
}: HeroHeaderProps) {
|
}: HeroHeaderProps) {
|
||||||
|
const hotelTheme = getTheme()
|
||||||
|
const isThemed = hotelTheme !== DEFAULT_THEME
|
||||||
return (
|
return (
|
||||||
<div className={styles.header}>
|
<div className={cx(styles.header, { [styles.isThemed]: isThemed })}>
|
||||||
<Suspense fallback={<BreadcrumbsSkeleton size="contentWidth" />}>
|
<Suspense fallback={<BreadcrumbsSkeleton size="contentWidth" />}>
|
||||||
<Breadcrumbs subpageTitle={breadcrumbsTitle} size="contentWidth" />
|
<Breadcrumbs
|
||||||
|
subpageTitle={breadcrumbsTitle}
|
||||||
|
size="contentWidth"
|
||||||
|
isThemed={isThemed}
|
||||||
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
|
|
||||||
{heroImage ? (
|
{heroImage ? (
|
||||||
|
|||||||
@@ -1,21 +1,39 @@
|
|||||||
.ul,
|
.ul,
|
||||||
.ol {
|
.ol {
|
||||||
padding: var(--Space-x2) var(--Space-x0);
|
padding: 0;
|
||||||
display: grid;
|
margin: var(--Space-x2) 0;
|
||||||
gap: var(--Space-x1);
|
|
||||||
margin-left: var(--Space-x2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.ol > li::marker {
|
|
||||||
color: var(--Primary-Light-On-Surface-Accent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.li {
|
.li {
|
||||||
margin-left: var(--Space-x3);
|
display: flex;
|
||||||
|
gap: var(--Space-x1);
|
||||||
|
|
||||||
|
* {
|
||||||
|
display: inline;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.li > p {
|
.ul {
|
||||||
display: inline;
|
list-style-type: none;
|
||||||
|
|
||||||
|
.li::before {
|
||||||
|
content: "";
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-image: url("/_static/icons/heart.svg");
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol > .li::marker {
|
||||||
|
color: var(--Icon-Accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
@@ -27,8 +45,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
.ol:has(li:nth-last-child(n + 5)),
|
.ol:has(.li:nth-last-child(n + 5)),
|
||||||
.ul:has(li:nth-last-child(n + 5)) {
|
.ul:has(.li:nth-last-child(n + 5)) {
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ElementType } from "domelementtype"
|
import { ElementType } from "domelementtype"
|
||||||
import parse, { type DOMNode, Element, type Text } from "html-react-parser"
|
import parse, { type DOMNode, Element, type Text } from "html-react-parser"
|
||||||
|
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
|
||||||
import Table from "@scandic-hotels/design-system/Table"
|
import Table from "@scandic-hotels/design-system/Table"
|
||||||
|
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import { NodeNames } from "./utils"
|
import { NodeNames } from "./utils"
|
||||||
@@ -98,16 +98,14 @@ function renderNode(domNode: Node, idx: number) {
|
|||||||
return <span>{renderChildren(domNode)}</span>
|
return <span>{renderChildren(domNode)}</span>
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Link
|
<TextLink
|
||||||
key={domNode.name + idx}
|
key={domNode.name + idx}
|
||||||
color="Text/Interactive/Secondary"
|
|
||||||
textDecoration="underline"
|
|
||||||
weight="bold"
|
|
||||||
target="_blank" //Always open in new tab
|
target="_blank" //Always open in new tab
|
||||||
href={domNode.attribs.href}
|
href={domNode.attribs.href}
|
||||||
|
isInline
|
||||||
>
|
>
|
||||||
{renderChildren(domNode)}
|
{renderChildren(domNode)}
|
||||||
</Link>
|
</TextLink>
|
||||||
)
|
)
|
||||||
|
|
||||||
case NodeNames.ul:
|
case NodeNames.ul:
|
||||||
@@ -117,19 +115,23 @@ function renderNode(domNode: Node, idx: number) {
|
|||||||
numberOfRows = Math.ceil(half)
|
numberOfRows = Math.ceil(half)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ul
|
<Typography
|
||||||
key={domNode.name + idx}
|
key={domNode.name + idx}
|
||||||
className={styles.ul}
|
variant="Body/Paragraph/mdRegular"
|
||||||
style={
|
|
||||||
numberOfRows
|
|
||||||
? {
|
|
||||||
gridTemplateRows: `repeat(${numberOfRows}, auto)`,
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{renderChildren(domNode)}
|
<ul
|
||||||
</ul>
|
className={styles.ul}
|
||||||
|
style={
|
||||||
|
numberOfRows
|
||||||
|
? {
|
||||||
|
gridTemplateRows: `repeat(${numberOfRows}, auto)`,
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{renderChildren(domNode)}
|
||||||
|
</ul>
|
||||||
|
</Typography>
|
||||||
)
|
)
|
||||||
|
|
||||||
case NodeNames.ol:
|
case NodeNames.ol:
|
||||||
@@ -139,23 +141,31 @@ function renderNode(domNode: Node, idx: number) {
|
|||||||
numberOfOlRows = Math.ceil(half)
|
numberOfOlRows = Math.ceil(half)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ol
|
<Typography
|
||||||
key={domNode.name + idx}
|
key={domNode.name + idx}
|
||||||
className={styles.ol}
|
variant="Body/Paragraph/mdRegular"
|
||||||
style={
|
|
||||||
numberOfOlRows
|
|
||||||
? {
|
|
||||||
gridTemplateRows: `repeat(${numberOfOlRows}, auto)`,
|
|
||||||
}
|
|
||||||
: {}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{renderChildren(domNode)}
|
<ol
|
||||||
</ol>
|
className={styles.ol}
|
||||||
|
style={
|
||||||
|
numberOfOlRows
|
||||||
|
? {
|
||||||
|
gridTemplateRows: `repeat(${numberOfOlRows}, auto)`,
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{renderChildren(domNode)}
|
||||||
|
</ol>
|
||||||
|
</Typography>
|
||||||
)
|
)
|
||||||
|
|
||||||
case NodeNames.li:
|
case NodeNames.li:
|
||||||
return <li key={domNode.name + idx}>{renderChildren(domNode)}</li>
|
return (
|
||||||
|
<li className={styles.li} key={domNode.name + idx}>
|
||||||
|
{renderChildren(domNode)}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
|
||||||
case NodeNames.td:
|
case NodeNames.td:
|
||||||
return (
|
return (
|
||||||
@@ -208,13 +218,24 @@ function renderNode(domNode: Node, idx: number) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
case NodeNames.em:
|
case NodeNames.em:
|
||||||
return <em>{renderChildren(domNode)}</em>
|
return <em key={domNode.name + idx}>{renderChildren(domNode)}</em>
|
||||||
|
|
||||||
case NodeNames.strong:
|
case NodeNames.strong:
|
||||||
return <strong>{renderChildren(domNode)}</strong>
|
return (
|
||||||
|
<Typography variant="Body/Paragraph/mdBold" key={domNode.name + idx}>
|
||||||
|
<strong>{renderChildren(domNode)}</strong>
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
|
|
||||||
case NodeNames.span:
|
case NodeNames.span:
|
||||||
return <span>{renderChildren(domNode)}</span>
|
return (
|
||||||
|
<Typography
|
||||||
|
variant="Body/Paragraph/mdRegular"
|
||||||
|
key={domNode.name + idx}
|
||||||
|
>
|
||||||
|
<span>{renderChildren(domNode)}</span>
|
||||||
|
</Typography>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else if (domNode.type === ElementType.Text) {
|
} else if (domNode.type === ElementType.Text) {
|
||||||
return domNode.data
|
return domNode.data
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import Image from "@scandic-hotels/design-system/Image"
|
import Image from "@scandic-hotels/design-system/Image"
|
||||||
import ImageFallback from "@scandic-hotels/design-system/ImageFallback"
|
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import ShowMoreButton from "../ShowMoreButton"
|
import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
|
||||||
|
|
||||||
import { translateRoomLighting, translateSeatingType } from "./utils"
|
import { translateRoomLighting, translateSeatingType } from "./utils"
|
||||||
|
|
||||||
import styles from "./meetingRoomCard.module.css"
|
import styles from "./meetingRoomCard.module.css"
|
||||||
@@ -34,72 +33,51 @@ export default function MeetingRoomCard({ room }: MeetingRoomCardProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<article className={styles.card}>
|
<article className={styles.card}>
|
||||||
{image?.src ? (
|
<Image
|
||||||
<Image
|
src={image?.src || ""}
|
||||||
src={image.src}
|
alt={image?.altText || image?.altText_En || ""}
|
||||||
alt={image.altText || image.altText_En || ""}
|
className={styles.image}
|
||||||
className={styles.image}
|
width={386}
|
||||||
width={386}
|
height={200}
|
||||||
height={200}
|
sizes="(min-width: 768px) 386px, 100vw"
|
||||||
sizes="(min-width: 768px) 386px, 100vw"
|
/>
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<ImageFallback />
|
|
||||||
)}
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Typography variant="Title/Subtitle/lg">
|
<Typography variant="Title/Subtitle/lg">
|
||||||
<h3>{room.name}</h3>
|
<h3>{room.name}</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={styles.capacity}>
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
<div className={styles.iconText}>
|
<div className={styles.capacity}>
|
||||||
<MaterialIcon
|
<span className={styles.roomDetails}>
|
||||||
icon="straighten"
|
<MaterialIcon icon="straighten" color="CurrentColor" size={16} />
|
||||||
color="Icon/Interactive/Placeholder"
|
|
||||||
/>
|
|
||||||
<Typography
|
|
||||||
variant="Body/Supporting text (caption)/smRegular"
|
|
||||||
className={styles.roomDetails}
|
|
||||||
>
|
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
<span>{room.size} m²</span>
|
{room.size} m²
|
||||||
</Typography>
|
</span>
|
||||||
|
{maxSeatings ? (
|
||||||
|
<span className={styles.roomDetails}>
|
||||||
|
<MaterialIcon icon="person" color="CurrentColor" size={16} />
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
id: "meetingRoomCard.maxSeatings",
|
||||||
|
defaultMessage: "max {seatings} pers",
|
||||||
|
},
|
||||||
|
{ seatings: maxSeatings }
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{maxSeatings ? (
|
</Typography>
|
||||||
<div className={styles.iconText}>
|
|
||||||
<MaterialIcon
|
|
||||||
icon="person"
|
|
||||||
color="Icon/Interactive/Placeholder"
|
|
||||||
size={16}
|
|
||||||
/>
|
|
||||||
<Typography
|
|
||||||
variant="Body/Supporting text (caption)/smRegular"
|
|
||||||
className={styles.roomDetails}
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
{intl.formatMessage(
|
|
||||||
{
|
|
||||||
id: "meetingRoomCard.maxSeatings",
|
|
||||||
defaultMessage: "max {seatings} pers",
|
|
||||||
},
|
|
||||||
{ seatings: maxSeatings }
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
{room.content.texts.descriptions.medium ? (
|
{room.content.texts.descriptions.medium ? (
|
||||||
<Typography>
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<p>{room.content.texts.descriptions.medium}</p>
|
<p>{room.content.texts.descriptions.medium}</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
{opened && (
|
{opened && (
|
||||||
<table className={styles.openedInfo}>
|
<table className={styles.infoTable}>
|
||||||
<tbody className={styles.rowItem}>
|
<tbody className={styles.tableBody}>
|
||||||
{room.seatings.map((seating, idx) => (
|
{room.seatings.map((seating, idx) => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={seating.type}
|
key={seating.type}
|
||||||
id={String(seating.capacity) + seating.type + idx}
|
id={`${seating.capacity} ${seating.type} ${idx}`}
|
||||||
name={translateSeatingType(seating.type, intl)}
|
name={translateSeatingType(seating.type, intl)}
|
||||||
value={intl.formatMessage(
|
value={intl.formatMessage(
|
||||||
{
|
{
|
||||||
@@ -111,8 +89,7 @@ export default function MeetingRoomCard({ room }: MeetingRoomCardProps) {
|
|||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
<Divider color="Border/Divider/Subtle" />
|
<tbody className={styles.tableBody}>
|
||||||
<tbody className={styles.rowItem}>
|
|
||||||
<TableRow
|
<TableRow
|
||||||
name={intl.formatMessage({
|
name={intl.formatMessage({
|
||||||
id: "meetingRoomCard.locationInHotel",
|
id: "meetingRoomCard.locationInHotel",
|
||||||
@@ -1,38 +1,11 @@
|
|||||||
.card {
|
.card {
|
||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Surface-Primary-Default);
|
||||||
border-radius: var(--Corner-radius-md);
|
border-radius: var(--Corner-radius-md);
|
||||||
border: 1px solid var(--Base-Border-Subtle);
|
border: 1px solid var(--Border-Default);
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.capacity {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: var(--Space-x1);
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconText {
|
|
||||||
display: flex;
|
|
||||||
gap: var(--Space-x05);
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rowItem {
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.openedInfo {
|
|
||||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
|
||||||
border-radius: var(--Corner-radius-md);
|
|
||||||
padding: var(--Space-x2);
|
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.image {
|
.image {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -47,10 +20,38 @@
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.roomDetails {
|
.capacity {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: var(--Space-x1);
|
||||||
|
text-align: left;
|
||||||
color: var(--Text-Tertiary);
|
color: var(--Text-Tertiary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.roomDetails {
|
||||||
|
display: flex;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoTable {
|
||||||
|
background-color: var(--Surface-Primary-OnSurface-Default);
|
||||||
|
border-radius: var(--Corner-radius-md);
|
||||||
|
padding: var(--Space-x2);
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableBody {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
|
||||||
|
&:not(:first-of-type) {
|
||||||
|
border-top: 1px solid var(--Border-Divider-Default);
|
||||||
|
padding-top: var(--Space-x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.leftColumn {
|
.leftColumn {
|
||||||
color: var(--Text-Secondary);
|
color: var(--Text-Secondary);
|
||||||
font-weight: inherit;
|
font-weight: inherit;
|
||||||
@@ -1,19 +1,24 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
import { cx } from "class-variance-authority"
|
||||||
import { useRef, useState } from "react"
|
import { useRef, useState } from "react"
|
||||||
|
|
||||||
import Grids from "@/components/TempDesignSystem/Grids"
|
|
||||||
import MeetingRoomCard from "@/components/TempDesignSystem/MeetingRoomCard"
|
|
||||||
import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
|
import ShowMoreButton from "@/components/TempDesignSystem/ShowMoreButton"
|
||||||
|
|
||||||
|
import MeetingRoomCard from "./MeetingRoomCard"
|
||||||
|
|
||||||
import styles from "./meetingRooms.module.css"
|
import styles from "./meetingRooms.module.css"
|
||||||
|
|
||||||
import type { MeetingRooms } from "@/types/components/hotelPage/meetingRooms"
|
import type { MeetingRooms } from "@/types/components/hotelPage/meetingRooms"
|
||||||
|
|
||||||
interface MeetingRoomsProps {
|
interface MeetingRoomsProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
rooms: MeetingRooms
|
rooms: MeetingRooms
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MeetingRooms({ rooms }: MeetingRoomsProps) {
|
export default function MeetingRooms({
|
||||||
|
rooms,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}: MeetingRoomsProps) {
|
||||||
const showToggleButton = rooms.length > 3
|
const showToggleButton = rooms.length > 3
|
||||||
const [allRoomsVisible, setAllRoomsVisible] = useState(!showToggleButton)
|
const [allRoomsVisible, setAllRoomsVisible] = useState(!showToggleButton)
|
||||||
|
|
||||||
@@ -27,20 +32,29 @@ export default function MeetingRooms({ rooms }: MeetingRoomsProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.section} ref={scrollRef}>
|
<section
|
||||||
<Grids.Stackable
|
className={cx(styles.roomsContainer, className)}
|
||||||
className={`${styles.grid} ${allRoomsVisible ? styles.allVisible : ""}`}
|
ref={scrollRef}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<ul
|
||||||
|
className={cx(styles.roomsList, {
|
||||||
|
[styles.allVisible]: allRoomsVisible,
|
||||||
|
})}
|
||||||
>
|
>
|
||||||
{rooms.map((room) => (
|
{rooms.map((room) => (
|
||||||
<MeetingRoomCard key={room.id} room={room.attributes} />
|
<li key={room.id} className={styles.roomsItem}>
|
||||||
|
<MeetingRoomCard room={room.attributes} />
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
</Grids.Stackable>
|
</ul>
|
||||||
{showToggleButton ? (
|
{showToggleButton ? (
|
||||||
<ShowMoreButton
|
<ShowMoreButton
|
||||||
|
className={styles.showMoreButton}
|
||||||
loadMoreData={handleShowMore}
|
loadMoreData={handleShowMore}
|
||||||
showLess={allRoomsVisible}
|
showLess={allRoomsVisible}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,33 @@
|
|||||||
.grid {
|
.roomsContainer {
|
||||||
align-items: flex-start;
|
position: relative;
|
||||||
}
|
color: var(--Text-Default);
|
||||||
|
|
||||||
.grid:not(.allVisible) > :nth-child(n + 4) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x4);
|
gap: var(--Space-x3);
|
||||||
z-index: 0;
|
}
|
||||||
|
|
||||||
|
.roomsList {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x2);
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
&:not(.allVisible) > :nth-child(n + 4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.showMoreButton {
|
||||||
|
justify-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 768px) {
|
||||||
|
.roomsList {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1367px) {
|
||||||
|
.roomsList {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,12 +75,13 @@ export default async function MeetingsSubpage({
|
|||||||
|
|
||||||
{mainBody ? <HtmlContent html={mainBody} /> : null}
|
{mainBody ? <HtmlContent html={mainBody} /> : null}
|
||||||
</main>
|
</main>
|
||||||
{meetingRooms ? (
|
|
||||||
<div className={styles.meetingsInformation}>
|
|
||||||
<MeetingsAdditionalContent rooms={meetingRooms} />
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
{meetingRooms ? (
|
||||||
|
<MeetingsAdditionalContent
|
||||||
|
className={styles.additionalContent}
|
||||||
|
rooms={meetingRooms}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</section>
|
</section>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
.meetingsSubpage {
|
.meetingsSubpage {
|
||||||
|
display: grid;
|
||||||
padding-bottom: var(--Space-x9);
|
padding-bottom: var(--Space-x9);
|
||||||
color: var(--Text-Default);
|
color: var(--Text-Default);
|
||||||
display: grid;
|
|
||||||
gap: var(--Space-x4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contentContainer {
|
.contentContainer {
|
||||||
@@ -10,7 +9,11 @@
|
|||||||
gap: var(--Space-x3);
|
gap: var(--Space-x3);
|
||||||
width: var(--max-width-content);
|
width: var(--max-width-content);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
color: var(--Text-Default);
|
}
|
||||||
|
|
||||||
|
.additionalContent {
|
||||||
|
width: var(--max-width-content);
|
||||||
|
margin: var(--Space-x4) auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mainContent {
|
.mainContent {
|
||||||
@@ -48,6 +51,10 @@
|
|||||||
column-gap: var(--Space-x9);
|
column-gap: var(--Space-x9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.additionalContent {
|
||||||
|
margin-top: var(--Space-x7);
|
||||||
|
}
|
||||||
|
|
||||||
.divider {
|
.divider {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@@ -57,8 +64,4 @@
|
|||||||
grid-row: 1 / span 2;
|
grid-row: 1 / span 2;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.meetingsInformation {
|
|
||||||
grid-column: 1 / span 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export default async function RestaurantSubpage({
|
|||||||
<ButtonLink
|
<ButtonLink
|
||||||
href={bookTableUrl}
|
href={bookTableUrl}
|
||||||
variant="Primary"
|
variant="Primary"
|
||||||
|
size="Medium"
|
||||||
typography="Body/Paragraph/mdBold"
|
typography="Body/Paragraph/mdBold"
|
||||||
>
|
>
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
gap: var(--Space-x3);
|
gap: var(--Space-x3);
|
||||||
width: var(--max-width-content);
|
width: var(--max-width-content);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
color: var(--Text-Default);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mainContent {
|
.mainContent {
|
||||||
@@ -38,8 +37,8 @@
|
|||||||
.buttonContainer {
|
.buttonContainer {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
padding: var(--Space-x3) var(--Space-x2);
|
padding: var(--Space-x3) var(--Space-x2);
|
||||||
background-color: var(--Base-Surface-Secondary-light-Normal);
|
background-color: var(--Background-Primary);
|
||||||
border-top: 1px solid var(--Base-Border-Subtle);
|
border-top: 1px solid var(--Border-Default);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import LocalCallCharges from "@/components/LocalCallCharges"
|
import LocalCallCharges from "@/components/LocalCallCharges"
|
||||||
@@ -31,13 +31,9 @@ export default async function MeetingsSidebar({
|
|||||||
</h3>
|
</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={styles.contactDetails}>
|
<div className={styles.contactDetails}>
|
||||||
<Link href={`tel:${phoneNumber}`}>{phoneNumber}</Link>
|
<TextLink href={`tel:${phoneNumber}`}>{phoneNumber}</TextLink>
|
||||||
<LocalCallCharges country={country} />
|
<LocalCallCharges country={country} />
|
||||||
{email && (
|
{email ? <TextLink href={`mailto:${email}`}>{email}</TextLink> : null}
|
||||||
<Link textDecoration="underline" href={`mailto:${email}`}>
|
|
||||||
{email}
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import LocalCallCharges from "@/components/LocalCallCharges"
|
import LocalCallCharges from "@/components/LocalCallCharges"
|
||||||
@@ -52,16 +52,13 @@ export default async function ParkingSidebar({
|
|||||||
</h3>
|
</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={styles.contactDetails}>
|
<div className={styles.contactDetails}>
|
||||||
<Link href={`tel:${contactInformation.phoneNumber}`}>
|
<TextLink href={`tel:${contactInformation.phoneNumber}`}>
|
||||||
{contactInformation.phoneNumber}
|
{contactInformation.phoneNumber}
|
||||||
</Link>
|
</TextLink>
|
||||||
<LocalCallCharges country={address.country} />
|
<LocalCallCharges country={address.country} />
|
||||||
<Link
|
<TextLink href={`mailto:${contactInformation.email}`}>
|
||||||
textDecoration="underline"
|
|
||||||
href={`mailto:${contactInformation.email}`}
|
|
||||||
>
|
|
||||||
{contactInformation.email}
|
{contactInformation.email}
|
||||||
</Link>
|
</TextLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
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 { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
|
|
||||||
import Link from "@scandic-hotels/design-system/OldDSLink"
|
|
||||||
import OpeningHours from "@scandic-hotels/design-system/OpeningHours"
|
import OpeningHours from "@scandic-hotels/design-system/OpeningHours"
|
||||||
|
import { TextLink } from "@scandic-hotels/design-system/TextLink"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import LocalCallCharges from "@/components/LocalCallCharges"
|
import LocalCallCharges from "@/components/LocalCallCharges"
|
||||||
@@ -47,14 +47,17 @@ export default async function RestaurantSidebar({
|
|||||||
) : null}
|
) : null}
|
||||||
{bookTableUrl && (
|
{bookTableUrl && (
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<Button intent="primary" theme="base" asChild>
|
<ButtonLink
|
||||||
<a href={bookTableUrl}>
|
href={bookTableUrl}
|
||||||
{intl.formatMessage({
|
variant="Primary"
|
||||||
id: "restaurantBar.bookATable",
|
size="Medium"
|
||||||
defaultMessage: "Book a table",
|
typography="Body/Paragraph/mdBold"
|
||||||
})}
|
>
|
||||||
</a>
|
{intl.formatMessage({
|
||||||
</Button>
|
id: "restaurantBar.bookATable",
|
||||||
|
defaultMessage: "Book a table",
|
||||||
|
})}
|
||||||
|
</ButtonLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{restaurant.menus.length ? (
|
{restaurant.menus.length ? (
|
||||||
@@ -70,19 +73,14 @@ export default async function RestaurantSidebar({
|
|||||||
<ul className={styles.menuList}>
|
<ul className={styles.menuList}>
|
||||||
{restaurant.menus.map(({ name, url }) => (
|
{restaurant.menus.map(({ name, url }) => (
|
||||||
<li key={name}>
|
<li key={name}>
|
||||||
<Link
|
<TextLink href={url} target="_blank">
|
||||||
href={url}
|
|
||||||
color="Text/Interactive/Secondary"
|
|
||||||
textDecoration="underline"
|
|
||||||
variant="icon"
|
|
||||||
>
|
|
||||||
{name}
|
{name}
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="open_in_new"
|
icon="open_in_new"
|
||||||
size={20}
|
size={24}
|
||||||
color="CurrentColor"
|
color="CurrentColor"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</TextLink>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -116,17 +114,15 @@ export default async function RestaurantSidebar({
|
|||||||
</h3>
|
</h3>
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={styles.contactDetails}>
|
<div className={styles.contactDetails}>
|
||||||
{phoneNumber && (
|
{phoneNumber ? (
|
||||||
<>
|
<>
|
||||||
<Link href={`tel:${phoneNumber}`}>{phoneNumber}</Link>
|
<TextLink href={`tel:${phoneNumber}`}>{phoneNumber}</TextLink>
|
||||||
<LocalCallCharges country={hotelAddress.country} />
|
<LocalCallCharges country={hotelAddress.country} />
|
||||||
</>
|
</>
|
||||||
)}
|
) : null}
|
||||||
{email && (
|
{email ? (
|
||||||
<Link textDecoration="underline" href={`mailto:${email}`}>
|
<TextLink href={`mailto:${email}`}>{email}</TextLink>
|
||||||
{email}
|
) : null}
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
.content {
|
.content {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Space-x15);
|
gap: var(--Space-x15);
|
||||||
|
color: var(--Text-Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuList {
|
.menuList {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.checkbox:has(input:checked) {
|
.checkbox:has(input:checked) {
|
||||||
border-color: var(--Border-Interactive-Selected);
|
border-color: var(--Border-Interactive-Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.checkbox:has(input:checked) span[class*="checkbox_checkbox_"] {
|
.checkbox:has(input:checked) span[class*="checkbox_checkbox_"] {
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
<svg width="33" height="32" viewBox="0 0 33 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||||
<mask id="mask0_2991_3013" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="33" height="32">
|
<path d="M7.08333 9.21667L5.65738 7.79072C5.53579 7.66913 5.38889 7.60833 5.21667 7.60833C5.04444 7.60833 4.89722 7.66944 4.775 7.79167C4.65278 7.91389 4.59167 8.06111 4.59167 8.23333C4.59167 8.40556 4.6518 8.5518 4.77207 8.67207L6.64167 10.5417C6.76742 10.6694 6.91414 10.7333 7.08182 10.7333C7.2495 10.7333 7.39722 10.6694 7.525 10.5417L11.225 6.84167C11.3472 6.71944 11.4083 6.57222 11.4083 6.4C11.4083 6.22778 11.3472 6.08056 11.225 5.95833C11.1028 5.83611 10.9556 5.775 10.7833 5.775C10.6111 5.775 10.4646 5.83538 10.3439 5.95613L7.08333 9.21667ZM8 14.5C7.10103 14.5 6.25623 14.3291 5.46558 13.9873C4.67493 13.6455 3.98717 13.1816 3.4023 12.5956C2.81743 12.0097 2.35417 11.3217 2.0125 10.5319C1.67083 9.74202 1.5 8.89806 1.5 8C1.5 7.10103 1.67091 6.25623 2.01272 5.46558C2.35453 4.67493 2.81842 3.98717 3.40438 3.4023C3.99035 2.81743 4.67826 2.35417 5.46812 2.0125C6.25798 1.67083 7.10194 1.5 8 1.5C8.89897 1.5 9.74377 1.67091 10.5344 2.01272C11.3251 2.35453 12.0128 2.81842 12.5977 3.40438C13.1826 3.99035 13.6458 4.67826 13.9875 5.46812C14.3292 6.25798 14.5 7.10194 14.5 8C14.5 8.89897 14.3291 9.74377 13.9873 10.5344C13.6455 11.3251 13.1816 12.0128 12.5956 12.5977C12.0097 13.1826 11.3217 13.6458 10.5319 13.9875C9.74202 14.3292 8.89806 14.5 8 14.5ZM8 13.25C9.46111 13.25 10.7014 12.7403 11.7208 11.7208C12.7403 10.7014 13.25 9.46111 13.25 8C13.25 6.53889 12.7403 5.29861 11.7208 4.27917C10.7014 3.25972 9.46111 2.75 8 2.75C6.53889 2.75 5.29861 3.25972 4.27917 4.27917C3.25972 5.29861 2.75 6.53889 2.75 8C2.75 9.46111 3.25972 10.7014 4.27917 11.7208C5.29861 12.7403 6.53889 13.25 8 13.25Z" fill="CurrentColor"/>
|
||||||
<rect x="0.5" width="32" height="32" fill="#D9D9D9"/>
|
|
||||||
</mask>
|
|
||||||
<g mask="url(#mask0_2991_3013)">
|
|
||||||
<path d="M14.6667 18.4333L11.8148 15.5814C11.5716 15.3383 11.2778 15.2167 10.9333 15.2167C10.5889 15.2167 10.2944 15.3389 10.05 15.5833C9.80556 15.8278 9.68333 16.1222 9.68333 16.4667C9.68333 16.8111 9.8036 17.1036 10.0441 17.3441L13.7833 21.0833C14.0348 21.3389 14.3283 21.4667 14.6636 21.4667C14.999 21.4667 15.2944 21.3389 15.55 21.0833L22.95 13.6833C23.1944 13.4389 23.3167 13.1444 23.3167 12.8C23.3167 12.4556 23.1944 12.1611 22.95 11.9167C22.7056 11.6722 22.4111 11.55 22.0667 11.55C21.7222 11.55 21.4292 11.6708 21.1877 11.9123L14.6667 18.4333ZM16.5 29C14.7021 29 13.0125 28.6582 11.4312 27.9746C9.84986 27.2909 8.47433 26.3632 7.3046 25.1912C6.13487 24.0193 5.20833 22.6435 4.525 21.0638C3.84167 19.484 3.5 17.7961 3.5 16C3.5 14.2021 3.84181 12.5125 4.52543 10.9312C5.20906 9.34986 6.13683 7.97433 7.30877 6.8046C8.4807 5.63487 9.85652 4.70833 11.4362 4.025C13.016 3.34167 14.7039 3 16.5 3C18.2979 3 19.9875 3.34181 21.5688 4.02543C23.1501 4.70906 24.5257 5.63683 25.6954 6.80877C26.8651 7.9807 27.7917 9.35652 28.475 10.9362C29.1583 12.516 29.5 14.2039 29.5 16C29.5 17.7979 29.1582 19.4875 28.4746 21.0688C27.7909 22.6501 26.8632 24.0257 25.6912 25.1954C24.5193 26.3651 23.1435 27.2917 21.5638 27.975C19.984 28.6583 18.2961 29 16.5 29Z" fill="#33800A"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -1,8 +1,3 @@
|
|||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
|
||||||
<mask id="mask0_5625_32301" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="16" height="16">
|
<path d="M7.99994 13.4167L7.23327 12.725C6.14142 11.752 5.24068 10.9184 4.53105 10.2244C3.82142 9.53035 3.26225 8.91443 2.85354 8.37663C2.44481 7.83884 2.16148 7.34728 2.00353 6.90195C1.84558 6.45663 1.7666 6.00042 1.7666 5.53333C1.7666 4.57768 2.09435 3.77209 2.74985 3.11658C3.40536 2.46108 4.21095 2.13333 5.1666 2.13333C5.70314 2.13333 6.22338 2.25 6.72734 2.48333C7.23129 2.71666 7.65549 3.05 7.99994 3.48333C8.36105 3.05 8.78882 2.71666 9.28327 2.48333C9.77771 2.25 10.2944 2.13333 10.8333 2.13333C11.7889 2.13333 12.5945 2.46108 13.25 3.11658C13.9055 3.77209 14.2333 4.57768 14.2333 5.53333C14.2333 6.00042 14.1571 6.45107 14.0047 6.88528C13.8523 7.3195 13.5717 7.80273 13.163 8.33496C12.7543 8.86721 12.1923 9.48591 11.4772 10.1911C10.762 10.8962 9.84734 11.752 8.73327 12.7583L7.99994 13.4167Z" fill="CurrentColor"/>
|
||||||
<rect width="16" height="16" fill="#D9D9D9"/>
|
|
||||||
</mask>
|
|
||||||
<g mask="url(#mask0_5625_32301)">
|
|
||||||
<path d="M7.99994 13.4171L7.23327 12.7255C6.14142 11.7524 5.24068 10.9189 4.53105 10.2249C3.82142 9.53081 3.26225 8.91489 2.85354 8.37709C2.44481 7.8393 2.16148 7.34774 2.00353 6.90241C1.84558 6.45708 1.7666 6.00088 1.7666 5.53379C1.7666 4.57813 2.09435 3.77255 2.74985 3.11704C3.40536 2.46154 4.21095 2.13379 5.1666 2.13379C5.70314 2.13379 6.22338 2.25046 6.72734 2.48379C7.23129 2.71712 7.65549 3.05046 7.99994 3.48379C8.36105 3.05046 8.78882 2.71712 9.28327 2.48379C9.77771 2.25046 10.2944 2.13379 10.8333 2.13379C11.7889 2.13379 12.5945 2.46154 13.25 3.11704C13.9055 3.77255 14.2333 4.57813 14.2333 5.53379C14.2333 6.00088 14.1571 6.45153 14.0047 6.88574C13.8523 7.31996 13.5717 7.80319 13.163 8.33542C12.7543 8.86767 12.1923 9.48637 11.4772 10.1915C10.762 10.8967 9.84734 11.7524 8.73327 12.7588L7.99994 13.4171Z" fill="#B05B65"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 931 B |
@@ -64,7 +64,8 @@
|
|||||||
"./utils/promiseWithTimeout": "./utils/promiseWithTimeout.ts",
|
"./utils/promiseWithTimeout": "./utils/promiseWithTimeout.ts",
|
||||||
"./utils/rangeArray": "./utils/rangeArray.ts",
|
"./utils/rangeArray": "./utils/rangeArray.ts",
|
||||||
"./utils/safeTry": "./utils/safeTry.ts",
|
"./utils/safeTry": "./utils/safeTry.ts",
|
||||||
"./utils/theme": "./utils/theme.ts",
|
"./utils/theme": "./utils/theme/index.ts",
|
||||||
|
"./utils/theme/serverContext": "./utils/theme/serverContext.ts",
|
||||||
"./utils/toCapitalCase": "./utils/toCapitalCase.ts",
|
"./utils/toCapitalCase": "./utils/toCapitalCase.ts",
|
||||||
"./utils/url": "./utils/url.ts",
|
"./utils/url": "./utils/url.ts",
|
||||||
"./utils/zod/*": "./utils/zod/*.ts"
|
"./utils/zod/*": "./utils/zod/*.ts"
|
||||||
|
|||||||
31
packages/common/utils/theme/serverContext.ts
Normal file
31
packages/common/utils/theme/serverContext.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import "server-only"
|
||||||
|
|
||||||
|
import { cache } from "react"
|
||||||
|
|
||||||
|
import { DEFAULT_THEME, type Theme } from "."
|
||||||
|
|
||||||
|
const getRef = cache(() => ({ current: DEFAULT_THEME as Theme }))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the global theme
|
||||||
|
*
|
||||||
|
* It works kind of like React's context,
|
||||||
|
* but on the server side, per request.
|
||||||
|
*
|
||||||
|
* @param newTheme
|
||||||
|
*/
|
||||||
|
export function setTheme(newTheme: Theme) {
|
||||||
|
getRef().current = newTheme
|
||||||
|
|
||||||
|
return newTheme
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the global theme
|
||||||
|
*
|
||||||
|
* Note: This must be called after setTheme() has been called in the page/layout.
|
||||||
|
* If called before setTheme(), it will return DEFAULT_THEME.
|
||||||
|
*/
|
||||||
|
export function getTheme(): Theme {
|
||||||
|
return getRef().current ?? DEFAULT_THEME
|
||||||
|
}
|
||||||
@@ -27,12 +27,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.Outlined:active {
|
.Outlined:active {
|
||||||
border-color: var(--Border-Interactive-Selected);
|
border-color: var(--Border-Interactive-Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.FilterRounded {
|
.FilterRounded {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: 1px solid var(--Border-Interactive-Selected);
|
border: 1px solid var(--Border-Interactive-Active);
|
||||||
border-radius: var(--Corner-radius-rounded);
|
border-radius: var(--Corner-radius-rounded);
|
||||||
padding: var(--Space-x025) var(--Space-x2);
|
padding: var(--Space-x025) var(--Space-x2);
|
||||||
color: var(--Text-Default);
|
color: var(--Text-Default);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label:has(:checked) {
|
.label:has(:checked) {
|
||||||
border: 2px solid var(--Border-Interactive-Selected);
|
border: 2px solid var(--Border-Interactive-Active);
|
||||||
}
|
}
|
||||||
|
|
||||||
.label:not(:has(:checked)) .selectedIcon {
|
.label:not(:has(:checked)) .selectedIcon {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import NextImage, { ImageProps as NextImageProps } from 'next/image'
|
|||||||
|
|
||||||
import ImageFallback from '../ImageFallback'
|
import ImageFallback from '../ImageFallback'
|
||||||
|
|
||||||
import type { CSSProperties } from 'react'
|
import { useState, type CSSProperties, type SyntheticEvent } from 'react'
|
||||||
import { imageLoader } from './imageLoader'
|
import { imageLoader } from './imageLoader'
|
||||||
|
|
||||||
type FocalPoint = {
|
type FocalPoint = {
|
||||||
@@ -22,8 +22,11 @@ export default function Image({
|
|||||||
focalPoint,
|
focalPoint,
|
||||||
dimensions,
|
dimensions,
|
||||||
style,
|
style,
|
||||||
|
src,
|
||||||
|
onError,
|
||||||
...props
|
...props
|
||||||
}: ImageProps) {
|
}: ImageProps) {
|
||||||
|
const [imageError, setImageError] = useState(false)
|
||||||
const styles: CSSProperties = focalPoint
|
const styles: CSSProperties = focalPoint
|
||||||
? {
|
? {
|
||||||
objectFit: 'cover',
|
objectFit: 'cover',
|
||||||
@@ -32,14 +35,24 @@ export default function Image({
|
|||||||
}
|
}
|
||||||
: { ...style }
|
: { ...style }
|
||||||
|
|
||||||
if (!props.src) {
|
function handleError(error: SyntheticEvent<HTMLImageElement, Event>) {
|
||||||
|
if (onError) {
|
||||||
|
onError(error)
|
||||||
|
} else {
|
||||||
|
setImageError(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src || imageError) {
|
||||||
return <ImageFallback />
|
return <ImageFallback />
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NextImage
|
<NextImage
|
||||||
{...props}
|
{...props}
|
||||||
|
src={src}
|
||||||
style={styles}
|
style={styles}
|
||||||
|
onError={handleError}
|
||||||
loader={imageLoader({ dimensions, focalPoint })}
|
loader={imageLoader({ dimensions, focalPoint })}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -87,19 +87,26 @@
|
|||||||
.li:has(.heart)::before,
|
.li:has(.heart)::before,
|
||||||
.check > .li::before,
|
.check > .li::before,
|
||||||
.li:has(.check)::before {
|
.li:has(.check)::before {
|
||||||
|
content: '';
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 8px;
|
|
||||||
top: 3px;
|
top: 3px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
.check > .li::before,
|
.check > .li::before,
|
||||||
.li:has(.check)::before {
|
.li:has(.check)::before {
|
||||||
content: url('/_static/icons/check-ring.svg');
|
mask-image: url('/_static/icons/check_circle.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.heart > .li::before,
|
.heart > .li::before,
|
||||||
.li:has(.heart)::before {
|
.li:has(.heart)::before {
|
||||||
content: url('/_static/icons/heart.svg');
|
mask-image: url('/_static/icons/heart.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.li > * {
|
.li > * {
|
||||||
|
|||||||
@@ -4,77 +4,63 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.mapContainer :global(.gm-style .gm-style-iw-d) {
|
&::after {
|
||||||
padding: 0 !important;
|
content: '';
|
||||||
overflow: hidden !important;
|
position: absolute;
|
||||||
max-height: none !important;
|
top: 0;
|
||||||
max-width: none !important;
|
right: 0;
|
||||||
}
|
background: linear-gradient(
|
||||||
|
43deg,
|
||||||
|
rgba(172, 172, 172, 0) 57.66%,
|
||||||
|
rgba(0, 0, 0, 0.25) 92.45%
|
||||||
|
);
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mapContainer :global(.gm-style .gm-style-iw-c) {
|
:global(.gm-style .gm-style-iw-d),
|
||||||
padding: 0 !important;
|
:global(.gm-style .gm-style-iw-c) {
|
||||||
overflow: hidden !important;
|
padding: 0 !important;
|
||||||
max-height: none !important;
|
overflow: hidden !important;
|
||||||
max-width: none !important;
|
max-height: none !important;
|
||||||
}
|
max-width: none !important;
|
||||||
|
}
|
||||||
.mapContainer::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
background: linear-gradient(
|
|
||||||
43deg,
|
|
||||||
rgba(172, 172, 172, 0) 57.66%,
|
|
||||||
rgba(0, 0, 0, 0.25) 92.45%
|
|
||||||
);
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ctaButtons {
|
.ctaButtons {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: var(--Spacing-x2);
|
top: var(--Space-x2);
|
||||||
right: var(--Spacing-x2);
|
right: var(--Space-x2);
|
||||||
z-index: 1;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
gap: var(--Space-x7);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--Spacing-x7);
|
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomButtons {
|
.zoomButtons {
|
||||||
display: grid;
|
display: flex;
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Space-x2);
|
||||||
}
|
|
||||||
|
|
||||||
.closeButton {
|
|
||||||
pointer-events: initial;
|
|
||||||
box-shadow: var(--button-box-shadow);
|
|
||||||
gap: var(--Spacing-x-half);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomButton {
|
.zoomButton {
|
||||||
width: var(--Space-x5);
|
|
||||||
height: var(--Space-x5);
|
|
||||||
padding: 0;
|
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
box-shadow: var(--button-box-shadow);
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 767px) {
|
||||||
|
.zoomButtons {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
@media screen and (min-width: 768px) {
|
||||||
.ctaButtons {
|
.ctaButtons {
|
||||||
top: var(--Spacing-x4);
|
top: var(--Space-x4);
|
||||||
right: var(--Spacing-x5);
|
right: var(--Space-x5);
|
||||||
bottom: var(--Spacing-x7);
|
bottom: var(--Space-x7);
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomButtons {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import { IconByIconName } from '../../../Icons/IconByIconName'
|
import { IconByIconName } from '../../../Icons/IconByIconName'
|
||||||
|
|
||||||
import { getIconByPoiGroupAndCategory } from '../utils'
|
import {
|
||||||
|
getIconByPoiGroupAndCategory,
|
||||||
|
type PointOfInterestGroup,
|
||||||
|
} from '../utils'
|
||||||
import { poiVariants } from './variants'
|
import { poiVariants } from './variants'
|
||||||
|
|
||||||
import { VariantProps } from 'class-variance-authority'
|
import type { VariantProps } from 'class-variance-authority'
|
||||||
|
|
||||||
export type PointOfInterestGroup =
|
interface PoiMarkerProps extends VariantProps<typeof poiVariants> {
|
||||||
| 'Public transport'
|
|
||||||
| 'Attractions'
|
|
||||||
| 'Business'
|
|
||||||
| 'Location'
|
|
||||||
| 'Parking'
|
|
||||||
| 'Shopping & Dining'
|
|
||||||
|
|
||||||
export interface PoiMarkerProps extends VariantProps<typeof poiVariants> {
|
|
||||||
group: PointOfInterestGroup
|
group: PointOfInterestGroup
|
||||||
categoryName?: string
|
categoryName?: string
|
||||||
className?: string
|
className?: string
|
||||||
@@ -33,7 +28,7 @@ export function PoiMarker({
|
|||||||
<span className={classNames}>
|
<span className={classNames}>
|
||||||
<IconByIconName
|
<IconByIconName
|
||||||
iconName={iconName}
|
iconName={iconName}
|
||||||
color={skipBackground ? 'Icon/Feedback/Neutral' : 'Icon/Inverted'}
|
color={skipBackground ? 'CurrentColor' : 'Icon/Inverted'}
|
||||||
size={size === 'small' ? 16 : size === 'large' ? 24 : 20}
|
size={size === 'small' ? 16 : size === 'large' ? 24 : 20}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,9 +1,37 @@
|
|||||||
.icon {
|
.poiMarker {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: var(--Corner-radius-rounded);
|
border-radius: var(--Corner-radius-rounded);
|
||||||
background-color: var(--Surface-UI-Fill-Default);
|
background-color: var(--Surface-Feedback-Neutral);
|
||||||
|
|
||||||
|
> span {
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.skipBackground {
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.shoppingDining {
|
||||||
|
background-color: var(--Surface-Accent-1);
|
||||||
|
}
|
||||||
|
.publicTransport {
|
||||||
|
background-color: var(--Surface-Accent-2);
|
||||||
|
}
|
||||||
|
.attractions {
|
||||||
|
background-color: var(--Surface-Accent-3);
|
||||||
|
}
|
||||||
|
.business {
|
||||||
|
background-color: var(--Surface-Accent-4);
|
||||||
|
}
|
||||||
|
.parking {
|
||||||
|
background-color: var(--Surface-Accent-5);
|
||||||
|
}
|
||||||
|
.location {
|
||||||
|
background-color: var(--Surface-Feedback-Neutral);
|
||||||
}
|
}
|
||||||
|
|
||||||
.small {
|
.small {
|
||||||
@@ -14,27 +42,3 @@
|
|||||||
width: var(--Space-x4);
|
width: var(--Space-x4);
|
||||||
height: var(--Space-x4);
|
height: var(--Space-x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.attractions {
|
|
||||||
background-color: var(--Surface-Accent-3);
|
|
||||||
}
|
|
||||||
.business {
|
|
||||||
background-color: var(--Surface-Accent-4);
|
|
||||||
}
|
|
||||||
.location {
|
|
||||||
background-color: var(--Surface-Feedback-Neutral);
|
|
||||||
}
|
|
||||||
.parking {
|
|
||||||
background-color: var(--Surface-Accent-5);
|
|
||||||
}
|
|
||||||
.publicTransport {
|
|
||||||
background-color: var(--Surface-Accent-2);
|
|
||||||
}
|
|
||||||
.shoppingDining {
|
|
||||||
background-color: var(--Surface-Accent-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon.transparent {
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { cva } from 'class-variance-authority'
|
import { cva } from 'class-variance-authority'
|
||||||
|
|
||||||
import styles from './poi.module.css'
|
import type { PointOfInterestGroup } from '../utils'
|
||||||
import { PointOfInterestGroup } from '.'
|
import styles from './poiMarker.module.css'
|
||||||
|
|
||||||
export const poiVariants = cva(styles.icon, {
|
export const poiVariants = cva(styles.poiMarker, {
|
||||||
variants: {
|
variants: {
|
||||||
group: {
|
group: {
|
||||||
['Attractions']: styles.attractions,
|
['Attractions']: styles.attractions,
|
||||||
@@ -14,7 +14,7 @@ export const poiVariants = cva(styles.icon, {
|
|||||||
['Shopping & Dining']: styles.shoppingDining,
|
['Shopping & Dining']: styles.shoppingDining,
|
||||||
} satisfies Record<PointOfInterestGroup, string>,
|
} satisfies Record<PointOfInterestGroup, string>,
|
||||||
skipBackground: {
|
skipBackground: {
|
||||||
true: styles.transparent,
|
true: styles.skipBackground,
|
||||||
false: '',
|
false: '',
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
import { IconName } from '../../Icons/iconName'
|
import { IconName } from '../../Icons/iconName'
|
||||||
import { PointOfInterestGroup } from './PoiMarker'
|
|
||||||
|
export type PointOfInterestGroup =
|
||||||
|
| 'Public transport'
|
||||||
|
| 'Attractions'
|
||||||
|
| 'Business'
|
||||||
|
| 'Location'
|
||||||
|
| 'Parking'
|
||||||
|
| 'Shopping & Dining'
|
||||||
|
|
||||||
export function getIconByPoiGroupAndCategory(
|
export function getIconByPoiGroupAndCategory(
|
||||||
group: PointOfInterestGroup,
|
group: PointOfInterestGroup,
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ export default function ParkingList({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
<ul className={styles.listStyling}>
|
<ul className={styles.list}>
|
||||||
{numberOfChargingSpaces ? (
|
{numberOfChargingSpaces ? (
|
||||||
<li>
|
<li className={styles.listItem}>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{
|
{
|
||||||
id: 'parkingInformation.numberOfChargingPoints',
|
id: 'parkingInformation.numberOfChargingPoints',
|
||||||
@@ -50,13 +50,13 @@ export default function ParkingList({
|
|||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
<li>
|
<li className={styles.listItem}>
|
||||||
{canMakeReservation
|
{canMakeReservation
|
||||||
? canMakeReservationYesMsg
|
? canMakeReservationYesMsg
|
||||||
: canMakeReservationNoMsg}
|
: canMakeReservationNoMsg}
|
||||||
</li>
|
</li>
|
||||||
{numberOfParkingSpots ? (
|
{numberOfParkingSpots ? (
|
||||||
<li>
|
<li className={styles.listItem}>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{
|
{
|
||||||
id: 'parkingInformation.numberOfParkingSpots',
|
id: 'parkingInformation.numberOfParkingSpots',
|
||||||
@@ -67,7 +67,7 @@ export default function ParkingList({
|
|||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
{distanceToHotel ? (
|
{distanceToHotel ? (
|
||||||
<li>
|
<li className={styles.listItem}>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{
|
{
|
||||||
id: 'parkingInformation.distanceToHotel',
|
id: 'parkingInformation.distanceToHotel',
|
||||||
@@ -78,7 +78,7 @@ export default function ParkingList({
|
|||||||
</li>
|
</li>
|
||||||
) : null}
|
) : null}
|
||||||
{address ? (
|
{address ? (
|
||||||
<li>
|
<li className={styles.listItem}>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{
|
{
|
||||||
id: 'parkingInformation.address',
|
id: 'parkingInformation.address',
|
||||||
|
|||||||
@@ -1,11 +1,24 @@
|
|||||||
.listStyling {
|
.list {
|
||||||
|
display: grid;
|
||||||
|
gap: var(--Space-x1);
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listStyling > li::before {
|
.listItem {
|
||||||
content: url('/_static/icons/heart.svg');
|
display: flex;
|
||||||
position: relative;
|
gap: var(--Space-x1);
|
||||||
height: 8px;
|
|
||||||
top: 3px;
|
&::before {
|
||||||
margin-right: var(--Spacing-x1);
|
content: '';
|
||||||
|
position: relative;
|
||||||
|
top: 3px;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background-color: var(--Icon-Accent);
|
||||||
|
mask-image: url('/_static/icons/heart.svg');
|
||||||
|
mask-size: contain;
|
||||||
|
mask-repeat: no-repeat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl'
|
||||||
|
|
||||||
|
import ButtonLink from '../ButtonLink'
|
||||||
import { Divider } from '../Divider'
|
import { Divider } from '../Divider'
|
||||||
import { MaterialIcon } from '../Icons/MaterialIcon'
|
import { MaterialIcon } from '../Icons/MaterialIcon'
|
||||||
import { Typography } from '../Typography'
|
import { Typography } from '../Typography'
|
||||||
import ButtonLink from '../ButtonLink'
|
|
||||||
import ParkingList from './ParkingList'
|
import ParkingList from './ParkingList'
|
||||||
import ParkingPrices from './ParkingPrices'
|
import ParkingPrices from './ParkingPrices'
|
||||||
|
|
||||||
@@ -88,6 +88,7 @@ export default function ParkingInformation({
|
|||||||
{parking.externalParkingUrl && showExternalParkingButton && (
|
{parking.externalParkingUrl && showExternalParkingButton && (
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
typography="Body/Paragraph/mdBold"
|
typography="Body/Paragraph/mdBold"
|
||||||
|
size="Medium"
|
||||||
href={parking.externalParkingUrl}
|
href={parking.externalParkingUrl}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
.parkingInformation {
|
.parkingInformation {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Spacing-x3);
|
gap: var(--Space-x3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list,
|
.list,
|
||||||
.prices {
|
.prices {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Spacing-x-one-and-half);
|
gap: var(--Space-x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
.priceWrapper {
|
.priceWrapper {
|
||||||
background-color: var(--Base-Surface-Subtle-Normal);
|
background-color: var(--Surface-Secondary-Default);
|
||||||
border-radius: var(--Corner-radius-md);
|
border-radius: var(--Corner-radius-md);
|
||||||
padding: var(--Spacing-x2) var(--Spacing-x3);
|
padding: var(--Space-x2) var(--Space-x3);
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Spacing-x1);
|
gap: var(--Space-x1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
.theme-primary:not(.disabled) {
|
.theme-primary:not(.disabled) {
|
||||||
color: var(--Text-Interactive-Secondary);
|
color: var(--Text-Interactive-Secondary);
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: var(--Text-Interactive-Secondary-Hover);
|
color: var(--Text-Interactive-Secondary-Hover);
|
||||||
@@ -28,7 +27,6 @@
|
|||||||
|
|
||||||
.theme-inverted:not(.disabled) {
|
.theme-inverted:not(.disabled) {
|
||||||
color: var(--Text-Inverted);
|
color: var(--Text-Inverted);
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
|
|||||||
Reference in New Issue
Block a user