From d73f8d844ee38364eb307d081adeb50a695de8ab Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Mon, 26 May 2025 12:32:18 +0000 Subject: [PATCH] feat(SW-1960): Improved scrolling and tabnavigation on hotel pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Approved-by: Matilda Landström --- apps/scandic-web/app/globals.css | 1 + .../Blocks/Accordion/accordion.module.css | 4 + .../components/Blocks/Accordion/index.tsx | 5 +- .../HotelPage/TabNavigation/index.tsx | 95 +++++++++++++++---- .../TabNavigation/tabNavigation.module.css | 74 ++++++++++++--- .../HotelPage/hotelPage.module.css | 4 + .../TabFilters/tabFilters.module.css | 60 ++++++------ apps/scandic-web/hooks/useScrollSpy.ts | 31 +++++- 8 files changed, 205 insertions(+), 69 deletions(-) diff --git a/apps/scandic-web/app/globals.css b/apps/scandic-web/app/globals.css index da3d4cfd6..379fd4a54 100644 --- a/apps/scandic-web/app/globals.css +++ b/apps/scandic-web/app/globals.css @@ -18,6 +18,7 @@ --main-menu-mobile-height: 75px; --main-menu-desktop-height: 125px; --booking-widget-mobile-height: 75px; + --booking-widget-tablet-height: 150px; --booking-widget-desktop-height: 77px; --hotel-page-map-desktop-width: 23.75rem; diff --git a/apps/scandic-web/components/Blocks/Accordion/accordion.module.css b/apps/scandic-web/components/Blocks/Accordion/accordion.module.css index 0dd49a0b7..4ed099213 100644 --- a/apps/scandic-web/components/Blocks/Accordion/accordion.module.css +++ b/apps/scandic-web/components/Blocks/Accordion/accordion.module.css @@ -1,3 +1,7 @@ +.accordionSection { + scroll-margin-top: var(--hotel-page-scroll-margin-top); +} + .accordion:not(.allVisible) :nth-child(n + 6) { display: none; } diff --git a/apps/scandic-web/components/Blocks/Accordion/index.tsx b/apps/scandic-web/components/Blocks/Accordion/index.tsx index 7c38c45b9..e617293f9 100644 --- a/apps/scandic-web/components/Blocks/Accordion/index.tsx +++ b/apps/scandic-web/components/Blocks/Accordion/index.tsx @@ -24,7 +24,10 @@ export default function AccordionSection({ accordion, title }: AccordionProps) { } return ( - + (null) + const tabRefs = useMemo(() => new Map(), []) + useStickyPosition({ ref: tabNavigationRef, name: StickyElementNameEnum.HOTEL_TAB_NAVIGATION, group: "hotelPage", }) + const { containerRef, showLeftShadow, showRightShadow } = + useScrollShadows() + const tabLinks: { hash: HotelHashValues; text: string }[] = [ { hash: HotelHashValues.overview, @@ -120,6 +129,41 @@ export default function TabNavigation({ tabLinks.map(({ hash }) => hash) ) + const scrollLinkToCenter = useCallback( + (hash: string) => { + requestAnimationFrame(() => { + const activeTab = tabRefs.get(hash) + if (!containerRef.current || !activeTab) { + return + } + + const container = containerRef.current + const containerWidth = container.offsetWidth + const tabWidth = activeTab.offsetWidth + const tabLeft = activeTab.offsetLeft + const scrollLeft = tabLeft - containerWidth / 2 + tabWidth / 2 + const maxScrollLeft = container.scrollWidth - containerWidth + + // Ensure scrollLeft is inside the viewport + const boundedScrollLeft = Math.max( + 0, + Math.min(scrollLeft, maxScrollLeft) + ) + + container.scrollTo({ + left: boundedScrollLeft, + behavior: "smooth", + }) + }) + }, + [containerRef, tabRefs] + ) + + useLayoutEffect(() => { + const activeHash = hash || HotelHashValues.overview + scrollLinkToCenter(activeHash) + }, [hash, scrollLinkToCenter]) + useEffect(() => { if (activeSectionId) { router.replace(`#${activeSectionId}`, { scroll: false }) @@ -127,28 +171,45 @@ export default function TabNavigation({ }, [activeSectionId, router]) return ( -
-