Skip to content

Commit

Permalink
refactor(theme-{classic,common}): change how site/page/search metadat…
Browse files Browse the repository at this point in the history
…a is handled (#6925)
  • Loading branch information
slorber authored Mar 18, 2022
1 parent 74e37e8 commit 74f653d
Show file tree
Hide file tree
Showing 36 changed files with 802 additions and 619 deletions.
6 changes: 4 additions & 2 deletions packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ declare module '@theme/Layout' {

export interface Props {
readonly children?: ReactNode;
readonly title?: string;
readonly description?: string;
}
export default function Layout(props: Props): JSX.Element;
}
Expand All @@ -117,6 +115,10 @@ declare module '@theme/Root' {
export default function Root({children}: Props): JSX.Element;
}

declare module '@theme/SiteMetadata' {
export default function SiteMetadata(): JSX.Element;
}

declare module '@docusaurus/constants' {
export const DEFAULT_PLUGIN_ID: 'default';
}
Expand Down
38 changes: 5 additions & 33 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,31 +364,17 @@ declare module '@theme/Layout' {

export interface Props {
readonly children?: ReactNode;
readonly title?: string;
readonly noFooter?: boolean;
readonly description?: string;
readonly image?: string;
readonly keywords?: string | string[];
readonly permalink?: string;
readonly wrapperClassName?: string;
readonly pageClassName?: string;
readonly searchMetadata?: {
readonly version?: string;
readonly tag?: string;
};

// Not really layout-related, but kept for convenience/retro-compatibility
readonly title?: string;
readonly description?: string;
}

export default function Layout(props: Props): JSX.Element;
}

declare module '@theme/LayoutHead' {
import type {Props as LayoutProps} from '@theme/Layout';

export interface Props extends Omit<LayoutProps, 'children'> {}

export default function LayoutHead(props: Props): JSX.Element;
}

declare module '@theme/LayoutProviders' {
import type {ReactNode} from 'react';

Expand Down Expand Up @@ -480,7 +466,7 @@ declare module '@theme/Navbar/Content' {

declare module '@theme/Navbar/Layout' {
export interface Props {
children: React.ReactNode;
readonly children: React.ReactNode;
}

export default function NavbarLayout(props: Props): JSX.Element;
Expand Down Expand Up @@ -927,17 +913,3 @@ declare module '@theme/prism-include-languages' {
PrismObject: typeof PrismNamespace,
): void;
}

declare module '@theme/Seo' {
import type {ReactNode} from 'react';

export interface Props {
readonly title?: string;
readonly description?: string;
readonly keywords?: readonly string[] | string;
readonly image?: string;
readonly children?: ReactNode;
}

export default function Seo(props: Props): JSX.Element;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
import type {ArchiveBlogPost, Props} from '@theme/BlogArchivePage';
import {translate} from '@docusaurus/Translate';
import {PageMetadata} from '@docusaurus/theme-common';

type YearProp = {
year: string;
Expand Down Expand Up @@ -75,14 +76,17 @@ export default function BlogArchive({archive}: Props): JSX.Element {
});
const years = listPostsByYears(archive.blogPosts);
return (
<Layout title={title} description={description}>
<header className="hero hero--primary">
<div className="container">
<h1 className="hero__title">{title}</h1>
<p className="hero__subtitle">{description}</p>
</div>
</header>
<main>{years.length > 0 && <YearsSection years={years} />}</main>
</Layout>
<>
<PageMetadata title={title} description={description} />
<Layout>
<header className="hero hero--primary">
<div className="container">
<h1 className="hero__title">{title}</h1>
<p className="hero__subtitle">{description}</p>
</div>
</header>
<main>{years.length > 0 && <YearsSection years={years} />}</main>
</Layout>
</>
);
}
45 changes: 32 additions & 13 deletions packages/docusaurus-theme-classic/src/theme/BlogListPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,34 @@ import BlogLayout from '@theme/BlogLayout';
import BlogPostItem from '@theme/BlogPostItem';
import BlogListPaginator from '@theme/BlogListPaginator';
import type {Props} from '@theme/BlogListPage';
import {ThemeClassNames} from '@docusaurus/theme-common';
import {
PageMetadata,
HtmlClassNameProvider,
ThemeClassNames,
} from '@docusaurus/theme-common';
import SearchMetadata from '@theme/SearchMetadata';
import clsx from 'clsx';

export default function BlogListPage(props: Props): JSX.Element {
const {metadata, items, sidebar} = props;
function BlogListPageMetadata(props: Props): JSX.Element {
const {metadata} = props;
const {
siteConfig: {title: siteTitle},
} = useDocusaurusContext();
const {blogDescription, blogTitle, permalink} = metadata;
const isBlogOnlyMode = permalink === '/';
const title = isBlogOnlyMode ? siteTitle : blogTitle;
return (
<>
<PageMetadata title={title} description={blogDescription} />
<SearchMetadata tag="blog_posts_list" />
</>
);
}

function BlogListPageContent(props: Props): JSX.Element {
const {metadata, items, sidebar} = props;
return (
<BlogLayout
title={title}
description={blogDescription}
wrapperClassName={ThemeClassNames.wrapper.blogPages}
pageClassName={ThemeClassNames.page.blogListPage}
searchMetadata={{
// assign unique search tag to exclude this page from search results!
tag: 'blog_posts_list',
}}
sidebar={sidebar}>
<BlogLayout sidebar={sidebar}>
{items.map(({content: BlogPostContent}) => (
<BlogPostItem
key={BlogPostContent.metadata.permalink}
Expand All @@ -48,3 +54,16 @@ export default function BlogListPage(props: Props): JSX.Element {
</BlogLayout>
);
}

export default function BlogListPage(props: Props): JSX.Element {
return (
<HtmlClassNameProvider
className={clsx(
ThemeClassNames.wrapper.blogPages,
ThemeClassNames.page.blogListPage,
)}>
<BlogListPageMetadata {...props} />
<BlogListPageContent {...props} />
</HtmlClassNameProvider>
);
}
103 changes: 55 additions & 48 deletions packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,63 @@
*/

import React from 'react';
import Seo from '@theme/Seo';
import BlogLayout from '@theme/BlogLayout';
import BlogPostItem from '@theme/BlogPostItem';
import BlogPostPaginator from '@theme/BlogPostPaginator';
import type {Props} from '@theme/BlogPostPage';
import {ThemeClassNames} from '@docusaurus/theme-common';
import {
PageMetadata,
HtmlClassNameProvider,
ThemeClassNames,
} from '@docusaurus/theme-common';
import TOC from '@theme/TOC';
import clsx from 'clsx';

export default function BlogPostPage(props: Props): JSX.Element {
function BlogPostPageMetadata(props: Props): JSX.Element {
const {content: BlogPostContents} = props;
const {assets, metadata} = BlogPostContents;
const {title, description, date, tags, authors, frontMatter} = metadata;
const {keywords} = frontMatter;
const image = assets.image ?? frontMatter.image;
return (
<PageMetadata
title={title}
description={description}
keywords={keywords}
image={image}>
<meta property="og:type" content="article" />
<meta property="article:published_time" content={date} />
{/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */}
{authors.some((author) => author.url) && (
<meta
property="article:author"
content={authors
.map((author) => author.url)
.filter(Boolean)
.join(',')}
/>
)}
{tags.length > 0 && (
<meta
property="article:tag"
content={tags.map((tag) => tag.label).join(',')}
/>
)}
</PageMetadata>
);
}

function BlogPostPageContent(props: Props): JSX.Element {
const {content: BlogPostContents, sidebar} = props;
const {assets, metadata} = BlogPostContents;
const {
title,
description,
nextItem,
prevItem,
date,
tags,
authors,
frontMatter,
} = metadata;
const {nextItem, prevItem, frontMatter} = metadata;
const {
hide_table_of_contents: hideTableOfContents,
keywords,
toc_min_heading_level: tocMinHeadingLevel,
toc_max_heading_level: tocMaxHeadingLevel,
} = frontMatter;

const image = assets.image ?? frontMatter.image;

return (
<BlogLayout
wrapperClassName={ThemeClassNames.wrapper.blogPages}
pageClassName={ThemeClassNames.page.blogPostPage}
sidebar={sidebar}
toc={
!hideTableOfContents &&
Expand All @@ -52,35 +75,6 @@ export default function BlogPostPage(props: Props): JSX.Element {
/>
) : undefined
}>
<Seo
// TODO refactor needed: it's a bit annoying but Seo MUST be inside
// BlogLayout, otherwise default image (set by BlogLayout) would shadow
// the custom blog post image
title={title}
description={description}
keywords={keywords}
image={image}>
<meta property="og:type" content="article" />
<meta property="article:published_time" content={date} />

{/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */}
{authors.some((author) => author.url) && (
<meta
property="article:author"
content={authors
.map((author) => author.url)
.filter(Boolean)
.join(',')}
/>
)}
{tags.length > 0 && (
<meta
property="article:tag"
content={tags.map((tag) => tag.label).join(',')}
/>
)}
</Seo>

<BlogPostItem
frontMatter={frontMatter}
assets={assets}
Expand All @@ -95,3 +89,16 @@ export default function BlogPostPage(props: Props): JSX.Element {
</BlogLayout>
);
}

export default function BlogPostPage(props: Props): JSX.Element {
return (
<HtmlClassNameProvider
className={clsx(
ThemeClassNames.wrapper.blogPages,
ThemeClassNames.page.blogPostPage,
)}>
<BlogPostPageMetadata {...props} />
<BlogPostPageContent {...props} />
</HtmlClassNameProvider>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,29 @@ import BlogLayout from '@theme/BlogLayout';
import TagsListByLetter from '@theme/TagsListByLetter';
import type {Props} from '@theme/BlogTagsListPage';
import {
PageMetadata,
HtmlClassNameProvider,
ThemeClassNames,
translateTagsPageTitle,
} from '@docusaurus/theme-common';
import SearchMetadata from '../SearchMetadata';
import clsx from 'clsx';

export default function BlogTagsListPage(props: Props): JSX.Element {
const {tags, sidebar} = props;
const title = translateTagsPageTitle();
return (
<BlogLayout
title={title}
wrapperClassName={ThemeClassNames.wrapper.blogPages}
pageClassName={ThemeClassNames.page.blogTagsListPage}
searchMetadata={{
// assign unique search tag to exclude this page from search results!
tag: 'blog_tags_list',
}}
sidebar={sidebar}>
<h1>{title}</h1>
<TagsListByLetter tags={Object.values(tags)} />
</BlogLayout>
<HtmlClassNameProvider
className={clsx(
ThemeClassNames.wrapper.blogPages,
ThemeClassNames.page.blogTagsListPage,
)}>
<PageMetadata title={title} />
<SearchMetadata tag="blog_tags_list" />
<BlogLayout sidebar={sidebar}>
<h1>{title}</h1>
<TagsListByLetter tags={Object.values(tags)} />
</BlogLayout>
</HtmlClassNameProvider>
);
}
Loading

0 comments on commit 74f653d

Please sign in to comment.