From ebe79c43e0d47f3d2a895984df66be0b09584459 Mon Sep 17 00:00:00 2001 From: Chuma McPhoy Date: Thu, 18 Jul 2024 00:40:49 +0200 Subject: [PATCH] feat: Add tab navigation to hotel page --- app/globals.css | 1 + .../ContentType/HotelPage/HotelPage.tsx | 30 +++++++------ .../ContentType/HotelPage/Rooms/index.tsx | 4 +- .../HotelPage/TabNavigation/index.tsx | 44 +++++++++++++++++++ .../TabNavigation/tabNavigation.module.css | 11 +++++ .../HotelPage/TabNavigation/types.ts | 8 ++++ .../HotelPage/hotelPage.module.css | 16 ++++++- components/MyPages/Breadcrumbs/index.tsx | 2 +- components/TempDesignSystem/Link/index.tsx | 5 ++- .../TempDesignSystem/Link/link.module.css | 11 +++++ components/TempDesignSystem/Link/variants.ts | 1 + hooks/useHash.tsx | 22 ++++++++++ i18n/dictionaries/en.json | 8 +++- i18n/dictionaries/sv.json | 2 +- 14 files changed, 145 insertions(+), 20 deletions(-) create mode 100644 components/ContentType/HotelPage/TabNavigation/index.tsx create mode 100644 components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css create mode 100644 components/ContentType/HotelPage/TabNavigation/types.ts create mode 100644 hooks/useHash.tsx diff --git a/app/globals.css b/app/globals.css index 99216e464..52b84b9e6 100644 --- a/app/globals.css +++ b/app/globals.css @@ -108,6 +108,7 @@ html, body { margin: 0; padding: 0; + scroll-behavior: smooth; } body { diff --git a/components/ContentType/HotelPage/HotelPage.tsx b/components/ContentType/HotelPage/HotelPage.tsx index d57b3c36a..e1678b435 100644 --- a/components/ContentType/HotelPage/HotelPage.tsx +++ b/components/ContentType/HotelPage/HotelPage.tsx @@ -3,6 +3,7 @@ import { serverClient } from "@/lib/trpc/server" import AmenitiesList from "./AmenitiesList" import IntroSection from "./IntroSection" import { Rooms } from "./Rooms" +import TabNavigation from "./TabNavigation" import styles from "./hotelPage.module.css" @@ -23,18 +24,21 @@ export default async function HotelPage({ lang }: LangParams) { }) return ( -
-
- - -
- -
+
+ +
+
+ + +
+ +
+
) } diff --git a/components/ContentType/HotelPage/Rooms/index.tsx b/components/ContentType/HotelPage/Rooms/index.tsx index c865e23e7..109c48448 100644 --- a/components/ContentType/HotelPage/Rooms/index.tsx +++ b/components/ContentType/HotelPage/Rooms/index.tsx @@ -30,10 +30,10 @@ export async function Rooms({ rooms }: RoomsProps) { .sort((a, b) => a.sortOrder - b.sortOrder) .slice(0, 3) //TODO: Remove this and render all rooms once we've implemented "show more" logic in SW-203. return ( - + diff --git a/components/ContentType/HotelPage/TabNavigation/index.tsx b/components/ContentType/HotelPage/TabNavigation/index.tsx new file mode 100644 index 000000000..d04575a00 --- /dev/null +++ b/components/ContentType/HotelPage/TabNavigation/index.tsx @@ -0,0 +1,44 @@ +"use client" +import { useIntl } from "react-intl" + +import Link from "@/components/TempDesignSystem/Link" +import useHash from "@/hooks/useHash" + +import { HotelHashValues } from "./types" + +import styles from "./tabNavigation.module.css" + +export default function TabNavigation() { + const hash = useHash() + const { formatMessage } = useIntl() + const hotelTabLinks: { href: HotelHashValues; text: string }[] = [ + { href: "#overview", text: "Overview" }, + { href: "#rooms-section", text: "Rooms" }, + { href: "#restaurant-and-bar", text: "Restaurant & Bar" }, + { href: "#meetings-and-conferences", text: "Meetings & Conferences" }, + { href: "#wellness-and-exercise", text: "Wellness & Exercise" }, + { href: "#activities", text: "Activities" }, + { href: "#faq", text: "FAQ" }, + ] + return ( + + ) +} diff --git a/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css b/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css new file mode 100644 index 000000000..c7749c9c5 --- /dev/null +++ b/components/ContentType/HotelPage/TabNavigation/tabNavigation.module.css @@ -0,0 +1,11 @@ +.tabsContainer { + display: flex; + overflow-x: auto; + white-space: nowrap; + gap: var(--Spacing-x4); + background: var(--Base-Surface-Subtle-Normal); + justify-content: flex-start; + padding-left: var(--Spacing-x4); + padding-right: var(--Spacing-x3); + border-bottom: 1px solid var(--Base-Border-Subtle); +} diff --git a/components/ContentType/HotelPage/TabNavigation/types.ts b/components/ContentType/HotelPage/TabNavigation/types.ts new file mode 100644 index 000000000..d8cc2e3a7 --- /dev/null +++ b/components/ContentType/HotelPage/TabNavigation/types.ts @@ -0,0 +1,8 @@ +export type HotelHashValues = + | "#overview" + | "#rooms-section" + | "#restaurant-and-bar" + | "#meetings-and-conferences" + | "#wellness-and-exercise" + | "#activities" + | "#faq" diff --git a/components/ContentType/HotelPage/hotelPage.module.css b/components/ContentType/HotelPage/hotelPage.module.css index d168ea390..bb9c7f0c9 100644 --- a/components/ContentType/HotelPage/hotelPage.module.css +++ b/components/ContentType/HotelPage/hotelPage.module.css @@ -1,4 +1,13 @@ .pageContainer { + overflow-x: auto; +} + +.pageContainer > * { + padding-left: var(--Spacing-x4); + padding-right: var(--Spacing-x3); +} + +.mainSection { display: grid; gap: var(--Spacing-x9); padding: var(--Spacing-x5) var(--Spacing-x3) var(--Spacing-x4); @@ -11,9 +20,14 @@ } @media screen and (min-width: 1367px) { - .pageContainer { + .pageContainer > *:not(nav) { padding: var(--Spacing-x9) var(--Spacing-x5); } + + .pageContainer > nav { + padding-left: var(--Spacing-x5); + padding-right: var(--Spacing-x5); + } .introContainer { display: grid; /* use justify-content: space between once we have the map component*/ diff --git a/components/MyPages/Breadcrumbs/index.tsx b/components/MyPages/Breadcrumbs/index.tsx index 36cacbf17..ccb09401a 100644 --- a/components/MyPages/Breadcrumbs/index.tsx +++ b/components/MyPages/Breadcrumbs/index.tsx @@ -8,7 +8,7 @@ import styles from "./breadcrumbs.module.css" export default async function Breadcrumbs() { const breadcrumbs = await serverClient().contentstack.breadcrumbs.get() - if (!breadcrumbs) { + if (!breadcrumbs || breadcrumbs.length === 0) { return null } const homeBreadcrumb = breadcrumbs.shift() diff --git a/components/TempDesignSystem/Link/index.tsx b/components/TempDesignSystem/Link/index.tsx index 80a3bd981..1a2e46415 100644 --- a/components/TempDesignSystem/Link/index.tsx +++ b/components/TempDesignSystem/Link/index.tsx @@ -10,6 +10,7 @@ import { linkVariants } from "./variants" import type { LinkProps } from "./link" export default function Link({ + active, className, color, href, @@ -23,10 +24,12 @@ export default function Link({ ...props }: LinkProps) { const currentPageSlug = usePathname() - let isActive = currentPageSlug === href + let isActive = active || currentPageSlug === href + if (partialMatch && !isActive) { isActive = currentPageSlug === href } + const classNames = linkVariants({ active: isActive, className, diff --git a/components/TempDesignSystem/Link/link.module.css b/components/TempDesignSystem/Link/link.module.css index 4cfd8b94d..0261002de 100644 --- a/components/TempDesignSystem/Link/link.module.css +++ b/components/TempDesignSystem/Link/link.module.css @@ -93,6 +93,17 @@ background-color: var(--Scandic-Peach-20); } +.tab { + font-family: var(--typography-Body-Regular-fontFamily); + padding: var(--Spacing-x2) var(--Spacing-x0); + color: var(--Base-Text-High-contrast); + text-decoration: none; +} + +.tab.active { + border-bottom: 2px solid var(--Scandic-Brand-Burgundy); +} + .black { color: #000; } diff --git a/components/TempDesignSystem/Link/variants.ts b/components/TempDesignSystem/Link/variants.ts index 91e17df3e..fa0738c50 100644 --- a/components/TempDesignSystem/Link/variants.ts +++ b/components/TempDesignSystem/Link/variants.ts @@ -31,6 +31,7 @@ export const linkVariants = cva(styles.link, { myPageMobileDropdown: styles.myPageMobileDropdown, shortcut: styles.shortcut, sidebar: styles.sidebar, + tab: styles.tab, }, }, defaultVariants: { diff --git a/hooks/useHash.tsx b/hooks/useHash.tsx new file mode 100644 index 000000000..8a3990122 --- /dev/null +++ b/hooks/useHash.tsx @@ -0,0 +1,22 @@ +"use client" + +import { useParams } from "next/navigation" +import { useEffect, useState } from "react" + +const getHash = () => + typeof window !== "undefined" ? window.location.hash : undefined + +const useHash = () => { + const [isClient, setIsClient] = useState(false) + const [hash, setHash] = useState(getHash()) + const params = useParams() + + useEffect(() => { + setIsClient(true) + setHash(getHash()) + }, [params]) + + return isClient ? hash : null +} + +export default useHash diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index b2f0d47eb..3383c05c4 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -1,5 +1,6 @@ { "A photo of the room": "A photo of the room", + "Activities": "Activities", "Add new card": "Add new card", "Address": "Address", "All our beds are from Bliss, allowing you to adjust the firmness for your perfect comfort.": "All our beds are from Bliss, allowing you to adjust the firmness for your perfect comfort.", @@ -44,12 +45,12 @@ "Email": "Email", "There are no transactions to display": "There are no transactions to display", "Explore all levels and benefits": "Explore all levels and benefits", + "FAQ": "FAQ", "Find booking": "Find booking", "Flexibility": "Flexibility", "From": "From", "Get inspired": "Get inspired", "Go back to overview": "Go back to overview", - "hotelPages.rooms.title": "Rooms", "hotelPages.rooms.roomCard.person": "person", "hotelPages.rooms.roomCard.persons": "persons", "hotelPages.rooms.roomCard.seeRoomDetails": "See room details", @@ -63,6 +64,7 @@ "Log in": "Log in", "Log in here": "Log in here", "Log out": "Log out", + "Meetings & Conferences": "Meetings & Conferences", "Members": "Members", "Membership cards": "Membership cards", "Membership ID": "Membership ID", @@ -85,6 +87,7 @@ "On your journey": "On your journey", "Open": "Open", "or": "or", + "Overview": "Overview", "Password": "Password", "Phone": "Phone", "Phone is required": "Phone is required", @@ -98,7 +101,9 @@ "Previous victories": "Previous victories", "Read more": "Read more", "Read more about the hotel": "Read more about the hotel", + "Restaurant & Bar": "Restaurant & Bar", "Retype new password": "Retype new password", + "Rooms": "Rooms", "Save": "Save", "Select a country": "Select a country", "Select country of residence": "Select country of residence", @@ -121,6 +126,7 @@ "Welcome": "Welcome", "Visiting address": "Visiting address", "Welcome to": "Welcome to", + "Wellness & Exercise": "Wellness & Exercise", "Where should you go next?": "Where should you go next?", "Which room class suits you the best?": "Which room class suits you the best?", "Year": "Year", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index a5bb53782..a57f1a73b 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -51,7 +51,6 @@ "Highest level": "Högsta nivå", "How do you want to sleep?": "Hur vill du sova?", "How it works": "Hur det fungerar", - "hotelPages.rooms.title": "Rum", "hotelPages.rooms.roomCard.person": "person", "hotelPages.rooms.roomCard.persons": "personer", "hotelPages.rooms.roomCard.seeRoomDetails": "Se rumsdetaljer", @@ -98,6 +97,7 @@ "Read more": "Läs mer", "Read more about the hotel": "Läs mer om hotellet", "Retype new password": "Upprepa nytt lösenord", + "Rooms": "Rum", "Save": "Spara", "Select a country": "Välj ett land", "Select country of residence": "Välj bosättningsland",