@docusaurus/theme-classic 2.0.0-beta.18 → 2.0.0-beta.19
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.
- package/lib/admonitions.css +4 -0
- package/lib/default.css +3038 -0
- package/lib/getSwizzleConfig.js +9 -2
- package/lib/index.js +4 -4
- package/lib/nprogress.css +41 -0
- package/lib/nprogress.js +46 -0
- package/lib/theme-classic.d.ts +315 -33
- package/lib/validateThemeConfig.js +72 -14
- package/lib-next/theme/BackToTopButton/index.js +6 -102
- package/lib-next/theme/BlogLayout/index.js +1 -5
- package/lib-next/theme/BlogListPaginator/index.js +25 -28
- package/lib-next/theme/BlogPostAuthor/index.js +3 -6
- package/lib-next/theme/BlogPostItem/styles.module.css +9 -0
- package/lib-next/theme/BlogPostPaginator/index.js +25 -28
- package/lib-next/theme/BlogSidebar/Desktop/index.js +41 -0
- package/lib-next/theme/BlogSidebar/{styles.module.css → Desktop/styles.module.css} +1 -2
- package/lib-next/theme/BlogSidebar/Mobile/index.js +36 -0
- package/lib-next/theme/BlogSidebar/index.js +11 -31
- package/lib-next/theme/BlogTagsListPage/index.js +2 -3
- package/lib-next/theme/BlogTagsPostsPage/index.js +4 -6
- package/lib-next/theme/CodeBlock/Container/index.js +29 -0
- package/lib-next/theme/CodeBlock/Container/styles.module.css +14 -0
- package/lib-next/theme/CodeBlock/Content/Element.js +23 -0
- package/lib-next/theme/CodeBlock/Content/String.js +104 -0
- package/{src/theme/CodeBlock → lib-next/theme/CodeBlock/Content}/styles.module.css +39 -9
- package/lib-next/theme/CodeBlock/CopyButton/index.js +3 -2
- package/lib-next/theme/CodeBlock/CopyButton/styles.module.css +0 -19
- package/lib-next/theme/CodeBlock/Line/index.js +49 -0
- package/lib-next/theme/CodeBlock/Line/styles.module.css +51 -0
- package/lib-next/theme/CodeBlock/WordWrapButton/index.js +40 -0
- package/lib-next/theme/CodeBlock/WordWrapButton/styles.module.css +15 -0
- package/lib-next/theme/CodeBlock/index.js +27 -133
- package/lib-next/theme/Details/index.js +1 -1
- package/lib-next/theme/DocBreadcrumbs/index.js +50 -23
- package/lib-next/theme/DocBreadcrumbs/styles.module.css +8 -0
- package/lib-next/theme/DocCardList/index.js +6 -4
- package/lib-next/theme/DocCategoryGeneratedIndexPage/index.js +3 -3
- package/lib-next/theme/DocCategoryGeneratedIndexPage/styles.module.css +8 -0
- package/lib-next/theme/DocItem/index.js +1 -1
- package/lib-next/theme/DocItem/styles.module.css +6 -0
- package/lib-next/theme/DocPage/Layout/Main/index.js +29 -0
- package/lib-next/theme/DocPage/Layout/Main/styles.module.css +28 -0
- package/lib-next/theme/DocPage/Layout/Sidebar/ExpandButton/index.js +34 -0
- package/lib-next/theme/DocPage/Layout/Sidebar/ExpandButton/styles.module.css +33 -0
- package/lib-next/theme/DocPage/Layout/Sidebar/index.js +68 -0
- package/lib-next/theme/DocPage/Layout/Sidebar/index.module.css +32 -0
- package/lib-next/theme/DocPage/Layout/index.js +34 -0
- package/lib-next/theme/{BlogPostAuthor/styles.module.css → DocPage/Layout/index.module.css} +6 -3
- package/lib-next/theme/DocPage/index.js +28 -146
- package/lib-next/theme/DocPaginator/index.js +25 -28
- package/lib-next/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +11 -9
- package/lib-next/theme/DocSidebar/Desktop/Content/styles.module.css +6 -0
- package/lib-next/theme/DocSidebar/Desktop/index.js +4 -2
- package/lib-next/theme/DocSidebarItem/Category.js +197 -0
- package/lib-next/theme/DocSidebarItem/Html.js +27 -0
- package/{src/theme/DocSidebarItem/styles.module.css → lib-next/theme/DocSidebarItem/Html.module.css} +0 -4
- package/lib-next/theme/DocSidebarItem/Link.js +53 -0
- package/{src/theme/MDXComponents/Ul.module.css → lib-next/theme/DocSidebarItem/Link.module.css} +2 -3
- package/lib-next/theme/DocSidebarItem/index.js +4 -246
- package/lib-next/theme/DocSidebarItems/index.js +1 -6
- package/lib-next/theme/DocTagDocListPage/index.js +3 -3
- package/lib-next/theme/DocVersionBanner/index.js +2 -2
- package/lib-next/theme/Footer/Links/MultiColumn/index.js +1 -1
- package/lib-next/theme/Heading/index.js +4 -20
- package/lib-next/theme/IconHome/index.js +17 -0
- package/lib-next/theme/LastUpdated/index.js +1 -0
- package/lib-next/theme/Layout/index.js +1 -1
- package/lib-next/theme/MDXComponents/Ul.js +2 -4
- package/lib-next/theme/Navbar/Content/index.js +6 -1
- package/lib-next/theme/Navbar/Logo/index.js +1 -1
- package/lib-next/theme/Navbar/Search/index.js +11 -0
- package/lib-next/theme/Navbar/Search/styles.module.css +20 -0
- package/lib-next/theme/NavbarItem/ComponentTypes.js +27 -0
- package/lib-next/theme/NavbarItem/DocNavbarItem.js +11 -28
- package/lib-next/theme/NavbarItem/DocSidebarNavbarItem.js +10 -42
- package/lib-next/theme/NavbarItem/DocsVersionDropdownNavbarItem.js +25 -29
- package/lib-next/theme/NavbarItem/DocsVersionNavbarItem.js +2 -9
- package/lib-next/theme/NavbarItem/DropdownNavbarItem.js +4 -1
- package/lib-next/theme/NavbarItem/HtmlNavbarItem.js +30 -0
- package/lib-next/theme/NavbarItem/LocaleDropdownNavbarItem/index.js +5 -10
- package/lib-next/theme/NavbarItem/NavbarNavLink.js +49 -31
- package/lib-next/theme/NavbarItem/SearchNavbarItem.js +6 -1
- package/lib-next/theme/NavbarItem/index.js +4 -23
- package/lib-next/theme/NavbarItem/utils.js +2 -1
- package/lib-next/theme/PaginatorNavLink/index.js +8 -2
- package/lib-next/theme/SiteMetadata/index.js +8 -7
- package/lib-next/theme/SkipToContent/index.js +3 -29
- package/lib-next/theme/TOCCollapsible/CollapseButton.js +29 -0
- package/{src/theme/TOCCollapsible/styles.module.css → lib-next/theme/TOCCollapsible/CollapseButton.module.css} +1 -22
- package/lib-next/theme/TOCCollapsible/index.js +3 -13
- package/lib-next/theme/TOCCollapsible/index.module.css +31 -0
- package/lib-next/theme/TOCItems/Tree.js +40 -0
- package/lib-next/theme/TOCItems/index.js +3 -34
- package/lib-next/theme/TabItem/index.js +3 -1
- package/lib-next/theme/{MDXComponents/Ul.module.css → TabItem/styles.module.css} +2 -3
- package/lib-next/theme/Tabs/__tests__/index.test.js +3 -3
- package/lib-next/theme/Tabs/index.js +3 -3
- package/lib-next/theme/Tabs/styles.module.css +4 -0
- package/lib-next/theme/Tag/index.js +2 -3
- package/lib-next/theme/TagsListInline/index.js +1 -1
- package/package.json +23 -18
- package/src/admonitions.css +4 -0
- package/src/getSwizzleConfig.ts +10 -2
- package/src/index.ts +4 -3
- package/src/nprogress.css +41 -0
- package/src/nprogress.ts +31 -0
- package/src/theme/BackToTopButton/index.tsx +5 -112
- package/src/theme/BlogLayout/index.tsx +1 -5
- package/src/theme/BlogListPaginator/index.tsx +25 -28
- package/src/theme/BlogPostAuthor/index.tsx +3 -7
- package/src/theme/BlogPostItem/styles.module.css +9 -0
- package/src/theme/BlogPostPaginator/index.tsx +25 -28
- package/src/theme/BlogSidebar/Desktop/index.tsx +45 -0
- package/src/theme/BlogSidebar/{styles.module.css → Desktop/styles.module.css} +1 -2
- package/src/theme/BlogSidebar/Mobile/index.tsx +38 -0
- package/src/theme/BlogSidebar/index.tsx +10 -31
- package/src/theme/BlogTagsListPage/index.tsx +2 -3
- package/src/theme/BlogTagsPostsPage/index.tsx +8 -5
- package/src/theme/CodeBlock/Container/index.tsx +35 -0
- package/src/theme/CodeBlock/Container/styles.module.css +14 -0
- package/src/theme/CodeBlock/Content/Element.tsx +30 -0
- package/src/theme/CodeBlock/Content/String.tsx +111 -0
- package/{lib-next/theme/CodeBlock → src/theme/CodeBlock/Content}/styles.module.css +39 -9
- package/src/theme/CodeBlock/CopyButton/index.tsx +3 -2
- package/src/theme/CodeBlock/CopyButton/styles.module.css +0 -19
- package/src/theme/CodeBlock/Line/index.tsx +48 -0
- package/src/theme/CodeBlock/Line/styles.module.css +51 -0
- package/src/theme/CodeBlock/WordWrapButton/index.tsx +49 -0
- package/src/theme/CodeBlock/WordWrapButton/styles.module.css +15 -0
- package/src/theme/CodeBlock/index.tsx +29 -133
- package/src/theme/Details/index.tsx +1 -1
- package/src/theme/DocBreadcrumbs/index.tsx +50 -20
- package/src/theme/DocBreadcrumbs/styles.module.css +8 -0
- package/src/theme/DocCardList/index.tsx +5 -7
- package/src/theme/DocCategoryGeneratedIndexPage/index.tsx +3 -3
- package/src/theme/DocCategoryGeneratedIndexPage/styles.module.css +8 -0
- package/src/theme/DocItem/index.tsx +1 -1
- package/src/theme/DocItem/styles.module.css +6 -0
- package/src/theme/DocPage/Layout/Main/index.tsx +37 -0
- package/src/theme/DocPage/Layout/Main/styles.module.css +28 -0
- package/src/theme/DocPage/Layout/Sidebar/ExpandButton/index.tsx +40 -0
- package/src/theme/DocPage/Layout/Sidebar/ExpandButton/styles.module.css +33 -0
- package/src/theme/DocPage/Layout/Sidebar/index.module.css +32 -0
- package/src/theme/DocPage/Layout/Sidebar/index.tsx +74 -0
- package/src/theme/{BlogPostAuthor/styles.module.css → DocPage/Layout/index.module.css} +6 -3
- package/src/theme/DocPage/Layout/index.tsx +39 -0
- package/src/theme/DocPage/index.tsx +28 -157
- package/src/theme/DocPaginator/index.tsx +25 -28
- package/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +11 -9
- package/src/theme/DocSidebar/Desktop/Content/styles.module.css +6 -0
- package/src/theme/DocSidebar/Desktop/index.tsx +4 -2
- package/src/theme/DocSidebarItem/Category.tsx +210 -0
- package/{lib-next/theme/DocSidebarItem/styles.module.css → src/theme/DocSidebarItem/Html.module.css} +0 -4
- package/src/theme/DocSidebarItem/Html.tsx +34 -0
- package/src/theme/DocSidebarItem/Link.module.css +10 -0
- package/src/theme/DocSidebarItem/Link.tsx +58 -0
- package/src/theme/DocSidebarItem/index.tsx +4 -259
- package/src/theme/DocSidebarItems/index.tsx +1 -6
- package/src/theme/DocTagDocListPage/index.tsx +3 -4
- package/src/theme/DocVersionBanner/index.tsx +2 -2
- package/src/theme/Footer/Links/MultiColumn/index.tsx +1 -1
- package/src/theme/Heading/index.tsx +4 -18
- package/src/theme/IconHome/index.tsx +20 -0
- package/src/theme/LastUpdated/index.tsx +1 -0
- package/src/theme/Layout/index.tsx +1 -1
- package/src/theme/MDXComponents/Details.tsx +2 -3
- package/src/theme/MDXComponents/Ul.tsx +2 -6
- package/src/theme/Navbar/Content/index.tsx +6 -1
- package/src/theme/Navbar/Logo/index.tsx +1 -1
- package/src/theme/Navbar/Search/index.tsx +15 -0
- package/src/theme/Navbar/Search/styles.module.css +20 -0
- package/src/theme/NavbarItem/ComponentTypes.tsx +32 -0
- package/src/theme/NavbarItem/DocNavbarItem.tsx +13 -32
- package/src/theme/NavbarItem/DocSidebarNavbarItem.tsx +9 -49
- package/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +26 -33
- package/src/theme/NavbarItem/DocsVersionNavbarItem.tsx +3 -10
- package/src/theme/NavbarItem/DropdownNavbarItem.tsx +4 -1
- package/src/theme/NavbarItem/HtmlNavbarItem.tsx +32 -0
- package/src/theme/NavbarItem/LocaleDropdownNavbarItem/index.tsx +5 -9
- package/src/theme/NavbarItem/NavbarNavLink.tsx +41 -25
- package/src/theme/NavbarItem/SearchNavbarItem.tsx +6 -1
- package/src/theme/NavbarItem/index.tsx +9 -38
- package/src/theme/NavbarItem/utils.ts +5 -2
- package/src/theme/PaginatorNavLink/index.tsx +8 -2
- package/src/theme/SiteMetadata/index.tsx +8 -8
- package/src/theme/SkipToContent/index.tsx +3 -29
- package/{lib-next/theme/TOCCollapsible/styles.module.css → src/theme/TOCCollapsible/CollapseButton.module.css} +1 -22
- package/src/theme/TOCCollapsible/CollapseButton.tsx +35 -0
- package/src/theme/TOCCollapsible/index.module.css +31 -0
- package/src/theme/TOCCollapsible/index.tsx +3 -14
- package/src/theme/TOCItems/Tree.tsx +46 -0
- package/src/theme/TOCItems/index.tsx +2 -41
- package/src/theme/TabItem/index.tsx +7 -1
- package/src/theme/TabItem/styles.module.css +10 -0
- package/src/theme/Tabs/index.tsx +3 -3
- package/src/theme/Tabs/styles.module.css +4 -0
- package/src/theme/Tag/index.tsx +2 -4
- package/src/theme/TagsListInline/index.tsx +1 -1
- package/src/theme-classic.d.ts +315 -33
- package/src/validateThemeConfig.ts +80 -13
- package/lib/types.d.ts +0 -11
- package/lib-next/theme/DocPage/styles.module.css +0 -82
- package/src/theme/DocPage/styles.module.css +0 -82
- package/src/types.d.ts +0 -11
|
@@ -0,0 +1,45 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import Link from '@docusaurus/Link';
|
|
11
|
+
import {translate} from '@docusaurus/Translate';
|
|
12
|
+
|
|
13
|
+
import styles from './styles.module.css';
|
|
14
|
+
import type {Props} from '@theme/BlogSidebar/Desktop';
|
|
15
|
+
|
|
16
|
+
export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element {
|
|
17
|
+
return (
|
|
18
|
+
<aside className="col col--3">
|
|
19
|
+
<nav
|
|
20
|
+
className={clsx(styles.sidebar, 'thin-scrollbar')}
|
|
21
|
+
aria-label={translate({
|
|
22
|
+
id: 'theme.blog.sidebar.navAriaLabel',
|
|
23
|
+
message: 'Blog recent posts navigation',
|
|
24
|
+
description: 'The ARIA label for recent posts in the blog sidebar',
|
|
25
|
+
})}>
|
|
26
|
+
<div className={clsx(styles.sidebarItemTitle, 'margin-bottom--md')}>
|
|
27
|
+
{sidebar.title}
|
|
28
|
+
</div>
|
|
29
|
+
<ul className={clsx(styles.sidebarItemList, 'clean-list')}>
|
|
30
|
+
{sidebar.items.map((item) => (
|
|
31
|
+
<li key={item.permalink} className={styles.sidebarItem}>
|
|
32
|
+
<Link
|
|
33
|
+
isNavLink
|
|
34
|
+
to={item.permalink}
|
|
35
|
+
className={styles.sidebarItemLink}
|
|
36
|
+
activeClassName={styles.sidebarItemLinkActive}>
|
|
37
|
+
{item.title}
|
|
38
|
+
</Link>
|
|
39
|
+
</li>
|
|
40
|
+
))}
|
|
41
|
+
</ul>
|
|
42
|
+
</nav>
|
|
43
|
+
</aside>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.sidebarItemList {
|
|
21
|
-
list-style: none;
|
|
22
21
|
font-size: 0.9rem;
|
|
23
|
-
padding-left: 0;
|
|
24
22
|
}
|
|
25
23
|
|
|
26
24
|
.sidebarItem {
|
|
@@ -29,6 +27,7 @@
|
|
|
29
27
|
|
|
30
28
|
.sidebarItemLink {
|
|
31
29
|
color: var(--ifm-font-color-base);
|
|
30
|
+
display: block;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
.sidebarItemLink:hover {
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import Link from '@docusaurus/Link';
|
|
10
|
+
import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common';
|
|
11
|
+
import type {Props} from '@theme/BlogSidebar/Mobile';
|
|
12
|
+
|
|
13
|
+
function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element {
|
|
14
|
+
return (
|
|
15
|
+
<ul className="menu__list">
|
|
16
|
+
{sidebar.items.map((item) => (
|
|
17
|
+
<li key={item.permalink} className="menu__list-item">
|
|
18
|
+
<Link
|
|
19
|
+
isNavLink
|
|
20
|
+
to={item.permalink}
|
|
21
|
+
className="menu__link"
|
|
22
|
+
activeClassName="menu__link--active">
|
|
23
|
+
{item.title}
|
|
24
|
+
</Link>
|
|
25
|
+
</li>
|
|
26
|
+
))}
|
|
27
|
+
</ul>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default function BlogSidebarMobile(props: Props): JSX.Element {
|
|
32
|
+
return (
|
|
33
|
+
<NavbarSecondaryMenuFiller
|
|
34
|
+
component={BlogSidebarMobileSecondaryMenu}
|
|
35
|
+
props={props}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -6,40 +6,19 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import BlogSidebarDesktop from '@theme/BlogSidebar/Desktop';
|
|
10
|
+
import BlogSidebarMobile from '@theme/BlogSidebar/Mobile';
|
|
11
|
+
import {useWindowSize} from '@docusaurus/theme-common';
|
|
11
12
|
import type {Props} from '@theme/BlogSidebar';
|
|
12
|
-
import styles from './styles.module.css';
|
|
13
|
-
import {translate} from '@docusaurus/Translate';
|
|
14
13
|
|
|
15
14
|
export default function BlogSidebar({sidebar}: Props): JSX.Element | null {
|
|
16
|
-
|
|
15
|
+
const windowSize = useWindowSize();
|
|
16
|
+
if (!sidebar?.items.length) {
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
message: 'Blog recent posts navigation',
|
|
25
|
-
description: 'The ARIA label for recent posts in the blog sidebar',
|
|
26
|
-
})}>
|
|
27
|
-
<div className={clsx(styles.sidebarItemTitle, 'margin-bottom--md')}>
|
|
28
|
-
{sidebar.title}
|
|
29
|
-
</div>
|
|
30
|
-
<ul className={styles.sidebarItemList}>
|
|
31
|
-
{sidebar.items.map((item) => (
|
|
32
|
-
<li key={item.permalink} className={styles.sidebarItem}>
|
|
33
|
-
<Link
|
|
34
|
-
isNavLink
|
|
35
|
-
to={item.permalink}
|
|
36
|
-
className={styles.sidebarItemLink}
|
|
37
|
-
activeClassName={styles.sidebarItemLinkActive}>
|
|
38
|
-
{item.title}
|
|
39
|
-
</Link>
|
|
40
|
-
</li>
|
|
41
|
-
))}
|
|
42
|
-
</ul>
|
|
43
|
-
</nav>
|
|
44
|
-
);
|
|
19
|
+
// Mobile sidebar doesn't need to be server-rendered
|
|
20
|
+
if (windowSize === 'mobile') {
|
|
21
|
+
return <BlogSidebarMobile sidebar={sidebar} />;
|
|
22
|
+
}
|
|
23
|
+
return <BlogSidebarDesktop sidebar={sidebar} />;
|
|
45
24
|
}
|
|
@@ -19,8 +19,7 @@ import {
|
|
|
19
19
|
import SearchMetadata from '../SearchMetadata';
|
|
20
20
|
import clsx from 'clsx';
|
|
21
21
|
|
|
22
|
-
export default function BlogTagsListPage(
|
|
23
|
-
const {tags, sidebar} = props;
|
|
22
|
+
export default function BlogTagsListPage({tags, sidebar}: Props): JSX.Element {
|
|
24
23
|
const title = translateTagsPageTitle();
|
|
25
24
|
return (
|
|
26
25
|
<HtmlClassNameProvider
|
|
@@ -32,7 +31,7 @@ export default function BlogTagsListPage(props: Props): JSX.Element {
|
|
|
32
31
|
<SearchMetadata tag="blog_tags_list" />
|
|
33
32
|
<BlogLayout sidebar={sidebar}>
|
|
34
33
|
<h1>{title}</h1>
|
|
35
|
-
<TagsListByLetter tags={
|
|
34
|
+
<TagsListByLetter tags={tags} />
|
|
36
35
|
</BlogLayout>
|
|
37
36
|
</HtmlClassNameProvider>
|
|
38
37
|
);
|
|
@@ -40,9 +40,12 @@ function useBlogPostsPlural() {
|
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
export default function BlogTagsPostsPage(
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
export default function BlogTagsPostsPage({
|
|
44
|
+
tag,
|
|
45
|
+
items,
|
|
46
|
+
sidebar,
|
|
47
|
+
listMetadata,
|
|
48
|
+
}: Props): JSX.Element {
|
|
46
49
|
const blogPostsPlural = useBlogPostsPlural();
|
|
47
50
|
const title = translate(
|
|
48
51
|
{
|
|
@@ -50,7 +53,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
|
|
50
53
|
description: 'The title of the page for a blog tag',
|
|
51
54
|
message: '{nPosts} tagged with "{tagName}"',
|
|
52
55
|
},
|
|
53
|
-
{nPosts: blogPostsPlural(count), tagName},
|
|
56
|
+
{nPosts: blogPostsPlural(tag.count), tagName: tag.label},
|
|
54
57
|
);
|
|
55
58
|
|
|
56
59
|
return (
|
|
@@ -65,7 +68,7 @@ export default function BlogTagsPostsPage(props: Props): JSX.Element {
|
|
|
65
68
|
<header className="margin-bottom--xl">
|
|
66
69
|
<h1>{title}</h1>
|
|
67
70
|
|
|
68
|
-
<Link href={allTagsPath}>
|
|
71
|
+
<Link href={tag.allTagsPath}>
|
|
69
72
|
<Translate
|
|
70
73
|
id="theme.tags.tagsPageLink"
|
|
71
74
|
description="The label of the link targeting the tag list page">
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
+
import React, {type ComponentProps} from 'react';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import {
|
|
11
|
+
usePrismTheme,
|
|
12
|
+
getPrismCssVariables,
|
|
13
|
+
ThemeClassNames,
|
|
14
|
+
} from '@docusaurus/theme-common';
|
|
15
|
+
import styles from './styles.module.css';
|
|
16
|
+
|
|
17
|
+
export default function CodeBlockContainer<T extends 'div' | 'pre'>({
|
|
18
|
+
as: As,
|
|
19
|
+
...props
|
|
20
|
+
}: {as: T} & ComponentProps<T>): JSX.Element {
|
|
21
|
+
const prismTheme = usePrismTheme();
|
|
22
|
+
const prismCssVariables = getPrismCssVariables(prismTheme);
|
|
23
|
+
return (
|
|
24
|
+
<As
|
|
25
|
+
// Polymorphic components are hard to type, without `oneOf` generics
|
|
26
|
+
{...(props as never)}
|
|
27
|
+
style={prismCssVariables}
|
|
28
|
+
className={clsx(
|
|
29
|
+
props.className,
|
|
30
|
+
styles.codeBlockContainer,
|
|
31
|
+
ThemeClassNames.common.codeBlock,
|
|
32
|
+
)}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
+
.codeBlockContainer {
|
|
9
|
+
background: var(--prism-background-color);
|
|
10
|
+
color: var(--prism-color);
|
|
11
|
+
margin-bottom: var(--ifm-leading);
|
|
12
|
+
box-shadow: var(--ifm-global-shadow-lw);
|
|
13
|
+
border-radius: var(--ifm-code-border-radius);
|
|
14
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import Container from '@theme/CodeBlock/Container';
|
|
10
|
+
import clsx from 'clsx';
|
|
11
|
+
import type {Props} from '@theme/CodeBlock/Content/Element';
|
|
12
|
+
|
|
13
|
+
import styles from './styles.module.css';
|
|
14
|
+
|
|
15
|
+
// <pre> tags in markdown map to CodeBlocks. They may contain JSX children. When
|
|
16
|
+
// the children is not a simple string, we just return a styled block without
|
|
17
|
+
// actually highlighting.
|
|
18
|
+
export default function CodeBlockJSX({
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
}: Props): JSX.Element {
|
|
22
|
+
return (
|
|
23
|
+
<Container
|
|
24
|
+
as="pre"
|
|
25
|
+
tabIndex={0}
|
|
26
|
+
className={clsx(styles.codeBlockStandalone, 'thin-scrollbar', className)}>
|
|
27
|
+
<code className={styles.codeBlockLines}>{children}</code>
|
|
28
|
+
</Container>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import {
|
|
10
|
+
useThemeConfig,
|
|
11
|
+
parseCodeBlockTitle,
|
|
12
|
+
parseLanguage,
|
|
13
|
+
parseLines,
|
|
14
|
+
containsLineNumbers,
|
|
15
|
+
usePrismTheme,
|
|
16
|
+
useCodeWordWrap,
|
|
17
|
+
} from '@docusaurus/theme-common';
|
|
18
|
+
import clsx from 'clsx';
|
|
19
|
+
import Highlight, {defaultProps, type Language} from 'prism-react-renderer';
|
|
20
|
+
import Line from '@theme/CodeBlock/Line';
|
|
21
|
+
import CopyButton from '@theme/CodeBlock/CopyButton';
|
|
22
|
+
import WordWrapButton from '@theme/CodeBlock/WordWrapButton';
|
|
23
|
+
import Container from '@theme/CodeBlock/Container';
|
|
24
|
+
import type {Props} from '@theme/CodeBlock/Content/String';
|
|
25
|
+
|
|
26
|
+
import styles from './styles.module.css';
|
|
27
|
+
|
|
28
|
+
export default function CodeBlockString({
|
|
29
|
+
children,
|
|
30
|
+
className: blockClassName = '',
|
|
31
|
+
metastring,
|
|
32
|
+
title: titleProp,
|
|
33
|
+
showLineNumbers: showLineNumbersProp,
|
|
34
|
+
language: languageProp,
|
|
35
|
+
}: Props): JSX.Element {
|
|
36
|
+
const {
|
|
37
|
+
prism: {defaultLanguage, magicComments},
|
|
38
|
+
} = useThemeConfig();
|
|
39
|
+
const language =
|
|
40
|
+
languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
|
|
41
|
+
const prismTheme = usePrismTheme();
|
|
42
|
+
const wordWrap = useCodeWordWrap();
|
|
43
|
+
|
|
44
|
+
// We still parse the metastring in case we want to support more syntax in the
|
|
45
|
+
// future. Note that MDX doesn't strip quotes when parsing metastring:
|
|
46
|
+
// "title=\"xyz\"" => title: "\"xyz\""
|
|
47
|
+
const title = parseCodeBlockTitle(metastring) || titleProp;
|
|
48
|
+
|
|
49
|
+
const {lineClassNames, code} = parseLines(children, {
|
|
50
|
+
metastring,
|
|
51
|
+
language,
|
|
52
|
+
magicComments,
|
|
53
|
+
});
|
|
54
|
+
const showLineNumbers =
|
|
55
|
+
showLineNumbersProp || containsLineNumbers(metastring);
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Container
|
|
59
|
+
as="div"
|
|
60
|
+
className={clsx(
|
|
61
|
+
blockClassName,
|
|
62
|
+
language &&
|
|
63
|
+
!blockClassName.includes(`language-${language}`) &&
|
|
64
|
+
`language-${language}`,
|
|
65
|
+
)}>
|
|
66
|
+
{title && <div className={styles.codeBlockTitle}>{title}</div>}
|
|
67
|
+
<div className={styles.codeBlockContent}>
|
|
68
|
+
<Highlight
|
|
69
|
+
{...defaultProps}
|
|
70
|
+
theme={prismTheme}
|
|
71
|
+
code={code}
|
|
72
|
+
language={(language ?? 'text') as Language}>
|
|
73
|
+
{({className, tokens, getLineProps, getTokenProps}) => (
|
|
74
|
+
<pre
|
|
75
|
+
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
|
76
|
+
tabIndex={0}
|
|
77
|
+
ref={wordWrap.codeBlockRef}
|
|
78
|
+
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
|
79
|
+
<code
|
|
80
|
+
className={clsx(
|
|
81
|
+
styles.codeBlockLines,
|
|
82
|
+
showLineNumbers && styles.codeBlockLinesWithNumbering,
|
|
83
|
+
)}>
|
|
84
|
+
{tokens.map((line, i) => (
|
|
85
|
+
<Line
|
|
86
|
+
key={i}
|
|
87
|
+
line={line}
|
|
88
|
+
getLineProps={getLineProps}
|
|
89
|
+
getTokenProps={getTokenProps}
|
|
90
|
+
classNames={lineClassNames[i]}
|
|
91
|
+
showLineNumbers={showLineNumbers}
|
|
92
|
+
/>
|
|
93
|
+
))}
|
|
94
|
+
</code>
|
|
95
|
+
</pre>
|
|
96
|
+
)}
|
|
97
|
+
</Highlight>
|
|
98
|
+
<div className={styles.buttonGroup}>
|
|
99
|
+
{(wordWrap.isEnabled || wordWrap.isCodeScrollable) && (
|
|
100
|
+
<WordWrapButton
|
|
101
|
+
className={styles.codeButton}
|
|
102
|
+
onClick={() => wordWrap.toggle()}
|
|
103
|
+
isEnabled={wordWrap.isEnabled}
|
|
104
|
+
/>
|
|
105
|
+
)}
|
|
106
|
+
<CopyButton className={styles.codeButton} code={code} />
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</Container>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -5,16 +5,11 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
.codeBlockContainer {
|
|
9
|
-
margin-bottom: var(--ifm-leading);
|
|
10
|
-
box-shadow: var(--ifm-global-shadow-lw);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
8
|
.codeBlockContent {
|
|
14
9
|
position: relative;
|
|
15
10
|
/* rtl:ignore */
|
|
16
11
|
direction: ltr;
|
|
17
|
-
border-radius:
|
|
12
|
+
border-radius: inherit;
|
|
18
13
|
}
|
|
19
14
|
|
|
20
15
|
.codeBlockTitle {
|
|
@@ -22,14 +17,14 @@
|
|
|
22
17
|
font-size: var(--ifm-code-font-size);
|
|
23
18
|
font-weight: 500;
|
|
24
19
|
padding: 0.75rem var(--ifm-pre-padding);
|
|
25
|
-
border-top-left-radius:
|
|
26
|
-
border-top-right-radius:
|
|
20
|
+
border-top-left-radius: inherit;
|
|
21
|
+
border-top-right-radius: inherit;
|
|
27
22
|
}
|
|
28
23
|
|
|
29
24
|
.codeBlock {
|
|
25
|
+
--ifm-pre-background: var(--prism-background-color);
|
|
30
26
|
margin: 0;
|
|
31
27
|
padding: 0;
|
|
32
|
-
background-color: inherit;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
.codeBlockTitle + .codeBlockContent .codeBlock {
|
|
@@ -49,8 +44,43 @@
|
|
|
49
44
|
padding: var(--ifm-pre-padding);
|
|
50
45
|
}
|
|
51
46
|
|
|
47
|
+
.codeBlockLinesWithNumbering {
|
|
48
|
+
display: table;
|
|
49
|
+
padding: var(--ifm-pre-padding) 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
52
|
@media print {
|
|
53
53
|
.codeBlockLines {
|
|
54
54
|
white-space: pre-wrap;
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
.buttonGroup {
|
|
59
|
+
display: flex;
|
|
60
|
+
column-gap: 0.2rem;
|
|
61
|
+
position: absolute;
|
|
62
|
+
right: calc(var(--ifm-pre-padding) / 2);
|
|
63
|
+
top: calc(var(--ifm-pre-padding) / 2);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.buttonGroup button {
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
background: var(--prism-background-color);
|
|
70
|
+
color: var(--prism-color);
|
|
71
|
+
border: 1px solid var(--ifm-color-emphasis-300);
|
|
72
|
+
border-radius: var(--ifm-global-radius);
|
|
73
|
+
padding: 0.4rem;
|
|
74
|
+
line-height: 0;
|
|
75
|
+
transition: opacity 200ms ease-in-out;
|
|
76
|
+
opacity: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.buttonGroup button:focus-visible,
|
|
80
|
+
.buttonGroup button:hover {
|
|
81
|
+
opacity: 1 !important;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:global(.theme-code-block:hover) .buttonGroup button {
|
|
85
|
+
opacity: 0.4;
|
|
86
|
+
}
|
|
@@ -13,7 +13,7 @@ import type {Props} from '@theme/CodeBlock/CopyButton';
|
|
|
13
13
|
|
|
14
14
|
import styles from './styles.module.css';
|
|
15
15
|
|
|
16
|
-
export default function CopyButton({code}: Props): JSX.Element {
|
|
16
|
+
export default function CopyButton({code, className}: Props): JSX.Element {
|
|
17
17
|
const [isCopied, setIsCopied] = useState(false);
|
|
18
18
|
const copyTimeout = useRef<number | undefined>(undefined);
|
|
19
19
|
const handleCopyCode = useCallback(() => {
|
|
@@ -48,8 +48,9 @@ export default function CopyButton({code}: Props): JSX.Element {
|
|
|
48
48
|
description: 'The copy button label on code blocks',
|
|
49
49
|
})}
|
|
50
50
|
className={clsx(
|
|
51
|
-
styles.copyButton,
|
|
52
51
|
'clean-btn',
|
|
52
|
+
className,
|
|
53
|
+
styles.copyButton,
|
|
53
54
|
isCopied && styles.copyButtonCopied,
|
|
54
55
|
)}
|
|
55
56
|
onClick={handleCopyCode}>
|
|
@@ -5,29 +5,10 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
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
8
|
:global(.theme-code-block:hover) .copyButtonCopied {
|
|
24
9
|
opacity: 1 !important;
|
|
25
10
|
}
|
|
26
11
|
|
|
27
|
-
:global(.theme-code-block:hover) .copyButton:not(.copyButtonCopied) {
|
|
28
|
-
opacity: 0.4;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
12
|
.copyButtonIcons {
|
|
32
13
|
position: relative;
|
|
33
14
|
width: 1.125rem;
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import type {Props} from '@theme/CodeBlock/Line';
|
|
11
|
+
import styles from './styles.module.css';
|
|
12
|
+
|
|
13
|
+
export default function CodeBlockLine({
|
|
14
|
+
line,
|
|
15
|
+
classNames,
|
|
16
|
+
showLineNumbers,
|
|
17
|
+
getLineProps,
|
|
18
|
+
getTokenProps,
|
|
19
|
+
}: Props): JSX.Element {
|
|
20
|
+
if (line.length === 1 && line[0]!.content === '\n') {
|
|
21
|
+
line[0]!.content = '';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const lineProps = getLineProps({
|
|
25
|
+
line,
|
|
26
|
+
className: clsx(classNames, showLineNumbers && styles.codeLine),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const lineTokens = line.map((token, key) => (
|
|
30
|
+
<span key={key} {...getTokenProps({token, key})} />
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<span {...lineProps}>
|
|
35
|
+
{showLineNumbers ? (
|
|
36
|
+
<>
|
|
37
|
+
<span className={styles.codeLineNumber} />
|
|
38
|
+
<span className={styles.codeLineContent}>{lineTokens}</span>
|
|
39
|
+
</>
|
|
40
|
+
) : (
|
|
41
|
+
<>
|
|
42
|
+
{lineTokens}
|
|
43
|
+
<br />
|
|
44
|
+
</>
|
|
45
|
+
)}
|
|
46
|
+
</span>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
:global(.theme-code-block-highlighted-line) {
|
|
9
|
+
background-color: var(--docusaurus-highlighted-code-line-bg);
|
|
10
|
+
display: block;
|
|
11
|
+
margin: 0 calc(-1 * var(--ifm-pre-padding));
|
|
12
|
+
padding: 0 var(--ifm-pre-padding);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Intentionally has zero specificity, so that to be able to override
|
|
16
|
+
the background in custom CSS file due bug https://github.com/facebook/docusaurus/issues/3678 */
|
|
17
|
+
:where(:root) {
|
|
18
|
+
--docusaurus-highlighted-code-line-bg: rgb(72 77 91);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:where([data-theme='dark']) {
|
|
22
|
+
--docusaurus-highlighted-code-line-bg: rgb(100 100 100);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.codeLine {
|
|
26
|
+
display: table-row;
|
|
27
|
+
counter-increment: line-count;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.codeLineNumber {
|
|
31
|
+
display: table-cell;
|
|
32
|
+
text-align: right;
|
|
33
|
+
width: 1%;
|
|
34
|
+
position: sticky;
|
|
35
|
+
left: 0;
|
|
36
|
+
padding: 0 var(--ifm-pre-padding);
|
|
37
|
+
background: var(--ifm-pre-background);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.codeLineNumber::before {
|
|
41
|
+
content: counter(line-count);
|
|
42
|
+
opacity: 0.4;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.highlightedCodeLine .codeLineNumber::before {
|
|
46
|
+
opacity: 0.8;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.codeLineContent {
|
|
50
|
+
padding-right: var(--ifm-pre-padding);
|
|
51
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
import React from 'react';
|
|
9
|
+
import clsx from 'clsx';
|
|
10
|
+
import {translate} from '@docusaurus/Translate';
|
|
11
|
+
import type {Props} from '@theme/CodeBlock/WordWrapButton';
|
|
12
|
+
|
|
13
|
+
import styles from './styles.module.css';
|
|
14
|
+
|
|
15
|
+
export default function WordWrapButton({
|
|
16
|
+
className,
|
|
17
|
+
onClick,
|
|
18
|
+
isEnabled,
|
|
19
|
+
}: Props): JSX.Element | null {
|
|
20
|
+
const title = translate({
|
|
21
|
+
id: 'theme.CodeBlock.wordWrapToggle',
|
|
22
|
+
message: 'Toggle word wrap',
|
|
23
|
+
description:
|
|
24
|
+
'The title attribute for toggle word wrapping button of code block lines',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
onClick={onClick}
|
|
31
|
+
className={clsx(
|
|
32
|
+
'clean-btn',
|
|
33
|
+
className,
|
|
34
|
+
isEnabled && styles.wordWrapButtonEnabled,
|
|
35
|
+
)}
|
|
36
|
+
aria-label={title}
|
|
37
|
+
title={title}>
|
|
38
|
+
<svg
|
|
39
|
+
className={styles.wordWrapButtonIcon}
|
|
40
|
+
viewBox="0 0 24 24"
|
|
41
|
+
aria-hidden="true">
|
|
42
|
+
<path
|
|
43
|
+
fill="currentColor"
|
|
44
|
+
d="M4 19h6v-2H4v2zM20 5H4v2h16V5zm-3 6H4v2h13.25c1.1 0 2 .9 2 2s-.9 2-2 2H15v-2l-3 3l3 3v-2h2c2.21 0 4-1.79 4-4s-1.79-4-4-4z"
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
</button>
|
|
48
|
+
);
|
|
49
|
+
}
|