From 834f8b98f8976c565bfdd27df5ae73f080b5f3b7 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Sun, 31 May 2020 17:29:11 +0300 Subject: [PATCH 1/2] feat(v2): allow specifying meta image for blog posts --- .../src/theme/BlogPostItem/index.js | 75 +++++++++++-------- .../src/theme/DocItem/index.js | 6 +- .../src/theme/Footer/index.js | 2 +- .../src/theme/Layout/index.js | 8 +- .../src/theme/Navbar/index.js | 2 +- .../client/exports/__tests__/useBaseUrl.ts | 14 ++++ .../src/client/exports/useBaseUrl.ts | 22 +++--- website/docs/blog.md | 2 + 8 files changed, 77 insertions(+), 54 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.js b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.js index 6dc0c05a192d..8bc7dbdab59c 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.js +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostItem/index.js @@ -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,38 +95,48 @@ function BlogPostItem(props) { }; return ( -
- {renderPostHeader()} -
- {children} -
- {(tags.length > 0 || truncated) && ( -
- {tags.length > 0 && ( -
- Tags: - {tags.map(({label, permalink: tagPermalink}) => ( + <> + + {image && } + {image && } + {image && ( + + )} + + +
+ {renderPostHeader()} +
+ {children} +
+ {(tags.length > 0 || truncated) && ( +
+ {tags.length > 0 && ( +
+ Tags: + {tags.map(({label, permalink: tagPermalink}) => ( + + {label} + + ))} +
+ )} + {truncated && ( +
- {label} + to={metadata.permalink} + aria-label={`Read more about ${title}`}> + Read More - ))} -
- )} - {truncated && ( -
- - Read More - -
- )} -
- )} -
+
+ )} +
+ )} +
+ ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.js b/packages/docusaurus-theme-classic/src/theme/DocItem/index.js index de7ade12dc04..b14ccf2a3ba2 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.js +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.js @@ -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 ( <> diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/index.js b/packages/docusaurus-theme-classic/src/theme/Footer/index.js index a3dafd090e4a..8adcf20ca2af 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/index.js +++ b/packages/docusaurus-theme-classic/src/theme/Footer/index.js @@ -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 ( { 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', + ); }); }); diff --git a/packages/docusaurus/src/client/exports/useBaseUrl.ts b/packages/docusaurus/src/client/exports/useBaseUrl.ts index f7c05f97a94f..09ba43e5e971 100644 --- a/packages/docusaurus/src/client/exports/useBaseUrl.ts +++ b/packages/docusaurus/src/client/exports/useBaseUrl.ts @@ -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 = {}, ): 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; } diff --git a/website/docs/blog.md b/website/docs/blog.md index a0a4bc41ab36..75b021479749 100644 --- a/website/docs/blog.md +++ b/website/docs/blog.md @@ -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 From 3227024ad327083505c58ce4b1c15f5aa9f724ab Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 1 Jun 2020 13:59:47 +0300 Subject: [PATCH 2/2] Update docs [skip ci] --- website/docs/docusaurus-core.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/docs/docusaurus-core.md b/website/docs/docusaurus-core.md index 92e54798ca2d..40fa01f1c535 100644 --- a/website/docs/docusaurus-core.md +++ b/website/docs/docusaurus-core.md @@ -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}