Merged in feat/SW-1450-destination-page-cs-components (pull request #1204)
feat(SW-1450): added components in destination pages from cs * feat(SW-1450): added components in destination pages from cs * feat(SW-1450): added correct refs and removed classNames Approved-by: Fredrik Thorsson
This commit is contained in:
@@ -1,10 +0,0 @@
|
||||
.pageContainer {
|
||||
display: grid;
|
||||
max-width: var(--max-width);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.pageContainer {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
|
||||
import styles from "./destinationCityPage.module.css"
|
||||
|
||||
export default async function DestinationCityPage() {
|
||||
const pageData = await getDestinationCityPage()
|
||||
|
||||
if (!pageData) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { tracking, destinationCityPage } = pageData
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.pageContainer}>
|
||||
<h1>Destination City Page</h1>
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<TrackingSDK pageData={tracking} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
.pageContainer {
|
||||
display: grid;
|
||||
max-width: var(--max-width);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.pageContainer {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { getDestinationCountryPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
|
||||
import styles from "./destinationCountryPage.module.css"
|
||||
|
||||
export default async function DestinationCountryPage() {
|
||||
const pageData = await getDestinationCountryPage()
|
||||
|
||||
if (!pageData) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { tracking, destinationCountryPage } = pageData
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.pageContainer}>
|
||||
<h1>Destination Country Page</h1>
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<TrackingSDK pageData={tracking} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
.pageContainer {
|
||||
--map-desktop-width: 23.75rem;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"sidebar"
|
||||
"mainSection";
|
||||
width: 100%;
|
||||
gap: var(--Spacing-x4);
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
.mainSection {
|
||||
grid-area: mainSection;
|
||||
padding-bottom: var(--Spacing-x7);
|
||||
min-height: 500px; /* This is a temporary value because of no content atm */
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
}
|
||||
|
||||
.experienceList {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mapWrapper {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mapWrapper img {
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.pageContainer {
|
||||
max-width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
gap: var(--Spacing-x4);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.pageContainer {
|
||||
grid-template-areas:
|
||||
"header sidebar"
|
||||
"mainSection sidebar";
|
||||
grid-template-columns: 1fr var(--map-desktop-width);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { getDestinationCityPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||
import StaticMap from "@/components/Maps/StaticMap"
|
||||
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||
import Chip from "@/components/TempDesignSystem/Chip"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import SidebarContentWrapper from "../SidebarContentWrapper"
|
||||
import DestinationPageSidePeek from "../Sidepeek"
|
||||
import TopImages from "../TopImages"
|
||||
import { mapExperiencesToListData } from "../utils"
|
||||
|
||||
import styles from "./destinationCityPage.module.css"
|
||||
|
||||
import { PageContentTypeEnum } from "@/types/requests/contentType"
|
||||
|
||||
export default async function DestinationCityPage() {
|
||||
const [intl, pageData] = await Promise.all([
|
||||
getIntl(),
|
||||
getDestinationCityPage(),
|
||||
])
|
||||
|
||||
if (!pageData) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { tracking, destinationCityPage } = pageData
|
||||
const {
|
||||
images,
|
||||
heading,
|
||||
preamble,
|
||||
experiences,
|
||||
has_sidepeek,
|
||||
sidepeek_button_text,
|
||||
sidepeek_content,
|
||||
destination_settings,
|
||||
} = destinationCityPage
|
||||
const experiencesList = await mapExperiencesToListData(experiences)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.pageContainer}>
|
||||
<header className={styles.header}>
|
||||
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
||||
<Breadcrumbs variant={PageContentTypeEnum.destinationCityPage} />
|
||||
</Suspense>
|
||||
<TopImages images={images} />
|
||||
</header>
|
||||
<main className={styles.mainSection}>
|
||||
{/* TODO: Add hotel listing by cityIdentifier */}
|
||||
{">>>> MAIN CONTENT <<<<"}
|
||||
</main>
|
||||
<aside className={styles.sidebar}>
|
||||
<SidebarContentWrapper>
|
||||
<Title level="h2">{heading}</Title>
|
||||
<Body color="uiTextMediumContrast">{preamble}</Body>
|
||||
<ul className={styles.experienceList}>
|
||||
{experiencesList.map(({ Icon, name }) => (
|
||||
<li key={name}>
|
||||
<Chip variant="tag">
|
||||
<Icon width={20} height={20} />
|
||||
{name}
|
||||
</Chip>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{has_sidepeek && (
|
||||
<DestinationPageSidePeek
|
||||
buttonText={sidepeek_button_text}
|
||||
sidePeekContent={sidepeek_content}
|
||||
/>
|
||||
)}
|
||||
|
||||
{destination_settings.city && (
|
||||
<div className={styles.mapWrapper}>
|
||||
<StaticMap
|
||||
city={destination_settings.city}
|
||||
country={destination_settings.country}
|
||||
width={320}
|
||||
height={200}
|
||||
zoomLevel={10}
|
||||
altText={intl.formatMessage({ id: "Map of the city center" })}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</SidebarContentWrapper>
|
||||
</aside>
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<TrackingSDK pageData={tracking} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
.pageContainer {
|
||||
--map-desktop-width: 23.75rem;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"header"
|
||||
"sidebar"
|
||||
"mainSection";
|
||||
width: 100%;
|
||||
gap: var(--Spacing-x4);
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
}
|
||||
|
||||
.mainSection {
|
||||
grid-area: mainSection;
|
||||
padding-bottom: var(--Spacing-x7);
|
||||
min-height: 500px; /* This is a temporary value because of no content atm */
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--Base-Surface-Subtle-Normal);
|
||||
}
|
||||
|
||||
.experienceList {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
gap: var(--Spacing-x1);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mapWrapper {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mapWrapper img {
|
||||
border-radius: var(--Corner-radius-Large);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.pageContainer {
|
||||
max-width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
gap: var(--Spacing-x4);
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.pageContainer {
|
||||
grid-template-areas:
|
||||
"header sidebar"
|
||||
"mainSection sidebar";
|
||||
grid-template-columns: 1fr var(--map-desktop-width);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Suspense } from "react"
|
||||
|
||||
import { getDestinationCountryPage } from "@/lib/trpc/memoizedRequests"
|
||||
|
||||
import Breadcrumbs from "@/components/Breadcrumbs"
|
||||
import StaticMap from "@/components/Maps/StaticMap"
|
||||
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
|
||||
import Chip from "@/components/TempDesignSystem/Chip"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import Title from "@/components/TempDesignSystem/Text/Title"
|
||||
import TrackingSDK from "@/components/TrackingSDK"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import SidebarContentWrapper from "../SidebarContentWrapper"
|
||||
import DestinationPageSidePeek from "../Sidepeek"
|
||||
import TopImages from "../TopImages"
|
||||
import { mapExperiencesToListData } from "../utils"
|
||||
|
||||
import styles from "./destinationCountryPage.module.css"
|
||||
|
||||
import { PageContentTypeEnum } from "@/types/requests/contentType"
|
||||
|
||||
export default async function DestinationCountryPage() {
|
||||
const [intl, pageData] = await Promise.all([
|
||||
getIntl(),
|
||||
getDestinationCountryPage(),
|
||||
])
|
||||
|
||||
if (!pageData) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { tracking, destinationCountryPage } = pageData
|
||||
const {
|
||||
images,
|
||||
heading,
|
||||
preamble,
|
||||
experiences,
|
||||
has_sidepeek,
|
||||
sidepeek_button_text,
|
||||
sidepeek_content,
|
||||
destination_settings,
|
||||
} = destinationCountryPage
|
||||
const experiencesList = await mapExperiencesToListData(experiences)
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.pageContainer}>
|
||||
<header className={styles.header}>
|
||||
<Suspense fallback={<BreadcrumbsSkeleton />}>
|
||||
<Breadcrumbs variant={PageContentTypeEnum.destinationCityPage} />
|
||||
</Suspense>
|
||||
<TopImages images={images} />
|
||||
</header>
|
||||
<main className={styles.mainSection}>
|
||||
{/* TODO: Add city listing by cityIdentifier */}
|
||||
{">>>> MAIN CONTENT <<<<"}
|
||||
</main>
|
||||
<aside className={styles.sidebar}>
|
||||
<SidebarContentWrapper>
|
||||
<Title level="h2">{heading}</Title>
|
||||
<Body color="uiTextMediumContrast">{preamble}</Body>
|
||||
<ul className={styles.experienceList}>
|
||||
{experiencesList.map(({ Icon, name }) => (
|
||||
<li key={name}>
|
||||
<Chip variant="tag">
|
||||
<Icon width={20} height={20} />
|
||||
{name}
|
||||
</Chip>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{has_sidepeek && (
|
||||
<DestinationPageSidePeek
|
||||
buttonText={sidepeek_button_text}
|
||||
sidePeekContent={sidepeek_content}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className={styles.mapWrapper}>
|
||||
<StaticMap
|
||||
country={destination_settings.country}
|
||||
width={320}
|
||||
height={200}
|
||||
zoomLevel={3}
|
||||
altText={intl.formatMessage({ id: "Map of the country" })}
|
||||
/>
|
||||
</div>
|
||||
</SidebarContentWrapper>
|
||||
</aside>
|
||||
</div>
|
||||
<Suspense fallback={null}>
|
||||
<TrackingSDK pageData={tracking} />
|
||||
</Suspense>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
"use client"
|
||||
|
||||
import { useRef } from "react"
|
||||
|
||||
import { StickyElementNameEnum } from "@/stores/sticky-position"
|
||||
|
||||
import useStickyPosition from "@/hooks/useStickyPosition"
|
||||
|
||||
import styles from "./sidebarContentWrapper.module.css"
|
||||
|
||||
export default function SidebarContentWrapper({
|
||||
children,
|
||||
}: React.PropsWithChildren) {
|
||||
const sidebarRef = useRef<HTMLDivElement>(null)
|
||||
useStickyPosition({
|
||||
ref: sidebarRef,
|
||||
name: StickyElementNameEnum.DESTINATION_SIDEBAR,
|
||||
})
|
||||
|
||||
return (
|
||||
<div ref={sidebarRef} className={styles.sidebarContent}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
.sidebarContent {
|
||||
display: grid;
|
||||
align-content: start;
|
||||
gap: var(--Spacing-x2);
|
||||
padding: var(--Spacing-x4);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.sidebarContent {
|
||||
position: sticky;
|
||||
}
|
||||
}
|
||||
52
components/ContentType/DestinationPage/Sidepeek/index.tsx
Normal file
52
components/ContentType/DestinationPage/Sidepeek/index.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
|
||||
import { ChevronRightSmallIcon } from "@/components/Icons"
|
||||
import JsonToHtml from "@/components/JsonToHtml"
|
||||
import Button from "@/components/TempDesignSystem/Button"
|
||||
import SidePeek from "@/components/TempDesignSystem/SidePeek"
|
||||
|
||||
import type { DestinationCityPageData } from "@/types/trpc/routers/contentstack/destinationCityPage"
|
||||
import type { DestinationCountryPageData } from "@/types/trpc/routers/contentstack/destinationCountryPage"
|
||||
|
||||
interface DestinationPageSidepeekProps {
|
||||
buttonText: string
|
||||
sidePeekContent: NonNullable<
|
||||
| DestinationCityPageData["sidepeek_content"]
|
||||
| DestinationCountryPageData["sidepeek_content"]
|
||||
>
|
||||
}
|
||||
export default function DestinationPageSidepeek({
|
||||
buttonText,
|
||||
sidePeekContent,
|
||||
}: DestinationPageSidepeekProps) {
|
||||
const [sidePeekIsOpen, setSidePeekIsOpen] = useState(false)
|
||||
const { heading, content } = sidePeekContent
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button
|
||||
onPress={() => setSidePeekIsOpen(true)}
|
||||
theme="base"
|
||||
variant="icon"
|
||||
intent="text"
|
||||
size="small"
|
||||
wrapping
|
||||
>
|
||||
{buttonText}
|
||||
<ChevronRightSmallIcon />
|
||||
</Button>
|
||||
<SidePeek
|
||||
title={heading}
|
||||
isOpen={sidePeekIsOpen}
|
||||
handleClose={() => setSidePeekIsOpen(false)}
|
||||
>
|
||||
<JsonToHtml
|
||||
nodes={content.json.children}
|
||||
embeds={content.embedded_itemsConnection.edges}
|
||||
/>
|
||||
</SidePeek>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
.ctaContainer {
|
||||
display: grid;
|
||||
gap: var(--Spacing-x2);
|
||||
}
|
||||
34
components/ContentType/DestinationPage/TopImages/index.tsx
Normal file
34
components/ContentType/DestinationPage/TopImages/index.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
"use client"
|
||||
|
||||
import Image from "@/components/Image"
|
||||
|
||||
import styles from "./topImages.module.css"
|
||||
|
||||
import type { ImageVaultAsset } from "@/types/components/imageVault"
|
||||
|
||||
interface TopImageProps {
|
||||
images: ImageVaultAsset[]
|
||||
}
|
||||
|
||||
export default function TopImages({ images }: TopImageProps) {
|
||||
const maxWidth = 1020
|
||||
|
||||
return (
|
||||
<div className={styles.imageWrapper}>
|
||||
{images.slice(0, 3).map((image, index) => (
|
||||
<Image
|
||||
key={image.url}
|
||||
src={image.url}
|
||||
alt={image.meta.alt || image.meta.caption || ""}
|
||||
width={index === 0 ? maxWidth : maxWidth / 3}
|
||||
height={Math.ceil(
|
||||
(index === 0 ? maxWidth : maxWidth / 3) /
|
||||
image.dimensions.aspectRatio
|
||||
)}
|
||||
focalPoint={image.focalPoint}
|
||||
className={styles.image}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
.imageWrapper {
|
||||
max-width: var(--max-width-page);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.image {
|
||||
height: 200px;
|
||||
max-height: 40dvh;
|
||||
width: 100%;
|
||||
border-radius: var(--Corner-radius-Medium);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 767px) {
|
||||
.image:not(:first-child) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.imageWrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
gap: var(--Spacing-x1);
|
||||
}
|
||||
|
||||
.imageWrapper > .image:first-child {
|
||||
grid-column: span 2;
|
||||
grid-row: span 2;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.imageWrapper > .image:only-child {
|
||||
grid-column: span 3;
|
||||
}
|
||||
|
||||
.imageWrapper > .image:nth-child(2):nth-last-child(1) {
|
||||
grid-column: span 1;
|
||||
grid-row: span 2;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.imageWrapper > .image:nth-child(2):nth-last-child(2),
|
||||
.imageWrapper > .image:nth-child(3) {
|
||||
grid-column: span 1;
|
||||
grid-row: span 1;
|
||||
height: calc(150px - var(--Spacing-x-half));
|
||||
max-height: calc(20dvh - var(--Spacing-x-half));
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1367px) {
|
||||
.imageWrapper > .image:first-child,
|
||||
.imageWrapper > .image:nth-child(2):nth-last-child(1) {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.imageWrapper > .image:nth-child(2):nth-last-child(2),
|
||||
.imageWrapper > .image:nth-child(3) {
|
||||
height: calc(200px - var(--Spacing-x-half));
|
||||
}
|
||||
}
|
||||
59
components/ContentType/DestinationPage/utils.ts
Normal file
59
components/ContentType/DestinationPage/utils.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
BikeIcon,
|
||||
CityIcon,
|
||||
FamilyIcon,
|
||||
KayakingIcon,
|
||||
MuseumIcon,
|
||||
NightlifeIcon,
|
||||
StarFilledIcon,
|
||||
} from "@/components/Icons"
|
||||
import { getIntl } from "@/i18n"
|
||||
|
||||
import type { FC } from "react"
|
||||
|
||||
import type { IconProps } from "@/types/components/icon"
|
||||
|
||||
export async function mapExperiencesToListData(
|
||||
experiences: string[]
|
||||
): Promise<{ Icon: FC<IconProps>; name: string }[]> {
|
||||
const intl = await getIntl()
|
||||
|
||||
return experiences.map((experience) => {
|
||||
switch (experience) {
|
||||
case "Hiking":
|
||||
return {
|
||||
Icon: StarFilledIcon,
|
||||
name: intl.formatMessage({ id: "Hiking" }),
|
||||
}
|
||||
case "Kayaking":
|
||||
return {
|
||||
Icon: KayakingIcon,
|
||||
name: intl.formatMessage({ id: "Kayaking" }),
|
||||
}
|
||||
case "Bike friendly":
|
||||
return {
|
||||
Icon: BikeIcon,
|
||||
name: intl.formatMessage({ id: "Bike friendly" }),
|
||||
}
|
||||
case "Museums":
|
||||
return { Icon: MuseumIcon, name: intl.formatMessage({ id: "Museums" }) }
|
||||
case "Family friendly":
|
||||
return {
|
||||
Icon: FamilyIcon,
|
||||
name: intl.formatMessage({ id: "Family friendly" }),
|
||||
}
|
||||
case "City pulse":
|
||||
return {
|
||||
Icon: CityIcon,
|
||||
name: intl.formatMessage({ id: "City pulse" }),
|
||||
}
|
||||
case "Nightlife":
|
||||
return {
|
||||
Icon: NightlifeIcon,
|
||||
name: intl.formatMessage({ id: "Nightlife" }),
|
||||
}
|
||||
default:
|
||||
return { Icon: StarFilledIcon, name: experience }
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default function HotelCardDialogImage({
|
||||
/>
|
||||
)}
|
||||
<div className={styles.tripAdvisor}>
|
||||
<Chip intent="secondary" className={styles.tripAdvisor}>
|
||||
<Chip className={styles.tripAdvisor}>
|
||||
<TripAdvisorIcon color="burgundy" />
|
||||
{ratings}
|
||||
</Chip>
|
||||
|
||||
@@ -14,14 +14,16 @@ function getCenter({
|
||||
city?: string
|
||||
country?: string
|
||||
}): string | undefined {
|
||||
switch (true) {
|
||||
case !!coordinates:
|
||||
return `${coordinates.lat},${coordinates.lng}`
|
||||
case !!country:
|
||||
return `${city}, ${country}`
|
||||
default:
|
||||
return city
|
||||
if (coordinates) {
|
||||
return `${coordinates.lat},${coordinates.lng}`
|
||||
}
|
||||
if (city && country) {
|
||||
return `${city}, ${country}`
|
||||
}
|
||||
if (country) {
|
||||
return country
|
||||
}
|
||||
return city
|
||||
}
|
||||
|
||||
export default function StaticMap({
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.hotelHeaderWidth.breadcrumbs {
|
||||
.headerWidth.breadcrumbs {
|
||||
max-width: min(var(--max-width-page), calc(100% - var(--max-width-spacing)));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,10 @@ export const breadcrumbsVariants = cva(styles.breadcrumbs, {
|
||||
[PageContentTypeEnum.accountPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.contentPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.collectionPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.destinationOverviewPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.destinationCountryPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.destinationCityPage]: styles.contentWidth,
|
||||
[PageContentTypeEnum.hotelPage]: styles.hotelHeaderWidth,
|
||||
[PageContentTypeEnum.destinationOverviewPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.destinationCountryPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.destinationCityPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.hotelPage]: styles.headerWidth,
|
||||
[PageContentTypeEnum.loyaltyPage]: styles.fullWidth,
|
||||
[PageContentTypeEnum.startPage]: styles.contentWidth,
|
||||
default: styles.fullWidth,
|
||||
|
||||
@@ -1,19 +1,31 @@
|
||||
div.chip {
|
||||
align-items: center;
|
||||
border-radius: var(--Corner-radius-xLarge);
|
||||
--chip-text-color: var(--Base-Text-High-contrast);
|
||||
--chip-background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
display: flex;
|
||||
gap: var(--Spacing-x-half);
|
||||
height: 22px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
||||
gap: var(--Spacing-x-half);
|
||||
border-radius: var(--Corner-radius-Small);
|
||||
color: var(--chip-text-color);
|
||||
background-color: var(--chip-background-color);
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--Scandic-Red-90);
|
||||
color: var(--Primary-Dark-On-Surface-Accent);
|
||||
.chip *,
|
||||
.chip svg * {
|
||||
fill: var(--chip-text-color);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||
color: var(--Primary-Light-On-Surface-Text);
|
||||
.chip.burgundy {
|
||||
--chip-text-color: var(--Primary-Dark-On-Surface-Text);
|
||||
--chip-background-color: var(--Base-Text-High-contrast);
|
||||
}
|
||||
|
||||
.chip.transparent {
|
||||
--chip-text-color: var(--UI-Input-Controls-On-Fill-Normal);
|
||||
--chip-background-color: rgba(64, 57, 55, 0.9);
|
||||
}
|
||||
|
||||
.chip.tag {
|
||||
--chip-background-color: var(--Base-Surface-Subtle-Hover);
|
||||
}
|
||||
|
||||
@@ -4,15 +4,9 @@ import { chipVariants } from "./variants"
|
||||
|
||||
import type { ChipProps } from "./chip"
|
||||
|
||||
export default function Chip({
|
||||
children,
|
||||
className,
|
||||
intent,
|
||||
variant,
|
||||
}: ChipProps) {
|
||||
export default function Chip({ children, className, variant }: ChipProps) {
|
||||
const classNames = chipVariants({
|
||||
className,
|
||||
intent,
|
||||
variant,
|
||||
})
|
||||
return (
|
||||
|
||||
@@ -4,16 +4,14 @@ import styles from "./chip.module.css"
|
||||
|
||||
export const chipVariants = cva(styles.chip, {
|
||||
variants: {
|
||||
intent: {
|
||||
primary: styles.primary,
|
||||
secondary: styles.secondary,
|
||||
},
|
||||
variant: {
|
||||
default: styles.default,
|
||||
burgundy: styles.burgundy,
|
||||
transparent: styles.transparent,
|
||||
tag: styles.tag,
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
intent: "primary",
|
||||
variant: "default",
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user