@redocly/theme 0.7.4 → 0.7.5
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/Catalog/Catalog.d.ts +8 -0
- package/lib/Catalog/Catalog.js +167 -0
- package/lib/Catalog/CatalogCard.d.ts +5 -0
- package/lib/Catalog/CatalogCard.js +113 -0
- package/lib/Catalog/Filter.d.ts +5 -0
- package/lib/Catalog/Filter.js +88 -0
- package/lib/Catalog/Tags.d.ts +4 -0
- package/lib/Catalog/Tags.js +32 -0
- package/lib/Feedback/ReportDialog.d.ts +3 -0
- package/lib/Feedback/ReportDialog.js +66 -0
- package/lib/Feedback/index.d.ts +2 -0
- package/lib/Feedback/index.js +5 -1
- package/lib/Feedback/types.d.ts +5 -3
- package/lib/Feedback/useReportDialog.d.ts +7 -0
- package/lib/Feedback/useReportDialog.js +28 -0
- package/lib/Markdown/CodeSample/CodeSample.js +5 -38
- package/lib/Sidebar/ArrowBack.js +2 -2
- package/lib/Sidebar/SidebarLayout.d.ts +5 -1
- package/lib/Sidebar/SidebarLayout.js +26 -1
- package/lib/config.js +2 -2
- package/lib/globalStyle.js +12 -10
- package/lib/mocks/hooks/index.d.ts +4 -0
- package/lib/mocks/hooks/index.js +9 -1
- package/lib/ui/Checkbox.d.ts +1 -0
- package/lib/ui/Checkbox.js +70 -0
- package/lib/ui/Highlight.d.ts +5 -0
- package/lib/ui/Highlight.js +63 -0
- package/lib/ui/darkColors.js +4 -2
- package/package.json +4 -2
- package/src/Catalog/Catalog.tsx +198 -0
- package/src/Catalog/CatalogCard.tsx +95 -0
- package/src/Catalog/Filter.tsx +103 -0
- package/src/Catalog/Tags.tsx +36 -0
- package/src/Feedback/ReportDialog.tsx +51 -0
- package/src/Feedback/index.ts +2 -0
- package/src/Feedback/types.ts +5 -3
- package/src/Feedback/useReportDialog.ts +34 -0
- package/src/Markdown/CodeSample/CodeSample.tsx +7 -50
- package/src/Sidebar/ArrowBack.tsx +2 -2
- package/src/Sidebar/SidebarLayout.tsx +38 -1
- package/src/config.ts +2 -2
- package/src/globalStyle.ts +12 -10
- package/src/mocks/hooks/index.ts +10 -1
- package/src/types/portal/src/shared/types/catalog.d.ts +55 -0
- package/src/ui/Checkbox.tsx +64 -0
- package/src/ui/Highlight.tsx +48 -0
- package/src/ui/darkColors.tsx +4 -2
- package/lib/hooks/useReportDialog.d.ts +0 -1
- package/lib/hooks/useReportDialog.js +0 -16
- package/src/hooks/useReportDialog.ts +0 -14
|
@@ -2,6 +2,10 @@ import React from 'react';
|
|
|
2
2
|
interface SidebarLayoutProps {
|
|
3
3
|
versions: React.ReactNode;
|
|
4
4
|
menu: React.ReactNode;
|
|
5
|
+
backLink?: {
|
|
6
|
+
label: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
};
|
|
5
9
|
}
|
|
6
|
-
export declare function SidebarLayout({ versions, menu }: SidebarLayoutProps): JSX.Element | null;
|
|
10
|
+
export declare function SidebarLayout({ versions, menu, backLink, }: SidebarLayoutProps): JSX.Element | null;
|
|
7
11
|
export {};
|
|
@@ -12,7 +12,9 @@ const MobileSidebarButton_1 = require("../Sidebar/MobileSidebarButton");
|
|
|
12
12
|
const MenuContainer_1 = require("../Sidebar/MenuContainer");
|
|
13
13
|
const SidebarSearch_1 = require("../Search/SidebarSearch");
|
|
14
14
|
const useThemeConfig_1 = require("../hooks/useThemeConfig");
|
|
15
|
-
|
|
15
|
+
const ArrowBack_1 = require("../Sidebar/ArrowBack");
|
|
16
|
+
const Link_1 = require("../mocks/Link");
|
|
17
|
+
function SidebarLayout({ versions, menu, backLink, }) {
|
|
16
18
|
const [isOpen, setIsOpen] = (0, useMobileMenu_1.useMobileMenu)();
|
|
17
19
|
const toggleMenu = () => setIsOpen(!isOpen);
|
|
18
20
|
const { search, sidebar } = (0, useThemeConfig_1.useThemeConfig)();
|
|
@@ -23,9 +25,32 @@ function SidebarLayout({ versions, menu }) {
|
|
|
23
25
|
react_1.default.createElement(MobileSidebarButton_1.MobileSidebarButton, { opened: isOpen, onClick: toggleMenu }),
|
|
24
26
|
!(search === null || search === void 0 ? void 0 : search.hide) && (search === null || search === void 0 ? void 0 : search.placement) === 'sidebar' ? react_1.default.createElement(SidebarSearch_1.SidebarSearch, null) : null,
|
|
25
27
|
react_1.default.createElement(Sidebar_1.Sidebar, { animate: true, opened: isOpen },
|
|
28
|
+
(backLink && (react_1.default.createElement(BackLinkWrapper, null,
|
|
29
|
+
react_1.default.createElement(Link_1.Link, { to: backLink.slug },
|
|
30
|
+
react_1.default.createElement(ArrowBack_1.ArrowBack, null),
|
|
31
|
+
"Back to ",
|
|
32
|
+
backLink.label)))) ||
|
|
33
|
+
null,
|
|
26
34
|
versions,
|
|
27
35
|
react_1.default.createElement(MenuContainer_1.MenuContainer, null, menu))));
|
|
28
36
|
}
|
|
29
37
|
exports.SidebarLayout = SidebarLayout;
|
|
38
|
+
const BackLinkWrapper = styled_components_1.default.div `
|
|
39
|
+
padding: var(--sidebar-offset-top) var(--sidebar-item-padding-horizontal)
|
|
40
|
+
var(--sidebar-item-padding-horizontal)
|
|
41
|
+
calc(var(--sidebar-offset-left) + var(--sidebar-item-padding-horizontal));
|
|
42
|
+
|
|
43
|
+
a {
|
|
44
|
+
color: var(--sidebar-back-button-text-color);
|
|
45
|
+
font-size: var(--sidebar-back-button-font-size);
|
|
46
|
+
font-family: var(--sidebar-back-button-font-family);
|
|
47
|
+
text-decoration: none;
|
|
48
|
+
&:hover {
|
|
49
|
+
color: var(--sidebar-back-button-hover-text-color);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
border-bottom: 1px solid var(--sidebar-border-color);
|
|
54
|
+
`;
|
|
30
55
|
const Wrapper = styled_components_1.default.div ``;
|
|
31
56
|
//# sourceMappingURL=SidebarLayout.js.map
|
package/lib/config.js
CHANGED
|
@@ -123,7 +123,7 @@ exports.ThemeConfig = zod_1.z
|
|
|
123
123
|
.object({
|
|
124
124
|
buttonText: zod_1.z.string().default('Copy').optional(),
|
|
125
125
|
tooltipText: zod_1.z.string().default('Copy to clipboard').optional(),
|
|
126
|
-
toasterText: zod_1.z.string().default('Copied').optional(),
|
|
126
|
+
toasterText: zod_1.z.string().default('Copied!').optional(),
|
|
127
127
|
toasterDuration: zod_1.z.number().default(1500).optional(),
|
|
128
128
|
})
|
|
129
129
|
.extend(HideConfig.shape)
|
|
@@ -136,7 +136,7 @@ exports.ThemeConfig = zod_1.z
|
|
|
136
136
|
})
|
|
137
137
|
.extend(HideConfig.shape)
|
|
138
138
|
.optional()
|
|
139
|
-
.default({}),
|
|
139
|
+
.default({ hide: true }),
|
|
140
140
|
})
|
|
141
141
|
.strict()
|
|
142
142
|
.default({})
|
package/lib/globalStyle.js
CHANGED
|
@@ -512,7 +512,7 @@ const sidebar = (0, styled_components_1.css) `
|
|
|
512
512
|
--sidebar-back-button-font-family: var(--sidebar-item-font-family);
|
|
513
513
|
--sidebar-back-button-font-size: var(--sidebar-item-font-size);
|
|
514
514
|
--sidebar-back-button-transform: inherit;
|
|
515
|
-
--sidebar-back-button-text-color: var(--
|
|
515
|
+
--sidebar-back-button-text-color: var(--link-text-color);
|
|
516
516
|
--sidebar-back-button-background-color: transparent;
|
|
517
517
|
--sidebar-back-button-hover-text-color: var(--sidebar-item-active-color);
|
|
518
518
|
--sidebar-back-button-hover-background-color: transparent;
|
|
@@ -1687,7 +1687,7 @@ const inputs = (0, styled_components_1.css) `
|
|
|
1687
1687
|
--input-border: none; // @presenter Border
|
|
1688
1688
|
--input-border-radius: var(--border-radius); // @presenter BorderRadius
|
|
1689
1689
|
--input-font-size: var(--font-size-base); // @presenter FontSize
|
|
1690
|
-
--input-font-family: var(--
|
|
1690
|
+
--input-font-family: var(--font-family-base); // @presenter FontFamily
|
|
1691
1691
|
--input-line-height: 1.15em; // @presenter LineHeight
|
|
1692
1692
|
--input-padding: 8px;
|
|
1693
1693
|
|
|
@@ -1697,6 +1697,8 @@ const inputs = (0, styled_components_1.css) `
|
|
|
1697
1697
|
--input-focus-text-color: var(--text-color-inverse); // @presenter Color
|
|
1698
1698
|
--input-placeholder-text-color: var(--text-color-inverse); // @presenter Color
|
|
1699
1699
|
|
|
1700
|
+
--checkbox-backround-color: var(--background-color);
|
|
1701
|
+
--checkbox-checked-backround-color: var(--color-primary-500);
|
|
1700
1702
|
// @tokens End
|
|
1701
1703
|
`;
|
|
1702
1704
|
const markdown = (0, styled_components_1.css) `
|
|
@@ -1899,7 +1901,7 @@ const pages = (0, styled_components_1.css) `
|
|
|
1899
1901
|
|
|
1900
1902
|
--page-404-font-family: var(--font-family-base); // @presenter FontFamily
|
|
1901
1903
|
|
|
1902
|
-
--page-404-header-text-color: #000;
|
|
1904
|
+
--page-404-header-text-color: #000;
|
|
1903
1905
|
--page-404-header-font-size: 14em; // @presenter FontSize
|
|
1904
1906
|
--page-404-header-font-weight: 600; // @presenter FontWeight
|
|
1905
1907
|
--page-404-header-line-height: 1.2; // @presenter LineHeight
|
|
@@ -1919,30 +1921,30 @@ const pages = (0, styled_components_1.css) `
|
|
|
1919
1921
|
* @tokens 403 Page
|
|
1920
1922
|
* @presenter Color
|
|
1921
1923
|
*/
|
|
1922
|
-
|
|
1924
|
+
|
|
1923
1925
|
--page-403-font-family: var(--font-family-base); // @presenter FontFamily
|
|
1924
|
-
|
|
1926
|
+
|
|
1925
1927
|
--page-403-header-text-color: #000;
|
|
1926
1928
|
--page-403-header-font-size: 14em; // @presenter FontSize
|
|
1927
1929
|
--page-403-header-font-weight: 600; // @presenter FontWeight
|
|
1928
1930
|
--page-403-header-line-height: 1.2; // @presenter LineHeight
|
|
1929
1931
|
--page-403-header-margin: 0; // @presenter Spacing
|
|
1930
|
-
|
|
1932
|
+
|
|
1931
1933
|
--page-403-description-text-color: #000;
|
|
1932
1934
|
--page-403-description-font-size: 2em; // @presenter FontSize
|
|
1933
1935
|
--page-403-description-font-weight: 400; // @presenter FontWeight
|
|
1934
1936
|
--page-403-description-line-height: 1; // @presenter LineHeight
|
|
1935
1937
|
--page-403-description-margin: 0; // @presenter Spacing
|
|
1936
|
-
|
|
1938
|
+
|
|
1937
1939
|
--page-403-button-margin: 4em; // @presenter Spacing
|
|
1938
|
-
|
|
1940
|
+
|
|
1939
1941
|
// @tokens End
|
|
1940
1942
|
`;
|
|
1941
1943
|
const modal = (0, styled_components_1.css) `
|
|
1942
|
-
body:has(
|
|
1944
|
+
body:has(.modal) {
|
|
1943
1945
|
overflow: hidden;
|
|
1944
1946
|
}
|
|
1945
|
-
|
|
1947
|
+
|
|
1946
1948
|
--modal-box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.6);
|
|
1947
1949
|
--modal-overlay-background-color: rgba(206, 206, 206, 0.49);
|
|
1948
1950
|
--modal-background-color: var(--background-color);
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ThemeUIConfig } from '../../config';
|
|
2
|
+
import type { ResolvedNavItem } from '@theme/types/portal';
|
|
3
|
+
import type { CatalogConfig, FilteredCatalog } from '@theme/types/portal/src/shared/types/catalog';
|
|
2
4
|
interface PageLink {
|
|
3
5
|
label: string;
|
|
4
6
|
link: string;
|
|
@@ -9,4 +11,6 @@ export declare function useSidebarSiblingsData(): {
|
|
|
9
11
|
nextPage: PageLink | null;
|
|
10
12
|
prevPage: PageLink | null;
|
|
11
13
|
};
|
|
14
|
+
export declare function usePageSharedData<T = unknown>(_id: string): T;
|
|
15
|
+
export declare function useCatalog(_items: ResolvedNavItem[], _config: CatalogConfig): FilteredCatalog;
|
|
12
16
|
export {};
|
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.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
3
|
+
exports.useCatalog = exports.usePageSharedData = exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
4
4
|
function useThemeConfig() {
|
|
5
5
|
return {
|
|
6
6
|
search: {
|
|
@@ -61,4 +61,12 @@ function useSidebarSiblingsData() {
|
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
exports.useSidebarSiblingsData = useSidebarSiblingsData;
|
|
64
|
+
function usePageSharedData(_id) {
|
|
65
|
+
throw new Error('Mock not implemented yet.');
|
|
66
|
+
}
|
|
67
|
+
exports.usePageSharedData = usePageSharedData;
|
|
68
|
+
function useCatalog(_items, _config) {
|
|
69
|
+
throw new Error('Mock not implemented yet.');
|
|
70
|
+
}
|
|
71
|
+
exports.useCatalog = useCatalog;
|
|
64
72
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const Checkbox: import("styled-components").StyledComponent<"input", any, {}, never>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Checkbox = void 0;
|
|
7
|
+
const styled_components_1 = __importDefault(require("styled-components"));
|
|
8
|
+
exports.Checkbox = styled_components_1.default.input `
|
|
9
|
+
position: absolute;
|
|
10
|
+
opacity: 0;
|
|
11
|
+
|
|
12
|
+
& + label {
|
|
13
|
+
position: relative;
|
|
14
|
+
cursor: pointer;
|
|
15
|
+
padding: 0;
|
|
16
|
+
display: flex;
|
|
17
|
+
|
|
18
|
+
div {
|
|
19
|
+
margin-top: 1px;
|
|
20
|
+
}
|
|
21
|
+
p {
|
|
22
|
+
line-height: 1.2;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&::before {
|
|
26
|
+
content: '';
|
|
27
|
+
margin-right: 10px;
|
|
28
|
+
display: inline-block;
|
|
29
|
+
vertical-align: top;
|
|
30
|
+
width: 18px;
|
|
31
|
+
height: 18px;
|
|
32
|
+
background: var(--checkbox-backround-color);
|
|
33
|
+
border: 1px solid rgba(0, 0, 0, 0.23);
|
|
34
|
+
border-radius: 2px;
|
|
35
|
+
flex-shrink: 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
&:focus + label:before {
|
|
40
|
+
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.12);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:checked + label {
|
|
44
|
+
&::before {
|
|
45
|
+
background: var(--checkbox-checked-backround-color);
|
|
46
|
+
}
|
|
47
|
+
&::after {
|
|
48
|
+
content: '';
|
|
49
|
+
position: absolute;
|
|
50
|
+
left: 5px;
|
|
51
|
+
top: 10px;
|
|
52
|
+
background: var(--checkbox-backround-color);
|
|
53
|
+
width: 2px;
|
|
54
|
+
height: 2px;
|
|
55
|
+
box-shadow: 2px 0 0 white, 4px 0 0 white, 4px -2px 0 white, 4px -4px 0 white, 4px -6px 0 white,
|
|
56
|
+
4px -8px 0 white;
|
|
57
|
+
transform: rotate(45deg);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&:disabled + label {
|
|
62
|
+
color: #b8b8b8;
|
|
63
|
+
cursor: auto;
|
|
64
|
+
&::before {
|
|
65
|
+
box-shadow: none;
|
|
66
|
+
background: #ddd;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
//# sourceMappingURL=Checkbox.js.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Highlight = exports.HighlightContext = void 0;
|
|
27
|
+
const React = __importStar(require("react"));
|
|
28
|
+
const highlight_words_core_1 = require("highlight-words-core");
|
|
29
|
+
exports.HighlightContext = React.createContext([]);
|
|
30
|
+
function Highlight(props) {
|
|
31
|
+
const { children } = props;
|
|
32
|
+
const searchWords = React.useContext(exports.HighlightContext);
|
|
33
|
+
if (!searchWords.length) {
|
|
34
|
+
return React.createElement(React.Fragment, null, "children") || null;
|
|
35
|
+
}
|
|
36
|
+
function highlight(str, childIdx = 0) {
|
|
37
|
+
const chunks = (0, highlight_words_core_1.findAll)({
|
|
38
|
+
searchWords,
|
|
39
|
+
textToHighlight: str,
|
|
40
|
+
});
|
|
41
|
+
return (React.createElement(React.Fragment, { key: childIdx }, chunks.map((chunk, idx) => {
|
|
42
|
+
const { end, highlight, start } = chunk;
|
|
43
|
+
const text = str.substr(start, end - start);
|
|
44
|
+
if (highlight) {
|
|
45
|
+
return React.createElement("mark", { key: idx }, text);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return text;
|
|
49
|
+
}
|
|
50
|
+
})));
|
|
51
|
+
}
|
|
52
|
+
if (typeof children === 'string') {
|
|
53
|
+
return highlight(children);
|
|
54
|
+
}
|
|
55
|
+
else if (Array.isArray(children)) {
|
|
56
|
+
return (React.createElement(React.Fragment, null, children.map((child, idx) => typeof children === 'string' ? highlight(child, idx) : child || null)));
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
return React.createElement(React.Fragment, null, "children") || null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.Highlight = Highlight;
|
|
63
|
+
//# sourceMappingURL=Highlight.js.map
|
package/lib/ui/darkColors.js
CHANGED
|
@@ -62,12 +62,14 @@ exports.darkMode = (0, styled_components_1.css) `
|
|
|
62
62
|
--tooltip-text-color: #fff;
|
|
63
63
|
--md-table-head-background-color: var(--color-secondary-300);
|
|
64
64
|
--md-tabs-hover-tab-border-color: var(--color-secondary-500);
|
|
65
|
-
--
|
|
66
|
-
--
|
|
65
|
+
--thin-tile-background-color: #1d242d;
|
|
66
|
+
--wide-tile-background-color: #1d242d;
|
|
67
67
|
--page-404-header-text-color: #fff;
|
|
68
68
|
--page-404-description-text-color: #fff;
|
|
69
69
|
--page-403-header-text-color: #fff;
|
|
70
70
|
--page-403-description-text-color: #fff;
|
|
71
|
+
--checkbox-backround-color: var(--color-secondary-900);
|
|
72
|
+
--checkbox-checked-backround-color: var(--color-primary-400);
|
|
71
73
|
|
|
72
74
|
background-color: var(--background-color);
|
|
73
75
|
color: var(--text-color);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "Shared UI components lib",
|
|
5
5
|
"author": "team@redocly.com",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"@testing-library/react": "^12.1.4",
|
|
64
64
|
"@testing-library/react-hooks": "^8.0.1",
|
|
65
65
|
"@testing-library/user-event": "^13.5.0",
|
|
66
|
+
"@types/highlight-words-core": "^1.2.1",
|
|
66
67
|
"@types/jest": "^29.2.1",
|
|
67
68
|
"@types/jest-when": "^3.5.2",
|
|
68
69
|
"@types/lodash.throttle": "^4.1.7",
|
|
@@ -103,7 +104,8 @@
|
|
|
103
104
|
},
|
|
104
105
|
"dependencies": {
|
|
105
106
|
"hotkeys-js": "^3.10.1",
|
|
106
|
-
"timeago.js": "^4.0.2"
|
|
107
|
+
"timeago.js": "^4.0.2",
|
|
108
|
+
"highlight-words-core": "^1.2.2"
|
|
107
109
|
},
|
|
108
110
|
"nx": {
|
|
109
111
|
"namedInputs": {
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { ResolvedNavItem } from '@redocly/theme/src/types/portal';
|
|
5
|
+
|
|
6
|
+
import type { CatalogConfig } from '@theme/types/portal/src/shared/types/catalog';
|
|
7
|
+
import { usePageSharedData } from '@portal/hooks/index.js';
|
|
8
|
+
import { H2 } from '@theme/Typography/H2';
|
|
9
|
+
import { H3 } from '@theme/Typography/H3';
|
|
10
|
+
import { Button } from '@theme/Button/Button';
|
|
11
|
+
import { HighlightContext } from '@theme/ui/Highlight';
|
|
12
|
+
import { CatalogCard } from '@theme/Catalog/CatalogCard';
|
|
13
|
+
import { Filter } from '@theme/Catalog/Filter';
|
|
14
|
+
import { useCatalog } from '@portal/hooks/index';
|
|
15
|
+
|
|
16
|
+
export default function Catalog(props: {
|
|
17
|
+
pageProps: {
|
|
18
|
+
catalogId: string;
|
|
19
|
+
catalogConfig: CatalogConfig;
|
|
20
|
+
};
|
|
21
|
+
}) {
|
|
22
|
+
const { catalogConfig } = props.pageProps;
|
|
23
|
+
const items = usePageSharedData('catalog') as ResolvedNavItem[];
|
|
24
|
+
|
|
25
|
+
const { filterTerm, setFilterTerm, groups, filters } = useCatalog(items, catalogConfig);
|
|
26
|
+
const [isFilterPanelFocused, setIsFilterPanelFocused] = React.useState(false);
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<HighlightContext.Provider value={[filterTerm]}>
|
|
30
|
+
<CatalogPageWrapper>
|
|
31
|
+
<CatalogPageSidebar isActiveInMobileMode={isFilterPanelFocused}>
|
|
32
|
+
<StyledInput
|
|
33
|
+
placeholder="Filter..."
|
|
34
|
+
value={filterTerm}
|
|
35
|
+
onFocus={() => setIsFilterPanelFocused(true)}
|
|
36
|
+
onChange={(e) => setFilterTerm(e.target.value)}
|
|
37
|
+
/>
|
|
38
|
+
{filters.map((filter, idx) => (
|
|
39
|
+
<Filter filter={filter} key={filter.property + '-' + idx} />
|
|
40
|
+
))}
|
|
41
|
+
<MobileStickyApplyFilters>
|
|
42
|
+
<Button color="secondary" onClick={() => setIsFilterPanelFocused(false)}>
|
|
43
|
+
Apply filters
|
|
44
|
+
</Button>
|
|
45
|
+
</MobileStickyApplyFilters>
|
|
46
|
+
</CatalogPageSidebar>
|
|
47
|
+
<CatalogPageContent>
|
|
48
|
+
{catalogConfig.title ? <CatalogTitle> {catalogConfig.title} </CatalogTitle> : null}
|
|
49
|
+
{catalogConfig.description ? (
|
|
50
|
+
<CatalogDescription> {catalogConfig.description} </CatalogDescription>
|
|
51
|
+
) : null}
|
|
52
|
+
{groups.map((group) => (
|
|
53
|
+
<React.Fragment key={group.title}>
|
|
54
|
+
<H3>
|
|
55
|
+
{group.title} ({group.items.length})
|
|
56
|
+
</H3>
|
|
57
|
+
<CatalogCards>
|
|
58
|
+
{group.items.map((item) => (
|
|
59
|
+
<CatalogCard item={item} key={item.link} />
|
|
60
|
+
))}
|
|
61
|
+
</CatalogCards>
|
|
62
|
+
</React.Fragment>
|
|
63
|
+
))}
|
|
64
|
+
</CatalogPageContent>
|
|
65
|
+
</CatalogPageWrapper>
|
|
66
|
+
</HighlightContext.Provider>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const MobileStickyApplyFilters = styled.div`
|
|
71
|
+
position: fixed;
|
|
72
|
+
display: none;
|
|
73
|
+
background-color: var(--sidebar-background-color);
|
|
74
|
+
bottom: 0;
|
|
75
|
+
padding: 16px 30px;
|
|
76
|
+
left: 0px;
|
|
77
|
+
right: 0px;
|
|
78
|
+
|
|
79
|
+
${Button} {
|
|
80
|
+
width: 100%;
|
|
81
|
+
margin: 0;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
const CatalogPageSidebar = styled.aside<{ isActiveInMobileMode?: boolean }>`
|
|
86
|
+
width: var(--sidebar-width);
|
|
87
|
+
border-right: 1px solid var(--sidebar-border-color);
|
|
88
|
+
padding: 20px 30px;
|
|
89
|
+
position: sticky;
|
|
90
|
+
top: var(--navbar-height);
|
|
91
|
+
height: calc(100vh - var(--navbar-height));
|
|
92
|
+
overflow: auto;
|
|
93
|
+
|
|
94
|
+
@media screen and (max-width: 767px) {
|
|
95
|
+
transition: height 0.2s ease-in-out;
|
|
96
|
+
width: 100%;
|
|
97
|
+
${({ isActiveInMobileMode }) =>
|
|
98
|
+
isActiveInMobileMode ? 'padding-bottom: 66px;' : 'height: 76px;'};
|
|
99
|
+
background-color: var(--sidebar-background-color);
|
|
100
|
+
border-bottom: 1px solid var(--sidebar-border-color);
|
|
101
|
+
z-index: 100;
|
|
102
|
+
|
|
103
|
+
${MobileStickyApplyFilters} {
|
|
104
|
+
display: ${({ isActiveInMobileMode }) => (isActiveInMobileMode ? 'block' : 'none')};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
`;
|
|
108
|
+
|
|
109
|
+
const CatalogPageContent = styled.main`
|
|
110
|
+
flex: 1;
|
|
111
|
+
padding: 32px;
|
|
112
|
+
`;
|
|
113
|
+
|
|
114
|
+
const CatalogCards = styled.div`
|
|
115
|
+
display: grid;
|
|
116
|
+
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
117
|
+
gap: 32px;
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const CatalogTitle = styled(H2)`
|
|
121
|
+
&& {
|
|
122
|
+
margin: 0;
|
|
123
|
+
}
|
|
124
|
+
`;
|
|
125
|
+
|
|
126
|
+
const CatalogDescription = styled.p`
|
|
127
|
+
margin: 16px 0 32px 0;
|
|
128
|
+
font-size: 16px;
|
|
129
|
+
color: var(--text-color-secondary);
|
|
130
|
+
`;
|
|
131
|
+
|
|
132
|
+
const CatalogPageWrapper = styled.div`
|
|
133
|
+
--sidebar-width: var(--catalog-sidebar-width, 300px);
|
|
134
|
+
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-direction: row;
|
|
137
|
+
|
|
138
|
+
font-weight: var(--font-weight-regular);
|
|
139
|
+
padding: 0;
|
|
140
|
+
|
|
141
|
+
color: var(--text-color);
|
|
142
|
+
font-size: var(--font-size-base);
|
|
143
|
+
font-family: var(--font-family-base);
|
|
144
|
+
line-height: var(--line-height-base);
|
|
145
|
+
|
|
146
|
+
hr {
|
|
147
|
+
border: 0;
|
|
148
|
+
width: calc(100% + 48px);
|
|
149
|
+
margin: auto -24px 0 -24px;
|
|
150
|
+
border-top: 1px solid var(--border-color);
|
|
151
|
+
}
|
|
152
|
+
a:not([role='button']) {
|
|
153
|
+
text-decoration: none;
|
|
154
|
+
color: var(--link-text-color);
|
|
155
|
+
font-weight: var(--link-font-weight);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@media screen and (max-width: 767px) {
|
|
159
|
+
flex-direction: column;
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
|
|
163
|
+
// TODO: merge this input with the input from reference docs
|
|
164
|
+
// the on in ref docs is dark, needs separate variables most likely
|
|
165
|
+
const StyledInput = styled.input`
|
|
166
|
+
border: 1px solid rgba(0, 0, 0, 0.23);
|
|
167
|
+
min-width: 200px;
|
|
168
|
+
outline-color: var(--color-primary-500);
|
|
169
|
+
width: 100%;
|
|
170
|
+
|
|
171
|
+
outline: none;
|
|
172
|
+
padding: var(--input-padding);
|
|
173
|
+
border-radius: var(--input-border-radius);
|
|
174
|
+
background-color: var(--input-background-color);
|
|
175
|
+
color: var(--text-color);
|
|
176
|
+
font-family: var(--input-font-family);
|
|
177
|
+
font-size: var(--input-font-size);
|
|
178
|
+
line-height: var(--input-line-height);
|
|
179
|
+
|
|
180
|
+
&::placeholder {
|
|
181
|
+
opacity: 0.6;
|
|
182
|
+
color: var(--text-color);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
&:hover {
|
|
186
|
+
color: var(--text-color);
|
|
187
|
+
border: 1px solid rgba(0, 0, 0, 0.23);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
&:focus {
|
|
191
|
+
color: var(--text-color);
|
|
192
|
+
border: 1px solid rgba(0, 0, 0, 0.23);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
&:-webkit-autofill {
|
|
196
|
+
background-color: var(--input-background-color);
|
|
197
|
+
}
|
|
198
|
+
`;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { CatalogItem } from '@theme/types/portal/src/shared/types/catalog';
|
|
5
|
+
import { Link } from '@portal/Link';
|
|
6
|
+
import { Highlight } from '@theme/ui/Highlight';
|
|
7
|
+
import { Tags } from '@theme/Catalog/Tags';
|
|
8
|
+
|
|
9
|
+
export function CatalogCard({ item }: { item: CatalogItem }): JSX.Element {
|
|
10
|
+
return (
|
|
11
|
+
<Link key={item.docsLink || item.link} to={item.docsLink || item.link}>
|
|
12
|
+
<StyledCard>
|
|
13
|
+
<CardTitle>
|
|
14
|
+
<Highlight>{item.title}</Highlight>
|
|
15
|
+
</CardTitle>
|
|
16
|
+
{/* <div>{item.image}</div> */}
|
|
17
|
+
<CardDescription>
|
|
18
|
+
<Highlight>{item.description ?? ''}</Highlight>
|
|
19
|
+
</CardDescription>
|
|
20
|
+
{item.tags ? <Tags tags={item.tags as string[]} /> : null}
|
|
21
|
+
<hr />
|
|
22
|
+
<CardFooter>View documentation</CardFooter>
|
|
23
|
+
</StyledCard>
|
|
24
|
+
</Link>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const StyledCard = styled.div`
|
|
29
|
+
min-height: 268px;
|
|
30
|
+
height: 100%;
|
|
31
|
+
box-shadow: var(--box-shadow);
|
|
32
|
+
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
|
|
36
|
+
color: var(--text-color);
|
|
37
|
+
background-color: var(--thin-tile-background-color);
|
|
38
|
+
border-radius: 4px;
|
|
39
|
+
|
|
40
|
+
border: 1px solid var(--border-color);
|
|
41
|
+
box-shadow: 0px 0px 10px 0px rgba(35, 35, 35, 0.05);
|
|
42
|
+
transition: all 0.2s ease-in-out;
|
|
43
|
+
|
|
44
|
+
&:hover {
|
|
45
|
+
/* box-shadow: 0px 12px 30px 0px rgba(35, 35, 35, 0.2); */
|
|
46
|
+
box-shadow: 0px 10px 30px 0px rgba(35, 35, 35, 0.1);
|
|
47
|
+
border: 1px solid var(--border-color);
|
|
48
|
+
transform: translateY(-2px);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
border-radius: 8px;
|
|
52
|
+
width: 100%;
|
|
53
|
+
padding: 24px 24px 0;
|
|
54
|
+
display: flex;
|
|
55
|
+
flex-direction: column;
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
const CardTitle = styled.h4`
|
|
60
|
+
line-height: 26px;
|
|
61
|
+
letter-spacing: 0.8px;
|
|
62
|
+
font-size: 20px;
|
|
63
|
+
font-weight: var(--font-weight-bold);
|
|
64
|
+
margin: 0;
|
|
65
|
+
margin-bottom: 16px;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const CardDescription = styled.div`
|
|
69
|
+
display: -webkit-box;
|
|
70
|
+
-webkit-line-clamp: 3;
|
|
71
|
+
-webkit-box-orient: vertical;
|
|
72
|
+
overflow: hidden;
|
|
73
|
+
text-overflow: ellipsis;
|
|
74
|
+
line-height: var(--line-height);
|
|
75
|
+
letter-spacing: 0px;
|
|
76
|
+
font-size: 16px;
|
|
77
|
+
color: var(--text-color-secondary);
|
|
78
|
+
text-align: inherit;
|
|
79
|
+
font-weight: 400;
|
|
80
|
+
`;
|
|
81
|
+
|
|
82
|
+
const CardFooter = styled.div`
|
|
83
|
+
height: 46px;
|
|
84
|
+
display: flex;
|
|
85
|
+
align-items: flex-start;
|
|
86
|
+
justify-content: center;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
font-size: 16px;
|
|
89
|
+
font-weight: var(--font-weight-bold);
|
|
90
|
+
|
|
91
|
+
a:hover & {
|
|
92
|
+
text-decoration: var(--link-hover-text-decoration);
|
|
93
|
+
color: var(--link-hover-text-color);
|
|
94
|
+
}
|
|
95
|
+
`;
|