Use FAQPage (#6017)

This commit is contained in:
Kamil Kisiela 2024-11-21 16:06:03 +01:00 committed by GitHub
parent c86368204f
commit c337719a48
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 100 additions and 25 deletions

View file

@ -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"
>
<li>
<Accordion.Header>
<Accordion.Trigger className="hive-focus hover:bg-beige-100/80 -mx-2 my-1 flex w-[calc(100%+1rem)] items-center justify-between rounded-xl bg-white px-2 py-3 text-left font-medium transition-colors duration-[.8s] md:my-2 md:py-4">
{question}
<span itemProp="name">{question}</span>
<ChevronDownIcon className="size-5 [[data-state='open']_&]:[transform:rotateX(180deg)]" />
</Accordion.Trigger>
</Accordion.Header>
<Accordion.Content
forceMount
className="space-y-2 overflow-hidden bg-white text-green-800 data-[state=closed]:hidden"
className="overflow-hidden bg-white text-green-800 data-[state=closed]:hidden"
itemScope
itemProp="acceptedAnswer"
itemType="https://schema.org/Answer"
>
{answers.map((answer, i) => (
<p key={i}>{answer}</p>
))}
<div itemProp="text" className="space-y-2">
{answers.map((answer, i) => (
<p key={i}>{answer}</p>
))}
</div>
</Accordion.Content>
</li>
</Accordion.Item>
@ -82,27 +90,35 @@ const components = {
};
export function FrequentlyAskedQuestions({ className }: { className?: string }) {
usePageFAQSchema();
return (
<section
className={cn(
className,
'text-green-1000 flex flex-col gap-x-6 gap-y-2 px-4 py-6 md:flex-row md:px-10 lg:gap-x-24 lg:px-[120px] lg:py-24',
)}
>
<HomeQuestions components={components} />
</section>
<>
<section
className={cn(
className,
'text-green-1000 flex flex-col gap-x-6 gap-y-2 px-4 py-6 md:flex-row md:px-10 lg:gap-x-24 lg:px-[120px] lg:py-24',
)}
>
<HomeQuestions components={components} />
</section>
</>
);
}
export function FrequentlyAskedFederationQuestions({ className }: { className?: string }) {
usePageFAQSchema();
return (
<section
className={cn(
className,
'text-green-1000 flex flex-col gap-x-6 gap-y-2 px-4 py-6 md:flex-row md:px-10 lg:gap-x-24 lg:px-[120px] lg:py-24',
)}
>
<FederationQuestions components={components} />
</section>
<>
<section
className={cn(
className,
'text-green-1000 flex flex-col gap-x-6 gap-y-2 px-4 py-6 md:flex-row md:px-10 lg:gap-x-24 lg:px-[120px] lg:py-24',
)}
>
<FederationQuestions components={components} />
</section>
</>
);
}

View file

@ -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');
};
}
}, []);
}

View file

@ -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 <Head><html .../></Head>...
// 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
<Html lang="en">
<Html
lang="en"
{...(isFAQPage
? {
itemScope: true,
itemType: 'https://schema.org/FAQPage',
}
: {})}
>
<Head />
<body>
<Main />