From c7e495c913a89dcd742762d5f77bee81250f085c Mon Sep 17 00:00:00 2001 From: Ady Beraud Date: Thu, 16 May 2024 16:55:11 +0300 Subject: [PATCH] modified html + added anchor tag within headers --- .../ui/layout/articles/ArticleContent.tsx | 7 +++- .../user-guide/UserGuideContent.tsx | 6 ++- .../user-guide/UserGuideSidebarSection.tsx | 3 +- .../shared-utils/wrapHeadingsWithAnchor.tsx | 40 +++++++++++++++++++ 4 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx diff --git a/packages/twenty-website/src/app/_components/ui/layout/articles/ArticleContent.tsx b/packages/twenty-website/src/app/_components/ui/layout/articles/ArticleContent.tsx index b9492a8cdec9..9041e504a051 100644 --- a/packages/twenty-website/src/app/_components/ui/layout/articles/ArticleContent.tsx +++ b/packages/twenty-website/src/app/_components/ui/layout/articles/ArticleContent.tsx @@ -4,6 +4,7 @@ import { ReactNode } from 'react'; import styled from '@emotion/styled'; import { Theme } from '@/app/_components/ui/theme/theme'; +import { wrapHeadingsWithAnchor } from '@/shared-utils/wrapHeadingsWithAnchor'; const StyledContent = styled.div` flex: 1; @@ -27,6 +28,10 @@ const StyledContent = styled.div` font-family: var(--font-gabarito); color: ${Theme.text.color.primary}; font-weight: 700; + a { + text-decoration: none; + color: ${Theme.text.color.primary}; + } } h1 { @@ -89,5 +94,5 @@ const StyledContent = styled.div` `; export const ArticleContent = ({ children }: { children: ReactNode }) => { - return {children}; + return {wrapHeadingsWithAnchor(children)}; }; diff --git a/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx b/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx index 1b0166ec6fd0..39f3239a8b02 100644 --- a/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx +++ b/packages/twenty-website/src/app/_components/user-guide/UserGuideContent.tsx @@ -54,10 +54,11 @@ const StyledHeader = styled.div` } `; -const StyledHeading = styled.div` +const StyledHeading = styled.h1` font-size: 40px; font-weight: 700; font-family: var(--font-gabarito); + margin: 0px; @media (max-width: 800px) { font-size: 28px; } @@ -77,12 +78,13 @@ const StyledHeaderInfoSectionTitle = styled.div` font-family: var(--font-gabarito); `; -const StyledHeaderInfoSectionSub = styled.div` +const StyledHeaderInfoSectionSub = styled.p` display: flex; flex-direction: column; gap: ${Theme.spacing(4)}; color: ${Theme.text.color.tertiary}; line-height: 1.8; + margin: 0px; `; const StyledRectangle = styled.div` diff --git a/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebarSection.tsx b/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebarSection.tsx index 79f42929052e..8a8e33ac4154 100644 --- a/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebarSection.tsx +++ b/packages/twenty-website/src/app/_components/user-guide/UserGuideSidebarSection.tsx @@ -31,7 +31,7 @@ const StyledTitle = styled.div` font-weight: 600; `; -const StyledSubTopicItem = styled.div<{ isselected: boolean }>` +const StyledSubTopicItem = styled.a<{ isselected: boolean }>` cursor: pointer; display: flex; flex-direction: row; @@ -135,6 +135,7 @@ const UserGuideSidebarSection = ({ router.push(`/user-guide/${card.fileName}`)} onMouseEnter={() => setHoveredItem(card.title)} onMouseLeave={() => setHoveredItem(null)} diff --git a/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx new file mode 100644 index 000000000000..3b7c85582e99 --- /dev/null +++ b/packages/twenty-website/src/shared-utils/wrapHeadingsWithAnchor.tsx @@ -0,0 +1,40 @@ +import React, { + Children, + cloneElement, + isValidElement, + ReactElement, + ReactNode, +} from 'react'; + +export const wrapHeadingsWithAnchor = (children: ReactNode): ReactNode => { + const hasChildren = ( + element: ReactElement, + ): element is ReactElement<{ children: ReactNode }> => { + return element.props.children !== undefined; + }; + + return Children.map(children, (child) => { + if ( + isValidElement(child) && + typeof child.type === 'string' && + ['h1', 'h2', 'h3', 'h4'].includes(child.type) + ) { + const id = child.props.children + .toString() + .replace(/\s+/g, '-') + .toLowerCase(); + return cloneElement(child as ReactElement, { + id: id, + children: {child.props.children}, + }); + } + + if (isValidElement(child) && hasChildren(child)) { + return cloneElement(child, { + children: wrapHeadingsWithAnchor(child.props.children), + }); + } + + return child; + }); +};