@redocly/theme 0.11.5 → 0.12.0
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/I18n/LanguagePicker.d.ts +4 -0
- package/lib/I18n/LanguagePicker.js +111 -0
- package/lib/I18n/index.d.ts +1 -0
- package/lib/I18n/index.js +6 -0
- package/lib/components/Cards/Card.js +3 -1
- package/lib/components/Catalog/Catalog.js +14 -9
- package/lib/components/Catalog/CatalogCard.js +6 -1
- package/lib/components/Catalog/useCatalog.js +4 -1
- package/lib/components/CodeSample/CodeSample.js +11 -3
- package/lib/components/Feedback/Comment.js +12 -4
- package/lib/components/Feedback/Rating.js +8 -2
- package/lib/components/Feedback/Reasons.js +11 -4
- package/lib/components/Feedback/Sentiment.js +12 -4
- package/lib/components/Feedback/Thumbs.js +31 -18
- package/lib/components/Feedback/useReportDialog.js +8 -2
- package/lib/components/Filter/Filter.js +15 -8
- package/lib/components/Footer/FooterColumn.js +4 -2
- package/lib/components/Footer/FooterCopyright.d.ts +1 -2
- package/lib/components/Footer/FooterCopyright.js +6 -1
- package/lib/components/LastUpdated/LastUpdated.js +8 -4
- package/lib/components/Markdown/MarkdownLayout.js +6 -1
- package/lib/components/Menu/MenuGroup.js +3 -1
- package/lib/components/Menu/MenuItem.js +3 -1
- package/lib/components/Navbar/MobileNavbarItem.js +6 -2
- package/lib/components/Navbar/Navbar.d.ts +1 -0
- package/lib/components/Navbar/Navbar.js +6 -1
- package/lib/components/Navbar/NavbarDropdown.js +3 -1
- package/lib/components/Navbar/NavbarItem.js +9 -4
- package/lib/components/PageNavigation/NextButton.js +7 -2
- package/lib/components/PageNavigation/PreviousButton.js +10 -2
- package/lib/components/Profile/LoginLink.js +6 -1
- package/lib/components/Profile/UserProfileMenu.js +10 -4
- package/lib/components/Search/Autocomplete.d.ts +3 -3
- package/lib/components/Search/Autocomplete.js +21 -11
- package/lib/components/Search/ClearIcon.js +1 -1
- package/lib/components/Search/Search.js +6 -4
- package/lib/components/Separator/Separator.js +3 -1
- package/lib/components/Sidebar/DrilldownMenu.js +6 -1
- package/lib/components/Sidebar/DrilldownMenuItem.js +4 -2
- package/lib/components/Sidebar/types.d.ts +2 -0
- package/lib/components/TableOfContent/TableOfContent.js +6 -1
- package/lib/icons/SpinnerIcon/SpinnerIcon.d.ts +8 -0
- package/lib/icons/SpinnerIcon/SpinnerIcon.js +32 -0
- package/lib/icons/SpinnerIcon/index.d.ts +1 -0
- package/lib/icons/SpinnerIcon/index.js +6 -0
- package/lib/icons/index.d.ts +1 -0
- package/lib/icons/index.js +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/layouts/Forbidden.js +8 -2
- package/lib/layouts/NotFound.js +8 -2
- package/lib/mocks/hooks/index.d.ts +15 -1
- package/lib/mocks/hooks/index.js +19 -1
- package/lib/mocks/search.d.ts +1 -0
- package/lib/mocks/search.js +1 -0
- package/lib/mocks/utils.d.ts +5 -0
- package/lib/mocks/utils.js +9 -1
- package/lib/types/portal/index.d.ts +1 -0
- package/lib/types/portal/index.js +1 -0
- package/lib/types/portal/src/shared/types/catalog.d.ts +4 -0
- package/lib/types/portal/src/shared/types/nav.d.ts +7 -0
- package/package.json +1 -1
- package/src/I18n/LanguagePicker.tsx +113 -0
- package/src/I18n/index.ts +1 -0
- package/src/components/Cards/Card.tsx +5 -1
- package/src/components/Catalog/Catalog.tsx +23 -6
- package/src/components/Catalog/CatalogCard.tsx +8 -1
- package/src/components/Catalog/useCatalog.ts +4 -2
- package/src/components/CodeSample/CodeSample.tsx +22 -4
- package/src/components/Feedback/Comment.tsx +25 -4
- package/src/components/Feedback/Rating.tsx +15 -2
- package/src/components/Feedback/Reasons.tsx +23 -5
- package/src/components/Feedback/Sentiment.tsx +25 -4
- package/src/components/Feedback/Thumbs.tsx +61 -46
- package/src/components/Feedback/useReportDialog.ts +11 -2
- package/src/components/Filter/Filter.tsx +17 -9
- package/src/components/Footer/CustomFooter.tsx +1 -1
- package/src/components/Footer/FooterColumn.tsx +5 -3
- package/src/components/Footer/FooterCopyright.tsx +12 -3
- package/src/components/LastUpdated/LastUpdated.tsx +10 -2
- package/src/components/Markdown/MarkdownLayout.tsx +11 -1
- package/src/components/Menu/MenuGroup.tsx +4 -1
- package/src/components/Menu/MenuItem.tsx +3 -1
- package/src/components/Navbar/MobileNavbarItem.tsx +7 -1
- package/src/components/Navbar/Navbar.tsx +8 -0
- package/src/components/Navbar/NavbarDropdown.tsx +3 -1
- package/src/components/Navbar/NavbarItem.tsx +9 -3
- package/src/components/PageNavigation/NextButton.tsx +8 -2
- package/src/components/PageNavigation/PreviousButton.tsx +11 -2
- package/src/components/Profile/LoginLink.tsx +11 -1
- package/src/components/Profile/UserProfileMenu.tsx +13 -3
- package/src/components/Search/Autocomplete.tsx +31 -17
- package/src/components/Search/ClearIcon.tsx +1 -1
- package/src/components/Search/Search.tsx +8 -7
- package/src/components/Separator/Separator.tsx +4 -1
- package/src/components/Sidebar/DrilldownMenu.tsx +8 -1
- package/src/components/Sidebar/DrilldownMenuItem.tsx +7 -2
- package/src/components/Sidebar/types.ts +2 -0
- package/src/components/TableOfContent/TableOfContent.tsx +11 -1
- package/src/icons/SpinnerIcon/SpinnerIcon.tsx +42 -0
- package/src/icons/SpinnerIcon/index.ts +1 -0
- package/src/icons/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/layouts/Forbidden.tsx +18 -3
- package/src/layouts/NotFound.tsx +17 -3
- package/src/mocks/hooks/index.ts +20 -1
- package/src/mocks/search.ts +2 -0
- package/src/mocks/utils.ts +13 -0
- package/src/types/portal/index.ts +1 -0
- package/src/types/portal/src/shared/types/catalog.ts +4 -0
- package/src/types/portal/src/shared/types/i18n.d.ts +3 -0
- package/src/types/portal/src/shared/types/nav.ts +7 -0
|
@@ -3,10 +3,17 @@ import styled from 'styled-components';
|
|
|
3
3
|
|
|
4
4
|
import { Button } from '@theme/components/Button/Button';
|
|
5
5
|
import type { ReasonsProps } from '@theme/components/Feedback';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
export const Reasons = ({ settings, onSubmit }: ReasonsProps): JSX.Element => {
|
|
8
9
|
const { label, multi, buttonText, items = [] } = settings;
|
|
9
10
|
const [checkedState, setCheckedState] = React.useState(new Array(items.length).fill(false));
|
|
11
|
+
const { translate } = useTranslate();
|
|
12
|
+
const translationKeys = {
|
|
13
|
+
label: 'theme.feedback.settings.reasons.label',
|
|
14
|
+
items: 'theme.feedback.settings.reasons.items',
|
|
15
|
+
send: 'theme.feedback.settings.reasons.send',
|
|
16
|
+
};
|
|
10
17
|
|
|
11
18
|
if (!items.length) {
|
|
12
19
|
return <></>;
|
|
@@ -27,8 +34,13 @@ export const Reasons = ({ settings, onSubmit }: ReasonsProps): JSX.Element => {
|
|
|
27
34
|
};
|
|
28
35
|
|
|
29
36
|
return (
|
|
30
|
-
<Wrapper data-component-name="Feedback/Reasons">
|
|
31
|
-
<Label>
|
|
37
|
+
<Wrapper data-component-name="Feedback/Reasons" data-translation-key={translationKeys.label}>
|
|
38
|
+
<Label>
|
|
39
|
+
{translate(
|
|
40
|
+
translationKeys.label,
|
|
41
|
+
label || 'Which statement describes your thoughts about this page?',
|
|
42
|
+
)}
|
|
43
|
+
</Label>
|
|
32
44
|
{items.map((reason, idx) => (
|
|
33
45
|
<OptionWrapper key={reason}>
|
|
34
46
|
<input
|
|
@@ -38,12 +50,18 @@ export const Reasons = ({ settings, onSubmit }: ReasonsProps): JSX.Element => {
|
|
|
38
50
|
name="reasons"
|
|
39
51
|
onChange={() => handleOptionChange(idx)}
|
|
40
52
|
/>
|
|
41
|
-
<label
|
|
42
|
-
{
|
|
53
|
+
<label
|
|
54
|
+
data-translation-key={`${translationKeys.items}.${idx + 1}`}
|
|
55
|
+
id={reason}
|
|
56
|
+
onClick={() => handleOptionChange(idx)}
|
|
57
|
+
>
|
|
58
|
+
{translate(`${translationKeys.items}.${idx + 1}`, reason)}
|
|
43
59
|
</label>
|
|
44
60
|
</OptionWrapper>
|
|
45
61
|
))}
|
|
46
|
-
<SendButton onClick={submitForm}>
|
|
62
|
+
<SendButton data-translation-key={translationKeys.send} onClick={submitForm}>
|
|
63
|
+
{translate(translationKeys.send, buttonText || 'Send')}
|
|
64
|
+
</SendButton>
|
|
47
65
|
</Wrapper>
|
|
48
66
|
);
|
|
49
67
|
};
|
|
@@ -4,12 +4,20 @@ import styled from 'styled-components';
|
|
|
4
4
|
import type { SentimentProps, ReasonsProps } from '@theme/components/Feedback';
|
|
5
5
|
import { Comment, Reasons } from '@theme/components/Feedback';
|
|
6
6
|
import { ThumbUp, ThumbDown } from '@theme/components/Feedback/Thumbs';
|
|
7
|
+
import { useTranslate } from '@portal/hooks';
|
|
7
8
|
|
|
8
9
|
export const Sentiment = ({ settings, onSubmit }: SentimentProps): JSX.Element => {
|
|
9
10
|
const { label, submitText, comment: commentSettings, reasons: reasonsSettings } = settings || {};
|
|
10
11
|
const [score, setScore] = React.useState(0);
|
|
11
12
|
const [comment, setComment] = React.useState('');
|
|
12
13
|
const [reasons, setReasons] = React.useState([] as ReasonsProps['settings']['items']);
|
|
14
|
+
const { translate } = useTranslate();
|
|
15
|
+
const translationKeys = {
|
|
16
|
+
submitText: 'theme.feedback.settings.submitText',
|
|
17
|
+
label: 'theme.feedback.settings.label',
|
|
18
|
+
likeLabel: 'theme.feedback.settings.comment.likeLabel',
|
|
19
|
+
dislikeLabel: 'theme.feedback.settings.comment.dislikeLabel',
|
|
20
|
+
};
|
|
13
21
|
|
|
14
22
|
if (score && reasonsSettings?.enable && !reasons.length) {
|
|
15
23
|
const { label: reasonsLabel, items, multi } = reasonsSettings;
|
|
@@ -25,8 +33,14 @@ export const Sentiment = ({ settings, onSubmit }: SentimentProps): JSX.Element =
|
|
|
25
33
|
if (score && commentSettings?.enable && !comment) {
|
|
26
34
|
const commentLabel =
|
|
27
35
|
score === 1
|
|
28
|
-
?
|
|
29
|
-
|
|
36
|
+
? translate(
|
|
37
|
+
translationKeys.likeLabel,
|
|
38
|
+
commentSettings.likeLabel || 'What was most helpful?',
|
|
39
|
+
)
|
|
40
|
+
: translate(
|
|
41
|
+
translationKeys.dislikeLabel,
|
|
42
|
+
commentSettings.dislikeLabel || 'What can we improve?',
|
|
43
|
+
);
|
|
30
44
|
return (
|
|
31
45
|
<Comment onSubmit={({ comment }) => setComment(comment)} settings={{ label: commentLabel }} />
|
|
32
46
|
);
|
|
@@ -40,14 +54,21 @@ export const Sentiment = ({ settings, onSubmit }: SentimentProps): JSX.Element =
|
|
|
40
54
|
});
|
|
41
55
|
return (
|
|
42
56
|
<Wrapper>
|
|
43
|
-
<Label
|
|
57
|
+
<Label data-translation-key={translationKeys.submitText}>
|
|
58
|
+
{translate(
|
|
59
|
+
translationKeys.submitText,
|
|
60
|
+
submitText || 'Thank you for helping improve our documentation!',
|
|
61
|
+
)}
|
|
62
|
+
</Label>
|
|
44
63
|
</Wrapper>
|
|
45
64
|
);
|
|
46
65
|
}
|
|
47
66
|
|
|
48
67
|
return (
|
|
49
68
|
<Wrapper data-component-name="Feedback/Sentiment">
|
|
50
|
-
<Label
|
|
69
|
+
<Label data-translation-key={translationKeys.label}>
|
|
70
|
+
{translate(translationKeys.label, label || 'Was this page helpful?')}
|
|
71
|
+
</Label>
|
|
51
72
|
<Vote onClick={() => setScore(1)}>
|
|
52
73
|
<ThumbUp text="Yes" />
|
|
53
74
|
</Vote>
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
import { useTranslate } from '@portal/hooks';
|
|
5
|
+
|
|
6
|
+
export const ThumbUp = ({ text }: { text?: string }) => {
|
|
7
|
+
const { translate } = useTranslate();
|
|
8
|
+
const translationKeys = {
|
|
9
|
+
thumbUp: 'theme.feedback.sentiment.thumbUp',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<Wrapper style={{ alignItems: 'normal' }}>
|
|
14
|
+
<Icon>
|
|
15
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 512 512">
|
|
9
16
|
<g>
|
|
10
17
|
<g>
|
|
11
|
-
<
|
|
12
|
-
|
|
18
|
+
<g>
|
|
19
|
+
<path
|
|
20
|
+
d="M495.736,290.773C509.397,282.317,512,269.397,512,260.796c0-22.4-18.253-47.462-42.667-47.462H349.918
|
|
13
21
|
c-4.284-0.051-25.651-1.51-25.651-25.6c0-4.71-3.814-8.533-8.533-8.533s-8.533,3.823-8.533,8.533
|
|
14
22
|
c0,33.749,27.913,42.667,42.667,42.667h119.467c14.182,0,25.6,16.631,25.6,30.396c0,4.437,0,17.946-26.53,20.855
|
|
15
23
|
c-4.506,0.495-7.834,4.42-7.586,8.951c0.239,4.523,3.985,8.064,8.516,8.064c14.114,0,25.6,11.486,25.6,25.6
|
|
@@ -20,45 +28,51 @@ export const ThumbUp = ({ text }: { text?: string }) => (
|
|
|
20
28
|
c15.497,8.542,31.505,17.374,71.526,17.374h128c17.869,0,34.133-16.273,34.133-34.133c0-6.229-1.775-12.134-4.83-17.229
|
|
21
29
|
c21.794-1.877,38.963-20.224,38.963-42.505c0-10.829-4.062-20.736-10.735-28.271C500.42,358.212,512,342.571,512,324.267
|
|
22
30
|
C512,310.699,505.634,298.59,495.736,290.773z"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
/>
|
|
32
|
+
<path
|
|
33
|
+
d="M76.8,443.733c9.412,0,17.067-7.654,17.067-17.067S86.212,409.6,76.8,409.6c-9.412,0-17.067,7.654-17.067,17.067
|
|
26
34
|
S67.388,443.733,76.8,443.733z"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
/>
|
|
36
|
+
<path
|
|
37
|
+
d="M179.2,247.467c25.353,0,57.429-28.297,74.3-45.167c36.634-36.634,36.634-82.167,36.634-151.1
|
|
30
38
|
c0-5.342,3.191-8.533,8.533-8.533c29.508,0,42.667,13.158,42.667,42.667v102.4c0,4.71,3.814,8.533,8.533,8.533
|
|
31
39
|
s8.533-3.823,8.533-8.533v-102.4c0-39.083-20.659-59.733-59.733-59.733c-14.831,0-25.6,10.769-25.6,25.6
|
|
32
40
|
c0,66.978,0,107.401-31.633,139.034C216.661,215.006,192.811,230.4,179.2,230.4c-4.719,0-8.533,3.823-8.533,8.533
|
|
33
41
|
S174.481,247.467,179.2,247.467z"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
/>
|
|
43
|
+
<path
|
|
44
|
+
d="M145.067,213.333H8.533c-4.719,0-8.533,3.823-8.533,8.533v256c0,4.71,3.814,8.533,8.533,8.533h136.533
|
|
37
45
|
c4.719,0,8.533-3.823,8.533-8.533v-256C153.6,217.156,149.786,213.333,145.067,213.333z M136.533,469.333H17.067V230.4h119.467
|
|
38
46
|
V469.333z"
|
|
39
|
-
|
|
47
|
+
/>
|
|
48
|
+
</g>
|
|
40
49
|
</g>
|
|
41
50
|
</g>
|
|
42
|
-
</
|
|
43
|
-
</
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
</svg>
|
|
52
|
+
</Icon>
|
|
53
|
+
<span>{translate(translationKeys.thumbUp, text || 'Yes')}</span>
|
|
54
|
+
</Wrapper>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
48
57
|
|
|
49
|
-
export const ThumbDown = ({ text }: { text?: string }) =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
export const ThumbDown = ({ text }: { text?: string }) => {
|
|
59
|
+
const { translate } = useTranslate();
|
|
60
|
+
const translationKeys = {
|
|
61
|
+
thumbDown: 'theme.feedback.sentiment.thumbDown',
|
|
62
|
+
};
|
|
63
|
+
return (
|
|
64
|
+
<Wrapper style={{ alignItems: 'end' }}>
|
|
65
|
+
<Icon>
|
|
66
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 512 512">
|
|
54
67
|
<g>
|
|
55
68
|
<g>
|
|
56
|
-
<
|
|
57
|
-
|
|
69
|
+
<g>
|
|
70
|
+
<path
|
|
71
|
+
d="M76.8,247.467c9.412,0,17.067-7.654,17.067-17.067c0-9.412-7.654-17.067-17.067-17.067
|
|
58
72
|
c-9.412,0-17.067,7.654-17.067,17.067C59.733,239.812,67.388,247.467,76.8,247.467z"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
73
|
+
/>
|
|
74
|
+
<path
|
|
75
|
+
d="M495.736,221.227C505.634,213.41,512,201.301,512,187.733c0-18.295-11.58-33.946-27.802-39.996
|
|
62
76
|
c6.673-7.535,10.735-17.434,10.735-28.271c0-22.281-17.169-40.627-38.963-42.505c3.055-5.094,4.83-10.999,4.83-17.229
|
|
63
77
|
c0-17.86-16.265-34.133-34.133-34.133h-128c-40.021,0-56.03,8.832-71.526,17.374c-11.827,6.519-24.047,13.261-49.152,16.845
|
|
64
78
|
c-4.668,0.666-7.902,4.992-7.236,9.66c0.666,4.659,4.949,7.885,9.66,7.236c28.177-4.028,42.411-11.87,54.963-18.79
|
|
@@ -69,26 +83,27 @@ export const ThumbDown = ({ text }: { text?: string }) => (
|
|
|
69
83
|
c26.53,2.91,26.53,16.418,26.53,20.847c0,13.773-11.418,30.404-25.6,30.404H349.867c-14.763,0-42.667,8.917-42.667,42.667
|
|
70
84
|
c0,4.71,3.814,8.533,8.533,8.533s8.533-3.823,8.533-8.533c0-24.09,21.367-25.549,25.6-25.6h119.467
|
|
71
85
|
c24.414,0,42.667-25.054,42.667-47.471C512,242.603,509.397,229.683,495.736,221.227z"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
/>
|
|
87
|
+
<path
|
|
88
|
+
d="M349.867,315.733c-4.719,0-8.533,3.823-8.533,8.533v102.4c0,29.508-13.158,42.667-42.667,42.667
|
|
75
89
|
c-5.342,0-8.533-3.192-8.533-8.533c0-68.932,0-114.466-36.634-151.1c-16.87-16.87-48.947-45.167-74.3-45.167
|
|
76
90
|
c-4.719,0-8.533,3.823-8.533,8.533s3.814,8.533,8.533,8.533c13.611,0,37.461,15.394,62.234,40.166
|
|
77
91
|
c31.633,31.633,31.633,72.055,31.633,139.034c0,14.831,10.769,25.6,25.6,25.6c39.074,0,59.733-20.651,59.733-59.733v-102.4
|
|
78
92
|
C358.4,319.556,354.586,315.733,349.867,315.733z"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
93
|
+
/>
|
|
94
|
+
<path
|
|
95
|
+
d="M145.067,25.6H8.533C3.814,25.6,0,29.423,0,34.133v256c0,4.71,3.814,8.533,8.533,8.533h136.533
|
|
82
96
|
c4.719,0,8.533-3.823,8.533-8.533v-256C153.6,29.423,149.786,25.6,145.067,25.6z M136.533,281.6H17.067V42.667h119.467V281.6z"
|
|
83
|
-
|
|
97
|
+
/>
|
|
98
|
+
</g>
|
|
84
99
|
</g>
|
|
85
100
|
</g>
|
|
86
|
-
</
|
|
87
|
-
</
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
101
|
+
</svg>
|
|
102
|
+
</Icon>
|
|
103
|
+
<span>{translate(translationKeys.thumbDown, text || 'No')}</span>
|
|
104
|
+
</Wrapper>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
92
107
|
|
|
93
108
|
const Wrapper = styled.div`
|
|
94
109
|
font-family: var(--font-family-base);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import type { ReportDialogProps } from '@theme/components/Feedback/types';
|
|
4
|
+
import { useTranslate } from '@portal/hooks';
|
|
4
5
|
|
|
5
6
|
type ReportSettings = {
|
|
6
7
|
hide?: boolean;
|
|
@@ -11,6 +12,11 @@ type ReportSettings = {
|
|
|
11
12
|
export function useReportDialog(reportSettings: ReportSettings): Record<string, any> {
|
|
12
13
|
const [isReportDialogShown, setIsReportDialogShown] = useState(false);
|
|
13
14
|
const isReportButtonShown = reportSettings.hide === false; // TODO: report temporary disabled by default
|
|
15
|
+
const { translate } = useTranslate();
|
|
16
|
+
const translationKeys = {
|
|
17
|
+
tooltipText: 'theme.codeSnippet.report.tooltipText',
|
|
18
|
+
label: 'theme.codeSnippet.report.label',
|
|
19
|
+
};
|
|
14
20
|
|
|
15
21
|
const showReportDialog = () => {
|
|
16
22
|
setIsReportDialogShown(true);
|
|
@@ -20,11 +26,14 @@ export function useReportDialog(reportSettings: ReportSettings): Record<string,
|
|
|
20
26
|
};
|
|
21
27
|
const reportButtonProps = {
|
|
22
28
|
onClick: showReportDialog,
|
|
23
|
-
title: reportSettings.tooltipText || 'Report a problem',
|
|
29
|
+
title: translate(translationKeys.tooltipText, reportSettings.tooltipText || 'Report a problem'),
|
|
24
30
|
};
|
|
25
31
|
const reportDialogProps: Partial<ReportDialogProps> = {
|
|
26
32
|
settings: {
|
|
27
|
-
label:
|
|
33
|
+
label: translate(
|
|
34
|
+
translationKeys.label,
|
|
35
|
+
reportSettings.label || 'What is wrong with this code?',
|
|
36
|
+
),
|
|
28
37
|
},
|
|
29
38
|
onSubmit: hideReportDialog,
|
|
30
39
|
onCancel: hideReportDialog,
|
|
@@ -3,25 +3,33 @@ import styled from 'styled-components';
|
|
|
3
3
|
|
|
4
4
|
import type { ResolvedFilter } from '@theme/types/portal/src/shared/types/catalog';
|
|
5
5
|
import { Checkbox } from '@theme/ui/Checkbox';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
export function Filter({ filter }: { filter: ResolvedFilter }) {
|
|
9
|
+
const { translate } = useTranslate();
|
|
10
|
+
const translationKeys = {
|
|
11
|
+
selectAll: 'theme.catalog.filters.select.all',
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
if (!filter.parentUsed) return null;
|
|
9
15
|
return (
|
|
10
16
|
<FilterGroup key={filter.property + filter.title}>
|
|
11
|
-
<FilterTitle>{filter.title}</FilterTitle>
|
|
17
|
+
<FilterTitle>{translate(filter.titleTranslationKey, filter.title)}</FilterTitle>
|
|
12
18
|
{filter.type === 'select' ? (
|
|
13
19
|
<StyledSelect
|
|
14
20
|
onChange={(e) => filter.selectOption(e.target.value)}
|
|
15
21
|
value={filter.selectedOptions.values().next()?.value || ''}
|
|
16
22
|
>
|
|
17
|
-
<option key="none" value="">
|
|
18
|
-
All
|
|
23
|
+
<option key="none" value="" data-translation-key={translationKeys.selectAll}>
|
|
24
|
+
{translate(translationKeys.selectAll, 'All')}
|
|
19
25
|
</option>
|
|
20
|
-
{filter.filteredOptions.map((value: any) =>
|
|
21
|
-
|
|
22
|
-
{value.value}
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
{filter.filteredOptions.map((value: any) => {
|
|
27
|
+
return (
|
|
28
|
+
<option key={value.value} value={value.value}>
|
|
29
|
+
{translate(value.value)} ({value.count})
|
|
30
|
+
</option>
|
|
31
|
+
);
|
|
32
|
+
})}
|
|
25
33
|
</StyledSelect>
|
|
26
34
|
) : (
|
|
27
35
|
filter.filteredOptions.map((value: any) => {
|
|
@@ -35,7 +43,7 @@ export function Filter({ filter }: { filter: ResolvedFilter }) {
|
|
|
35
43
|
onChange={() => filter.toggleOption(value.value)}
|
|
36
44
|
/>
|
|
37
45
|
<label htmlFor={id}>
|
|
38
|
-
{value.value} ({value.count})
|
|
46
|
+
{translate(value.value)} ({value.count})
|
|
39
47
|
</label>
|
|
40
48
|
</FilterValue>
|
|
41
49
|
);
|
|
@@ -3,15 +3,17 @@ import styled from 'styled-components';
|
|
|
3
3
|
|
|
4
4
|
import { Link } from '@portal/Link';
|
|
5
5
|
import type { ResolvedNavItem } from '@theme/types/portal';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
interface FooterColumnProps {
|
|
8
9
|
column: ResolvedNavItem;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function FooterColumn({ column }: FooterColumnProps): JSX.Element {
|
|
13
|
+
const { translate } = useTranslate();
|
|
12
14
|
return (
|
|
13
15
|
<FooterColumnContainer data-component-name="Footer/FooterColumn">
|
|
14
|
-
<FooterColumnTitle>{column.label}</FooterColumnTitle>
|
|
16
|
+
<FooterColumnTitle>{translate(column.labelTranslationKey, column.label)}</FooterColumnTitle>
|
|
15
17
|
{column?.items?.map((columnItem, columnItemIndex) => {
|
|
16
18
|
if (columnItem.type === 'error') {
|
|
17
19
|
return null;
|
|
@@ -19,7 +21,7 @@ export function FooterColumn({ column }: FooterColumnProps): JSX.Element {
|
|
|
19
21
|
|
|
20
22
|
return columnItem.type === 'separator' ? (
|
|
21
23
|
<FooterSeparator key={columnItem.label + '_' + columnItemIndex}>
|
|
22
|
-
{columnItem.label}
|
|
24
|
+
{translate(columnItem.labelTranslationKey, columnItem.label)}
|
|
23
25
|
</FooterSeparator>
|
|
24
26
|
) : (
|
|
25
27
|
<FooterLink
|
|
@@ -29,7 +31,7 @@ export function FooterColumn({ column }: FooterColumnProps): JSX.Element {
|
|
|
29
31
|
target={columnItem.target}
|
|
30
32
|
data-cy={columnItem.label}
|
|
31
33
|
>
|
|
32
|
-
{columnItem.label}
|
|
34
|
+
{translate(columnItem.labelTranslationKey, columnItem.label)}
|
|
33
35
|
</FooterLink>
|
|
34
36
|
);
|
|
35
37
|
})}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import { useTranslate } from '@portal/hooks';
|
|
5
5
|
|
|
6
6
|
interface FooterCopyrightProps {
|
|
7
|
-
copyrightText:
|
|
7
|
+
copyrightText: string;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function FooterCopyright({ copyrightText = '' }: FooterCopyrightProps): JSX.Element | null {
|
|
11
|
+
const { translate } = useTranslate();
|
|
12
|
+
const translationKeys = {
|
|
13
|
+
copyrightText: 'theme.footer.copyrightText',
|
|
14
|
+
};
|
|
11
15
|
return copyrightText ? (
|
|
12
|
-
<Wrapper
|
|
16
|
+
<Wrapper
|
|
17
|
+
data-component-name="Footer/FooterCopyright"
|
|
18
|
+
data-translation-key={translationKeys.copyrightText}
|
|
19
|
+
>
|
|
20
|
+
{translate(translationKeys.copyrightText, copyrightText)}
|
|
21
|
+
</Wrapper>
|
|
13
22
|
) : null;
|
|
14
23
|
}
|
|
15
24
|
|
|
@@ -3,6 +3,7 @@ import styled from 'styled-components';
|
|
|
3
3
|
import { format } from 'timeago.js';
|
|
4
4
|
|
|
5
5
|
import { useThemeConfig } from '@theme/hooks/useThemeConfig';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
const FORMATS = {
|
|
8
9
|
timeago: (date: Date, locale: string) => format(date, locale),
|
|
@@ -21,6 +22,7 @@ export interface LastUpdatedProps {
|
|
|
21
22
|
|
|
22
23
|
export function LastUpdated(props: LastUpdatedProps): JSX.Element | null {
|
|
23
24
|
const { markdown: { lastUpdatedBlock = {} } = {} } = useThemeConfig();
|
|
25
|
+
const { translate } = useTranslate();
|
|
24
26
|
|
|
25
27
|
if (lastUpdatedBlock?.hide) {
|
|
26
28
|
return null;
|
|
@@ -32,16 +34,22 @@ export function LastUpdated(props: LastUpdatedProps): JSX.Element | null {
|
|
|
32
34
|
const isoDate = lastModified.toISOString().split('T')[0];
|
|
33
35
|
|
|
34
36
|
const lastUpdatedString = FORMATS[format as keyof typeof FORMATS](lastModified, locale);
|
|
37
|
+
const translationKey =
|
|
38
|
+
format === 'timeago' ? 'theme.page.lastUpdated.timeago' : 'theme.page.lastUpdated.on';
|
|
35
39
|
|
|
36
|
-
const
|
|
40
|
+
const text =
|
|
41
|
+
format === 'timeago'
|
|
42
|
+
? translate(translationKey, 'Last updated ')
|
|
43
|
+
: translate(translationKey, 'Last updated on');
|
|
37
44
|
|
|
38
45
|
return (
|
|
39
46
|
<Wrapper
|
|
40
47
|
data-component-name="LastUpdated/LastUpdated"
|
|
41
48
|
rawOnPrint={format === 'timeago'}
|
|
42
49
|
data-print-datetime={isoDate}
|
|
50
|
+
data-translation-key={translationKey}
|
|
43
51
|
>
|
|
44
|
-
|
|
52
|
+
{text}
|
|
45
53
|
{/* TODO: fix issue with snapshot tests - they should not depend on current date */}
|
|
46
54
|
<time dateTime={isoDate}>{lastUpdatedString}</time>
|
|
47
55
|
</Wrapper>
|
|
@@ -8,6 +8,7 @@ import { EditPageButton } from '@theme/components/EditPageButton';
|
|
|
8
8
|
import { LastUpdated } from '@theme/components/LastUpdated/LastUpdated';
|
|
9
9
|
import { useThemeConfig } from '@theme/hooks';
|
|
10
10
|
import type { ResolvedNavItemWithLink } from '@theme/types/portal';
|
|
11
|
+
import { useTranslate } from '@portal/hooks';
|
|
11
12
|
|
|
12
13
|
type MarkdownLayoutProps = {
|
|
13
14
|
tableOfContent: React.ReactNode;
|
|
@@ -34,6 +35,10 @@ export function MarkdownLayout({
|
|
|
34
35
|
prevPage,
|
|
35
36
|
}: MarkdownLayoutProps): JSX.Element {
|
|
36
37
|
const { markdown } = useThemeConfig();
|
|
38
|
+
const { translate } = useTranslate();
|
|
39
|
+
const translationKeys = {
|
|
40
|
+
text: 'theme.markdown.editPage.text',
|
|
41
|
+
};
|
|
37
42
|
const { editPage: themeEditPage } = markdown || {};
|
|
38
43
|
|
|
39
44
|
const mergedConf = editPage ? { ...themeEditPage, ...editPage } : undefined;
|
|
@@ -44,7 +49,12 @@ export function MarkdownLayout({
|
|
|
44
49
|
<LayoutTop>
|
|
45
50
|
{lastModified && <LastUpdated lastModified={new Date(lastModified)} />}
|
|
46
51
|
{mergedConf && (
|
|
47
|
-
<EditPageButton
|
|
52
|
+
<EditPageButton
|
|
53
|
+
text={translate(translationKeys.text, mergedConf.text)}
|
|
54
|
+
to={mergedConf.to}
|
|
55
|
+
icon={mergedConf.icon}
|
|
56
|
+
data-translation-key={translationKeys.text}
|
|
57
|
+
/>
|
|
48
58
|
)}
|
|
49
59
|
</LayoutTop>
|
|
50
60
|
{markdownWrapper}
|
|
@@ -6,6 +6,7 @@ import { MenuLinkItem } from '@theme/components/Menu/MenuLinkItem';
|
|
|
6
6
|
import { MenuItemLabel } from '@theme/components/Menu/MenuItemLabel';
|
|
7
7
|
import { SeparatorLine } from '@theme/components/Separator/SeparatorLine';
|
|
8
8
|
import type { ItemState } from '@theme/components/Sidebar/types';
|
|
9
|
+
import { useTranslate } from '@portal/hooks';
|
|
9
10
|
|
|
10
11
|
interface MenuGroupProps {
|
|
11
12
|
item: ItemState;
|
|
@@ -21,6 +22,8 @@ export function MenuGroup({
|
|
|
21
22
|
}: React.PropsWithChildren<MenuGroupProps>): JSX.Element {
|
|
22
23
|
const [showChildren, setShowChildren] = useState<boolean>(isExpanded);
|
|
23
24
|
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
25
|
+
const { translate } = useTranslate();
|
|
26
|
+
|
|
24
27
|
useEffect(() => {
|
|
25
28
|
timer.current && clearTimeout(timer.current);
|
|
26
29
|
if (isExpanded) {
|
|
@@ -47,7 +50,7 @@ export function MenuGroup({
|
|
|
47
50
|
visibility={item.items.length ? 'visible' : 'hidden'}
|
|
48
51
|
direction={isExpanded ? 'down' : 'right'}
|
|
49
52
|
/>
|
|
50
|
-
{item.label}
|
|
53
|
+
{translate(item.labelTranslationKey, item.label)}
|
|
51
54
|
</MenuGroupLabel>
|
|
52
55
|
</MenuLinkItem>
|
|
53
56
|
|
|
@@ -6,13 +6,15 @@ import { ExternalIcon } from '@theme/icons/ExternalIcon';
|
|
|
6
6
|
import { MenuItemLabel } from '@theme/components/Menu/MenuItemLabel';
|
|
7
7
|
import { SeparatorLine } from '@theme/components/Separator/SeparatorLine';
|
|
8
8
|
import type { MenuItemProps } from '@theme/components/Sidebar/types';
|
|
9
|
+
import { useTranslate } from '@portal/hooks';
|
|
9
10
|
|
|
10
11
|
export function MenuItem({ item }: MenuItemProps): JSX.Element {
|
|
12
|
+
const { translate } = useTranslate();
|
|
11
13
|
return (
|
|
12
14
|
<Wrapper data-component-name="Sidebar/MenuItem">
|
|
13
15
|
<MenuLinkItem item={item}>
|
|
14
16
|
<MenuItemLabel active={item.active}>
|
|
15
|
-
{item.label}
|
|
17
|
+
{translate(item.labelTranslationKey, item.label)}
|
|
16
18
|
{item.external ? <ExternalIcon dataComponentName="Sidebar/ExternalIcon" /> : null}
|
|
17
19
|
</MenuItemLabel>
|
|
18
20
|
</MenuLinkItem>
|
|
@@ -3,6 +3,8 @@ import styled from 'styled-components';
|
|
|
3
3
|
import { useLocation } from 'react-router-dom';
|
|
4
4
|
|
|
5
5
|
import { Link } from '@portal/Link';
|
|
6
|
+
import { useI18nConfig } from '@portal/hooks';
|
|
7
|
+
import { getPathnameForLocale } from '@portal/utils';
|
|
6
8
|
import type {
|
|
7
9
|
ResolvedNavItem,
|
|
8
10
|
ResolvedNavLinkItem,
|
|
@@ -21,10 +23,14 @@ export function MobileNavbarItem({ navItem, className }: NavbarItemProps): JSX.E
|
|
|
21
23
|
const { pathname } = useLocation();
|
|
22
24
|
const [expandedDropdown, setExpandedDropdown] = useState(false);
|
|
23
25
|
const toggleDropdown = () => setExpandedDropdown(!expandedDropdown);
|
|
26
|
+
const { defaultLocale, currentLocale, locales } = useI18nConfig();
|
|
24
27
|
|
|
25
28
|
if ((navItem as ResolvedNavLinkItem).link) {
|
|
26
29
|
const item = navItem as ResolvedNavLinkItem;
|
|
27
|
-
const isActive =
|
|
30
|
+
const isActive =
|
|
31
|
+
pathname ===
|
|
32
|
+
withPathPrefix(getPathnameForLocale(item.link, defaultLocale, currentLocale, locales));
|
|
33
|
+
|
|
28
34
|
return (
|
|
29
35
|
<NavMenuItem
|
|
30
36
|
active={isActive}
|
|
@@ -13,6 +13,9 @@ import { useThemeConfig } from '@theme/hooks/useThemeConfig';
|
|
|
13
13
|
import { Search } from '@theme/components/Search/Search';
|
|
14
14
|
import { AuthUserProfile } from '@theme/components/Profile/AuthUserProfile';
|
|
15
15
|
import type { LogoConfig, ResolvedConfigLinks } from '@theme/types/portal';
|
|
16
|
+
import { useI18n } from '@portal/hooks';
|
|
17
|
+
|
|
18
|
+
import { LanguagePicker } from '../../I18n/LanguagePicker';
|
|
16
19
|
|
|
17
20
|
const EmptyNavbarHack = createGlobalStyle`
|
|
18
21
|
#redocly_root {
|
|
@@ -23,6 +26,7 @@ const EmptyNavbarHack = createGlobalStyle`
|
|
|
23
26
|
export function Navbar(): JSX.Element | null {
|
|
24
27
|
const [isOpen, setIsOpen] = useMobileMenu(false);
|
|
25
28
|
const themeConfig = useThemeConfig();
|
|
29
|
+
const { changeLanguage } = useI18n();
|
|
26
30
|
|
|
27
31
|
const menu = themeConfig.navbar?.items;
|
|
28
32
|
const logo = themeConfig.logo;
|
|
@@ -56,6 +60,7 @@ export function Navbar(): JSX.Element | null {
|
|
|
56
60
|
menu: menu as ResolvedConfigLinks,
|
|
57
61
|
logo: logo as Pick<LogoConfig, 'image' | 'link' | 'altText'>,
|
|
58
62
|
hideUserProfile,
|
|
63
|
+
changeLanguage,
|
|
59
64
|
}}
|
|
60
65
|
/>
|
|
61
66
|
);
|
|
@@ -69,6 +74,7 @@ interface NavbarPresentationalProps extends NavbarLogoProps {
|
|
|
69
74
|
hideSearch: boolean;
|
|
70
75
|
menu: ResolvedConfigLinks;
|
|
71
76
|
hideUserProfile: boolean | string | undefined;
|
|
77
|
+
changeLanguage: (value: string) => void;
|
|
72
78
|
}
|
|
73
79
|
|
|
74
80
|
export function NavbarPresentational(props: NavbarPresentationalProps): JSX.Element | null {
|
|
@@ -81,6 +87,7 @@ export function NavbarPresentational(props: NavbarPresentationalProps): JSX.Elem
|
|
|
81
87
|
logo,
|
|
82
88
|
menu,
|
|
83
89
|
hideUserProfile,
|
|
90
|
+
changeLanguage,
|
|
84
91
|
} = props;
|
|
85
92
|
return (
|
|
86
93
|
<NavbarContainer data-component-name="Navbar/Navbar">
|
|
@@ -97,6 +104,7 @@ export function NavbarPresentational(props: NavbarPresentationalProps): JSX.Elem
|
|
|
97
104
|
<NavbarLogo logo={logo} />
|
|
98
105
|
<NavbarMenu menuItems={menu as ResolvedConfigLinks} />
|
|
99
106
|
{hideSearch ? null : <Search />}
|
|
107
|
+
<LanguagePicker onChangeLanguage={changeLanguage} />
|
|
100
108
|
{hideUserProfile ? null : <AuthUserProfile />}
|
|
101
109
|
<ColorModeSwitcher />
|
|
102
110
|
</NavbarRow>
|
|
@@ -3,17 +3,19 @@ import styled from 'styled-components';
|
|
|
3
3
|
|
|
4
4
|
import { Link } from '@portal/Link';
|
|
5
5
|
import type { ResolvedNavLinkItem } from '@theme/types/portal';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
interface NavbarDropdownProps {
|
|
8
9
|
items: ResolvedNavLinkItem[];
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function NavbarDropdown({ items }: NavbarDropdownProps): JSX.Element {
|
|
13
|
+
const { translate } = useTranslate();
|
|
12
14
|
return (
|
|
13
15
|
<DropdownWrapper data-component-name="Navbar/NavbarDropdown">
|
|
14
16
|
{items.map((item, index) => (
|
|
15
17
|
<div key={`${item.label}_${index}`}>
|
|
16
|
-
<Link to={item.link}>{item.label}</Link>
|
|
18
|
+
<Link to={item.link}>{translate(item.labelTranslationKey, item.label)}</Link>
|
|
17
19
|
</div>
|
|
18
20
|
))}
|
|
19
21
|
</DropdownWrapper>
|