feat(v2): introduce Seo component for internal usage (#4243)

This commit is contained in:
Alexey Pyltsyn 2021-02-18 17:38:55 +03:00 committed by GitHub
parent f13448d5e1
commit 1ec2f04108
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 70 deletions

View file

@ -106,3 +106,15 @@ declare module '@theme/DocPage' {
const DocPage: (props: Props) => JSX.Element; const DocPage: (props: Props) => JSX.Element;
export default DocPage; export default DocPage;
} }
declare module '@theme/Seo' {
export type Props = {
readonly title?: string;
readonly description?: string;
readonly keywords?: readonly string[] | string;
readonly image?: string;
};
const Seo: (props: Props) => JSX.Element;
export default Seo;
}

View file

@ -9,11 +9,10 @@ import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import {MDXProvider} from '@mdx-js/react'; import {MDXProvider} from '@mdx-js/react';
import Translate from '@docusaurus/Translate'; import Translate from '@docusaurus/Translate';
import Head from '@docusaurus/Head';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import MDXComponents from '@theme/MDXComponents'; import MDXComponents from '@theme/MDXComponents';
import Seo from '@theme/Seo';
import type {Props} from '@theme/BlogPostItem'; import type {Props} from '@theme/BlogPostItem';
import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -47,7 +46,6 @@ function BlogPostItem(props: Props): JSX.Element {
const authorTitle = frontMatter.author_title || frontMatter.authorTitle; const authorTitle = frontMatter.author_title || frontMatter.authorTitle;
const authorImageURL = const authorImageURL =
frontMatter.author_image_url || frontMatter.authorImageURL; frontMatter.author_image_url || frontMatter.authorImageURL;
const imageUrl = useBaseUrl(image, {absolute: true});
const renderPostHeader = () => { const renderPostHeader = () => {
const TitleHeading = isBlogPostPage ? 'h1' : 'h2'; const TitleHeading = isBlogPostPage ? 'h1' : 'h2';
@ -91,16 +89,7 @@ function BlogPostItem(props: Props): JSX.Element {
return ( return (
<> <>
<Head> <Seo {...{keywords, image}} />
{keywords && keywords.length && (
<meta name="keywords" content={keywords.join(',')} />
)}
{image && <meta property="og:image" content={imageUrl} />}
{image && <meta name="twitter:image" content={imageUrl} />}
{image && (
<meta name="twitter:image:alt" content={`Image for ${title}`} />
)}
</Head>
<article className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}> <article className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}>
{renderPostHeader()} {renderPostHeader()}

View file

@ -6,12 +6,9 @@
*/ */
import React from 'react'; import React from 'react';
import Head from '@docusaurus/Head';
import {useTitleFormatter} from '@docusaurus/theme-common';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import DocPaginator from '@theme/DocPaginator'; import DocPaginator from '@theme/DocPaginator';
import DocVersionSuggestions from '@theme/DocVersionSuggestions'; import DocVersionSuggestions from '@theme/DocVersionSuggestions';
import Seo from '@theme/Seo';
import type {Props} from '@theme/DocItem'; import type {Props} from '@theme/DocItem';
import TOC from '@theme/TOC'; import TOC from '@theme/TOC';
import EditThisPage from '@theme/EditThisPage'; import EditThisPage from '@theme/EditThisPage';
@ -25,26 +22,17 @@ import {
} from '@theme/hooks/useDocs'; } from '@theme/hooks/useDocs';
function DocItem(props: Props): JSX.Element { function DocItem(props: Props): JSX.Element {
const {siteConfig} = useDocusaurusContext();
const {url: siteUrl} = siteConfig;
const {content: DocContent} = props; const {content: DocContent} = props;
const { const {
metadata, metadata,
frontMatter: { frontMatter: {
image: metaImage, image,
keywords, keywords,
hide_title: hideTitle, hide_title: hideTitle,
hide_table_of_contents: hideTableOfContents, hide_table_of_contents: hideTableOfContents,
}, },
} = DocContent; } = DocContent;
const { const {description, title, editUrl, lastUpdatedAt, lastUpdatedBy} = metadata;
description,
title,
permalink,
editUrl,
lastUpdatedAt,
lastUpdatedBy,
} = metadata;
const {pluginId} = useActivePlugin({failfast: true}); const {pluginId} = useActivePlugin({failfast: true});
const versions = useVersions(pluginId); const versions = useVersions(pluginId);
@ -55,28 +43,9 @@ function DocItem(props: Props): JSX.Element {
// See https://github.com/facebook/docusaurus/issues/3362 // See https://github.com/facebook/docusaurus/issues/3362
const showVersionBadge = versions.length > 1; const showVersionBadge = versions.length > 1;
const metaTitle = useTitleFormatter(title);
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
return ( return (
<> <>
<Head> <Seo {...{title, description, keywords, image}} />
<title>{metaTitle}</title>
<meta property="og:title" content={metaTitle} />
{description && <meta name="description" content={description} />}
{description && (
<meta property="og:description" content={description} />
)}
{keywords && keywords.length && (
<meta name="keywords" content={keywords.join(',')} />
)}
{metaImage && <meta property="og:image" content={metaImageUrl} />}
{metaImage && <meta name="twitter:image" content={metaImageUrl} />}
{metaImage && (
<meta name="twitter:image:alt" content={`Image for ${title}`} />
)}
{permalink && <meta property="og:url" content={siteUrl + permalink} />}
{permalink && <link rel="canonical" href={siteUrl + permalink} />}
</Head>
<div className="row"> <div className="row">
<div <div

View file

@ -11,9 +11,9 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import type {Props} from '@theme/Layout'; import type {Props} from '@theme/Layout';
import SearchMetadatas from '@theme/SearchMetadatas'; import SearchMetadatas from '@theme/SearchMetadatas';
import Seo from '@theme/Seo';
import { import {
DEFAULT_SEARCH_TAG, DEFAULT_SEARCH_TAG,
useTitleFormatter,
useAlternatePageUtils, useAlternatePageUtils,
} from '@docusaurus/theme-common'; } from '@docusaurus/theme-common';
import {useLocation} from '@docusaurus/router'; import {useLocation} from '@docusaurus/router';
@ -90,9 +90,7 @@ export default function LayoutHead(props: Props): JSX.Element {
themeConfig: {image: defaultImage, metadatas}, themeConfig: {image: defaultImage, metadatas},
} = siteConfig; } = siteConfig;
const {title, description, image, keywords, searchMetadatas} = props; const {title, description, image, keywords, searchMetadatas} = props;
const metaTitle = useTitleFormatter(title);
const metaImage = image || defaultImage;
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
const faviconUrl = useBaseUrl(favicon); const faviconUrl = useBaseUrl(favicon);
// See https://github.com/facebook/docusaurus/issues/3317#issuecomment-754661855 // See https://github.com/facebook/docusaurus/issues/3317#issuecomment-754661855
@ -104,27 +102,11 @@ export default function LayoutHead(props: Props): JSX.Element {
<> <>
<Head> <Head>
<html lang={htmlLang} dir={htmlDir} /> <html lang={htmlLang} dir={htmlDir} />
{metaTitle && <title>{metaTitle}</title>}
{metaTitle && <meta property="og:title" content={metaTitle} />}
{favicon && <link rel="shortcut icon" href={faviconUrl} />} {favicon && <link rel="shortcut icon" href={faviconUrl} />}
{description && <meta name="description" content={description} />}
{description && (
<meta property="og:description" content={description} />
)}
{keywords && keywords.length && (
<meta
name="keywords"
content={Array.isArray(keywords) ? keywords.join(',') : keywords}
/>
)}
{metaImage && <meta property="og:image" content={metaImageUrl} />}
{metaImage && <meta name="twitter:image" content={metaImageUrl} />}
{metaImage && (
<meta name="twitter:image:alt" content={`Image for ${metaTitle}`} />
)}
<meta name="twitter:card" content="summary_large_image" />
</Head> </Head>
<Seo {...{title, description, keywords, image: image || defaultImage}} />
<CanonicalUrlHeaders /> <CanonicalUrlHeaders />
<AlternateLangHeaders /> <AlternateLangHeaders />

View file

@ -0,0 +1,45 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import Head from '@docusaurus/Head';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {useTitleFormatter} from '@docusaurus/theme-common';
import type {Props} from '@theme/Seo';
export default function Seo({
title,
description,
keywords,
image,
}: Props): JSX.Element {
const metaTitle = useTitleFormatter(title);
const metaImageUrl = useBaseUrl(image, {absolute: true});
return (
<Head>
{title && <title>{metaTitle}</title>}
{title && <meta property="og:title" content={metaTitle} />}
{description && <meta name="description" content={description} />}
{description && <meta property="og:description" content={description} />}
{keywords && (
<meta
name="keywords"
content={
(Array.isArray(keywords) ? keywords.join(',') : keywords) as string
}
/>
)}
{image && <meta property="og:image" content={metaImageUrl} />}
{image && <meta name="twitter:image" content={metaImageUrl} />}
{image && <meta name="twitter:card" content="summary_large_image" />}
</Head>
);
}