From 566c775041820f6fd29244ef0d5f487bcd93e5ef Mon Sep 17 00:00:00 2001 From: nickbristow Date: Wed, 11 Dec 2024 11:51:10 -0500 Subject: [PATCH] auto change side nav current --- src/app/components/SideNav/SideNav.tsx | 86 ++++++++++++++++++++++++++ src/app/products/ecr-viewer/page.tsx | 85 +++---------------------- 2 files changed, 96 insertions(+), 75 deletions(-) create mode 100644 src/app/components/SideNav/SideNav.tsx diff --git a/src/app/components/SideNav/SideNav.tsx b/src/app/components/SideNav/SideNav.tsx new file mode 100644 index 0000000..2ea1fa4 --- /dev/null +++ b/src/app/components/SideNav/SideNav.tsx @@ -0,0 +1,86 @@ +import { useState, useEffect, SetStateAction } from 'react'; +import { SideNav as UswdsSideNav } from '@trussworks/react-uswds'; +import classNames from 'classnames'; + +interface Section { + title: string; + id: string; +} + +interface SideNavProps { + sections: Section[]; +} + +export const SideNav = ({ sections }: SideNavProps) => { + const [selectedHash, setSelectedHash] = useState(`#${sections[0].id}`); + + useEffect(() => { + let currentSection = ''; + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + const newSection = `#${entry.target.id}`; + if (currentSection !== newSection) { + currentSection = newSection; + setSelectedHash(newSection); + } + } + }); + }, + { + rootMargin: '-20% 0px -70% 0px', + threshold: 0, + }, + ); + + sections.forEach(({ id }) => { + const element = document.getElementById(id); + if (element) observer.observe(element); + }); + + return () => { + sections.forEach(({ id }) => { + const element = document.getElementById(id); + if (element) observer.unobserve(element); + }); + }; + }, [sections]); + + return ( + ( + + ))} + /> + ); +}; + +interface NavItemProps { + title: string; + id: string; + selectedHash: string; + setSelectedHash: (value: SetStateAction) => void; +} +function NavItem({ title, id, selectedHash, setSelectedHash }: NavItemProps) { + const itemHash = `#${id}`; + return ( + setSelectedHash(itemHash)} + > + {title} + + ); +} diff --git a/src/app/products/ecr-viewer/page.tsx b/src/app/products/ecr-viewer/page.tsx index fff3ff0..e5a8aad 100644 --- a/src/app/products/ecr-viewer/page.tsx +++ b/src/app/products/ecr-viewer/page.tsx @@ -8,11 +8,9 @@ import { ProcessListHeading, Accordion, Link, - SideNav, } from '@trussworks/react-uswds'; -import classNames from 'classnames'; +import { SideNav } from '@/app/components/SideNav/SideNav'; import Image from 'next/image'; -import { SetStateAction, useState } from 'react'; import './styles.scss'; export default function EcrViewer() { @@ -554,78 +552,15 @@ export default function EcrViewer() { } function Navigation() { - const [selectedHash, setSelectedHash] = useState('#overview'); - - return ( - , - , - , - , - , - , - ]} - /> - ); -} - -interface NavItemProps { - title: string; - id: string; - selectedHash: string; - setSelectedHash: (value: SetStateAction) => void; -} -function NavItem({ title, id, selectedHash, setSelectedHash }: NavItemProps) { - const itemHash = `#${id}`; - return ( - setSelectedHash(itemHash)} - > - {title} - - ); + const sections = [ + { title: 'Overview', id: 'overview' }, + { title: 'Product features', id: 'product-features' }, + { title: 'How it works', id: 'how-it-works' }, + { title: 'Getting started', id: 'getting-started' }, + { title: 'Technical resources', id: 'technical-resources' }, + { title: 'FAQs', id: 'faqs' }, + ]; + return ; } interface GithubNavProps {