From ca9dcec1707a3febf09baa7cb295bc59bff7d0c5 Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 17 Feb 2024 10:34:12 +0100 Subject: [PATCH] add md sidebar --- .../UI/common/ApplicantsSidebar.tsx | 21 ++++---- src/components/UI/md/MdSidebar.tsx | 50 +++++++++++++++++++ src/components/layout/MdLayout.tsx | 6 +-- src/hooks/useActiveHash.ts | 13 +++-- 4 files changed, 71 insertions(+), 19 deletions(-) create mode 100644 src/components/UI/md/MdSidebar.tsx diff --git a/src/components/UI/common/ApplicantsSidebar.tsx b/src/components/UI/common/ApplicantsSidebar.tsx index b3fa7e5c..3320f379 100644 --- a/src/components/UI/common/ApplicantsSidebar.tsx +++ b/src/components/UI/common/ApplicantsSidebar.tsx @@ -5,7 +5,6 @@ import NextLink from 'next/link'; import { PageText } from '..'; import { SidebarLink } from '../../../types'; -import { useActiveHash } from '../../../hooks/useActiveHash'; interface Props { sidebarLinks: SidebarLink[]; @@ -13,12 +12,10 @@ interface Props { } export const ApplicantsSidebar: FC = ({ sidebarLinks, sectionsInView }) => { - const hrefs = sidebarLinks.map(({ href }) => href); - const activeHash = useActiveHash(hrefs); - // mark a sidebar link as active if previous one is not visible // (by the iIntersection Observer) only, to avoid having more than 1 active link - const isActiveLink = (idx: number) => hrefs[idx] && !hrefs[idx - 1]; + const isActiveLink = (idx: number) => sectionsInView[idx] && !sectionsInView[idx - 1]; + return ( = ({ sidebarLinks, sectionsInView }) = - - - {text} - - + + + + {text} + + + ))} diff --git a/src/components/UI/md/MdSidebar.tsx b/src/components/UI/md/MdSidebar.tsx new file mode 100644 index 00000000..67fa8700 --- /dev/null +++ b/src/components/UI/md/MdSidebar.tsx @@ -0,0 +1,50 @@ +import { Box, Flex, Link } from '@chakra-ui/react'; +import { FC, useMemo } from 'react'; +import NextLink from 'next/link'; + +import { PageText } from '..'; + +import { SidebarLink } from '../../../types'; +import { useActiveHash } from '../../../hooks/useActiveHash'; + +interface Props { + sidebarLinks: SidebarLink[]; +} + +export const MdSidebar: FC = ({ sidebarLinks }) => { + const hrefs = useMemo(() => sidebarLinks.map(({ href }) => href), [sidebarLinks]); + const activeHash = useActiveHash(hrefs, '0px'); + + return ( + + {sidebarLinks.map(({ text, href }, idx) => ( + + + + + + + {text} + + + + + ))} + + ); +}; diff --git a/src/components/layout/MdLayout.tsx b/src/components/layout/MdLayout.tsx index 0d2433db..1330153f 100644 --- a/src/components/layout/MdLayout.tsx +++ b/src/components/layout/MdLayout.tsx @@ -1,7 +1,8 @@ import { ReactNode } from 'react'; import { Box, Flex, Stack } from '@chakra-ui/react'; -import { ApplicantsSidebar, PageMetadata } from '../UI'; +import { PageMetadata } from '../UI'; +import { MdSidebar } from '../UI/md/MdSidebar'; import type { Frontmatter, ToCNodeEntry, TocNodeType } from '../../types'; @@ -21,11 +22,10 @@ export const MdLayout = ({ children, frontmatter, tocNodeItems }: LayoutProps) = - !('items' in item)) .map(item => ({ text: item.title || '', href: item.url || '' }))} - sectionsInView={[]} /> diff --git a/src/hooks/useActiveHash.ts b/src/hooks/useActiveHash.ts index 8b72fc94..d9ddf53d 100644 --- a/src/hooks/useActiveHash.ts +++ b/src/hooks/useActiveHash.ts @@ -7,15 +7,16 @@ import { useEffect, useState } from 'react'; * @returns id of the element currently in viewport */ export const useActiveHash = (itemIds: Array, rootMargin = `0% 0% -80% 0%`): string => { - const [activeHash, setActiveHash] = useState(``); + const [hashes, setHashes] = useState>(() => + itemIds.reduce((acc, id, index) => ({ [id]: index === 0, ...acc }), {}) + ); useEffect(() => { const observer = new IntersectionObserver( entries => { entries.forEach(entry => { - if (entry.isIntersecting) { - setActiveHash(`#${entry.target.id}`); - } + const hash = `#${entry.target.id}`; + setHashes(hashes => ({ ...hashes, [hash]: entry.isIntersecting })); }); }, { rootMargin } @@ -39,5 +40,7 @@ export const useActiveHash = (itemIds: Array, rootMargin = `0% 0% -80% 0 }; }, [itemIds, rootMargin]); - return activeHash; + const firstActiveHash = itemIds.find(id => hashes[id]); + + return firstActiveHash || itemIds[0]; };