@redocly/theme 0.11.4 → 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/Markdown/MarkdownWrapper.js +4 -0
- 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/globalStyle.js +7 -0
- 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/Markdown/MarkdownWrapper.tsx +4 -0
- 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/globalStyle.ts +7 -0
- 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
package/lib/icons/index.d.ts
CHANGED
package/lib/icons/index.js
CHANGED
|
@@ -20,4 +20,5 @@ __exportStar(require("../icons/ArrowIcon"), exports);
|
|
|
20
20
|
__exportStar(require("../icons/ColorModeIcon"), exports);
|
|
21
21
|
__exportStar(require("../icons/AnchorIcon"), exports);
|
|
22
22
|
__exportStar(require("../icons/ExternalIcon"), exports);
|
|
23
|
+
__exportStar(require("../icons/SpinnerIcon"), exports);
|
|
23
24
|
//# sourceMappingURL=index.js.map
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -23,4 +23,5 @@ __exportStar(require("./globalStyle"), exports);
|
|
|
23
23
|
__exportStar(require("./types/config"), exports);
|
|
24
24
|
__exportStar(require("./config"), exports);
|
|
25
25
|
__exportStar(require("./ui"), exports);
|
|
26
|
+
__exportStar(require("./I18n"), exports);
|
|
26
27
|
//# sourceMappingURL=index.js.map
|
package/lib/layouts/Forbidden.js
CHANGED
|
@@ -7,11 +7,17 @@ exports.Forbidden = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
9
|
const _theme_1 = require("../index.js");
|
|
10
|
+
const hooks_1 = require("../mocks/hooks");
|
|
10
11
|
function Forbidden() {
|
|
12
|
+
const { translate } = (0, hooks_1.useTranslate)();
|
|
13
|
+
const translationKeys = {
|
|
14
|
+
title: 'theme.page.forbidden.title',
|
|
15
|
+
homeButton: 'theme.page.homeButton',
|
|
16
|
+
};
|
|
11
17
|
return (react_1.default.createElement(Wrapper, { "data-component-name": "Pages/Forbidden" },
|
|
12
18
|
react_1.default.createElement(Header, null, "403"),
|
|
13
|
-
react_1.default.createElement(Description,
|
|
14
|
-
react_1.default.createElement(HomeButton, { color: "primary", size: "large", to: "/" },
|
|
19
|
+
react_1.default.createElement(Description, { "data-translation-key": translationKeys.title }, translate(translationKeys.title, 'Access forbidden')),
|
|
20
|
+
react_1.default.createElement(HomeButton, { color: "primary", size: "large", to: "/", "data-translation-key": translationKeys.homeButton }, translate(translationKeys.homeButton, 'Open Homepage'))));
|
|
15
21
|
}
|
|
16
22
|
exports.Forbidden = Forbidden;
|
|
17
23
|
const Wrapper = styled_components_1.default.div `
|
package/lib/layouts/NotFound.js
CHANGED
|
@@ -7,11 +7,17 @@ exports.NotFound = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const styled_components_1 = __importDefault(require("styled-components"));
|
|
9
9
|
const Button_1 = require("../components/Button");
|
|
10
|
+
const hooks_1 = require("../mocks/hooks");
|
|
10
11
|
function NotFound() {
|
|
12
|
+
const { translate } = (0, hooks_1.useTranslate)();
|
|
13
|
+
const translationKeys = {
|
|
14
|
+
title: 'theme.page.notFound.title',
|
|
15
|
+
homeButton: 'theme.page.homeButton',
|
|
16
|
+
};
|
|
11
17
|
return (react_1.default.createElement(Wrapper, { "data-component-name": "Pages/NotFound" },
|
|
12
18
|
react_1.default.createElement(Header, null, "404"),
|
|
13
|
-
react_1.default.createElement(Description,
|
|
14
|
-
react_1.default.createElement(HomeButton, { color: "primary", size: "large", to: "/" },
|
|
19
|
+
react_1.default.createElement(Description, { "data-translation-key": translationKeys.title }, translate(translationKeys.title, `It looks like you're lost`)),
|
|
20
|
+
react_1.default.createElement(HomeButton, { color: "primary", size: "large", to: "/", "data-translation-key": translationKeys.homeButton }, translate(translationKeys.homeButton, 'Open Homepage'))));
|
|
15
21
|
}
|
|
16
22
|
exports.NotFound = NotFound;
|
|
17
23
|
const Wrapper = styled_components_1.default.div `
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ThemeUIConfig } from '../../config';
|
|
2
|
-
import type { ResolvedNavItem } from '../../types/portal';
|
|
2
|
+
import type { ResolvedNavItem, TFunction } from '../../types/portal';
|
|
3
3
|
import type { CatalogConfig, FilteredCatalog } from '../../types/portal/src/shared/types/catalog';
|
|
4
4
|
interface PageLink {
|
|
5
5
|
label: string;
|
|
@@ -13,4 +13,18 @@ export declare function useSidebarSiblingsData(): {
|
|
|
13
13
|
};
|
|
14
14
|
export declare function usePageSharedData<T = unknown>(_id: string): T;
|
|
15
15
|
export declare function useCatalog(_items: ResolvedNavItem[], _config: CatalogConfig): FilteredCatalog;
|
|
16
|
+
export declare function useTranslate(): {
|
|
17
|
+
translate: TFunction;
|
|
18
|
+
};
|
|
19
|
+
export declare function useI18n(): {
|
|
20
|
+
changeLanguage: (...args: any) => string;
|
|
21
|
+
};
|
|
16
22
|
export { useGlobalData } from '../useGlobalData';
|
|
23
|
+
export declare function useI18nConfig(): {
|
|
24
|
+
currentLocale: string;
|
|
25
|
+
defaultLocale: string;
|
|
26
|
+
locales: {
|
|
27
|
+
code: string;
|
|
28
|
+
name: string;
|
|
29
|
+
}[];
|
|
30
|
+
};
|
package/lib/mocks/hooks/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useGlobalData = exports.useCatalog = exports.usePageSharedData = exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
3
|
+
exports.useI18nConfig = exports.useGlobalData = exports.useI18n = exports.useTranslate = exports.useCatalog = exports.usePageSharedData = exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
4
4
|
function useThemeConfig() {
|
|
5
5
|
return {
|
|
6
6
|
search: {
|
|
@@ -69,6 +69,24 @@ function useCatalog(_items, _config) {
|
|
|
69
69
|
throw new Error('Mock not implemented yet.');
|
|
70
70
|
}
|
|
71
71
|
exports.useCatalog = useCatalog;
|
|
72
|
+
function useTranslate() {
|
|
73
|
+
const translate = (value, options) => (typeof options === 'string' ? options : options === null || options === void 0 ? void 0 : options.defaultValue) || value || '';
|
|
74
|
+
return { translate };
|
|
75
|
+
}
|
|
76
|
+
exports.useTranslate = useTranslate;
|
|
77
|
+
function useI18n() {
|
|
78
|
+
const changeLanguage = (...args) => args.value;
|
|
79
|
+
return { changeLanguage };
|
|
80
|
+
}
|
|
81
|
+
exports.useI18n = useI18n;
|
|
72
82
|
var useGlobalData_1 = require("../useGlobalData");
|
|
73
83
|
Object.defineProperty(exports, "useGlobalData", { enumerable: true, get: function () { return useGlobalData_1.useGlobalData; } });
|
|
84
|
+
function useI18nConfig() {
|
|
85
|
+
return {
|
|
86
|
+
currentLocale: 'en',
|
|
87
|
+
defaultLocale: 'en',
|
|
88
|
+
locales: [{ code: 'en', name: 'en' }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
exports.useI18nConfig = useI18nConfig;
|
|
74
92
|
//# sourceMappingURL=index.js.map
|
package/lib/mocks/search.d.ts
CHANGED
package/lib/mocks/search.js
CHANGED
package/lib/mocks/utils.d.ts
CHANGED
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
export declare function withPathPrefix(link: string): string;
|
|
2
|
+
export declare function withoutPathPrefix(link: string): string;
|
|
2
3
|
export declare function timeAgo(lastModified: string | Date): string;
|
|
4
|
+
export declare function getPathnameForLocale(pathname: string, _defaultLocale: string, _newLocale: string, _allLocales: {
|
|
5
|
+
code: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}[]): string;
|
package/lib/mocks/utils.js
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.timeAgo = exports.withPathPrefix = void 0;
|
|
3
|
+
exports.getPathnameForLocale = exports.timeAgo = exports.withoutPathPrefix = exports.withPathPrefix = void 0;
|
|
4
4
|
function withPathPrefix(link) {
|
|
5
5
|
return link;
|
|
6
6
|
}
|
|
7
7
|
exports.withPathPrefix = withPathPrefix;
|
|
8
|
+
function withoutPathPrefix(link) {
|
|
9
|
+
return link;
|
|
10
|
+
}
|
|
11
|
+
exports.withoutPathPrefix = withoutPathPrefix;
|
|
8
12
|
function timeAgo(lastModified) {
|
|
9
13
|
// should return format(lastModified) in portal
|
|
10
14
|
const d = new Date(lastModified);
|
|
11
15
|
return `${d.getDate()}-${d.getMonth() + 1}-${d.getFullYear()}`;
|
|
12
16
|
}
|
|
13
17
|
exports.timeAgo = timeAgo;
|
|
18
|
+
function getPathnameForLocale(pathname, _defaultLocale, _newLocale, _allLocales) {
|
|
19
|
+
return `${pathname}`;
|
|
20
|
+
}
|
|
21
|
+
exports.getPathnameForLocale = getPathnameForLocale;
|
|
14
22
|
//# sourceMappingURL=utils.js.map
|
|
@@ -15,4 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./src/shared/types/nav"), exports);
|
|
18
|
+
__exportStar(require("./src/shared/types/i18n"), exports);
|
|
18
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -11,9 +11,11 @@ export type FilteredCatalog = {
|
|
|
11
11
|
export type Filter = {
|
|
12
12
|
type?: 'select' | 'checkboxes';
|
|
13
13
|
title: string;
|
|
14
|
+
titleTranslationKey?: string;
|
|
14
15
|
property: string;
|
|
15
16
|
parentFilter?: string;
|
|
16
17
|
missingCategoryName?: string;
|
|
18
|
+
missingCategoryNameTranslationKey?: string;
|
|
17
19
|
options?: string[];
|
|
18
20
|
};
|
|
19
21
|
export type CatalogConfig = {
|
|
@@ -24,7 +26,9 @@ export type CatalogConfig = {
|
|
|
24
26
|
requiredPermission?: string;
|
|
25
27
|
separateVersions?: boolean;
|
|
26
28
|
title?: string;
|
|
29
|
+
titleTranslationKey?: string;
|
|
27
30
|
description?: string;
|
|
31
|
+
descriptionTranslationKey?: string;
|
|
28
32
|
};
|
|
29
33
|
export type ResolvedFilter = Omit<Filter, 'options'> & {
|
|
30
34
|
options: {
|
|
@@ -5,6 +5,7 @@ export type ResolvedNavLinkItem = {
|
|
|
5
5
|
metadata?: Record<string, unknown>;
|
|
6
6
|
link: string;
|
|
7
7
|
label: string;
|
|
8
|
+
labelTranslationKey?: string;
|
|
8
9
|
items?: ResolvedNavItem[];
|
|
9
10
|
sidebar?: ResolvedNavItem[];
|
|
10
11
|
external?: boolean;
|
|
@@ -23,6 +24,7 @@ export type ResolvedNavGroupItem = {
|
|
|
23
24
|
metadata?: Record<string, unknown>;
|
|
24
25
|
link?: string;
|
|
25
26
|
label?: string;
|
|
27
|
+
labelTranslationKey?: string;
|
|
26
28
|
items?: ResolvedNavItem[];
|
|
27
29
|
sidebar?: ResolvedNavItem[];
|
|
28
30
|
external?: boolean;
|
|
@@ -42,6 +44,7 @@ export type ResolvedNavItem = ResolvedNavLinkItem | ResolvedNavGroupItem | {
|
|
|
42
44
|
type: 'separator';
|
|
43
45
|
metadata?: Record<string, unknown>;
|
|
44
46
|
label?: string;
|
|
47
|
+
labelTranslationKey?: string;
|
|
45
48
|
routeSlug?: never;
|
|
46
49
|
version?: string;
|
|
47
50
|
isDefault?: boolean;
|
|
@@ -59,6 +62,7 @@ export type ResolvedNavItem = ResolvedNavLinkItem | ResolvedNavGroupItem | {
|
|
|
59
62
|
metadata?: Record<string, unknown>;
|
|
60
63
|
routeSlug?: never;
|
|
61
64
|
label: string;
|
|
65
|
+
labelTranslationKey?: string;
|
|
62
66
|
link?: undefined;
|
|
63
67
|
items?: ResolvedNavItem[];
|
|
64
68
|
sidebar?: ResolvedNavItem[];
|
|
@@ -101,10 +105,13 @@ export type NavItem = {
|
|
|
101
105
|
page?: string;
|
|
102
106
|
directory?: string;
|
|
103
107
|
group?: string;
|
|
108
|
+
groupTranslationKey?: string;
|
|
104
109
|
label?: string;
|
|
110
|
+
labelTranslationKey?: string;
|
|
105
111
|
href?: never;
|
|
106
112
|
items?: NavItem[];
|
|
107
113
|
separator?: string;
|
|
114
|
+
separatorTranslationKey?: string;
|
|
108
115
|
separatorLine?: boolean;
|
|
109
116
|
version?: string;
|
|
110
117
|
menuStyle?: MenuStyle;
|
package/package.json
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React, { useRef, useState } from 'react';
|
|
2
|
+
import { useLocation } from 'react-router-dom';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
import { getPathnameForLocale, withPathPrefix } from '@portal/utils';
|
|
6
|
+
import { usePreloadHistory } from '@portal/usePreloadHistory';
|
|
7
|
+
import { useI18nConfig } from '@portal/hooks';
|
|
8
|
+
|
|
9
|
+
import { useOutsideClick } from '../hooks';
|
|
10
|
+
|
|
11
|
+
export const LanguagePicker = (props: { onChangeLanguage: (newLang: string) => void }) => {
|
|
12
|
+
const { currentLocale, locales, defaultLocale } = useI18nConfig();
|
|
13
|
+
|
|
14
|
+
const dropdownRef = useRef<HTMLDivElement | null>(null);
|
|
15
|
+
|
|
16
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
17
|
+
useOutsideClick(dropdownRef, () => setIsOpen(false));
|
|
18
|
+
|
|
19
|
+
const location = useLocation();
|
|
20
|
+
const history = usePreloadHistory();
|
|
21
|
+
|
|
22
|
+
if (locales.length < 2) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Dropdown
|
|
28
|
+
data-component-name="I18n/LanguagePicker"
|
|
29
|
+
ref={dropdownRef}
|
|
30
|
+
isOpen={isOpen}
|
|
31
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
32
|
+
onBlur={() => setIsOpen(false)}
|
|
33
|
+
>
|
|
34
|
+
<DropdownValue>{currentLocale.toUpperCase()}</DropdownValue>
|
|
35
|
+
<DropdownMenu>
|
|
36
|
+
{locales.map((locale) => (
|
|
37
|
+
<MenuItem
|
|
38
|
+
onClick={() => {
|
|
39
|
+
const newLangPathname = withPathPrefix(
|
|
40
|
+
getPathnameForLocale(location.pathname, defaultLocale, locale.code, locales),
|
|
41
|
+
);
|
|
42
|
+
const newUrlWithLanguage = `${newLangPathname}${location.search}${location.hash}`;
|
|
43
|
+
history.push(newUrlWithLanguage);
|
|
44
|
+
props.onChangeLanguage(locale.code);
|
|
45
|
+
}}
|
|
46
|
+
key={locale.code}
|
|
47
|
+
>
|
|
48
|
+
{locale.name || locale.code || ''}
|
|
49
|
+
</MenuItem>
|
|
50
|
+
))}
|
|
51
|
+
</DropdownMenu>
|
|
52
|
+
</Dropdown>
|
|
53
|
+
);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const Dropdown = styled.div<{ isOpen: boolean }>`
|
|
57
|
+
font-size: var(--profile-menu-item-font-size);
|
|
58
|
+
font-family: var(--profile-menu-item-font-family);
|
|
59
|
+
font-weight: var(--profile-menu-item-font-weight);
|
|
60
|
+
line-height: var(--profile-menu-item-line-height);
|
|
61
|
+
|
|
62
|
+
${(props) =>
|
|
63
|
+
props.isOpen
|
|
64
|
+
? `
|
|
65
|
+
${DropdownMenu} {
|
|
66
|
+
display: block;
|
|
67
|
+
}
|
|
68
|
+
`
|
|
69
|
+
: ``}
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const DropdownValue = styled.div`
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
display: block;
|
|
75
|
+
|
|
76
|
+
color: var(--navbar-text-color);
|
|
77
|
+
padding: var(--navbar-item-paddin-vertical) var(--navbar-item-padding-horizontal);
|
|
78
|
+
border-radius: var(--navbar-item-border-radius);
|
|
79
|
+
|
|
80
|
+
&:hover {
|
|
81
|
+
color: var(--navbar-item-hover-text-color);
|
|
82
|
+
text-decoration: var(--navbar-item-hover-text-decoration);
|
|
83
|
+
background: var(--navbar-item-hover-background-color);
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const DropdownMenu = styled.ul`
|
|
88
|
+
position: absolute;
|
|
89
|
+
color: var(--profile-menu-item-text-color);
|
|
90
|
+
background-color: var(--profile-menu-background-color);
|
|
91
|
+
top: var(--navbar-height);
|
|
92
|
+
margin: 0;
|
|
93
|
+
box-shadow: 0 1px 2px rgb(204, 204, 204);
|
|
94
|
+
border-radius: 0 1px 2px 2px;
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
display: none;
|
|
97
|
+
overflow-y: auto;
|
|
98
|
+
z-index: 9;
|
|
99
|
+
padding: 0;
|
|
100
|
+
list-style: none;
|
|
101
|
+
`;
|
|
102
|
+
|
|
103
|
+
const MenuItem = styled.li`
|
|
104
|
+
padding: 10px;
|
|
105
|
+
transition: all 0.2s ease-in-out;
|
|
106
|
+
cursor: pointer;
|
|
107
|
+
|
|
108
|
+
&:hover {
|
|
109
|
+
color: var(--profile-menu-item-hover-text-color);
|
|
110
|
+
text-decoration: var(--profile-menu-item-hover-text-decoration);
|
|
111
|
+
background: var(--profile-menu-item-hover-background-color);
|
|
112
|
+
}
|
|
113
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { LanguagePicker } from '@theme/I18n/LanguagePicker';
|
|
@@ -4,6 +4,7 @@ import styled from 'styled-components';
|
|
|
4
4
|
import { Link } from '@portal/Link';
|
|
5
5
|
import { H3 } from '@theme/components/Typography/H3';
|
|
6
6
|
import type { ResolvedNavItem } from '@theme/types/portal';
|
|
7
|
+
import { useTranslate } from '@portal/hooks';
|
|
7
8
|
|
|
8
9
|
export interface CardProps {
|
|
9
10
|
title?: string;
|
|
@@ -12,6 +13,7 @@ export interface CardProps {
|
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export function Card(props: CardProps): JSX.Element {
|
|
16
|
+
const { translate } = useTranslate();
|
|
15
17
|
return (
|
|
16
18
|
<CardWrapper data-component-name="Cards/Card">
|
|
17
19
|
{props.icon && <img src={props?.icon} alt={props?.title} />}
|
|
@@ -20,7 +22,9 @@ export function Card(props: CardProps): JSX.Element {
|
|
|
20
22
|
<CardLinksList>
|
|
21
23
|
{props.links.items.map((item) => (
|
|
22
24
|
<li key={item.label}>
|
|
23
|
-
<Link to={item.link as string}>
|
|
25
|
+
<Link to={item.link as string}>
|
|
26
|
+
{translate(item.labelTranslationKey, item.label)}
|
|
27
|
+
</Link>
|
|
24
28
|
</li>
|
|
25
29
|
))}
|
|
26
30
|
</CardLinksList>
|
|
@@ -9,7 +9,7 @@ import { Filter } from '@theme/components/Filter';
|
|
|
9
9
|
import { H2 } from '@theme/components/Typography/H2';
|
|
10
10
|
import { H3 } from '@theme/components/Typography/H3';
|
|
11
11
|
import { CatalogCard } from '@theme/components/Catalog/CatalogCard';
|
|
12
|
-
import { usePageSharedData } from '@portal/hooks/index';
|
|
12
|
+
import { usePageSharedData, useTranslate } from '@portal/hooks/index';
|
|
13
13
|
|
|
14
14
|
import { useCatalog } from './useCatalog';
|
|
15
15
|
|
|
@@ -26,13 +26,18 @@ export default function Catalog(props: {
|
|
|
26
26
|
const { filterTerm, setFilterTerm, groups, filters } = useCatalog(items, catalogConfig);
|
|
27
27
|
|
|
28
28
|
const [isFilterPanelFocused, setIsFilterPanelFocused] = React.useState(false);
|
|
29
|
+
const { translate } = useTranslate();
|
|
30
|
+
const translationKeys = {
|
|
31
|
+
placeholder: 'theme.catalog.filters.placeholder',
|
|
32
|
+
applyFilter: 'theme.catalog.filters.apply',
|
|
33
|
+
};
|
|
29
34
|
|
|
30
35
|
return (
|
|
31
36
|
<HighlightContext.Provider value={[filterTerm]}>
|
|
32
37
|
<CatalogPageWrapper>
|
|
33
38
|
<CatalogPageSidebar isActiveInMobileMode={isFilterPanelFocused}>
|
|
34
39
|
<StyledInput
|
|
35
|
-
placeholder=
|
|
40
|
+
placeholder={translate(translationKeys.placeholder, 'Filter...')}
|
|
36
41
|
value={filterTerm}
|
|
37
42
|
onFocus={() => setIsFilterPanelFocused(true)}
|
|
38
43
|
onChange={(e) => setFilterTerm(e.target.value)}
|
|
@@ -41,15 +46,27 @@ export default function Catalog(props: {
|
|
|
41
46
|
<Filter filter={filter} key={filter.property + '-' + idx} />
|
|
42
47
|
))}
|
|
43
48
|
<MobileStickyApplyFilters>
|
|
44
|
-
<Button
|
|
45
|
-
|
|
49
|
+
<Button
|
|
50
|
+
data-translation-key={translationKeys.applyFilter}
|
|
51
|
+
color="secondary"
|
|
52
|
+
onClick={() => setIsFilterPanelFocused(false)}
|
|
53
|
+
>
|
|
54
|
+
{translate(translationKeys.applyFilter, 'Apply filters')}
|
|
46
55
|
</Button>
|
|
47
56
|
</MobileStickyApplyFilters>
|
|
48
57
|
</CatalogPageSidebar>
|
|
49
58
|
<CatalogPageContent>
|
|
50
|
-
{catalogConfig.title ?
|
|
59
|
+
{catalogConfig.title ? (
|
|
60
|
+
<CatalogTitle>
|
|
61
|
+
{' '}
|
|
62
|
+
{translate(catalogConfig.titleTranslationKey, catalogConfig.title)}{' '}
|
|
63
|
+
</CatalogTitle>
|
|
64
|
+
) : null}
|
|
51
65
|
{catalogConfig.description ? (
|
|
52
|
-
<CatalogDescription>
|
|
66
|
+
<CatalogDescription>
|
|
67
|
+
{' '}
|
|
68
|
+
{translate(catalogConfig.descriptionTranslationKey, catalogConfig.description)}{' '}
|
|
69
|
+
</CatalogDescription>
|
|
53
70
|
) : null}
|
|
54
71
|
{groups.map((group) => (
|
|
55
72
|
<React.Fragment key={group.title}>
|
|
@@ -5,8 +5,13 @@ import type { CatalogItem } from '@theme/types/portal/src/shared/types/catalog';
|
|
|
5
5
|
import { Link } from '@portal/Link';
|
|
6
6
|
import { Highlight } from '@theme/ui/Highlight';
|
|
7
7
|
import { Tags } from '@theme/components/Tags';
|
|
8
|
+
import { useTranslate } from '@portal/hooks';
|
|
8
9
|
|
|
9
10
|
export function CatalogCard({ item }: { item: CatalogItem }): JSX.Element {
|
|
11
|
+
const { translate } = useTranslate();
|
|
12
|
+
const translationKeys = {
|
|
13
|
+
footer: 'theme.catalog.card.footer',
|
|
14
|
+
};
|
|
10
15
|
return (
|
|
11
16
|
<Link key={item.docsLink || item.link} to={item.docsLink || item.link}>
|
|
12
17
|
<StyledCard>
|
|
@@ -19,7 +24,9 @@ export function CatalogCard({ item }: { item: CatalogItem }): JSX.Element {
|
|
|
19
24
|
</CardDescription>
|
|
20
25
|
{item.tags ? <Tags tags={item.tags as string[]} /> : null}
|
|
21
26
|
<hr />
|
|
22
|
-
<CardFooter
|
|
27
|
+
<CardFooter data-translation-key={translationKeys.footer}>
|
|
28
|
+
{translate(translationKeys.footer, 'View documentation')}
|
|
29
|
+
</CardFooter>
|
|
23
30
|
</StyledCard>
|
|
24
31
|
</Link>
|
|
25
32
|
);
|
|
@@ -254,9 +254,11 @@ function collectFilterOptions(
|
|
|
254
254
|
const options = Object.entries(usedOptions)
|
|
255
255
|
.map(([value, count]) => ({ value, count }))
|
|
256
256
|
.sort((a, b) => b.value.localeCompare(a.value));
|
|
257
|
-
|
|
258
257
|
if (othersCount) {
|
|
259
|
-
options.push({
|
|
258
|
+
options.push({
|
|
259
|
+
value: filter.missingCategoryNameTranslationKey || filter.missingCategoryName || 'Others',
|
|
260
|
+
count: othersCount,
|
|
261
|
+
});
|
|
260
262
|
}
|
|
261
263
|
return { ...filter, options };
|
|
262
264
|
});
|
|
@@ -4,6 +4,7 @@ import styled, { css } from 'styled-components';
|
|
|
4
4
|
import { ClipboardService } from '@theme/utils/ClipboardService';
|
|
5
5
|
import { useThemeConfig } from '@theme/hooks/useThemeConfig';
|
|
6
6
|
import { ReportDialog, useReportDialog } from '@theme/components/Feedback';
|
|
7
|
+
import { useTranslate } from '@portal/hooks';
|
|
7
8
|
|
|
8
9
|
export type CodeSampleProps = {
|
|
9
10
|
language: string;
|
|
@@ -27,6 +28,14 @@ export function CodeSample({
|
|
|
27
28
|
const { isReportDialogShown, isReportButtonShown, reportButtonProps, reportDialogProps } =
|
|
28
29
|
useReportDialog(report);
|
|
29
30
|
|
|
31
|
+
const { translate } = useTranslate();
|
|
32
|
+
const translationKeys = {
|
|
33
|
+
buttonText: 'theme.codeSnippet.copy.buttonText',
|
|
34
|
+
tooltipText: 'theme.codeSnippet.copy.tooltipText',
|
|
35
|
+
toasterText: 'theme.codeSnippet.copy.toasterText',
|
|
36
|
+
reportTitle: 'theme.codeSnippet.report.title',
|
|
37
|
+
};
|
|
38
|
+
|
|
30
39
|
const copyCode = (code: string) => {
|
|
31
40
|
ClipboardService.copyCustom(code);
|
|
32
41
|
setIsCopied(true);
|
|
@@ -46,16 +55,25 @@ export function CodeSample({
|
|
|
46
55
|
{!isCopied && (
|
|
47
56
|
<Button
|
|
48
57
|
onClick={() => copyCode(rawContent)}
|
|
49
|
-
title={
|
|
58
|
+
title={translate(
|
|
59
|
+
translationKeys.tooltipText,
|
|
60
|
+
copy.tooltipText || 'Copy to clipboard',
|
|
61
|
+
)}
|
|
50
62
|
>
|
|
51
|
-
{copy.buttonText || 'Copy'}
|
|
63
|
+
{translate(translationKeys.buttonText, copy.buttonText || 'Copy')}
|
|
52
64
|
</Button>
|
|
53
65
|
)}
|
|
54
|
-
{isCopied &&
|
|
66
|
+
{isCopied && (
|
|
67
|
+
<DoneIndicator>
|
|
68
|
+
{translate(translationKeys.toasterText, copy.toasterText || 'Copied!')}
|
|
69
|
+
</DoneIndicator>
|
|
70
|
+
)}
|
|
55
71
|
</>
|
|
56
72
|
)}
|
|
57
73
|
|
|
58
|
-
{isReportButtonShown &&
|
|
74
|
+
{isReportButtonShown && (
|
|
75
|
+
<Button {...reportButtonProps}>{translate(translationKeys.reportTitle, 'Report')}</Button>
|
|
76
|
+
)}
|
|
59
77
|
|
|
60
78
|
{isReportDialogShown && <ReportDialog {...reportDialogProps} location={rawContent} />}
|
|
61
79
|
</CodeSampleButtonContainer>
|
|
@@ -3,11 +3,19 @@ import styled from 'styled-components';
|
|
|
3
3
|
|
|
4
4
|
import { Button } from '@theme/components/Button/Button';
|
|
5
5
|
import type { CommentProps } from '@theme/components/Feedback';
|
|
6
|
+
import { useTranslate } from '@portal/hooks';
|
|
6
7
|
|
|
7
8
|
export const Comment = ({ settings, onSubmit, onCancel }: CommentProps): JSX.Element => {
|
|
8
9
|
const { label, submitText } = settings || {};
|
|
9
10
|
const [text, setText] = React.useState('');
|
|
10
11
|
const [submitValue, setSubmitValue] = React.useState('');
|
|
12
|
+
const { translate } = useTranslate();
|
|
13
|
+
const translationKeys = {
|
|
14
|
+
submitText: 'theme.feedback.settings.comment.submitText',
|
|
15
|
+
label: 'theme.feedback.settings.comment.label',
|
|
16
|
+
send: 'theme.feedback.settings.comment.send',
|
|
17
|
+
cancel: 'theme.feedback.settings.comment.cancel',
|
|
18
|
+
};
|
|
11
19
|
|
|
12
20
|
const send = () => {
|
|
13
21
|
if (!text) return;
|
|
@@ -21,18 +29,31 @@ export const Comment = ({ settings, onSubmit, onCancel }: CommentProps): JSX.Ele
|
|
|
21
29
|
if (submitValue) {
|
|
22
30
|
return (
|
|
23
31
|
<Wrapper>
|
|
24
|
-
<Label
|
|
32
|
+
<Label data-translation-key={translationKeys.submitText}>
|
|
33
|
+
{translate(
|
|
34
|
+
translationKeys.submitText,
|
|
35
|
+
submitText || 'Thank you for helping improve our documentation!',
|
|
36
|
+
)}
|
|
37
|
+
</Label>
|
|
25
38
|
</Wrapper>
|
|
26
39
|
);
|
|
27
40
|
}
|
|
28
41
|
|
|
29
42
|
return (
|
|
30
43
|
<Wrapper data-component-name="Feedback/Comment">
|
|
31
|
-
<Label
|
|
44
|
+
<Label data-translation-key={translationKeys.label}>
|
|
45
|
+
{translate(translationKeys.label, label || 'Please share your feedback with us.')}
|
|
46
|
+
</Label>
|
|
32
47
|
<TextArea rows={3} onChange={handleTextAreaChange} />
|
|
33
48
|
<ButtonsContainer>
|
|
34
|
-
<SendButton onClick={send}>
|
|
35
|
-
|
|
49
|
+
<SendButton data-translation-key={translationKeys.send} onClick={send}>
|
|
50
|
+
{translate(translationKeys.send, 'Send')}
|
|
51
|
+
</SendButton>
|
|
52
|
+
{onCancel && (
|
|
53
|
+
<CancelButton data-translation-key={translationKeys.cancel} onClick={onCancel}>
|
|
54
|
+
{translate(translationKeys.cancel, 'Cancel')}
|
|
55
|
+
</CancelButton>
|
|
56
|
+
)}
|
|
36
57
|
</ButtonsContainer>
|
|
37
58
|
</Wrapper>
|
|
38
59
|
);
|