mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-19 20:17:06 +02:00
feat(v2): introduce Seo component for internal usage (#4243)
This commit is contained in:
parent
f13448d5e1
commit
1ec2f04108
5 changed files with 67 additions and 70 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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()}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 />
|
||||||
|
|
45
packages/docusaurus-theme-classic/src/theme/Seo/index.tsx
Normal file
45
packages/docusaurus-theme-classic/src/theme/Seo/index.tsx
Normal 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>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue