refactor(SW-337): css only approach for sticky tab navigation

This commit is contained in:
Chuma McPhoy
2024-09-06 09:52:21 +02:00
parent 9a0768b49e
commit 0ddbd3c549
4 changed files with 44 additions and 63 deletions

View File

@@ -1,5 +1,4 @@
"use client" "use client"
import { useEffect, useRef } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
@@ -12,25 +11,6 @@ import { HotelHashValues } from "@/types/components/hotelPage/tabNavigation"
export default function TabNavigation() { export default function TabNavigation() {
const hash = useHash() const hash = useHash()
const intl = useIntl() const intl = useIntl()
const navRef = useRef<HTMLElement>(null)
useEffect(() => {
const nav = navRef.current
if (!nav) return
const sticky = nav.offsetTop
const handleScroll = () => {
if (window.scrollY > sticky) {
nav.classList.add(styles.sticky)
} else {
nav.classList.remove(styles.sticky)
}
}
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [])
const hotelTabLinks: { href: HotelHashValues; text: string }[] = [ const hotelTabLinks: { href: HotelHashValues; text: string }[] = [
{ href: HotelHashValues.overview, text: "Overview" }, { href: HotelHashValues.overview, text: "Overview" },
@@ -43,24 +23,26 @@ export default function TabNavigation() {
] ]
return ( return (
<nav ref={navRef} className={styles.tabsContainer}> <div className={styles.stickyWrapper}>
{hotelTabLinks.map((link) => { <nav className={styles.tabsContainer}>
const isActive = {hotelTabLinks.map((link) => {
hash === link.href || const isActive =
(hash === "" && link.href === HotelHashValues.overview) hash === link.href ||
return ( (hash === "" && link.href === HotelHashValues.overview)
<Link return (
key={link.href} <Link
href={link.href} key={link.href}
active={isActive} href={link.href}
variant="tab" active={isActive}
color="burgundy" variant="tab"
textDecoration="none" color="burgundy"
> textDecoration="none"
{intl.formatMessage({ id: link.text })} >
</Link> {intl.formatMessage({ id: link.text })}
) </Link>
})} )
</nav> })}
</nav>
</div>
) )
} }

View File

@@ -1,30 +1,24 @@
.tabsContainer { .stickyWrapper {
display: flex; position: sticky;
top: 0;
z-index: 10;
background-color: var(--Base-Surface-Subtle-Normal);
border-bottom: 1px solid var(--Base-Border-Subtle);
overflow-x: auto; overflow-x: auto;
white-space: nowrap; white-space: nowrap;
}
.tabsContainer {
display: flex;
gap: var(--Spacing-x4); gap: var(--Spacing-x4);
justify-content: flex-start; justify-content: flex-start;
padding: 0 var(--Spacing-x2); padding: 0 var(--Spacing-x2);
max-width: 100vw;
width: 100%;
background-color: var(--Base-Surface-Subtle-Normal);
z-index: 1000;
}
.sticky {
position: fixed;
top: 0;
left: 0;
right: 0;
border-bottom: 1px solid var(--Base-Border-Subtle);
width: 100%; width: 100%;
} }
@media screen and (min-width: 1367px) { @media screen and (min-width: 1367px) {
.tabsContainer { .tabsContainer {
padding: 0 var(--Spacing-x5); padding: 0 var(--Spacing-x5);
}
.sticky {
max-width: calc(100% - var(--hotel-page-map-desktop-width)); max-width: calc(100% - var(--hotel-page-map-desktop-width));
} }
} }

View File

@@ -2,20 +2,27 @@
display: grid; display: grid;
max-width: var(--max-width); max-width: var(--max-width);
margin: 0 auto; margin: 0 auto;
grid-template-areas:
"hotelImages"
"tabNavigation"
"mainSection"
"mapContainer";
} }
.topSection { .hotelImages {
grid-area: hotelImages;
background-color: var(--Base-Surface-Subtle-Normal); background-color: var(--Base-Surface-Subtle-Normal);
border-bottom: 1px solid var(--Base-Border-Subtle);
} }
.mainSection { .mainSection {
grid-area: mainSection;
display: grid; display: grid;
gap: var(--Spacing-x9); gap: var(--Spacing-x9);
padding: var(--Spacing-x4) var(--Spacing-x2); padding: var(--Spacing-x4) var(--Spacing-x2);
} }
.mapContainer { .mapContainer {
grid-area: mapContainer;
display: none; display: none;
} }
@@ -27,13 +34,11 @@
@media screen and (min-width: 1367px) { @media screen and (min-width: 1367px) {
.pageContainer { .pageContainer {
grid-template-areas: grid-template-areas:
"topSection mapContainer" "hotelImages mapContainer"
"tabNavigation mapContainer"
"mainSection mapContainer"; "mainSection mapContainer";
grid-template-columns: 1fr var(--hotel-page-map-desktop-width); grid-template-columns: 1fr var(--hotel-page-map-desktop-width);
} }
.topSection {
grid-area: topSection;
}
.mainSection { .mainSection {
grid-area: mainSection; grid-area: mainSection;
padding: var(--Spacing-x6) 0; padding: var(--Spacing-x6) 0;

View File

@@ -32,10 +32,10 @@ export default async function HotelPage() {
return ( return (
<div className={styles.pageContainer}> <div className={styles.pageContainer}>
<div className={styles.topSection}> <div className={styles.hotelImages}>
<PreviewImages images={hotelImages} /> <PreviewImages images={hotelImages} />
<TabNavigation />
</div> </div>
<TabNavigation />
<main className={styles.mainSection}> <main className={styles.mainSection}>
<div className={styles.introContainer}> <div className={styles.introContainer}>
<IntroSection <IntroSection