feat(tender-details): improve scrolling behavior and header offset management
- Introduced a new constant for the tender section scroll offset to enhance scrolling behavior when navigating to sections. - Updated the scroll-to-section logic to account for the sticky header and added a small gap for better visual alignment. - Refactored the useTenderSectionScrollSpy hook to utilize the new scroll offset, ensuring consistent behavior across sections. - Improved code organization by separating scroll offset calculations into a dedicated function.
This commit is contained in:
@@ -13,7 +13,11 @@ export const TENDER_SECTION_IDS = {
|
||||
aiSummary: "tender-section-ai-summary",
|
||||
} as const;
|
||||
|
||||
export const HEADER_SCROLL_MARGIN = "scroll-mt-[5.5rem]";
|
||||
/** Sticky app header clearance — keep in sync with `getTenderSectionScrollOffset`. */
|
||||
export const TENDER_SECTION_SCROLL_OFFSET_PX = 96;
|
||||
|
||||
/** For hash / native scroll-into-view (matches offset above). */
|
||||
export const HEADER_SCROLL_MARGIN = "scroll-mt-24";
|
||||
|
||||
/** Body area only: center content in the card; ShowcaseSection `title` is unchanged */
|
||||
export const SHOWCASE_CENTERED_BODY = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { getTenderSectionScrollOffset } from "../scroll-to-section";
|
||||
|
||||
export function useTenderSectionScrollSpy(sectionIds: string[]) {
|
||||
const [activeId, setActiveId] = useState(sectionIds[0] ?? "");
|
||||
@@ -17,7 +18,7 @@ export function useTenderSectionScrollSpy(sectionIds: string[]) {
|
||||
if (sectionIds.length === 0) return;
|
||||
|
||||
const pickActive = () => {
|
||||
const offset = 96;
|
||||
const offset = getTenderSectionScrollOffset();
|
||||
const scrollY = window.scrollY;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const documentHeight = Math.max(
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
import { TENDER_SECTION_SCROLL_OFFSET_PX } from "./constants";
|
||||
|
||||
const SECTION_SCROLL_GAP_PX = 8;
|
||||
|
||||
/** Pixels to leave above the section top (sticky header + small gap). */
|
||||
export function getTenderSectionScrollOffset(): number {
|
||||
if (typeof document === "undefined") {
|
||||
return TENDER_SECTION_SCROLL_OFFSET_PX + SECTION_SCROLL_GAP_PX;
|
||||
}
|
||||
const header = document.querySelector("header");
|
||||
const headerHeight = header?.getBoundingClientRect().height ?? 0;
|
||||
return (
|
||||
Math.max(TENDER_SECTION_SCROLL_OFFSET_PX, headerHeight) +
|
||||
SECTION_SCROLL_GAP_PX
|
||||
);
|
||||
}
|
||||
|
||||
export function scrollToTenderSection(id: string) {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
|
||||
const reduceMotion =
|
||||
typeof window !== "undefined" &&
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
el.scrollIntoView({
|
||||
|
||||
const offset = getTenderSectionScrollOffset();
|
||||
const top =
|
||||
el.getBoundingClientRect().top + window.scrollY - offset;
|
||||
|
||||
window.scrollTo({
|
||||
top: Math.max(0, top),
|
||||
behavior: reduceMotion ? "auto" : "smooth",
|
||||
block: "start",
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user