docusaurus/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.tsx
Sunghyun Cho a25e18ce32
fix(theme): show blog post edit link even when no tag & not truncated (#7727)
Show edit link even when no tag & not truncated.
2022-07-06 18:46:49 +02:00

161 lines
4.8 KiB
TypeScript

/**
* 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 clsx from 'clsx';
import Translate, {translate} from '@docusaurus/Translate';
import Link from '@docusaurus/Link';
import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
import {usePluralForm} from '@docusaurus/theme-common';
import {blogPostContainerID} from '@docusaurus/utils-common';
import MDXContent from '@theme/MDXContent';
import EditThisPage from '@theme/EditThisPage';
import TagsListInline from '@theme/TagsListInline';
import BlogPostAuthors from '@theme/BlogPostAuthors';
import type {Props} from '@theme/BlogPostItem';
import styles from './styles.module.css';
// Very simple pluralization: probably good enough for now
function useReadingTimePlural() {
const {selectMessage} = usePluralForm();
return (readingTimeFloat: number) => {
const readingTime = Math.ceil(readingTimeFloat);
return selectMessage(
readingTime,
translate(
{
id: 'theme.blog.post.readingTime.plurals',
description:
'Pluralized label for "{readingTime} min read". Use as much plural forms (separated by "|") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)',
message: 'One min read|{readingTime} min read',
},
{readingTime},
),
);
};
}
export default function BlogPostItem(props: Props): JSX.Element {
const readingTimePlural = useReadingTimePlural();
const {withBaseUrl} = useBaseUrlUtils();
const {
children,
frontMatter,
assets,
metadata,
truncated,
isBlogPostPage = false,
} = props;
const {
date,
formattedDate,
permalink,
tags,
readingTime,
title,
editUrl,
authors,
} = metadata;
const image = assets.image ?? frontMatter.image;
const truncatedPost = !isBlogPostPage && truncated;
const tagsExists = tags.length > 0;
const TitleHeading = isBlogPostPage ? 'h1' : 'h2';
return (
<article
className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}
itemProp="blogPost"
itemScope
itemType="http://schema.org/BlogPosting">
<header>
<TitleHeading className={styles.blogPostTitle} itemProp="headline">
{isBlogPostPage ? (
title
) : (
<Link itemProp="url" to={permalink}>
{title}
</Link>
)}
</TitleHeading>
<div className={clsx(styles.blogPostData, 'margin-vert--md')}>
<time dateTime={date} itemProp="datePublished">
{formattedDate}
</time>
{typeof readingTime !== 'undefined' && (
<>
{' · '}
{readingTimePlural(readingTime)}
</>
)}
</div>
<BlogPostAuthors authors={authors} assets={assets} />
</header>
{image && (
<meta itemProp="image" content={withBaseUrl(image, {absolute: true})} />
)}
<div
// This ID is used for the feed generation to locate the main content
id={isBlogPostPage ? blogPostContainerID : undefined}
className="markdown"
itemProp="articleBody">
<MDXContent>{children}</MDXContent>
</div>
{(tagsExists || truncated || editUrl) && (
<footer
className={clsx(
'row docusaurus-mt-lg',
isBlogPostPage && styles.blogPostDetailsFull,
)}>
{tagsExists && (
<div className={clsx('col', {'col--9': truncatedPost})}>
<TagsListInline tags={tags} />
</div>
)}
{isBlogPostPage && editUrl && (
<div className="col margin-top--sm">
<EditThisPage editUrl={editUrl} />
</div>
)}
{truncatedPost && (
<div
className={clsx('col text--right', {
'col--3': tagsExists,
})}>
<Link
to={metadata.permalink}
aria-label={translate(
{
message: 'Read more about {title}',
id: 'theme.blog.post.readMoreLabel',
description:
'The ARIA label for the link to full blog posts from excerpts',
},
{title},
)}>
<b>
<Translate
id="theme.blog.post.readMore"
description="The label used in blog post item excerpts to link to full blog posts">
Read More
</Translate>
</b>
</Link>
</div>
)}
</footer>
)}
</article>
);
}