@docusaurus/theme-classic 0.0.0-6010 → 0.0.0-6014
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/getSwizzleConfig.js +21 -0
- package/lib/theme/{BlogPostItem/Header → Blog/Components}/Author/Socials/index.d.ts +3 -4
- package/lib/theme/{BlogPostItem/Header → Blog/Components}/Author/Socials/index.js +3 -2
- package/lib/theme/{BlogPostItem/Header → Blog/Components}/Author/Socials/styles.module.css +7 -2
- package/lib/theme/{BlogPostItem/Header → Blog/Components}/Author/index.d.ts +2 -2
- package/lib/theme/Blog/Components/Author/index.js +86 -0
- package/lib/theme/Blog/Components/Author/styles.module.css +74 -0
- package/lib/theme/Blog/Pages/BlogAuthorsListPage/index.d.ts +9 -0
- package/lib/theme/Blog/Pages/BlogAuthorsListPage/index.js +54 -0
- package/lib/theme/Blog/Pages/BlogAuthorsListPage/styles.module.css +11 -0
- package/lib/theme/Blog/Pages/BlogAuthorsPostsPage/index.d.ts +8 -0
- package/lib/theme/Blog/Pages/BlogAuthorsPostsPage/index.js +67 -0
- package/lib/theme/BlogPostItem/Header/Authors/index.js +2 -3
- package/lib/theme/BlogTagsPostsPage/index.js +2 -30
- package/package.json +14 -14
- package/src/getSwizzleConfig.ts +21 -0
- package/src/theme/{BlogPostItem/Header → Blog/Components}/Author/Socials/index.tsx +8 -3
- package/src/theme/{BlogPostItem/Header → Blog/Components}/Author/Socials/styles.module.css +7 -2
- package/src/theme/Blog/Components/Author/index.tsx +99 -0
- package/src/theme/Blog/Components/Author/styles.module.css +74 -0
- package/src/theme/Blog/Pages/BlogAuthorsListPage/index.tsx +62 -0
- package/src/theme/Blog/Pages/BlogAuthorsListPage/styles.module.css +11 -0
- package/src/theme/Blog/Pages/BlogAuthorsPostsPage/index.tsx +73 -0
- package/src/theme/BlogPostItem/Header/Authors/index.tsx +2 -3
- package/src/theme/BlogTagsPostsPage/index.tsx +2 -32
- package/src/theme-classic.d.ts +24 -25
- package/lib/theme/BlogPostItem/Header/Author/index.js +0 -54
- package/lib/theme/BlogPostItem/Header/Author/styles.module.css +0 -21
- package/src/theme/BlogPostItem/Header/Author/index.tsx +0 -62
- package/src/theme/BlogPostItem/Header/Author/styles.module.css +0 -21
package/lib/getSwizzleConfig.js
CHANGED
|
@@ -117,6 +117,27 @@ function getSwizzleConfig() {
|
|
|
117
117
|
},
|
|
118
118
|
description: 'The object mapping admonition type to a React component.\nUse it to add custom admonition type components, or replace existing ones.\nCan be ejected or wrapped (only manually, see our documentation).',
|
|
119
119
|
},
|
|
120
|
+
Blog: {
|
|
121
|
+
actions: {
|
|
122
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
123
|
+
eject: 'forbidden',
|
|
124
|
+
wrap: 'forbidden',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'Blog/Components': {
|
|
128
|
+
actions: {
|
|
129
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
130
|
+
eject: 'forbidden',
|
|
131
|
+
wrap: 'forbidden',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
'Blog/Pages': {
|
|
135
|
+
actions: {
|
|
136
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
137
|
+
eject: 'forbidden',
|
|
138
|
+
wrap: 'forbidden',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
120
141
|
CodeBlock: {
|
|
121
142
|
actions: {
|
|
122
143
|
eject: 'safe',
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
export default function AuthorSocials({ author }: {
|
|
7
|
+
import type { Props } from '@theme/Blog/Components/Author/Socials';
|
|
8
|
+
export default function BlogAuthorSocials({ author, }: {
|
|
10
9
|
author: Props['author'];
|
|
11
|
-
}):
|
|
10
|
+
}): JSX.Element;
|
|
@@ -37,10 +37,11 @@ function SocialLink({platform, link}) {
|
|
|
37
37
|
</Link>
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
|
-
export default function
|
|
40
|
+
export default function BlogAuthorSocials({author}) {
|
|
41
|
+
const entries = Object.entries(author.socials ?? {});
|
|
41
42
|
return (
|
|
42
43
|
<div className={styles.authorSocials}>
|
|
43
|
-
{
|
|
44
|
+
{entries.map(([platform, linkUrl]) => {
|
|
44
45
|
return <SocialLink key={platform} platform={platform} link={linkUrl} />;
|
|
45
46
|
})}
|
|
46
47
|
</div>
|
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.authorSocials {
|
|
13
|
-
|
|
13
|
+
/*
|
|
14
|
+
This ensures that container takes height even if there's no social link
|
|
15
|
+
This keeps author names aligned even if only some have socials
|
|
16
|
+
*/
|
|
17
|
+
height: var(--docusaurus-blog-social-icon-size);
|
|
18
|
+
|
|
14
19
|
display: flex;
|
|
15
20
|
flex-wrap: wrap;
|
|
16
21
|
align-items: center;
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
height: var(--docusaurus-blog-social-icon-size);
|
|
26
31
|
width: var(--docusaurus-blog-social-icon-size);
|
|
27
32
|
line-height: 0;
|
|
28
|
-
margin-right: 0.
|
|
33
|
+
margin-right: 0.4rem;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
.authorSocialIcon {
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
|
-
import type { Props } from '@theme/
|
|
8
|
-
export default function
|
|
7
|
+
import type { Props } from '@theme/Blog/Components/Author';
|
|
8
|
+
export default function BlogAuthor({ as, author, className, count, }: Props): JSX.Element;
|
|
@@ -0,0 +1,86 @@
|
|
|
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 from 'react';
|
|
8
|
+
import clsx from 'clsx';
|
|
9
|
+
import Link from '@docusaurus/Link';
|
|
10
|
+
import AuthorSocials from '@theme/Blog/Components/Author/Socials';
|
|
11
|
+
import Heading from '@theme/Heading';
|
|
12
|
+
import styles from './styles.module.css';
|
|
13
|
+
function MaybeLink(props) {
|
|
14
|
+
if (props.href) {
|
|
15
|
+
return <Link {...props} />;
|
|
16
|
+
}
|
|
17
|
+
return <>{props.children}</>;
|
|
18
|
+
}
|
|
19
|
+
function AuthorTitle({title}) {
|
|
20
|
+
return (
|
|
21
|
+
<small className={styles.authorTitle} title={title}>
|
|
22
|
+
{title}
|
|
23
|
+
</small>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function AuthorName({name, as}) {
|
|
27
|
+
if (!as) {
|
|
28
|
+
return <span className={styles.authorName}>{name}</span>;
|
|
29
|
+
} else {
|
|
30
|
+
return (
|
|
31
|
+
<Heading as={as} className={styles.authorName}>
|
|
32
|
+
{name}
|
|
33
|
+
</Heading>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function AuthorBlogPostCount({count}) {
|
|
38
|
+
return <span className={clsx(styles.authorBlogPostCount)}>{count}</span>;
|
|
39
|
+
}
|
|
40
|
+
// Note: in the future we might want to have multiple "BlogAuthor" components
|
|
41
|
+
// Creating different display modes with the "as" prop may not be the best idea
|
|
42
|
+
// Explainer: https://kyleshevlin.com/prefer-multiple-compositions/
|
|
43
|
+
// For now, we almost use the same design for all cases, so it's good enough
|
|
44
|
+
export default function BlogAuthor({as, author, className, count}) {
|
|
45
|
+
const {name, title, url, imageURL, email, page} = author;
|
|
46
|
+
const link =
|
|
47
|
+
page?.permalink || url || (email && `mailto:${email}`) || undefined;
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
className={clsx(
|
|
51
|
+
'avatar margin-bottom--sm',
|
|
52
|
+
className,
|
|
53
|
+
styles[`author-as-${as}`],
|
|
54
|
+
)}>
|
|
55
|
+
{imageURL && (
|
|
56
|
+
<MaybeLink href={link} className="avatar__photo-link">
|
|
57
|
+
<img
|
|
58
|
+
className={clsx('avatar__photo', styles.authorImage)}
|
|
59
|
+
src={imageURL}
|
|
60
|
+
alt={name}
|
|
61
|
+
/>
|
|
62
|
+
</MaybeLink>
|
|
63
|
+
)}
|
|
64
|
+
|
|
65
|
+
{(name || title) && (
|
|
66
|
+
<div className={clsx('avatar__intro', styles.authorDetails)}>
|
|
67
|
+
<div className="avatar__name">
|
|
68
|
+
{name && (
|
|
69
|
+
<MaybeLink href={link}>
|
|
70
|
+
<AuthorName name={name} as={as} />
|
|
71
|
+
</MaybeLink>
|
|
72
|
+
)}
|
|
73
|
+
{count && <AuthorBlogPostCount count={count} />}
|
|
74
|
+
</div>
|
|
75
|
+
{!!title && <AuthorTitle title={title} />}
|
|
76
|
+
|
|
77
|
+
{/*
|
|
78
|
+
We always render AuthorSocials even if there's none
|
|
79
|
+
This keeps other things aligned with flexbox layout
|
|
80
|
+
*/}
|
|
81
|
+
<AuthorSocials author={author} />
|
|
82
|
+
</div>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
.authorImage {
|
|
9
|
+
--ifm-avatar-photo-size: 3.6rem;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.author-as-h1 .authorImage {
|
|
13
|
+
--ifm-avatar-photo-size: 7rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.author-as-h2 .authorImage {
|
|
17
|
+
--ifm-avatar-photo-size: 5.4rem;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.authorDetails {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: flex-start;
|
|
24
|
+
justify-content: space-around;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.authorName {
|
|
28
|
+
font-size: 1.1rem;
|
|
29
|
+
line-height: 1.1rem;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.author-as-h1 .authorName {
|
|
35
|
+
font-size: 2.4rem;
|
|
36
|
+
line-height: 2.4rem;
|
|
37
|
+
display: inline;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.author-as-h2 .authorName {
|
|
41
|
+
font-size: 1.4rem;
|
|
42
|
+
line-height: 1.4rem;
|
|
43
|
+
display: inline;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.authorTitle {
|
|
47
|
+
font-size: 0.8rem;
|
|
48
|
+
line-height: 0.8rem;
|
|
49
|
+
display: -webkit-box;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
line-clamp: 1;
|
|
52
|
+
-webkit-line-clamp: 1;
|
|
53
|
+
-webkit-box-orient: vertical;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.author-as-h1 .authorTitle {
|
|
57
|
+
font-size: 1.2rem;
|
|
58
|
+
line-height: 1.2rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.author-as-h2 .authorTitle {
|
|
62
|
+
font-size: 1rem;
|
|
63
|
+
line-height: 1rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.authorBlogPostCount {
|
|
67
|
+
background: var(--ifm-color-secondary);
|
|
68
|
+
color: var(--ifm-color-black);
|
|
69
|
+
font-size: 0.8rem;
|
|
70
|
+
line-height: 1.2;
|
|
71
|
+
border-radius: var(--ifm-global-radius);
|
|
72
|
+
padding: 0.1rem 0.4rem;
|
|
73
|
+
margin-left: 0.3rem;
|
|
74
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
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 { type ReactNode } from 'react';
|
|
8
|
+
import type { Props } from '@theme/Blog/Pages/BlogAuthorsListPage';
|
|
9
|
+
export default function BlogAuthorsListPage({ authors, sidebar, }: Props): ReactNode;
|
|
@@ -0,0 +1,54 @@
|
|
|
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 from 'react';
|
|
8
|
+
import clsx from 'clsx';
|
|
9
|
+
import {
|
|
10
|
+
PageMetadata,
|
|
11
|
+
HtmlClassNameProvider,
|
|
12
|
+
ThemeClassNames,
|
|
13
|
+
} from '@docusaurus/theme-common';
|
|
14
|
+
import {translateBlogAuthorsListPageTitle} from '@docusaurus/theme-common/internal';
|
|
15
|
+
import BlogLayout from '@theme/BlogLayout';
|
|
16
|
+
import SearchMetadata from '@theme/SearchMetadata';
|
|
17
|
+
import Heading from '@theme/Heading';
|
|
18
|
+
import Author from '@theme/Blog/Components/Author';
|
|
19
|
+
import styles from './styles.module.css';
|
|
20
|
+
function AuthorListItem({author}) {
|
|
21
|
+
return (
|
|
22
|
+
<li className={styles.authorListItem}>
|
|
23
|
+
<Author as="h2" author={author} count={author.count} />
|
|
24
|
+
</li>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function AuthorsList({authors}) {
|
|
28
|
+
return (
|
|
29
|
+
<section className={clsx('margin-vert--lg', styles.authorsListSection)}>
|
|
30
|
+
<ul>
|
|
31
|
+
{authors.map((author) => (
|
|
32
|
+
<AuthorListItem key={author.key} author={author} />
|
|
33
|
+
))}
|
|
34
|
+
</ul>
|
|
35
|
+
</section>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
export default function BlogAuthorsListPage({authors, sidebar}) {
|
|
39
|
+
const title = translateBlogAuthorsListPageTitle();
|
|
40
|
+
return (
|
|
41
|
+
<HtmlClassNameProvider
|
|
42
|
+
className={clsx(
|
|
43
|
+
ThemeClassNames.wrapper.blogPages,
|
|
44
|
+
ThemeClassNames.page.blogAuthorsListPage,
|
|
45
|
+
)}>
|
|
46
|
+
<PageMetadata title={title} />
|
|
47
|
+
<SearchMetadata tag="blog_authors_list" />
|
|
48
|
+
<BlogLayout sidebar={sidebar}>
|
|
49
|
+
<Heading as="h1">{title}</Heading>
|
|
50
|
+
<AuthorsList authors={authors} />
|
|
51
|
+
</BlogLayout>
|
|
52
|
+
</HtmlClassNameProvider>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
.authorListItem {
|
|
9
|
+
list-style-type: none;
|
|
10
|
+
margin-bottom: 2rem;
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
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 type { Props } from '@theme/Blog/Pages/BlogAuthorsPostsPage';
|
|
8
|
+
export default function BlogAuthorsPostsPage(props: Props): JSX.Element;
|
|
@@ -0,0 +1,67 @@
|
|
|
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 from 'react';
|
|
8
|
+
import clsx from 'clsx';
|
|
9
|
+
import {
|
|
10
|
+
PageMetadata,
|
|
11
|
+
HtmlClassNameProvider,
|
|
12
|
+
ThemeClassNames,
|
|
13
|
+
} from '@docusaurus/theme-common';
|
|
14
|
+
import {
|
|
15
|
+
useBlogAuthorPageTitle,
|
|
16
|
+
BlogAuthorsListViewAllLabel,
|
|
17
|
+
} from '@docusaurus/theme-common/internal';
|
|
18
|
+
import Link from '@docusaurus/Link';
|
|
19
|
+
import {useBlogMetadata} from '@docusaurus/plugin-content-blog/client';
|
|
20
|
+
import BlogLayout from '@theme/BlogLayout';
|
|
21
|
+
import BlogListPaginator from '@theme/BlogListPaginator';
|
|
22
|
+
import SearchMetadata from '@theme/SearchMetadata';
|
|
23
|
+
import BlogPostItems from '@theme/BlogPostItems';
|
|
24
|
+
import Author from '@theme/Blog/Components/Author';
|
|
25
|
+
function Metadata({author}) {
|
|
26
|
+
const title = useBlogAuthorPageTitle(author);
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<PageMetadata title={title} />
|
|
30
|
+
<SearchMetadata tag="blog_authors_posts" />
|
|
31
|
+
</>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
function ViewAllAuthorsLink() {
|
|
35
|
+
const {authorsListPath} = useBlogMetadata();
|
|
36
|
+
return (
|
|
37
|
+
<Link href={authorsListPath}>
|
|
38
|
+
<BlogAuthorsListViewAllLabel />
|
|
39
|
+
</Link>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function Content({author, items, sidebar, listMetadata}) {
|
|
43
|
+
return (
|
|
44
|
+
<BlogLayout sidebar={sidebar}>
|
|
45
|
+
<header className="margin-bottom--xl">
|
|
46
|
+
<Author as="h1" author={author} />
|
|
47
|
+
{author.description && <p>{author.description}</p>}
|
|
48
|
+
<ViewAllAuthorsLink />
|
|
49
|
+
</header>
|
|
50
|
+
<hr />
|
|
51
|
+
<BlogPostItems items={items} />
|
|
52
|
+
<BlogListPaginator metadata={listMetadata} />
|
|
53
|
+
</BlogLayout>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
export default function BlogAuthorsPostsPage(props) {
|
|
57
|
+
return (
|
|
58
|
+
<HtmlClassNameProvider
|
|
59
|
+
className={clsx(
|
|
60
|
+
ThemeClassNames.wrapper.blogPages,
|
|
61
|
+
ThemeClassNames.page.blogAuthorsPostsPage,
|
|
62
|
+
)}>
|
|
63
|
+
<Metadata {...props} />
|
|
64
|
+
<Content {...props} />
|
|
65
|
+
</HtmlClassNameProvider>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
9
|
import {useBlogPost} from '@docusaurus/plugin-content-blog/client';
|
|
10
|
-
import
|
|
10
|
+
import BlogAuthor from '@theme/Blog/Components/Author';
|
|
11
11
|
import styles from './styles.module.css';
|
|
12
12
|
// Component responsible for the authors layout
|
|
13
13
|
export default function BlogPostItemHeaderAuthors({className}) {
|
|
@@ -35,8 +35,7 @@ export default function BlogPostItemHeaderAuthors({className}) {
|
|
|
35
35
|
imageOnly ? styles.imageOnlyAuthorCol : styles.authorCol,
|
|
36
36
|
)}
|
|
37
37
|
key={idx}>
|
|
38
|
-
<
|
|
39
|
-
singleAuthor={singleAuthor}
|
|
38
|
+
<BlogAuthor
|
|
40
39
|
author={{
|
|
41
40
|
...author,
|
|
42
41
|
// Handle author images using relative paths
|
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import clsx from 'clsx';
|
|
9
|
-
import Translate
|
|
9
|
+
import Translate from '@docusaurus/Translate';
|
|
10
10
|
import {
|
|
11
11
|
PageMetadata,
|
|
12
12
|
HtmlClassNameProvider,
|
|
13
13
|
ThemeClassNames,
|
|
14
|
-
usePluralForm,
|
|
15
14
|
} from '@docusaurus/theme-common';
|
|
15
|
+
import {useBlogTagsPostsPageTitle} from '@docusaurus/theme-common/internal';
|
|
16
16
|
import Link from '@docusaurus/Link';
|
|
17
17
|
import BlogLayout from '@theme/BlogLayout';
|
|
18
18
|
import BlogListPaginator from '@theme/BlogListPaginator';
|
|
@@ -20,34 +20,6 @@ import SearchMetadata from '@theme/SearchMetadata';
|
|
|
20
20
|
import BlogPostItems from '@theme/BlogPostItems';
|
|
21
21
|
import Unlisted from '@theme/Unlisted';
|
|
22
22
|
import Heading from '@theme/Heading';
|
|
23
|
-
// Very simple pluralization: probably good enough for now
|
|
24
|
-
function useBlogPostsPlural() {
|
|
25
|
-
const {selectMessage} = usePluralForm();
|
|
26
|
-
return (count) =>
|
|
27
|
-
selectMessage(
|
|
28
|
-
count,
|
|
29
|
-
translate(
|
|
30
|
-
{
|
|
31
|
-
id: 'theme.blog.post.plurals',
|
|
32
|
-
description:
|
|
33
|
-
'Pluralized label for "{count} posts". 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)',
|
|
34
|
-
message: 'One post|{count} posts',
|
|
35
|
-
},
|
|
36
|
-
{count},
|
|
37
|
-
),
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
function useBlogTagsPostsPageTitle(tag) {
|
|
41
|
-
const blogPostsPlural = useBlogPostsPlural();
|
|
42
|
-
return translate(
|
|
43
|
-
{
|
|
44
|
-
id: 'theme.blog.tagTitle',
|
|
45
|
-
description: 'The title of the page for a blog tag',
|
|
46
|
-
message: '{nPosts} tagged with "{tagName}"',
|
|
47
|
-
},
|
|
48
|
-
{nPosts: blogPostsPlural(tag.count), tagName: tag.label},
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
23
|
function BlogTagsPostsPageMetadata({tag}) {
|
|
52
24
|
const title = useBlogTagsPostsPageTitle(tag);
|
|
53
25
|
return (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@docusaurus/theme-classic",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-6014",
|
|
4
4
|
"description": "Classic theme for Docusaurus",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "src/theme-classic.d.ts",
|
|
@@ -20,18 +20,18 @@
|
|
|
20
20
|
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@docusaurus/core": "0.0.0-
|
|
24
|
-
"@docusaurus/mdx-loader": "0.0.0-
|
|
25
|
-
"@docusaurus/module-type-aliases": "0.0.0-
|
|
26
|
-
"@docusaurus/plugin-content-blog": "0.0.0-
|
|
27
|
-
"@docusaurus/plugin-content-docs": "0.0.0-
|
|
28
|
-
"@docusaurus/plugin-content-pages": "0.0.0-
|
|
29
|
-
"@docusaurus/theme-common": "0.0.0-
|
|
30
|
-
"@docusaurus/theme-translations": "0.0.0-
|
|
31
|
-
"@docusaurus/types": "0.0.0-
|
|
32
|
-
"@docusaurus/utils": "0.0.0-
|
|
33
|
-
"@docusaurus/utils-common": "0.0.0-
|
|
34
|
-
"@docusaurus/utils-validation": "0.0.0-
|
|
23
|
+
"@docusaurus/core": "0.0.0-6014",
|
|
24
|
+
"@docusaurus/mdx-loader": "0.0.0-6014",
|
|
25
|
+
"@docusaurus/module-type-aliases": "0.0.0-6014",
|
|
26
|
+
"@docusaurus/plugin-content-blog": "0.0.0-6014",
|
|
27
|
+
"@docusaurus/plugin-content-docs": "0.0.0-6014",
|
|
28
|
+
"@docusaurus/plugin-content-pages": "0.0.0-6014",
|
|
29
|
+
"@docusaurus/theme-common": "0.0.0-6014",
|
|
30
|
+
"@docusaurus/theme-translations": "0.0.0-6014",
|
|
31
|
+
"@docusaurus/types": "0.0.0-6014",
|
|
32
|
+
"@docusaurus/utils": "0.0.0-6014",
|
|
33
|
+
"@docusaurus/utils-common": "0.0.0-6014",
|
|
34
|
+
"@docusaurus/utils-validation": "0.0.0-6014",
|
|
35
35
|
"@mdx-js/react": "^3.0.0",
|
|
36
36
|
"clsx": "^2.0.0",
|
|
37
37
|
"copy-text-to-clipboard": "^3.2.0",
|
|
@@ -61,5 +61,5 @@
|
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=18.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "77581424d709d71c35dface5df45925e2851c2c8"
|
|
65
65
|
}
|
package/src/getSwizzleConfig.ts
CHANGED
|
@@ -127,6 +127,27 @@ export default function getSwizzleConfig(): SwizzleConfig {
|
|
|
127
127
|
description:
|
|
128
128
|
'The object mapping admonition type to a React component.\nUse it to add custom admonition type components, or replace existing ones.\nCan be ejected or wrapped (only manually, see our documentation).',
|
|
129
129
|
},
|
|
130
|
+
Blog: {
|
|
131
|
+
actions: {
|
|
132
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
133
|
+
eject: 'forbidden',
|
|
134
|
+
wrap: 'forbidden',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
'Blog/Components': {
|
|
138
|
+
actions: {
|
|
139
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
140
|
+
eject: 'forbidden',
|
|
141
|
+
wrap: 'forbidden',
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
'Blog/Pages': {
|
|
145
|
+
actions: {
|
|
146
|
+
// Forbidden because it's a parent folder, makes the CLI crash atm
|
|
147
|
+
eject: 'forbidden',
|
|
148
|
+
wrap: 'forbidden',
|
|
149
|
+
},
|
|
150
|
+
},
|
|
130
151
|
CodeBlock: {
|
|
131
152
|
actions: {
|
|
132
153
|
eject: 'safe',
|
|
@@ -9,7 +9,7 @@ import type {ComponentType} from 'react';
|
|
|
9
9
|
import React from 'react';
|
|
10
10
|
import clsx from 'clsx';
|
|
11
11
|
import Link from '@docusaurus/Link';
|
|
12
|
-
import type {Props} from '@theme/
|
|
12
|
+
import type {Props} from '@theme/Blog/Components/Author/Socials';
|
|
13
13
|
|
|
14
14
|
import Twitter from '@theme/Icon/Socials/Twitter';
|
|
15
15
|
import GitHub from '@theme/Icon/Socials/GitHub';
|
|
@@ -50,10 +50,15 @@ function SocialLink({platform, link}: {platform: string; link: string}) {
|
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
export default function
|
|
53
|
+
export default function BlogAuthorSocials({
|
|
54
|
+
author,
|
|
55
|
+
}: {
|
|
56
|
+
author: Props['author'];
|
|
57
|
+
}): JSX.Element {
|
|
58
|
+
const entries = Object.entries(author.socials ?? {});
|
|
54
59
|
return (
|
|
55
60
|
<div className={styles.authorSocials}>
|
|
56
|
-
{
|
|
61
|
+
{entries.map(([platform, linkUrl]) => {
|
|
57
62
|
return <SocialLink key={platform} platform={platform} link={linkUrl} />;
|
|
58
63
|
})}
|
|
59
64
|
</div>
|
|
@@ -10,7 +10,12 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.authorSocials {
|
|
13
|
-
|
|
13
|
+
/*
|
|
14
|
+
This ensures that container takes height even if there's no social link
|
|
15
|
+
This keeps author names aligned even if only some have socials
|
|
16
|
+
*/
|
|
17
|
+
height: var(--docusaurus-blog-social-icon-size);
|
|
18
|
+
|
|
14
19
|
display: flex;
|
|
15
20
|
flex-wrap: wrap;
|
|
16
21
|
align-items: center;
|
|
@@ -25,7 +30,7 @@
|
|
|
25
30
|
height: var(--docusaurus-blog-social-icon-size);
|
|
26
31
|
width: var(--docusaurus-blog-social-icon-size);
|
|
27
32
|
line-height: 0;
|
|
28
|
-
margin-right: 0.
|
|
33
|
+
margin-right: 0.4rem;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
.authorSocialIcon {
|
|
@@ -0,0 +1,99 @@
|
|
|
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, {type Props as LinkProps} from '@docusaurus/Link';
|
|
11
|
+
import AuthorSocials from '@theme/Blog/Components/Author/Socials';
|
|
12
|
+
import type {Props} from '@theme/Blog/Components/Author';
|
|
13
|
+
import Heading from '@theme/Heading';
|
|
14
|
+
import styles from './styles.module.css';
|
|
15
|
+
|
|
16
|
+
function MaybeLink(props: LinkProps): JSX.Element {
|
|
17
|
+
if (props.href) {
|
|
18
|
+
return <Link {...props} />;
|
|
19
|
+
}
|
|
20
|
+
return <>{props.children}</>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function AuthorTitle({title}: {title: string}) {
|
|
24
|
+
return (
|
|
25
|
+
<small className={styles.authorTitle} title={title}>
|
|
26
|
+
{title}
|
|
27
|
+
</small>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AuthorName({name, as}: {name: string; as: Props['as']}) {
|
|
32
|
+
if (!as) {
|
|
33
|
+
return <span className={styles.authorName}>{name}</span>;
|
|
34
|
+
} else {
|
|
35
|
+
return (
|
|
36
|
+
<Heading as={as} className={styles.authorName}>
|
|
37
|
+
{name}
|
|
38
|
+
</Heading>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function AuthorBlogPostCount({count}: {count: number}) {
|
|
44
|
+
return <span className={clsx(styles.authorBlogPostCount)}>{count}</span>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Note: in the future we might want to have multiple "BlogAuthor" components
|
|
48
|
+
// Creating different display modes with the "as" prop may not be the best idea
|
|
49
|
+
// Explainer: https://kyleshevlin.com/prefer-multiple-compositions/
|
|
50
|
+
// For now, we almost use the same design for all cases, so it's good enough
|
|
51
|
+
export default function BlogAuthor({
|
|
52
|
+
as,
|
|
53
|
+
author,
|
|
54
|
+
className,
|
|
55
|
+
count,
|
|
56
|
+
}: Props): JSX.Element {
|
|
57
|
+
const {name, title, url, imageURL, email, page} = author;
|
|
58
|
+
const link =
|
|
59
|
+
page?.permalink || url || (email && `mailto:${email}`) || undefined;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<div
|
|
63
|
+
className={clsx(
|
|
64
|
+
'avatar margin-bottom--sm',
|
|
65
|
+
className,
|
|
66
|
+
styles[`author-as-${as}`],
|
|
67
|
+
)}>
|
|
68
|
+
{imageURL && (
|
|
69
|
+
<MaybeLink href={link} className="avatar__photo-link">
|
|
70
|
+
<img
|
|
71
|
+
className={clsx('avatar__photo', styles.authorImage)}
|
|
72
|
+
src={imageURL}
|
|
73
|
+
alt={name}
|
|
74
|
+
/>
|
|
75
|
+
</MaybeLink>
|
|
76
|
+
)}
|
|
77
|
+
|
|
78
|
+
{(name || title) && (
|
|
79
|
+
<div className={clsx('avatar__intro', styles.authorDetails)}>
|
|
80
|
+
<div className="avatar__name">
|
|
81
|
+
{name && (
|
|
82
|
+
<MaybeLink href={link}>
|
|
83
|
+
<AuthorName name={name} as={as} />
|
|
84
|
+
</MaybeLink>
|
|
85
|
+
)}
|
|
86
|
+
{count && <AuthorBlogPostCount count={count} />}
|
|
87
|
+
</div>
|
|
88
|
+
{!!title && <AuthorTitle title={title} />}
|
|
89
|
+
|
|
90
|
+
{/*
|
|
91
|
+
We always render AuthorSocials even if there's none
|
|
92
|
+
This keeps other things aligned with flexbox layout
|
|
93
|
+
*/}
|
|
94
|
+
<AuthorSocials author={author} />
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
.authorImage {
|
|
9
|
+
--ifm-avatar-photo-size: 3.6rem;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.author-as-h1 .authorImage {
|
|
13
|
+
--ifm-avatar-photo-size: 7rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.author-as-h2 .authorImage {
|
|
17
|
+
--ifm-avatar-photo-size: 5.4rem;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.authorDetails {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
align-items: flex-start;
|
|
24
|
+
justify-content: space-around;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.authorName {
|
|
28
|
+
font-size: 1.1rem;
|
|
29
|
+
line-height: 1.1rem;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: row;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.author-as-h1 .authorName {
|
|
35
|
+
font-size: 2.4rem;
|
|
36
|
+
line-height: 2.4rem;
|
|
37
|
+
display: inline;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.author-as-h2 .authorName {
|
|
41
|
+
font-size: 1.4rem;
|
|
42
|
+
line-height: 1.4rem;
|
|
43
|
+
display: inline;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.authorTitle {
|
|
47
|
+
font-size: 0.8rem;
|
|
48
|
+
line-height: 0.8rem;
|
|
49
|
+
display: -webkit-box;
|
|
50
|
+
overflow: hidden;
|
|
51
|
+
line-clamp: 1;
|
|
52
|
+
-webkit-line-clamp: 1;
|
|
53
|
+
-webkit-box-orient: vertical;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.author-as-h1 .authorTitle {
|
|
57
|
+
font-size: 1.2rem;
|
|
58
|
+
line-height: 1.2rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.author-as-h2 .authorTitle {
|
|
62
|
+
font-size: 1rem;
|
|
63
|
+
line-height: 1rem;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.authorBlogPostCount {
|
|
67
|
+
background: var(--ifm-color-secondary);
|
|
68
|
+
color: var(--ifm-color-black);
|
|
69
|
+
font-size: 0.8rem;
|
|
70
|
+
line-height: 1.2;
|
|
71
|
+
border-radius: var(--ifm-global-radius);
|
|
72
|
+
padding: 0.1rem 0.4rem;
|
|
73
|
+
margin-left: 0.3rem;
|
|
74
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
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, {type ReactNode} from 'react';
|
|
8
|
+
import clsx from 'clsx';
|
|
9
|
+
import {
|
|
10
|
+
PageMetadata,
|
|
11
|
+
HtmlClassNameProvider,
|
|
12
|
+
ThemeClassNames,
|
|
13
|
+
} from '@docusaurus/theme-common';
|
|
14
|
+
import {translateBlogAuthorsListPageTitle} from '@docusaurus/theme-common/internal';
|
|
15
|
+
import BlogLayout from '@theme/BlogLayout';
|
|
16
|
+
import type {Props} from '@theme/Blog/Pages/BlogAuthorsListPage';
|
|
17
|
+
import SearchMetadata from '@theme/SearchMetadata';
|
|
18
|
+
import Heading from '@theme/Heading';
|
|
19
|
+
import Author from '@theme/Blog/Components/Author';
|
|
20
|
+
import type {AuthorItemProp} from '@docusaurus/plugin-content-blog';
|
|
21
|
+
import styles from './styles.module.css';
|
|
22
|
+
|
|
23
|
+
function AuthorListItem({author}: {author: AuthorItemProp}) {
|
|
24
|
+
return (
|
|
25
|
+
<li className={styles.authorListItem}>
|
|
26
|
+
<Author as="h2" author={author} count={author.count} />
|
|
27
|
+
</li>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function AuthorsList({authors}: {authors: Props['authors']}) {
|
|
32
|
+
return (
|
|
33
|
+
<section className={clsx('margin-vert--lg', styles.authorsListSection)}>
|
|
34
|
+
<ul>
|
|
35
|
+
{authors.map((author) => (
|
|
36
|
+
<AuthorListItem key={author.key} author={author} />
|
|
37
|
+
))}
|
|
38
|
+
</ul>
|
|
39
|
+
</section>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default function BlogAuthorsListPage({
|
|
44
|
+
authors,
|
|
45
|
+
sidebar,
|
|
46
|
+
}: Props): ReactNode {
|
|
47
|
+
const title: string = translateBlogAuthorsListPageTitle();
|
|
48
|
+
return (
|
|
49
|
+
<HtmlClassNameProvider
|
|
50
|
+
className={clsx(
|
|
51
|
+
ThemeClassNames.wrapper.blogPages,
|
|
52
|
+
ThemeClassNames.page.blogAuthorsListPage,
|
|
53
|
+
)}>
|
|
54
|
+
<PageMetadata title={title} />
|
|
55
|
+
<SearchMetadata tag="blog_authors_list" />
|
|
56
|
+
<BlogLayout sidebar={sidebar}>
|
|
57
|
+
<Heading as="h1">{title}</Heading>
|
|
58
|
+
<AuthorsList authors={authors} />
|
|
59
|
+
</BlogLayout>
|
|
60
|
+
</HtmlClassNameProvider>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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
|
+
.authorListItem {
|
|
9
|
+
list-style-type: none;
|
|
10
|
+
margin-bottom: 2rem;
|
|
11
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
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 {
|
|
11
|
+
PageMetadata,
|
|
12
|
+
HtmlClassNameProvider,
|
|
13
|
+
ThemeClassNames,
|
|
14
|
+
} from '@docusaurus/theme-common';
|
|
15
|
+
import {
|
|
16
|
+
useBlogAuthorPageTitle,
|
|
17
|
+
BlogAuthorsListViewAllLabel,
|
|
18
|
+
} from '@docusaurus/theme-common/internal';
|
|
19
|
+
import Link from '@docusaurus/Link';
|
|
20
|
+
import {useBlogMetadata} from '@docusaurus/plugin-content-blog/client';
|
|
21
|
+
import BlogLayout from '@theme/BlogLayout';
|
|
22
|
+
import BlogListPaginator from '@theme/BlogListPaginator';
|
|
23
|
+
import SearchMetadata from '@theme/SearchMetadata';
|
|
24
|
+
import type {Props} from '@theme/Blog/Pages/BlogAuthorsPostsPage';
|
|
25
|
+
import BlogPostItems from '@theme/BlogPostItems';
|
|
26
|
+
import Author from '@theme/Blog/Components/Author';
|
|
27
|
+
|
|
28
|
+
function Metadata({author}: Props): JSX.Element {
|
|
29
|
+
const title = useBlogAuthorPageTitle(author);
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<PageMetadata title={title} />
|
|
33
|
+
<SearchMetadata tag="blog_authors_posts" />
|
|
34
|
+
</>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function ViewAllAuthorsLink() {
|
|
39
|
+
const {authorsListPath} = useBlogMetadata();
|
|
40
|
+
return (
|
|
41
|
+
<Link href={authorsListPath}>
|
|
42
|
+
<BlogAuthorsListViewAllLabel />
|
|
43
|
+
</Link>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function Content({author, items, sidebar, listMetadata}: Props): JSX.Element {
|
|
48
|
+
return (
|
|
49
|
+
<BlogLayout sidebar={sidebar}>
|
|
50
|
+
<header className="margin-bottom--xl">
|
|
51
|
+
<Author as="h1" author={author} />
|
|
52
|
+
{author.description && <p>{author.description}</p>}
|
|
53
|
+
<ViewAllAuthorsLink />
|
|
54
|
+
</header>
|
|
55
|
+
<hr />
|
|
56
|
+
<BlogPostItems items={items} />
|
|
57
|
+
<BlogListPaginator metadata={listMetadata} />
|
|
58
|
+
</BlogLayout>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default function BlogAuthorsPostsPage(props: Props): JSX.Element {
|
|
63
|
+
return (
|
|
64
|
+
<HtmlClassNameProvider
|
|
65
|
+
className={clsx(
|
|
66
|
+
ThemeClassNames.wrapper.blogPages,
|
|
67
|
+
ThemeClassNames.page.blogAuthorsPostsPage,
|
|
68
|
+
)}>
|
|
69
|
+
<Metadata {...props} />
|
|
70
|
+
<Content {...props} />
|
|
71
|
+
</HtmlClassNameProvider>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
10
|
import {useBlogPost} from '@docusaurus/plugin-content-blog/client';
|
|
11
|
-
import
|
|
11
|
+
import BlogAuthor from '@theme/Blog/Components/Author';
|
|
12
12
|
import type {Props} from '@theme/BlogPostItem/Header/Authors';
|
|
13
13
|
import styles from './styles.module.css';
|
|
14
14
|
|
|
@@ -40,8 +40,7 @@ export default function BlogPostItemHeaderAuthors({
|
|
|
40
40
|
imageOnly ? styles.imageOnlyAuthorCol : styles.authorCol,
|
|
41
41
|
)}
|
|
42
42
|
key={idx}>
|
|
43
|
-
<
|
|
44
|
-
singleAuthor={singleAuthor}
|
|
43
|
+
<BlogAuthor
|
|
45
44
|
author={{
|
|
46
45
|
...author,
|
|
47
46
|
// Handle author images using relative paths
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import clsx from 'clsx';
|
|
10
|
-
import Translate
|
|
10
|
+
import Translate from '@docusaurus/Translate';
|
|
11
11
|
import {
|
|
12
12
|
PageMetadata,
|
|
13
13
|
HtmlClassNameProvider,
|
|
14
14
|
ThemeClassNames,
|
|
15
|
-
usePluralForm,
|
|
16
15
|
} from '@docusaurus/theme-common';
|
|
16
|
+
import {useBlogTagsPostsPageTitle} from '@docusaurus/theme-common/internal';
|
|
17
17
|
import Link from '@docusaurus/Link';
|
|
18
18
|
import BlogLayout from '@theme/BlogLayout';
|
|
19
19
|
import BlogListPaginator from '@theme/BlogListPaginator';
|
|
@@ -23,36 +23,6 @@ import BlogPostItems from '@theme/BlogPostItems';
|
|
|
23
23
|
import Unlisted from '@theme/Unlisted';
|
|
24
24
|
import Heading from '@theme/Heading';
|
|
25
25
|
|
|
26
|
-
// Very simple pluralization: probably good enough for now
|
|
27
|
-
function useBlogPostsPlural() {
|
|
28
|
-
const {selectMessage} = usePluralForm();
|
|
29
|
-
return (count: number) =>
|
|
30
|
-
selectMessage(
|
|
31
|
-
count,
|
|
32
|
-
translate(
|
|
33
|
-
{
|
|
34
|
-
id: 'theme.blog.post.plurals',
|
|
35
|
-
description:
|
|
36
|
-
'Pluralized label for "{count} posts". 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)',
|
|
37
|
-
message: 'One post|{count} posts',
|
|
38
|
-
},
|
|
39
|
-
{count},
|
|
40
|
-
),
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function useBlogTagsPostsPageTitle(tag: Props['tag']): string {
|
|
45
|
-
const blogPostsPlural = useBlogPostsPlural();
|
|
46
|
-
return translate(
|
|
47
|
-
{
|
|
48
|
-
id: 'theme.blog.tagTitle',
|
|
49
|
-
description: 'The title of the page for a blog tag',
|
|
50
|
-
message: '{nPosts} tagged with "{tagName}"',
|
|
51
|
-
},
|
|
52
|
-
{nPosts: blogPostsPlural(tag.count), tagName: tag.label},
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
26
|
function BlogTagsPostsPageMetadata({tag}: Props): JSX.Element {
|
|
57
27
|
const title = useBlogTagsPostsPageTitle(tag);
|
|
58
28
|
return (
|
package/src/theme-classic.d.ts
CHANGED
|
@@ -185,6 +185,30 @@ declare module '@theme/BackToTopButton' {
|
|
|
185
185
|
export default function BackToTopButton(): JSX.Element;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
declare module '@theme/Blog/Components/Author' {
|
|
189
|
+
import type {Author} from '@docusaurus/plugin-content-blog';
|
|
190
|
+
|
|
191
|
+
export interface Props {
|
|
192
|
+
readonly as?: 'h1' | 'h2';
|
|
193
|
+
readonly author: Author;
|
|
194
|
+
readonly className?: string;
|
|
195
|
+
readonly count?: number;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export default function BlogAuthor(props: Props): JSX.Element;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
declare module '@theme/Blog/Components/Author/Socials' {
|
|
202
|
+
import type {Author} from '@docusaurus/plugin-content-blog';
|
|
203
|
+
|
|
204
|
+
export interface Props {
|
|
205
|
+
readonly author: Author;
|
|
206
|
+
readonly className?: string;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export default function BlogAuthorSocials(props: Props): JSX.Element;
|
|
210
|
+
}
|
|
211
|
+
|
|
188
212
|
declare module '@theme/BlogListPaginator' {
|
|
189
213
|
import type {BlogPaginatedMetadata} from '@docusaurus/plugin-content-blog';
|
|
190
214
|
|
|
@@ -291,31 +315,6 @@ declare module '@theme/BlogPostItem/Header/Info' {
|
|
|
291
315
|
export default function BlogPostItemHeaderInfo(): JSX.Element;
|
|
292
316
|
}
|
|
293
317
|
|
|
294
|
-
declare module '@theme/BlogPostItem/Header/Author' {
|
|
295
|
-
import type {Author} from '@docusaurus/plugin-content-blog';
|
|
296
|
-
|
|
297
|
-
export interface Props {
|
|
298
|
-
readonly author: Author;
|
|
299
|
-
readonly singleAuthor: boolean;
|
|
300
|
-
readonly className?: string;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
export default function BlogPostItemHeaderAuthor(props: Props): JSX.Element;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
declare module '@theme/BlogPostItem/Header/Author/Socials' {
|
|
307
|
-
import type {Author} from '@docusaurus/plugin-content-blog';
|
|
308
|
-
|
|
309
|
-
export interface Props {
|
|
310
|
-
readonly author: Author;
|
|
311
|
-
readonly className?: string;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
export default function BlogPostItemHeaderAuthorSocials(
|
|
315
|
-
props: Props,
|
|
316
|
-
): JSX.Element;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
318
|
declare module '@theme/BlogPostItem/Header/Authors' {
|
|
320
319
|
export interface Props {
|
|
321
320
|
readonly className?: string;
|
|
@@ -1,54 +0,0 @@
|
|
|
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 from 'react';
|
|
8
|
-
import clsx from 'clsx';
|
|
9
|
-
import Link from '@docusaurus/Link';
|
|
10
|
-
import AuthorSocials from '@theme/BlogPostItem/Header/Author/Socials';
|
|
11
|
-
import styles from './styles.module.css';
|
|
12
|
-
function MaybeLink(props) {
|
|
13
|
-
if (props.href) {
|
|
14
|
-
return <Link {...props} />;
|
|
15
|
-
}
|
|
16
|
-
return <>{props.children}</>;
|
|
17
|
-
}
|
|
18
|
-
function AuthorTitle({title}) {
|
|
19
|
-
return (
|
|
20
|
-
<small className={styles.authorTitle} title={title}>
|
|
21
|
-
{title}
|
|
22
|
-
</small>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
export default function BlogPostItemHeaderAuthor({
|
|
26
|
-
// singleAuthor, // may be useful in the future, or for swizzle users
|
|
27
|
-
author,
|
|
28
|
-
className,
|
|
29
|
-
}) {
|
|
30
|
-
const {name, title, url, socials, imageURL, email} = author;
|
|
31
|
-
const link = url || (email && `mailto:${email}`) || undefined;
|
|
32
|
-
const hasSocials = socials && Object.keys(socials).length > 0;
|
|
33
|
-
return (
|
|
34
|
-
<div className={clsx('avatar margin-bottom--sm', className)}>
|
|
35
|
-
{imageURL && (
|
|
36
|
-
<MaybeLink href={link} className="avatar__photo-link">
|
|
37
|
-
<img className="avatar__photo" src={imageURL} alt={name} />
|
|
38
|
-
</MaybeLink>
|
|
39
|
-
)}
|
|
40
|
-
|
|
41
|
-
{(name || title) && (
|
|
42
|
-
<div className="avatar__intro">
|
|
43
|
-
<div className="avatar__name">
|
|
44
|
-
<MaybeLink href={link}>
|
|
45
|
-
<span className={styles.authorName}>{name}</span>
|
|
46
|
-
</MaybeLink>
|
|
47
|
-
</div>
|
|
48
|
-
{!!title && <AuthorTitle title={title} />}
|
|
49
|
-
{hasSocials && <AuthorSocials author={author} />}
|
|
50
|
-
</div>
|
|
51
|
-
)}
|
|
52
|
-
</div>
|
|
53
|
-
);
|
|
54
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
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
|
-
.authorName {
|
|
9
|
-
font-size: 1.1rem;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.authorTitle {
|
|
13
|
-
margin-top: 0.06rem;
|
|
14
|
-
font-size: 0.8rem;
|
|
15
|
-
line-height: 0.8rem;
|
|
16
|
-
display: -webkit-box;
|
|
17
|
-
overflow: hidden;
|
|
18
|
-
line-clamp: 1;
|
|
19
|
-
-webkit-line-clamp: 1;
|
|
20
|
-
-webkit-box-orient: vertical;
|
|
21
|
-
}
|
|
@@ -1,62 +0,0 @@
|
|
|
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, {type Props as LinkProps} from '@docusaurus/Link';
|
|
11
|
-
import AuthorSocials from '@theme/BlogPostItem/Header/Author/Socials';
|
|
12
|
-
|
|
13
|
-
import type {Props} from '@theme/BlogPostItem/Header/Author';
|
|
14
|
-
import styles from './styles.module.css';
|
|
15
|
-
|
|
16
|
-
function MaybeLink(props: LinkProps): JSX.Element {
|
|
17
|
-
if (props.href) {
|
|
18
|
-
return <Link {...props} />;
|
|
19
|
-
}
|
|
20
|
-
return <>{props.children}</>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function AuthorTitle({title}: {title: string}) {
|
|
24
|
-
return (
|
|
25
|
-
<small className={styles.authorTitle} title={title}>
|
|
26
|
-
{title}
|
|
27
|
-
</small>
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export default function BlogPostItemHeaderAuthor({
|
|
32
|
-
// singleAuthor, // may be useful in the future, or for swizzle users
|
|
33
|
-
author,
|
|
34
|
-
className,
|
|
35
|
-
}: Props): JSX.Element {
|
|
36
|
-
const {name, title, url, socials, imageURL, email} = author;
|
|
37
|
-
const link = url || (email && `mailto:${email}`) || undefined;
|
|
38
|
-
|
|
39
|
-
const hasSocials = socials && Object.keys(socials).length > 0;
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div className={clsx('avatar margin-bottom--sm', className)}>
|
|
43
|
-
{imageURL && (
|
|
44
|
-
<MaybeLink href={link} className="avatar__photo-link">
|
|
45
|
-
<img className="avatar__photo" src={imageURL} alt={name} />
|
|
46
|
-
</MaybeLink>
|
|
47
|
-
)}
|
|
48
|
-
|
|
49
|
-
{(name || title) && (
|
|
50
|
-
<div className="avatar__intro">
|
|
51
|
-
<div className="avatar__name">
|
|
52
|
-
<MaybeLink href={link}>
|
|
53
|
-
<span className={styles.authorName}>{name}</span>
|
|
54
|
-
</MaybeLink>
|
|
55
|
-
</div>
|
|
56
|
-
{!!title && <AuthorTitle title={title} />}
|
|
57
|
-
{hasSocials && <AuthorSocials author={author} />}
|
|
58
|
-
</div>
|
|
59
|
-
)}
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
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
|
-
.authorName {
|
|
9
|
-
font-size: 1.1rem;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.authorTitle {
|
|
13
|
-
margin-top: 0.06rem;
|
|
14
|
-
font-size: 0.8rem;
|
|
15
|
-
line-height: 0.8rem;
|
|
16
|
-
display: -webkit-box;
|
|
17
|
-
overflow: hidden;
|
|
18
|
-
line-clamp: 1;
|
|
19
|
-
-webkit-line-clamp: 1;
|
|
20
|
-
-webkit-box-orient: vertical;
|
|
21
|
-
}
|