diff --git a/packages/twenty-website/src/app/(public)/user-guide/hooks/useHeadsObserver.tsx b/packages/twenty-website/src/app/(public)/user-guide/hooks/useHeadsObserver.tsx index 24ee7ae26..88cbd145b 100644 --- a/packages/twenty-website/src/app/(public)/user-guide/hooks/useHeadsObserver.tsx +++ b/packages/twenty-website/src/app/(public)/user-guide/hooks/useHeadsObserver.tsx @@ -1,13 +1,13 @@ import { useEffect, useRef, useState } from 'react'; export function useHeadsObserver(location: string) { - const [activeText, setActiveText] = useState(''); + const [activeId, setActiveId] = useState(''); const observer = useRef(null); useEffect(() => { const handleObsever = (entries: any[]) => { entries.forEach((entry) => { if (entry?.isIntersecting) { - setActiveText(entry.target.innerText); + setActiveId(entry.target.id); } }); }; @@ -21,5 +21,5 @@ export function useHeadsObserver(location: string) { return () => observer.current?.disconnect(); }, [location]); - return { activeText }; + return { activeId }; } diff --git a/packages/twenty-website/src/app/_components/docs/TableContent.tsx b/packages/twenty-website/src/app/_components/docs/TableContent.tsx index 169852a3d..f23880714 100644 --- a/packages/twenty-website/src/app/_components/docs/TableContent.tsx +++ b/packages/twenty-website/src/app/_components/docs/TableContent.tsx @@ -92,7 +92,7 @@ interface HeadingType { const DocsTableContents = () => { const [headings, setHeadings] = useState([]); const pathname = usePathname(); - const { activeText } = useHeadsObserver(pathname); + const { activeId } = useHeadsObserver(pathname); useEffect(() => { const nodes: HTMLElement[] = Array.from( @@ -126,11 +126,11 @@ const DocsTableContents = () => { {headings.map((heading) => ( { e.preventDefault(); const yOffset = -70; @@ -142,8 +142,7 @@ const DocsTableContents = () => { window.scrollTo({ top: y, behavior: 'smooth' }); }} style={{ - fontWeight: - activeText === heading.text ? 'bold' : 'normal', + fontWeight: activeId === heading.id ? 'bold' : 'normal', }} > {heading.text} diff --git a/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx index a80a9277e..0e6a15543 100644 --- a/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx +++ b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx @@ -1,4 +1,4 @@ -import React, { +import { Children, cloneElement, isValidElement, @@ -12,6 +12,7 @@ export const wrapHeadingsWithAnchor = (children: ReactNode): ReactNode => { ): element is ReactElement<{ children: ReactNode }> => { return element.props.children !== undefined; }; + const idCounts = new Map(); return Children.map(children, (child) => { if ( @@ -19,10 +20,15 @@ export const wrapHeadingsWithAnchor = (children: ReactNode): ReactNode => { typeof child.type === 'string' && ['h1', 'h2', 'h3', 'h4'].includes(child.type) ) { - const id = child.props.children + const baseId = child.props.children .toString() .replace(/\s+/g, '-') .toLowerCase(); + const idCount = idCounts.get(baseId) ?? 0; + + const id = idCount === 0 ? baseId : `${baseId}-${idCount}`; + idCounts.set(baseId, idCount + 1); + return cloneElement(child as ReactElement, { id, className: 'anchor',