diff --git a/packages/web/docs/src/components/frequently-asked-questions/index.tsx b/packages/web/docs/src/components/frequently-asked-questions/index.tsx index 622bcdc9a..f7a9968b6 100644 --- a/packages/web/docs/src/components/frequently-asked-questions/index.tsx +++ b/packages/web/docs/src/components/frequently-asked-questions/index.tsx @@ -2,7 +2,7 @@ import { Children, ComponentPropsWithoutRef } from 'react'; import * as Accordion from '@radix-ui/react-accordion'; import { ChevronDownIcon } from '@radix-ui/react-icons'; import { Anchor, Heading } from '@theguild/components'; -import { cn } from '../../lib'; +import { cn, usePageFAQSchema } from '../../lib'; import FederationQuestions from './federation-questions.mdx'; import HomeQuestions from './home-questions.mdx'; @@ -53,21 +53,29 @@ const li = (props: ComponentPropsWithoutRef<'li'>) => { asChild value={question} className="rdx-state-open:pb-4 relative pb-0 focus-within:z-10" + itemScope + itemProp="mainEntity" + itemType="https://schema.org/Question" >
  • - {question} + {question} - {answers.map((answer, i) => ( -

    {answer}

    - ))} +
    + {answers.map((answer, i) => ( +

    {answer}

    + ))} +
  • @@ -82,27 +90,35 @@ const components = { }; export function FrequentlyAskedQuestions({ className }: { className?: string }) { + usePageFAQSchema(); + return ( -
    - -
    + <> +
    + +
    + ); } export function FrequentlyAskedFederationQuestions({ className }: { className?: string }) { + usePageFAQSchema(); + return ( -
    - -
    + <> +
    + +
    + ); } diff --git a/packages/web/docs/src/lib.ts b/packages/web/docs/src/lib.ts index 18afcf38e..354d3eaa8 100644 --- a/packages/web/docs/src/lib.ts +++ b/packages/web/docs/src/lib.ts @@ -19,3 +19,36 @@ export function useTheme() { }; }, []); } + +const pagesWithFAQ = ['/', '/federation', '/pricing']; + +export function isPageWithFaq(path: string) { + return pagesWithFAQ.includes(path); +} + +export function usePageFAQSchema() { + useEffect(() => { + if (typeof window === 'undefined') { + return; + } + + const html = document.querySelector('html'); + + if (!html) { + // This should never happen + return; + } + + const path = window.location.pathname.replace('/graphql/hive', '/'); + + if (isPageWithFaq(path) && !html.hasAttribute('itemscope')) { + html.setAttribute('itemscope', ''); + html.setAttribute('itemtype', 'https://schema.org/FAQPage'); + + return () => { + html.removeAttribute('itemscope'); + html.removeAttribute('itemtype'); + }; + } + }, []); +} diff --git a/packages/web/docs/src/pages/_document.tsx b/packages/web/docs/src/pages/_document.tsx index f169fc4bb..9f74dcd4f 100644 --- a/packages/web/docs/src/pages/_document.tsx +++ b/packages/web/docs/src/pages/_document.tsx @@ -1,10 +1,36 @@ -import { Head, Html, Main, NextScript } from 'next/document'; +import { DocumentProps, Head, Html, Main, NextScript } from 'next/document'; +import { isPageWithFaq } from '../lib'; + +export default function Document(props: DocumentProps) { + // Can't do ... + // We need to add the structured data attributes + // to the html tag this way. + // We can remove this when Nextra is fixed + // Currently, the pages with FAQ are: + // / + // /federation + // /pricing + // + // This workaround works only partially. + // Yes, the structured data is added to the html tag on initial page visit, + // but when navigating to another page, the structured data is not updated, + // and the html tag is showing the structured data from the previous page. + // That's why we need to listen to the route change and update the structured data. + // See: usePageFAQSchema in lib.ts + const isFAQPage = isPageWithFaq(props.__NEXT_DATA__.page); -export default function Document() { return ( // We can drop it when Nextra is fixed // The html[lang] is not being added by Nextra - +