feat(v2): allow specifying meta image for blog posts (#2856)

* feat(v2): allow specifying meta image for blog posts

* Update docs [skip ci]
This commit is contained in:
Alexey Pyltsyn 2020-06-02 10:48:22 +03:00 committed by GitHub
parent 2cd326fe20
commit c0c7457e01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 54 deletions

View file

@ -9,8 +9,10 @@ import React from 'react';
import classnames from 'classnames';
import {MDXProvider} from '@mdx-js/react';
import Head from '@docusaurus/Head';
import Link from '@docusaurus/Link';
import MDXComponents from '@theme/MDXComponents';
import useBaseUrl from '@docusaurus/useBaseUrl';
import styles from './styles.module.css';
@ -38,12 +40,13 @@ function BlogPostItem(props) {
isBlogPostPage = false,
} = props;
const {date, permalink, tags, readingTime} = metadata;
const {author, title} = frontMatter;
const {author, title, image} = frontMatter;
const authorURL = frontMatter.author_url || frontMatter.authorURL;
const authorTitle = frontMatter.author_title || frontMatter.authorTitle;
const authorImageURL =
frontMatter.author_image_url || frontMatter.authorImageURL;
const imageUrl = useBaseUrl(image, {absolute: true});
const renderPostHeader = () => {
const TitleHeading = isBlogPostPage ? 'h1' : 'h2';
@ -92,6 +95,15 @@ function BlogPostItem(props) {
};
return (
<>
<Head>
{image && <meta property="og:image" content={imageUrl} />}
{image && <meta property="twitter:image" content={imageUrl} />}
{image && (
<meta name="twitter:image:alt" content={`Image for ${title}`} />
)}
</Head>
<article className={!isBlogPostPage ? 'margin-bottom--xl' : undefined}>
{renderPostHeader()}
<section className="markdown">
@ -124,6 +136,7 @@ function BlogPostItem(props) {
</footer>
)}
</article>
</>
);
}

View file

@ -8,7 +8,6 @@
import React from 'react';
import Head from '@docusaurus/Head';
import isInternalUrl from '@docusaurus/isInternalUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import DocPaginator from '@theme/DocPaginator';
@ -80,10 +79,7 @@ function DocItem(props) {
} = DocContent;
const metaTitle = title ? `${title} | ${siteTitle}` : siteTitle;
let metaImageUrl = siteUrl + useBaseUrl(metaImage);
if (!isInternalUrl(metaImage)) {
metaImageUrl = metaImage;
}
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
return (
<>

View file

@ -15,7 +15,7 @@ import styles from './styles.module.css';
function FooterLink({to, href, label, prependBaseUrlToHref, ...props}) {
const toUrl = useBaseUrl(to);
const normalizedHref = useBaseUrl(href, true);
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
return (
<Link

View file

@ -7,7 +7,6 @@
import React from 'react';
import Head from '@docusaurus/Head';
import isInternalUrl from '@docusaurus/isInternalUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
@ -39,13 +38,8 @@ function Layout(props) {
version,
} = props;
const metaTitle = title ? `${title} | ${siteTitle}` : siteTitle;
const metaImage = image || defaultImage;
let metaImageUrl = siteUrl + useBaseUrl(metaImage);
if (!isInternalUrl(metaImage)) {
metaImageUrl = metaImage;
}
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
const faviconUrl = useBaseUrl(favicon);
return (

View file

@ -32,7 +32,7 @@ function NavLink({
}) {
const toUrl = useBaseUrl(to);
const activeBaseUrl = useBaseUrl(activeBasePath);
const normalizedHref = useBaseUrl(href, true);
const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
return (
<Link

View file

@ -16,6 +16,7 @@ describe('useBaseUrl', () => {
mockedContext.mockImplementation(() => ({
siteConfig: {
baseUrl: '/',
url: 'https://v2.docusaurus.io',
},
}));
@ -29,12 +30,19 @@ describe('useBaseUrl', () => {
expect(useBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/');
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
expect(useBaseUrl('https://site.com', {forcePrependBaseUrl: true})).toEqual(
'/https://site.com',
);
expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/hello/byebye',
);
});
test('non-empty base URL', () => {
mockedContext.mockImplementation(() => ({
siteConfig: {
baseUrl: '/docusaurus/',
url: 'https://v2.docusaurus.io',
},
}));
@ -48,5 +56,11 @@ describe('useBaseUrl', () => {
expect(useBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
expect(useBaseUrl('https://site.com', {forcePrependBaseUrl: true})).toEqual(
'/docusaurus/https://site.com',
);
expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/docusaurus/hello/byebye',
);
});
});

View file

@ -6,13 +6,20 @@
*/
import useDocusaurusContext from './useDocusaurusContext';
import isInternalUrl from './isInternalUrl';
type BaseUrlOptions = {
forcePrependBaseUrl: boolean;
absolute: boolean;
};
export default function useBaseUrl(
url: string,
forcePrependBaseUrl: boolean = false,
{forcePrependBaseUrl = false, absolute = false}: Partial<BaseUrlOptions> = {},
): string {
const {siteConfig} = useDocusaurusContext();
const {baseUrl = '/'} = siteConfig || {};
const {
siteConfig: {baseUrl = '/', url: siteUrl} = {},
} = useDocusaurusContext();
if (!url) {
return url;
@ -22,14 +29,11 @@ export default function useBaseUrl(
return baseUrl + url;
}
const externalRegex = /^(https?:|\/\/)/;
if (externalRegex.test(url)) {
if (!isInternalUrl(url)) {
return url;
}
if (url.startsWith('/')) {
return baseUrl + url.slice(1);
}
const basePath = baseUrl + url.replace(/^\//, '');
return baseUrl + url;
return absolute ? siteUrl + basePath : basePath;
}

View file

@ -38,6 +38,7 @@ author_title: Co-creator of Docusaurus 1
author_url: https://github.com/JoelMarcey
author_image_url: https://graph.facebook.com/611217057/picture/?height=200&width=200
tags: [hello, docusaurus-v2]
image: https://i.imgur.com/mErPwqL.png
---
Welcome to this blog. This blog is created with [**Docusaurus 2 alpha**](https://v2.docusaurus.io/).
@ -59,6 +60,7 @@ The only required field is `title`; however, we provide options to add author in
- `title` - The blog post title.
- `tags` - A list of strings to tag to your post.
- `draft` - A boolean flag to indicate that the blog post is work in process and therefore should not be published yet. However, draft blog posts will be displayed during development.
- `image`: Cover or thumbnail image that will be used when displaying the link to your post.
## Summary truncation

View file

@ -153,6 +153,13 @@ const Test = () => {
React hook to automatically prepend `baseUrl` to a string automatically. This is particularly useful if you don't want to hardcode your config's `baseUrl`. We highly recommend you to use this.
```ts
type BaseUrlOptions = {
forcePrependBaseUrl: boolean;
absolute: boolean;
};
```
Example usage:
```jsx {3,11}