@docusaurus/theme-classic 2.0.0-beta.17 → 2.0.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/lib/getSwizzleConfig.js +113 -2
  2. package/lib/index.js +7 -12
  3. package/lib/theme-classic.d.ts +286 -60
  4. package/lib/translations.js +12 -2
  5. package/lib/validateThemeConfig.js +1 -1
  6. package/lib-next/theme/BackToTopButton/index.js +1 -3
  7. package/lib-next/theme/BlogArchivePage/index.js +14 -10
  8. package/lib-next/theme/BlogListPage/index.js +34 -13
  9. package/lib-next/theme/BlogPostItem/index.js +6 -6
  10. package/lib-next/theme/BlogPostPage/index.js +56 -45
  11. package/lib-next/theme/BlogTagsListPage/index.js +16 -12
  12. package/lib-next/theme/BlogTagsPostsPage/index.js +40 -33
  13. package/lib-next/theme/CodeBlock/CopyButton/index.js +60 -0
  14. package/lib-next/theme/CodeBlock/CopyButton/styles.module.css +66 -0
  15. package/lib-next/theme/CodeBlock/index.js +4 -36
  16. package/lib-next/theme/CodeBlock/styles.module.css +2 -22
  17. package/lib-next/theme/ColorModeToggle/index.js +36 -57
  18. package/lib-next/theme/ColorModeToggle/styles.module.css +8 -24
  19. package/lib-next/theme/DocBreadcrumbs/index.js +28 -11
  20. package/lib-next/theme/DocBreadcrumbs/styles.module.css +2 -17
  21. package/lib-next/theme/DocCard/index.js +17 -15
  22. package/lib-next/theme/DocCard/styles.module.css +8 -17
  23. package/lib-next/theme/DocCardList/index.js +15 -3
  24. package/lib-next/theme/DocCategoryGeneratedIndexPage/index.js +27 -6
  25. package/lib-next/theme/DocItem/index.js +84 -66
  26. package/lib-next/theme/DocPage/index.js +88 -89
  27. package/lib-next/theme/DocPage/styles.module.css +0 -4
  28. package/lib-next/theme/DocSidebar/Desktop/CollapseButton/index.js +34 -0
  29. package/lib-next/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +44 -0
  30. package/lib-next/theme/DocSidebar/Desktop/Content/index.js +46 -0
  31. package/lib-next/theme/DocSidebar/Desktop/Content/styles.module.css +17 -0
  32. package/lib-next/theme/DocSidebar/Desktop/index.js +34 -0
  33. package/lib-next/theme/DocSidebar/Desktop/styles.module.css +50 -0
  34. package/lib-next/theme/DocSidebar/Mobile/index.js +49 -0
  35. package/lib-next/theme/DocSidebar/index.js +6 -113
  36. package/lib-next/theme/DocSidebarItem/index.js +14 -13
  37. package/lib-next/theme/DocSidebarItem/styles.module.css +4 -0
  38. package/lib-next/theme/DocTagDocListPage/index.js +38 -31
  39. package/lib-next/theme/DocTagsListPage/index.js +21 -16
  40. package/lib-next/theme/Footer/Copyright/index.js +18 -0
  41. package/lib-next/theme/Footer/Layout/index.js +26 -0
  42. package/lib-next/theme/Footer/LinkItem/index.js +33 -0
  43. package/lib-next/theme/Footer/Links/MultiColumn/index.js +47 -0
  44. package/lib-next/theme/Footer/Links/Simple/index.js +41 -0
  45. package/lib-next/theme/Footer/Links/index.js +17 -0
  46. package/lib-next/theme/Footer/Logo/index.js +38 -0
  47. package/lib-next/theme/Footer/{styles.module.css → Logo/styles.module.css} +0 -0
  48. package/lib-next/theme/Footer/index.js +11 -163
  49. package/lib-next/theme/Heading/index.js +6 -4
  50. package/lib-next/theme/IconExternalLink/styles.module.css +0 -2
  51. package/lib-next/theme/Layout/index.js +15 -10
  52. package/lib-next/theme/LayoutProviders/index.js +5 -4
  53. package/lib-next/theme/MDXComponents/A.js +11 -0
  54. package/lib-next/theme/MDXComponents/Code.js +28 -0
  55. package/lib-next/theme/MDXComponents/Details.js +20 -0
  56. package/lib-next/theme/MDXComponents/Head.js +26 -0
  57. package/lib-next/theme/MDXComponents/Heading.js +11 -0
  58. package/lib-next/theme/MDXComponents/Img.js +24 -0
  59. package/lib-next/theme/MDXComponents/Img.module.css +10 -0
  60. package/lib-next/theme/MDXComponents/Pre.js +18 -0
  61. package/lib-next/theme/MDXComponents/Ul.js +23 -0
  62. package/{src/theme/MDXComponents/styles.css → lib-next/theme/MDXComponents/Ul.module.css} +1 -5
  63. package/lib-next/theme/MDXComponents/index.js +22 -71
  64. package/lib-next/theme/MDXContent/index.js +12 -0
  65. package/lib-next/theme/MDXPage/index.js +33 -28
  66. package/lib-next/theme/Navbar/ColorModeToggle/index.js +25 -0
  67. package/lib-next/theme/Navbar/Content/index.js +70 -0
  68. package/lib-next/theme/Navbar/Content/styles.module.css +15 -0
  69. package/lib-next/theme/Navbar/Layout/index.js +54 -0
  70. package/{src/theme/Navbar → lib-next/theme/Navbar/Layout}/styles.module.css +0 -13
  71. package/lib-next/theme/Navbar/Logo/index.js +17 -0
  72. package/lib-next/theme/Navbar/MobileSidebar/Header/index.js +33 -0
  73. package/lib-next/theme/Navbar/MobileSidebar/Layout/index.js +28 -0
  74. package/lib-next/theme/Navbar/MobileSidebar/PrimaryMenu/index.js +33 -0
  75. package/lib-next/theme/Navbar/MobileSidebar/SecondaryMenu/index.js +36 -0
  76. package/lib-next/theme/Navbar/MobileSidebar/Toggle/index.js +23 -0
  77. package/lib-next/theme/Navbar/MobileSidebar/index.js +31 -0
  78. package/lib-next/theme/Navbar/index.js +6 -271
  79. package/lib-next/theme/NavbarItem/DefaultNavbarItem.js +2 -6
  80. package/lib-next/theme/NavbarItem/DropdownNavbarItem.js +10 -2
  81. package/lib-next/theme/NavbarItem/NavbarNavLink.js +8 -12
  82. package/lib-next/theme/NotFound.js +38 -33
  83. package/lib-next/theme/{LayoutHead → SiteMetadata}/index.js +11 -26
  84. package/lib-next/theme/TOCCollapsible/index.js +1 -3
  85. package/lib-next/theme/Tabs/__tests__/index.test.js +5 -5
  86. package/lib-next/theme/Tabs/index.js +2 -2
  87. package/lib-next/theme/Tag/index.js +4 -4
  88. package/lib-next/theme/ThemedImage/index.js +3 -3
  89. package/package.json +17 -17
  90. package/src/getSwizzleConfig.ts +122 -1
  91. package/src/index.ts +10 -12
  92. package/src/theme/BackToTopButton/index.tsx +1 -3
  93. package/src/theme/BlogArchivePage/index.tsx +18 -17
  94. package/src/theme/BlogLayout/index.tsx +1 -1
  95. package/src/theme/BlogListPage/index.tsx +32 -13
  96. package/src/theme/BlogPostItem/index.tsx +6 -6
  97. package/src/theme/BlogPostPage/index.tsx +55 -48
  98. package/src/theme/BlogTagsListPage/index.tsx +16 -12
  99. package/src/theme/BlogTagsPostsPage/index.tsx +39 -32
  100. package/src/theme/CodeBlock/CopyButton/index.tsx +66 -0
  101. package/src/theme/CodeBlock/CopyButton/styles.module.css +66 -0
  102. package/src/theme/CodeBlock/index.tsx +6 -38
  103. package/src/theme/CodeBlock/styles.module.css +2 -22
  104. package/src/theme/ColorModeToggle/index.tsx +36 -61
  105. package/src/theme/ColorModeToggle/styles.module.css +8 -24
  106. package/src/theme/DocBreadcrumbs/index.tsx +29 -10
  107. package/src/theme/DocBreadcrumbs/styles.module.css +2 -17
  108. package/src/theme/DocCard/index.tsx +24 -17
  109. package/src/theme/DocCard/styles.module.css +8 -17
  110. package/src/theme/DocCardList/index.tsx +14 -3
  111. package/src/theme/DocCategoryGeneratedIndexPage/index.tsx +31 -4
  112. package/src/theme/DocItem/index.tsx +71 -55
  113. package/src/theme/DocPage/index.tsx +89 -90
  114. package/src/theme/DocPage/styles.module.css +0 -4
  115. package/src/theme/DocSidebar/Desktop/CollapseButton/index.tsx +38 -0
  116. package/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +44 -0
  117. package/src/theme/DocSidebar/Desktop/Content/index.tsx +55 -0
  118. package/src/theme/DocSidebar/Desktop/Content/styles.module.css +17 -0
  119. package/src/theme/DocSidebar/Desktop/index.tsx +38 -0
  120. package/src/theme/DocSidebar/Desktop/styles.module.css +50 -0
  121. package/src/theme/DocSidebar/Mobile/index.tsx +54 -0
  122. package/src/theme/DocSidebar/index.tsx +6 -121
  123. package/src/theme/DocSidebarItem/index.tsx +15 -16
  124. package/src/theme/DocSidebarItem/styles.module.css +4 -0
  125. package/src/theme/DocTagDocListPage/index.tsx +38 -30
  126. package/src/theme/DocTagsListPage/index.tsx +21 -16
  127. package/src/theme/DocVersionBanner/index.tsx +3 -4
  128. package/src/theme/Footer/Copyright/index.tsx +20 -0
  129. package/src/theme/Footer/Layout/index.tsx +34 -0
  130. package/src/theme/Footer/LinkItem/index.tsx +36 -0
  131. package/src/theme/Footer/Links/MultiColumn/index.tsx +51 -0
  132. package/src/theme/Footer/Links/Simple/index.tsx +42 -0
  133. package/src/theme/Footer/Links/index.tsx +21 -0
  134. package/src/theme/Footer/Logo/index.tsx +41 -0
  135. package/src/theme/Footer/{styles.module.css → Logo/styles.module.css} +0 -0
  136. package/src/theme/Footer/index.tsx +12 -186
  137. package/src/theme/Heading/index.tsx +6 -4
  138. package/src/theme/IconExternalLink/styles.module.css +0 -2
  139. package/src/theme/Layout/index.tsx +15 -10
  140. package/src/theme/LayoutProviders/index.tsx +5 -4
  141. package/src/theme/MDXComponents/A.tsx +14 -0
  142. package/src/theme/MDXComponents/Code.tsx +37 -0
  143. package/src/theme/MDXComponents/Details.tsx +26 -0
  144. package/src/theme/MDXComponents/Head.tsx +29 -0
  145. package/src/theme/MDXComponents/Heading.tsx +14 -0
  146. package/src/theme/MDXComponents/Img.module.css +10 -0
  147. package/src/theme/MDXComponents/Img.tsx +26 -0
  148. package/src/theme/MDXComponents/Pre.tsx +22 -0
  149. package/{lib-next/theme/MDXComponents/styles.css → src/theme/MDXComponents/Ul.module.css} +1 -5
  150. package/src/theme/MDXComponents/Ul.tsx +28 -0
  151. package/src/theme/MDXComponents/index.tsx +23 -80
  152. package/src/theme/MDXContent/index.tsx +15 -0
  153. package/src/theme/MDXPage/index.tsx +33 -28
  154. package/src/theme/Navbar/ColorModeToggle/index.tsx +30 -0
  155. package/src/theme/Navbar/Content/index.tsx +81 -0
  156. package/src/theme/Navbar/Content/styles.module.css +15 -0
  157. package/src/theme/Navbar/Layout/index.tsx +57 -0
  158. package/{lib-next/theme/Navbar → src/theme/Navbar/Layout}/styles.module.css +0 -13
  159. package/src/theme/Navbar/Logo/index.tsx +19 -0
  160. package/src/theme/Navbar/MobileSidebar/Header/index.tsx +34 -0
  161. package/src/theme/Navbar/MobileSidebar/Layout/index.tsx +31 -0
  162. package/src/theme/Navbar/MobileSidebar/PrimaryMenu/index.tsx +38 -0
  163. package/src/theme/Navbar/MobileSidebar/SecondaryMenu/index.tsx +38 -0
  164. package/src/theme/Navbar/MobileSidebar/Toggle/index.tsx +25 -0
  165. package/src/theme/Navbar/MobileSidebar/index.tsx +33 -0
  166. package/src/theme/Navbar/index.tsx +6 -286
  167. package/src/theme/NavbarItem/DefaultNavbarItem.tsx +2 -2
  168. package/src/theme/NavbarItem/DropdownNavbarItem.tsx +11 -2
  169. package/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx +1 -1
  170. package/src/theme/NavbarItem/NavbarNavLink.tsx +3 -7
  171. package/src/theme/NavbarItem/index.tsx +3 -4
  172. package/src/theme/NotFound.tsx +38 -33
  173. package/src/theme/{LayoutHead → SiteMetadata}/index.tsx +11 -25
  174. package/src/theme/TOCCollapsible/index.tsx +1 -3
  175. package/src/theme/Tabs/index.tsx +5 -6
  176. package/src/theme/Tag/index.tsx +4 -4
  177. package/src/theme/ThemedImage/index.tsx +4 -3
  178. package/src/theme-classic.d.ts +286 -60
  179. package/src/translations.ts +12 -6
  180. package/src/validateThemeConfig.ts +6 -6
  181. package/lib-next/theme/DocSidebar/styles.module.css +0 -107
  182. package/lib-next/theme/Seo/index.js +0 -40
  183. package/src/theme/DocSidebar/styles.module.css +0 -107
  184. package/src/theme/Seo/index.tsx +0 -49
@@ -257,7 +257,7 @@ const ThemeConfigSchema = _utilsValidation.Joi.object({
257
257
  style: _utilsValidation.Joi.string().equal('dark', 'light').default('light'),
258
258
  logo: _utilsValidation.Joi.object({
259
259
  alt: _utilsValidation.Joi.string().allow(''),
260
- src: _utilsValidation.Joi.string(),
260
+ src: _utilsValidation.Joi.string().required(),
261
261
  srcDark: _utilsValidation.Joi.string(),
262
262
  // TODO infer this from reading the image
263
263
  width: _utilsValidation.Joi.alternatives().try(_utilsValidation.Joi.string(), _utilsValidation.Joi.number()),
@@ -120,9 +120,7 @@ export default function BackToTopButton() {
120
120
  'clean-btn',
121
121
  ThemeClassNames.common.backToTopButton,
122
122
  styles.backToTopButton,
123
- {
124
- [styles.backToTopButtonShow]: show,
125
- },
123
+ show && styles.backToTopButtonShow,
126
124
  )}
127
125
  type="button"
128
126
  onClick={() => smoothScrollTop()}
@@ -8,6 +8,7 @@ import React from 'react';
8
8
  import Layout from '@theme/Layout';
9
9
  import Link from '@docusaurus/Link';
10
10
  import {translate} from '@docusaurus/Translate';
11
+ import {PageMetadata} from '@docusaurus/theme-common';
11
12
 
12
13
  function Year({year, posts}) {
13
14
  return (
@@ -45,7 +46,7 @@ function YearsSection({years}) {
45
46
  function listPostsByYears(blogPosts) {
46
47
  const postsByYear = blogPosts.reduceRight((posts, post) => {
47
48
  const year = post.metadata.date.split('-')[0];
48
- const yearPosts = posts.get(year) || [];
49
+ const yearPosts = posts.get(year) ?? [];
49
50
  return posts.set(year, [post, ...yearPosts]);
50
51
  }, new Map());
51
52
  return Array.from(postsByYear, ([year, posts]) => ({
@@ -67,14 +68,17 @@ export default function BlogArchive({archive}) {
67
68
  });
68
69
  const years = listPostsByYears(archive.blogPosts);
69
70
  return (
70
- <Layout title={title} description={description}>
71
- <header className="hero hero--primary">
72
- <div className="container">
73
- <h1 className="hero__title">{title}</h1>
74
- <p className="hero__subtitle">{description}</p>
75
- </div>
76
- </header>
77
- <main>{years.length > 0 && <YearsSection years={years} />}</main>
78
- </Layout>
71
+ <>
72
+ <PageMetadata title={title} description={description} />
73
+ <Layout>
74
+ <header className="hero hero--primary">
75
+ <div className="container">
76
+ <h1 className="hero__title">{title}</h1>
77
+ <p className="hero__subtitle">{description}</p>
78
+ </div>
79
+ </header>
80
+ <main>{years.length > 0 && <YearsSection years={years} />}</main>
81
+ </Layout>
82
+ </>
79
83
  );
80
84
  }
@@ -9,9 +9,16 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
9
9
  import BlogLayout from '@theme/BlogLayout';
10
10
  import BlogPostItem from '@theme/BlogPostItem';
11
11
  import BlogListPaginator from '@theme/BlogListPaginator';
12
- import {ThemeClassNames} from '@docusaurus/theme-common';
13
- export default function BlogListPage(props) {
14
- const {metadata, items, sidebar} = props;
12
+ import {
13
+ PageMetadata,
14
+ HtmlClassNameProvider,
15
+ ThemeClassNames,
16
+ } from '@docusaurus/theme-common';
17
+ import SearchMetadata from '@theme/SearchMetadata';
18
+ import clsx from 'clsx';
19
+
20
+ function BlogListPageMetadata(props) {
21
+ const {metadata} = props;
15
22
  const {
16
23
  siteConfig: {title: siteTitle},
17
24
  } = useDocusaurusContext();
@@ -19,16 +26,17 @@ export default function BlogListPage(props) {
19
26
  const isBlogOnlyMode = permalink === '/';
20
27
  const title = isBlogOnlyMode ? siteTitle : blogTitle;
21
28
  return (
22
- <BlogLayout
23
- title={title}
24
- description={blogDescription}
25
- wrapperClassName={ThemeClassNames.wrapper.blogPages}
26
- pageClassName={ThemeClassNames.page.blogListPage}
27
- searchMetadata={{
28
- // assign unique search tag to exclude this page from search results!
29
- tag: 'blog_posts_list',
30
- }}
31
- sidebar={sidebar}>
29
+ <>
30
+ <PageMetadata title={title} description={blogDescription} />
31
+ <SearchMetadata tag="blog_posts_list" />
32
+ </>
33
+ );
34
+ }
35
+
36
+ function BlogListPageContent(props) {
37
+ const {metadata, items, sidebar} = props;
38
+ return (
39
+ <BlogLayout sidebar={sidebar}>
32
40
  {items.map(({content: BlogPostContent}) => (
33
41
  <BlogPostItem
34
42
  key={BlogPostContent.metadata.permalink}
@@ -43,3 +51,16 @@ export default function BlogListPage(props) {
43
51
  </BlogLayout>
44
52
  );
45
53
  }
54
+
55
+ export default function BlogListPage(props) {
56
+ return (
57
+ <HtmlClassNameProvider
58
+ className={clsx(
59
+ ThemeClassNames.wrapper.blogPages,
60
+ ThemeClassNames.page.blogListPage,
61
+ )}>
62
+ <BlogListPageMetadata {...props} />
63
+ <BlogListPageContent {...props} />
64
+ </HtmlClassNameProvider>
65
+ );
66
+ }
@@ -6,13 +6,12 @@
6
6
  */
7
7
  import React from 'react';
8
8
  import clsx from 'clsx';
9
- import {MDXProvider} from '@mdx-js/react';
10
9
  import Translate, {translate} from '@docusaurus/Translate';
11
10
  import Link from '@docusaurus/Link';
12
11
  import {useBaseUrlUtils} from '@docusaurus/useBaseUrl';
13
12
  import {usePluralForm} from '@docusaurus/theme-common';
14
13
  import {blogPostContainerID} from '@docusaurus/utils-common';
15
- import MDXComponents from '@theme/MDXComponents';
14
+ import MDXContent from '@theme/MDXContent';
16
15
  import EditThisPage from '@theme/EditThisPage';
17
16
  import styles from './styles.module.css';
18
17
  import TagsListInline from '@theme/TagsListInline';
@@ -108,14 +107,15 @@ export default function BlogPostItem(props) {
108
107
  id={isBlogPostPage ? blogPostContainerID : undefined}
109
108
  className="markdown"
110
109
  itemProp="articleBody">
111
- <MDXProvider components={MDXComponents}>{children}</MDXProvider>
110
+ <MDXContent>{children}</MDXContent>
112
111
  </div>
113
112
 
114
113
  {(tagsExists || truncated) && (
115
114
  <footer
116
- className={clsx('row docusaurus-mt-lg', {
117
- [styles.blogPostDetailsFull]: isBlogPostPage,
118
- })}>
115
+ className={clsx(
116
+ 'row docusaurus-mt-lg',
117
+ isBlogPostPage && styles.blogPostDetailsFull,
118
+ )}>
119
119
  {tagsExists && (
120
120
  <div
121
121
  className={clsx('col', {
@@ -5,36 +5,62 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import Seo from '@theme/Seo';
9
8
  import BlogLayout from '@theme/BlogLayout';
10
9
  import BlogPostItem from '@theme/BlogPostItem';
11
10
  import BlogPostPaginator from '@theme/BlogPostPaginator';
12
- import {ThemeClassNames} from '@docusaurus/theme-common';
11
+ import {
12
+ PageMetadata,
13
+ HtmlClassNameProvider,
14
+ ThemeClassNames,
15
+ } from '@docusaurus/theme-common';
13
16
  import TOC from '@theme/TOC';
14
- export default function BlogPostPage(props) {
17
+ import clsx from 'clsx';
18
+
19
+ function BlogPostPageMetadata(props) {
20
+ const {content: BlogPostContents} = props;
21
+ const {assets, metadata} = BlogPostContents;
22
+ const {title, description, date, tags, authors, frontMatter} = metadata;
23
+ const {keywords} = frontMatter;
24
+ const image = assets.image ?? frontMatter.image;
25
+ return (
26
+ <PageMetadata
27
+ title={title}
28
+ description={description}
29
+ keywords={keywords}
30
+ image={image}>
31
+ <meta property="og:type" content="article" />
32
+ <meta property="article:published_time" content={date} />
33
+ {/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */}
34
+ {authors.some((author) => author.url) && (
35
+ <meta
36
+ property="article:author"
37
+ content={authors
38
+ .map((author) => author.url)
39
+ .filter(Boolean)
40
+ .join(',')}
41
+ />
42
+ )}
43
+ {tags.length > 0 && (
44
+ <meta
45
+ property="article:tag"
46
+ content={tags.map((tag) => tag.label).join(',')}
47
+ />
48
+ )}
49
+ </PageMetadata>
50
+ );
51
+ }
52
+
53
+ function BlogPostPageContent(props) {
15
54
  const {content: BlogPostContents, sidebar} = props;
16
55
  const {assets, metadata} = BlogPostContents;
17
- const {
18
- title,
19
- description,
20
- nextItem,
21
- prevItem,
22
- date,
23
- tags,
24
- authors,
25
- frontMatter,
26
- } = metadata;
56
+ const {nextItem, prevItem, frontMatter} = metadata;
27
57
  const {
28
58
  hide_table_of_contents: hideTableOfContents,
29
- keywords,
30
59
  toc_min_heading_level: tocMinHeadingLevel,
31
60
  toc_max_heading_level: tocMaxHeadingLevel,
32
61
  } = frontMatter;
33
- const image = assets.image ?? frontMatter.image;
34
62
  return (
35
63
  <BlogLayout
36
- wrapperClassName={ThemeClassNames.wrapper.blogPages}
37
- pageClassName={ThemeClassNames.page.blogPostPage}
38
64
  sidebar={sidebar}
39
65
  toc={
40
66
  !hideTableOfContents &&
@@ -47,34 +73,6 @@ export default function BlogPostPage(props) {
47
73
  />
48
74
  ) : undefined
49
75
  }>
50
- <Seo // TODO refactor needed: it's a bit annoying but Seo MUST be inside
51
- // BlogLayout, otherwise default image (set by BlogLayout) would shadow
52
- // the custom blog post image
53
- title={title}
54
- description={description}
55
- keywords={keywords}
56
- image={image}>
57
- <meta property="og:type" content="article" />
58
- <meta property="article:published_time" content={date} />
59
-
60
- {/* TODO double check those article meta array syntaxes, see https://ogp.me/#array */}
61
- {authors.some((author) => author.url) && (
62
- <meta
63
- property="article:author"
64
- content={authors
65
- .map((author) => author.url)
66
- .filter(Boolean)
67
- .join(',')}
68
- />
69
- )}
70
- {tags.length > 0 && (
71
- <meta
72
- property="article:tag"
73
- content={tags.map((tag) => tag.label).join(',')}
74
- />
75
- )}
76
- </Seo>
77
-
78
76
  <BlogPostItem
79
77
  frontMatter={frontMatter}
80
78
  assets={assets}
@@ -89,3 +87,16 @@ export default function BlogPostPage(props) {
89
87
  </BlogLayout>
90
88
  );
91
89
  }
90
+
91
+ export default function BlogPostPage(props) {
92
+ return (
93
+ <HtmlClassNameProvider
94
+ className={clsx(
95
+ ThemeClassNames.wrapper.blogPages,
96
+ ThemeClassNames.page.blogPostPage,
97
+ )}>
98
+ <BlogPostPageMetadata {...props} />
99
+ <BlogPostPageContent {...props} />
100
+ </HtmlClassNameProvider>
101
+ );
102
+ }
@@ -8,24 +8,28 @@ import React from 'react';
8
8
  import BlogLayout from '@theme/BlogLayout';
9
9
  import TagsListByLetter from '@theme/TagsListByLetter';
10
10
  import {
11
+ PageMetadata,
12
+ HtmlClassNameProvider,
11
13
  ThemeClassNames,
12
14
  translateTagsPageTitle,
13
15
  } from '@docusaurus/theme-common';
16
+ import SearchMetadata from '../SearchMetadata';
17
+ import clsx from 'clsx';
14
18
  export default function BlogTagsListPage(props) {
15
19
  const {tags, sidebar} = props;
16
20
  const title = translateTagsPageTitle();
17
21
  return (
18
- <BlogLayout
19
- title={title}
20
- wrapperClassName={ThemeClassNames.wrapper.blogPages}
21
- pageClassName={ThemeClassNames.page.blogTagsListPage}
22
- searchMetadata={{
23
- // assign unique search tag to exclude this page from search results!
24
- tag: 'blog_tags_list',
25
- }}
26
- sidebar={sidebar}>
27
- <h1>{title}</h1>
28
- <TagsListByLetter tags={Object.values(tags)} />
29
- </BlogLayout>
22
+ <HtmlClassNameProvider
23
+ className={clsx(
24
+ ThemeClassNames.wrapper.blogPages,
25
+ ThemeClassNames.page.blogTagsListPage,
26
+ )}>
27
+ <PageMetadata title={title} />
28
+ <SearchMetadata tag="blog_tags_list" />
29
+ <BlogLayout sidebar={sidebar}>
30
+ <h1>{title}</h1>
31
+ <TagsListByLetter tags={Object.values(tags)} />
32
+ </BlogLayout>
33
+ </HtmlClassNameProvider>
30
34
  );
31
35
  }
@@ -9,8 +9,15 @@ import Link from '@docusaurus/Link';
9
9
  import BlogLayout from '@theme/BlogLayout';
10
10
  import BlogPostItem from '@theme/BlogPostItem';
11
11
  import Translate, {translate} from '@docusaurus/Translate';
12
- import {ThemeClassNames, usePluralForm} from '@docusaurus/theme-common';
13
- import BlogListPaginator from '@theme/BlogListPaginator'; // Very simple pluralization: probably good enough for now
12
+ import {
13
+ PageMetadata,
14
+ HtmlClassNameProvider,
15
+ ThemeClassNames,
16
+ usePluralForm,
17
+ } from '@docusaurus/theme-common';
18
+ import BlogListPaginator from '@theme/BlogListPaginator';
19
+ import SearchMetadata from '@theme/SearchMetadata';
20
+ import clsx from 'clsx'; // Very simple pluralization: probably good enough for now
14
21
 
15
22
  function useBlogPostsPlural() {
16
23
  const {selectMessage} = usePluralForm();
@@ -47,38 +54,38 @@ export default function BlogTagsPostsPage(props) {
47
54
  },
48
55
  );
49
56
  return (
50
- <BlogLayout
51
- title={title}
52
- wrapperClassName={ThemeClassNames.wrapper.blogPages}
53
- pageClassName={ThemeClassNames.page.blogTagPostListPage}
54
- searchMetadata={{
55
- // assign unique search tag to exclude this page from search results!
56
- tag: 'blog_tags_posts',
57
- }}
58
- sidebar={sidebar}>
59
- <header className="margin-bottom--xl">
60
- <h1>{title}</h1>
57
+ <HtmlClassNameProvider
58
+ className={clsx(
59
+ ThemeClassNames.wrapper.blogPages,
60
+ ThemeClassNames.page.blogTagPostListPage,
61
+ )}>
62
+ <PageMetadata title={title} />
63
+ <SearchMetadata tag="blog_tags_posts" />
64
+ <BlogLayout sidebar={sidebar}>
65
+ <header className="margin-bottom--xl">
66
+ <h1>{title}</h1>
61
67
 
62
- <Link href={allTagsPath}>
63
- <Translate
64
- id="theme.tags.tagsPageLink"
65
- description="The label of the link targeting the tag list page">
66
- View All Tags
67
- </Translate>
68
- </Link>
69
- </header>
68
+ <Link href={allTagsPath}>
69
+ <Translate
70
+ id="theme.tags.tagsPageLink"
71
+ description="The label of the link targeting the tag list page">
72
+ View All Tags
73
+ </Translate>
74
+ </Link>
75
+ </header>
70
76
 
71
- {items.map(({content: BlogPostContent}) => (
72
- <BlogPostItem
73
- key={BlogPostContent.metadata.permalink}
74
- frontMatter={BlogPostContent.frontMatter}
75
- assets={BlogPostContent.assets}
76
- metadata={BlogPostContent.metadata}
77
- truncated>
78
- <BlogPostContent />
79
- </BlogPostItem>
80
- ))}
81
- <BlogListPaginator metadata={listMetadata} />
82
- </BlogLayout>
77
+ {items.map(({content: BlogPostContent}) => (
78
+ <BlogPostItem
79
+ key={BlogPostContent.metadata.permalink}
80
+ frontMatter={BlogPostContent.frontMatter}
81
+ assets={BlogPostContent.assets}
82
+ metadata={BlogPostContent.metadata}
83
+ truncated>
84
+ <BlogPostContent />
85
+ </BlogPostItem>
86
+ ))}
87
+ <BlogListPaginator metadata={listMetadata} />
88
+ </BlogLayout>
89
+ </HtmlClassNameProvider>
83
90
  );
84
91
  }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React, {useCallback, useState, useRef, useEffect} from 'react';
8
+ import clsx from 'clsx';
9
+ import copy from 'copy-text-to-clipboard';
10
+ import {translate} from '@docusaurus/Translate';
11
+ import styles from './styles.module.css';
12
+ export default function CopyButton({code}) {
13
+ const [isCopied, setIsCopied] = useState(false);
14
+ const copyTimeout = useRef(undefined);
15
+ const handleCopyCode = useCallback(() => {
16
+ copy(code);
17
+ setIsCopied(true);
18
+ copyTimeout.current = window.setTimeout(() => {
19
+ setIsCopied(false);
20
+ }, 1000);
21
+ }, [code]);
22
+ useEffect(() => () => window.clearTimeout(copyTimeout.current), []);
23
+ return (
24
+ <button
25
+ type="button"
26
+ aria-label={
27
+ isCopied
28
+ ? translate({
29
+ id: 'theme.CodeBlock.copied',
30
+ message: 'Copied',
31
+ description: 'The copied button label on code blocks',
32
+ })
33
+ : translate({
34
+ id: 'theme.CodeBlock.copyButtonAriaLabel',
35
+ message: 'Copy code to clipboard',
36
+ description: 'The ARIA label for copy code blocks button',
37
+ })
38
+ }
39
+ title={translate({
40
+ id: 'theme.CodeBlock.copy',
41
+ message: 'Copy',
42
+ description: 'The copy button label on code blocks',
43
+ })}
44
+ className={clsx(
45
+ styles.copyButton,
46
+ 'clean-btn',
47
+ isCopied && styles.copyButtonCopied,
48
+ )}
49
+ onClick={handleCopyCode}>
50
+ <span className={styles.copyButtonIcons} aria-hidden="true">
51
+ <svg className={styles.copyButtonIcon} viewBox="0 0 24 24">
52
+ <path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z" />
53
+ </svg>
54
+ <svg className={styles.copyButtonSuccessIcon} viewBox="0 0 24 24">
55
+ <path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z" />
56
+ </svg>
57
+ </span>
58
+ </button>
59
+ );
60
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .copyButton {
9
+ display: flex;
10
+ background: inherit;
11
+ border: 1px solid var(--ifm-color-emphasis-300);
12
+ border-radius: var(--ifm-global-radius);
13
+ padding: 0.4rem;
14
+ position: absolute;
15
+ right: calc(var(--ifm-pre-padding) / 2);
16
+ top: calc(var(--ifm-pre-padding) / 2);
17
+ transition: opacity 200ms ease-in-out;
18
+ opacity: 0;
19
+ }
20
+
21
+ .copyButton:focus-visible,
22
+ .copyButton:hover,
23
+ :global(.theme-code-block:hover) .copyButtonCopied {
24
+ opacity: 1 !important;
25
+ }
26
+
27
+ :global(.theme-code-block:hover) .copyButton:not(.copyButtonCopied) {
28
+ opacity: 0.4;
29
+ }
30
+
31
+ .copyButtonIcons {
32
+ position: relative;
33
+ width: 1.125rem;
34
+ height: 1.125rem;
35
+ }
36
+
37
+ .copyButtonIcon,
38
+ .copyButtonSuccessIcon {
39
+ position: absolute;
40
+ top: 0;
41
+ left: 0;
42
+ fill: currentColor;
43
+ opacity: inherit;
44
+ width: inherit;
45
+ height: inherit;
46
+ transition: all 0.15s ease;
47
+ }
48
+
49
+ .copyButtonSuccessIcon {
50
+ top: 50%;
51
+ left: 50%;
52
+ transform: translate(-50%, -50%) scale(0.33);
53
+ opacity: 0;
54
+ color: #00d600;
55
+ }
56
+
57
+ .copyButtonCopied .copyButtonIcon {
58
+ transform: scale(0.33);
59
+ opacity: 0;
60
+ }
61
+
62
+ .copyButtonCopied .copyButtonSuccessIcon {
63
+ transform: translate(-50%, -50%) scale(1);
64
+ opacity: 1;
65
+ transition-delay: 0.075s;
66
+ }
@@ -7,8 +7,6 @@
7
7
  import React, {isValidElement, useEffect, useState} from 'react';
8
8
  import clsx from 'clsx';
9
9
  import Highlight, {defaultProps} from 'prism-react-renderer';
10
- import copy from 'copy-text-to-clipboard';
11
- import Translate, {translate} from '@docusaurus/Translate';
12
10
  import {
13
11
  useThemeConfig,
14
12
  parseCodeBlockTitle,
@@ -17,6 +15,7 @@ import {
17
15
  ThemeClassNames,
18
16
  usePrismTheme,
19
17
  } from '@docusaurus/theme-common';
18
+ import CopyButton from '@theme/CodeBlock/CopyButton';
20
19
  import styles from './styles.module.css';
21
20
  export default function CodeBlock({
22
21
  children,
@@ -26,7 +25,6 @@ export default function CodeBlock({
26
25
  language: languageProp,
27
26
  }) {
28
27
  const {prism} = useThemeConfig();
29
- const [showCopied, setShowCopied] = useState(false);
30
28
  const [mounted, setMounted] = useState(false); // The Prism theme on SSR is always the default theme but the site theme
31
29
  // can be in a different mode. React hydration doesn't update DOM styles
32
30
  // that come from SSR. Hence force a re-render after mounting to apply the
@@ -78,13 +76,6 @@ export default function CodeBlock({
78
76
  const language =
79
77
  languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
80
78
  const {highlightLines, code} = parseLines(content, metastring, language);
81
-
82
- const handleCopyCode = () => {
83
- copy(code);
84
- setShowCopied(true);
85
- setTimeout(() => setShowCopied(false), 2000);
86
- };
87
-
88
79
  return (
89
80
  <Highlight
90
81
  {...defaultProps}
@@ -108,12 +99,11 @@ export default function CodeBlock({
108
99
  {codeBlockTitle}
109
100
  </div>
110
101
  )}
111
- <div className={clsx(styles.codeBlockContent, language)}>
102
+ <div className={styles.codeBlockContent} style={style}>
112
103
  <pre
113
104
  /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
114
105
  tabIndex={0}
115
- className={clsx(className, styles.codeBlock, 'thin-scrollbar')}
116
- style={style}>
106
+ className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
117
107
  <code className={styles.codeBlockLines}>
118
108
  {tokens.map((line, i) => {
119
109
  if (line.length === 1 && line[0].content === '\n') {
@@ -147,29 +137,7 @@ export default function CodeBlock({
147
137
  </code>
148
138
  </pre>
149
139
 
150
- <button
151
- type="button"
152
- aria-label={translate({
153
- id: 'theme.CodeBlock.copyButtonAriaLabel',
154
- message: 'Copy code to clipboard',
155
- description: 'The ARIA label for copy code blocks button',
156
- })}
157
- className={clsx(styles.copyButton, 'clean-btn')}
158
- onClick={handleCopyCode}>
159
- {showCopied ? (
160
- <Translate
161
- id="theme.CodeBlock.copied"
162
- description="The copied button label on code blocks">
163
- Copied
164
- </Translate>
165
- ) : (
166
- <Translate
167
- id="theme.CodeBlock.copy"
168
- description="The copy button label on code blocks">
169
- Copy
170
- </Translate>
171
- )}
172
- </button>
140
+ <CopyButton code={code} />
173
141
  </div>
174
142
  </div>
175
143
  )}