@redocly/theme 0.6.4 → 0.7.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/Feedback/Comment.d.ts +3 -0
- package/lib/Feedback/Comment.js +80 -0
- package/lib/Feedback/Rating.d.ts +3 -0
- package/lib/Feedback/Rating.js +82 -0
- package/lib/Feedback/Reasons.d.ts +3 -0
- package/lib/Feedback/Reasons.js +85 -0
- package/lib/Feedback/Sentiment.d.ts +3 -0
- package/lib/Feedback/Sentiment.js +79 -0
- package/lib/Feedback/Thumbs.d.ts +7 -0
- package/lib/Feedback/Thumbs.js +79 -0
- package/lib/Feedback/index.d.ts +5 -0
- package/lib/Feedback/index.js +27 -0
- package/lib/Feedback/types.d.ts +71 -0
- package/lib/Feedback/types.js +3 -0
- package/lib/Markdown/MarkdownLayout.d.ts +2 -1
- package/lib/Markdown/MarkdownLayout.js +8 -2
- package/lib/Markdown/Tabs/Tab.js +11 -5
- package/lib/Markdown/Tabs/Tabs.js +14 -5
- package/lib/Navbar/Navbar.js +6 -3
- package/lib/Pages/Forbidden.d.ts +2 -0
- package/lib/Pages/Forbidden.js +39 -0
- package/lib/Pages/NotFound.d.ts +2 -0
- package/lib/Pages/NotFound.js +39 -0
- package/lib/Pages/index.d.ts +1 -0
- package/lib/Pages/index.js +18 -0
- package/lib/Profile/LoginLink.d.ts +5 -0
- package/lib/Profile/LoginLink.js +30 -0
- package/lib/Profile/Profile.js +3 -1
- package/lib/Profile/UserProfile.d.ts +13 -0
- package/lib/Profile/UserProfile.js +82 -0
- package/lib/Profile/index.d.ts +4 -0
- package/lib/Profile/index.js +5 -1
- package/lib/Search/Autocomplete.d.ts +4 -1
- package/lib/Search/Autocomplete.js +19 -3
- package/lib/Search/ClearIcon.js +1 -1
- package/lib/Search/Input.js +1 -1
- package/lib/Search/Search.js +6 -1
- package/lib/Search/SearchIcon.js +1 -1
- package/lib/Search/ShortcutKey.d.ts +7 -0
- package/lib/Search/ShortcutKey.js +35 -0
- package/lib/config.d.ts +61 -0
- package/lib/config.js +19 -0
- package/lib/globalStyle.js +62 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/mocks/Link.js +1 -1
- package/lib/mocks/hooks/index.js +11 -1
- package/lib/mocks/search.js +18 -5
- package/lib/ui/Box.d.ts +2 -2
- package/lib/ui/Box.js +1 -0
- package/lib/ui/darkColors.js +5 -0
- package/package.json +9 -5
- package/src/Feedback/Comment.tsx +64 -0
- package/src/Feedback/Rating.tsx +107 -0
- package/src/Feedback/Reasons.tsx +81 -0
- package/src/Feedback/Sentiment.tsx +75 -0
- package/src/Feedback/Thumbs.tsx +116 -0
- package/src/Feedback/index.ts +5 -0
- package/src/Feedback/types.ts +63 -0
- package/src/Markdown/MarkdownLayout.tsx +10 -1
- package/src/Markdown/Tabs/Tab.tsx +11 -5
- package/src/Markdown/Tabs/Tabs.tsx +14 -5
- package/src/Navbar/Navbar.tsx +8 -3
- package/src/Pages/Forbidden.tsx +42 -0
- package/src/Pages/NotFound.tsx +42 -0
- package/src/Pages/index.ts +1 -0
- package/src/Profile/LoginLink.tsx +29 -0
- package/src/Profile/Profile.tsx +3 -1
- package/src/Profile/UserProfile.tsx +101 -0
- package/src/Profile/index.ts +4 -0
- package/src/Search/Autocomplete.tsx +26 -2
- package/src/Search/ClearIcon.tsx +1 -1
- package/src/Search/Input.tsx +1 -1
- package/src/Search/Search.tsx +3 -0
- package/src/Search/SearchIcon.tsx +1 -1
- package/src/Search/ShortcutKey.tsx +35 -0
- package/src/config.ts +23 -0
- package/src/globalStyle.ts +64 -0
- package/src/index.ts +2 -0
- package/src/mocks/Link.tsx +2 -1
- package/src/mocks/hooks/index.ts +11 -1
- package/src/mocks/search.ts +20 -5
- package/src/settings.yaml +2 -0
- package/src/types/portal/index.d.ts +1 -1
- package/src/ui/Box.tsx +5 -2
- package/src/ui/darkColors.tsx +5 -0
package/lib/globalStyle.js
CHANGED
|
@@ -1784,6 +1784,16 @@ const markdown = (0, styled_components_1.css) `
|
|
|
1784
1784
|
--md-numbered-list-number-padding: 0 5px; // @presenter Spacing
|
|
1785
1785
|
|
|
1786
1786
|
// @tokens End
|
|
1787
|
+
|
|
1788
|
+
/**
|
|
1789
|
+
* @tokens Markdown Tabs
|
|
1790
|
+
*/
|
|
1791
|
+
|
|
1792
|
+
--md-tabs-tab-text-color: var(--color-emphasis-600); // @presenter Color
|
|
1793
|
+
--md-tabs-active-tab-border-color: var(--text-color); // @presenter Color
|
|
1794
|
+
--md-tabs-hover-tab-border-color: var(--text-color-secondary); // @presenter Color
|
|
1795
|
+
|
|
1796
|
+
// @tokens End
|
|
1787
1797
|
`;
|
|
1788
1798
|
const search = (0, styled_components_1.css) `
|
|
1789
1799
|
/**
|
|
@@ -1878,6 +1888,56 @@ const tile = (0, styled_components_1.css) `
|
|
|
1878
1888
|
--wide-tile-background-color: var(--color-secondary-50);
|
|
1879
1889
|
--thin-tile-background-color: var(--color-secondary-50);
|
|
1880
1890
|
`;
|
|
1891
|
+
const apiLogsTable = (0, styled_components_1.css) `
|
|
1892
|
+
--api-logs-row-hover-background-color: var(--color-secondary-300);
|
|
1893
|
+
`;
|
|
1894
|
+
const pages = (0, styled_components_1.css) `
|
|
1895
|
+
/**
|
|
1896
|
+
* @tokens 404 Page
|
|
1897
|
+
* @presenter Color
|
|
1898
|
+
*/
|
|
1899
|
+
|
|
1900
|
+
--page-404-font-family: var(--font-family-base); // @presenter FontFamily
|
|
1901
|
+
|
|
1902
|
+
--page-404-header-text-color: #000;
|
|
1903
|
+
--page-404-header-font-size: 14em; // @presenter FontSize
|
|
1904
|
+
--page-404-header-font-weight: 600; // @presenter FontWeight
|
|
1905
|
+
--page-404-header-line-height: 1.2; // @presenter LineHeight
|
|
1906
|
+
--page-404-header-margin: 0; // @presenter Spacing
|
|
1907
|
+
|
|
1908
|
+
--page-404-description-text-color: #000;
|
|
1909
|
+
--page-404-description-font-size: 2em; // @presenter FontSize
|
|
1910
|
+
--page-404-description-font-weight: 400; // @presenter FontWeight
|
|
1911
|
+
--page-404-description-line-height: 1; // @presenter LineHeight
|
|
1912
|
+
--page-404-description-margin: 0; // @presenter Spacing
|
|
1913
|
+
|
|
1914
|
+
--page-404-button-margin: 4em; // @presenter Spacing
|
|
1915
|
+
|
|
1916
|
+
// @tokens End
|
|
1917
|
+
|
|
1918
|
+
/**
|
|
1919
|
+
* @tokens 403 Page
|
|
1920
|
+
* @presenter Color
|
|
1921
|
+
*/
|
|
1922
|
+
|
|
1923
|
+
--page-403-font-family: var(--font-family-base); // @presenter FontFamily
|
|
1924
|
+
|
|
1925
|
+
--page-403-header-text-color: #000;
|
|
1926
|
+
--page-403-header-font-size: 14em; // @presenter FontSize
|
|
1927
|
+
--page-403-header-font-weight: 600; // @presenter FontWeight
|
|
1928
|
+
--page-403-header-line-height: 1.2; // @presenter LineHeight
|
|
1929
|
+
--page-403-header-margin: 0; // @presenter Spacing
|
|
1930
|
+
|
|
1931
|
+
--page-403-description-text-color: #000;
|
|
1932
|
+
--page-403-description-font-size: 2em; // @presenter FontSize
|
|
1933
|
+
--page-403-description-font-weight: 400; // @presenter FontWeight
|
|
1934
|
+
--page-403-description-line-height: 1; // @presenter LineHeight
|
|
1935
|
+
--page-403-description-margin: 0; // @presenter Spacing
|
|
1936
|
+
|
|
1937
|
+
--page-403-button-margin: 4em; // @presenter Spacing
|
|
1938
|
+
|
|
1939
|
+
// @tokens End
|
|
1940
|
+
`;
|
|
1881
1941
|
exports.styles = (0, styled_components_1.css) `
|
|
1882
1942
|
:root {
|
|
1883
1943
|
${baseColors}
|
|
@@ -1906,6 +1966,8 @@ exports.styles = (0, styled_components_1.css) `
|
|
|
1906
1966
|
${lastUpdated}
|
|
1907
1967
|
${tile}
|
|
1908
1968
|
${loadProgressBar}
|
|
1969
|
+
${apiLogsTable}
|
|
1970
|
+
${pages}
|
|
1909
1971
|
}
|
|
1910
1972
|
|
|
1911
1973
|
:root.dark {
|
package/lib/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from './Tooltip';
|
|
|
10
10
|
export * from './SourceCode';
|
|
11
11
|
export * from './Panel';
|
|
12
12
|
export * from './icons';
|
|
13
|
+
export * from './Feedback';
|
|
13
14
|
export * from './hooks';
|
|
14
15
|
export * from './utils';
|
|
15
16
|
export * from './globalStyle';
|
|
@@ -20,3 +21,4 @@ export * from './ColorModeSwitcher';
|
|
|
20
21
|
export * from './Sidebar';
|
|
21
22
|
export * from './types/config';
|
|
22
23
|
export * from './config';
|
|
24
|
+
export * from './Pages';
|
package/lib/index.js
CHANGED
|
@@ -26,6 +26,7 @@ __exportStar(require("./Tooltip"), exports);
|
|
|
26
26
|
__exportStar(require("./SourceCode"), exports);
|
|
27
27
|
__exportStar(require("./Panel"), exports);
|
|
28
28
|
__exportStar(require("./icons"), exports);
|
|
29
|
+
__exportStar(require("./Feedback"), exports);
|
|
29
30
|
__exportStar(require("./hooks"), exports);
|
|
30
31
|
__exportStar(require("./utils"), exports);
|
|
31
32
|
__exportStar(require("./globalStyle"), exports);
|
|
@@ -36,4 +37,5 @@ __exportStar(require("./ColorModeSwitcher"), exports);
|
|
|
36
37
|
__exportStar(require("./Sidebar"), exports);
|
|
37
38
|
__exportStar(require("./types/config"), exports);
|
|
38
39
|
__exportStar(require("./config"), exports);
|
|
40
|
+
__exportStar(require("./Pages"), exports);
|
|
39
41
|
//# sourceMappingURL=index.js.map
|
package/lib/mocks/Link.js
CHANGED
|
@@ -21,7 +21,7 @@ const react_1 = __importDefault(require("react"));
|
|
|
21
21
|
function Link(props) {
|
|
22
22
|
const { active: _, httpVerb: _1, hasActiveSubItem: _2, routeSlug: _3, external: _4 } = props, filteredProps = __rest(props, ["active", "httpVerb", "hasActiveSubItem", "routeSlug", "external"]);
|
|
23
23
|
// We omit "active" property to avoid "Warning: Received `false` for a non-boolean attribute `active`."
|
|
24
|
-
return react_1.default.createElement("a", Object.assign({ href: filteredProps.to }, filteredProps));
|
|
24
|
+
return react_1.default.createElement("a", Object.assign({ href: filteredProps.to, ref: filteredProps.innerRef }, filteredProps));
|
|
25
25
|
}
|
|
26
26
|
exports.Link = Link;
|
|
27
27
|
//# sourceMappingURL=Link.js.map
|
package/lib/mocks/hooks/index.js
CHANGED
|
@@ -3,7 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.useSidebarSiblingsData = exports.useThemeConfig = void 0;
|
|
4
4
|
function useThemeConfig() {
|
|
5
5
|
return {
|
|
6
|
-
search: {
|
|
6
|
+
search: {
|
|
7
|
+
hide: false,
|
|
8
|
+
placement: 'navbar',
|
|
9
|
+
shortcuts: ['ctrl+f', 'cmd+k', '/'],
|
|
10
|
+
},
|
|
7
11
|
markdown: {
|
|
8
12
|
toc: { depth: 3, header: 'Table of contents', hide: false },
|
|
9
13
|
lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
|
|
@@ -27,6 +31,12 @@ function useThemeConfig() {
|
|
|
27
31
|
colorMode: {
|
|
28
32
|
modes: ['light', 'dark'],
|
|
29
33
|
},
|
|
34
|
+
feedback: {
|
|
35
|
+
type: 'sentiment',
|
|
36
|
+
},
|
|
37
|
+
userProfile: {
|
|
38
|
+
hide: false,
|
|
39
|
+
},
|
|
30
40
|
};
|
|
31
41
|
}
|
|
32
42
|
exports.useThemeConfig = useThemeConfig;
|
package/lib/mocks/search.js
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useFuseSearch = void 0;
|
|
4
|
+
const react_1 = require("react");
|
|
4
5
|
function useFuseSearch() {
|
|
6
|
+
const [query, setQuery] = (0, react_1.useState)('');
|
|
5
7
|
return {
|
|
6
|
-
query
|
|
7
|
-
setQuery
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
query,
|
|
9
|
+
setQuery,
|
|
10
|
+
items: [
|
|
11
|
+
{
|
|
12
|
+
id: '1',
|
|
13
|
+
url: '#someUrl1',
|
|
14
|
+
title: 'Some Dummy Result Item 1',
|
|
15
|
+
text: 'Some sample search text',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: '2',
|
|
19
|
+
url: '#someUrl2',
|
|
20
|
+
title: 'Some Dummy Result Item 2',
|
|
21
|
+
text: 'Some sample search text 2',
|
|
22
|
+
},
|
|
23
|
+
],
|
|
11
24
|
};
|
|
12
25
|
}
|
|
13
26
|
exports.useFuseSearch = useFuseSearch;
|
package/lib/ui/Box.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SpaceProps, LayoutProps, TextAlignProps, ColorProps, PositionProps, FlexProps, BordersProps } from 'styled-system';
|
|
2
|
-
export interface BoxProps extends SpaceProps, LayoutProps, PositionProps, FlexProps, TextAlignProps, ColorProps, BordersProps {
|
|
1
|
+
import type { SpaceProps, LayoutProps, TextAlignProps, ColorProps, PositionProps, FlexProps, BordersProps, GridProps } from 'styled-system';
|
|
2
|
+
export interface BoxProps extends SpaceProps, LayoutProps, PositionProps, FlexProps, TextAlignProps, ColorProps, BordersProps, GridProps {
|
|
3
3
|
}
|
|
4
4
|
export declare const Box: import("styled-components").StyledComponent<"div", any, {
|
|
5
5
|
'data-component-name': string;
|
package/lib/ui/Box.js
CHANGED
package/lib/ui/darkColors.js
CHANGED
|
@@ -61,8 +61,13 @@ exports.darkMode = (0, styled_components_1.css) `
|
|
|
61
61
|
--copy-button-tooltip-background-color: var(--tooltip-background-color);
|
|
62
62
|
--tooltip-text-color: #fff;
|
|
63
63
|
--md-table-head-background-color: var(--color-secondary-300);
|
|
64
|
+
--md-tabs-hover-tab-border-color: var(--color-secondary-500);
|
|
64
65
|
--wide-tile-background-color: #000000;
|
|
65
66
|
--thin-tile-background-color: #000000;
|
|
67
|
+
--page-404-header-text-color: #fff;
|
|
68
|
+
--page-404-description-text-color: #fff;
|
|
69
|
+
--page-403-header-text-color: #fff;
|
|
70
|
+
--page-403-description-text-color: #fff;
|
|
66
71
|
|
|
67
72
|
background-color: var(--background-color);
|
|
68
73
|
color: var(--text-color);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/theme",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Shared UI components",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Shared UI components lib",
|
|
5
5
|
"author": "team@redocly.com",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
7
7
|
"main": "lib/index.js",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"prismjs": "^1.28.0",
|
|
40
40
|
"react": "^17.0.2",
|
|
41
41
|
"react-dom": "^17.0.2",
|
|
42
|
+
"react-router": "^5.3.0",
|
|
42
43
|
"react-router-dom": "^5.3.0",
|
|
43
44
|
"styled-components": "^5.3.6",
|
|
44
45
|
"styled-system": "^5.1.5",
|
|
@@ -65,16 +66,18 @@
|
|
|
65
66
|
"@types/jest": "^29.2.1",
|
|
66
67
|
"@types/jest-when": "^3.5.2",
|
|
67
68
|
"@types/lodash.throttle": "^4.1.7",
|
|
68
|
-
"@types/node": "^
|
|
69
|
+
"@types/node": "^18.11.18",
|
|
69
70
|
"@types/prismjs": "^1.26.0",
|
|
70
71
|
"@types/react": "^17.0.43",
|
|
71
72
|
"@types/react-dom": "^17.0.14",
|
|
72
|
-
"@types/react-router-dom": "^5.3.
|
|
73
|
+
"@types/react-router-dom": "^5.3.3",
|
|
74
|
+
"@types/react-router": "^5.1.20",
|
|
73
75
|
"@types/styled-components": "^5.1.26",
|
|
74
76
|
"@types/styled-system": "^5.1.13",
|
|
75
77
|
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
|
76
78
|
"@typescript-eslint/parser": "^5.23.0",
|
|
77
79
|
"chromatic": "^6.10.2",
|
|
80
|
+
"concurrently": "^7.4.0",
|
|
78
81
|
"esbuild": "^0.15.11",
|
|
79
82
|
"jest": "^29.2.2",
|
|
80
83
|
"jest-environment-jsdom": "^29.2.2",
|
|
@@ -83,6 +86,7 @@
|
|
|
83
86
|
"lodash.throttle": "^4.1.1",
|
|
84
87
|
"npm-run-all": "^4.1.5",
|
|
85
88
|
"react-refresh": "^0.14.0",
|
|
89
|
+
"react-router": "^5.3.0",
|
|
86
90
|
"react-router-dom": "^5.3.0",
|
|
87
91
|
"storybook-addon-pseudo-states": "^1.15.1",
|
|
88
92
|
"storybook-design-token": "^2.7.1",
|
|
@@ -95,10 +99,10 @@
|
|
|
95
99
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
|
96
100
|
"typescript": "^4.8.4",
|
|
97
101
|
"webpack": "^5.72.0",
|
|
98
|
-
"concurrently": "^7.4.0",
|
|
99
102
|
"zod": ">=3.19.1"
|
|
100
103
|
},
|
|
101
104
|
"dependencies": {
|
|
105
|
+
"hotkeys-js": "^3.10.1",
|
|
102
106
|
"timeago.js": "^4.0.2"
|
|
103
107
|
},
|
|
104
108
|
"nx": {
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Button } from '@theme';
|
|
4
|
+
|
|
5
|
+
import type { CommentProps } from '@theme/Feedback';
|
|
6
|
+
|
|
7
|
+
export const Comment = ({ settings, onSubmit }: CommentProps): JSX.Element => {
|
|
8
|
+
const { label, submitText } = settings || {};
|
|
9
|
+
const [text, setText] = React.useState('');
|
|
10
|
+
const [submitValue, setSubmitValue] = React.useState('');
|
|
11
|
+
|
|
12
|
+
const send = () => {
|
|
13
|
+
if (!text) return;
|
|
14
|
+
setSubmitValue(text);
|
|
15
|
+
onSubmit({ comment: text });
|
|
16
|
+
};
|
|
17
|
+
const handleTextAreaChange = (e: any) => {
|
|
18
|
+
setText(e.target.value);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (submitValue) {
|
|
22
|
+
return (
|
|
23
|
+
<Wrapper>
|
|
24
|
+
<Label>{submitText || 'Thank you for helping improve our documentation!'}</Label>
|
|
25
|
+
</Wrapper>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Wrapper data-component-name="Feedback/Comment">
|
|
31
|
+
<Label>{label || 'Please share your feedback with us:'}</Label>
|
|
32
|
+
<TextArea rows={3} onChange={handleTextAreaChange} />
|
|
33
|
+
<SendButton onClick={send}>Send</SendButton>
|
|
34
|
+
</Wrapper>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const Wrapper = styled.div`
|
|
39
|
+
font-family: var(--font-family-base);
|
|
40
|
+
display: flex;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
width: 100%;
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const Label = styled.h3`
|
|
46
|
+
margin-right: 15px;
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
const TextArea = styled.textarea`
|
|
50
|
+
font-family: var(--font-family-base);
|
|
51
|
+
border: 1px solid #ccc;
|
|
52
|
+
border-radius: 5px;
|
|
53
|
+
color: black;
|
|
54
|
+
margin: 0 0 10px 0;
|
|
55
|
+
padding: 10px;
|
|
56
|
+
`;
|
|
57
|
+
|
|
58
|
+
const SendButton = styled(Button).attrs(() => ({
|
|
59
|
+
color: 'primary',
|
|
60
|
+
}))`
|
|
61
|
+
width: 100px;
|
|
62
|
+
margin-left: 0;
|
|
63
|
+
margin-right: 0;
|
|
64
|
+
`;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { RatingProps, ReasonsProps } from '@theme/Feedback';
|
|
5
|
+
import { Comment, Reasons } from '@theme/Feedback';
|
|
6
|
+
|
|
7
|
+
type StarsProps = {
|
|
8
|
+
onSubmit: (value: number) => void;
|
|
9
|
+
max: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Rating = ({ settings, onSubmit }: RatingProps): JSX.Element => {
|
|
13
|
+
const {
|
|
14
|
+
label,
|
|
15
|
+
max,
|
|
16
|
+
submitText,
|
|
17
|
+
comment: commentSettings,
|
|
18
|
+
reasons: reasonsSettings,
|
|
19
|
+
} = settings || {};
|
|
20
|
+
const [score, setScore] = React.useState(0);
|
|
21
|
+
const [comment, setComment] = React.useState('');
|
|
22
|
+
const [reasons, setReasons] = React.useState([] as ReasonsProps['settings']['items']);
|
|
23
|
+
|
|
24
|
+
if (score && reasonsSettings?.enable && !reasons.length) {
|
|
25
|
+
const { label: reasonsLabel, items, multi } = reasonsSettings;
|
|
26
|
+
const buttonText = commentSettings?.enable ? 'Next' : 'Send';
|
|
27
|
+
return (
|
|
28
|
+
<Reasons
|
|
29
|
+
onSubmit={({ reasons }) => setReasons(reasons)}
|
|
30
|
+
settings={{ label: reasonsLabel, items, multi, buttonText }}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (score && commentSettings?.enable && !comment) {
|
|
36
|
+
return (
|
|
37
|
+
<Comment
|
|
38
|
+
onSubmit={({ comment }) => setComment(comment)}
|
|
39
|
+
settings={{ label: commentSettings.label }}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (score) {
|
|
45
|
+
onSubmit({
|
|
46
|
+
score,
|
|
47
|
+
comment,
|
|
48
|
+
reasons,
|
|
49
|
+
});
|
|
50
|
+
return (
|
|
51
|
+
<Wrapper>
|
|
52
|
+
<Label>{submitText || 'Thank you for helping improve our documentation!'}</Label>
|
|
53
|
+
</Wrapper>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Wrapper data-component-name="Feedback/Rating">
|
|
59
|
+
<Label>{label || 'How helpful was this page?'}</Label>
|
|
60
|
+
<Stars max={max || 5} onSubmit={setScore} />
|
|
61
|
+
</Wrapper>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const Stars = ({ max, onSubmit }: StarsProps): JSX.Element => {
|
|
66
|
+
const [hovered, setHovered] = React.useState(0);
|
|
67
|
+
const stars: JSX.Element[] = [];
|
|
68
|
+
|
|
69
|
+
for (let index = 1; index <= max; index++) {
|
|
70
|
+
stars.push(
|
|
71
|
+
<Star
|
|
72
|
+
key={index}
|
|
73
|
+
onClick={() => onSubmit(index)}
|
|
74
|
+
onMouseOver={() => setHovered(index)}
|
|
75
|
+
onMouseLeave={() => setHovered(0)}
|
|
76
|
+
>
|
|
77
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
|
78
|
+
{hovered < index ? (
|
|
79
|
+
<g fill="#e8c002">
|
|
80
|
+
<path d="M20 7h-7L10 .5 7 7H0l5.46 5.47-1.64 7 6.18-3.7 6.18 3.73-1.63-7zm-10 6.9-3.76 2.27 1-4.28L3.5 8.5h4.61L10 4.6l1.9 3.9h4.6l-3.73 3.4 1 4.28z" />
|
|
81
|
+
</g>
|
|
82
|
+
) : (
|
|
83
|
+
<g fill="#e8c002">
|
|
84
|
+
<path d="M20 7h-7L10 .5 7 7H0l5.46 5.47-1.64 7 6.18-3.7 6.18 3.73-1.63-7z" />
|
|
85
|
+
</g>
|
|
86
|
+
)}
|
|
87
|
+
</svg>
|
|
88
|
+
</Star>,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return <>{stars}</>;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const Wrapper = styled.div`
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
`;
|
|
99
|
+
|
|
100
|
+
const Star = styled.span`
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
`;
|
|
103
|
+
|
|
104
|
+
const Label = styled.h3`
|
|
105
|
+
margin-right: 15px;
|
|
106
|
+
font-family: var(--font-family-base);
|
|
107
|
+
`;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
import { Button } from '@theme';
|
|
4
|
+
|
|
5
|
+
import type { ReasonsProps } from '@theme/Feedback';
|
|
6
|
+
|
|
7
|
+
export const Reasons = ({ settings, onSubmit }: ReasonsProps): JSX.Element => {
|
|
8
|
+
const { label, multi, buttonText, items = [] } = settings;
|
|
9
|
+
const [checkedState, setCheckedState] = React.useState(new Array(items.length).fill(false));
|
|
10
|
+
|
|
11
|
+
if (!items.length) {
|
|
12
|
+
return <></>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const input_type = multi ? 'checkbox' : 'radio';
|
|
16
|
+
|
|
17
|
+
const handleOptionChange = (position: number) => {
|
|
18
|
+
const updatedCheckedState = multi
|
|
19
|
+
? checkedState.map((item, index) => (index === position ? !item : item))
|
|
20
|
+
: items.map((_, idx) => position === idx);
|
|
21
|
+
|
|
22
|
+
setCheckedState(updatedCheckedState);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const submitForm = () => {
|
|
26
|
+
onSubmit({ reasons: items.filter((_, index) => !!checkedState[index]) });
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Wrapper data-component-name="Feedback/Reasons">
|
|
31
|
+
<Label>{label || 'Which statement describes your thoughts about this page?'}</Label>
|
|
32
|
+
{items.map((reason, idx) => (
|
|
33
|
+
<OptionWrapper key={reason}>
|
|
34
|
+
<input
|
|
35
|
+
type={input_type}
|
|
36
|
+
value={reason}
|
|
37
|
+
checked={checkedState[idx]}
|
|
38
|
+
name="reasons"
|
|
39
|
+
onChange={() => handleOptionChange(idx)}
|
|
40
|
+
/>
|
|
41
|
+
<label id={reason} onClick={() => handleOptionChange(idx)}>
|
|
42
|
+
{reason}
|
|
43
|
+
</label>
|
|
44
|
+
</OptionWrapper>
|
|
45
|
+
))}
|
|
46
|
+
<SendButton onClick={submitForm}>{buttonText || 'Send'}</SendButton>
|
|
47
|
+
</Wrapper>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const Wrapper = styled.div`
|
|
52
|
+
font-family: var(--font-family-base);
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
const Label = styled.h3`
|
|
58
|
+
margin-right: 15px;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const SendButton = styled(Button).attrs(() => ({
|
|
62
|
+
color: 'primary',
|
|
63
|
+
}))`
|
|
64
|
+
width: 100px;
|
|
65
|
+
margin-left: 0;
|
|
66
|
+
margin-right: 0;
|
|
67
|
+
margin-top: 15px;
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
const OptionWrapper = styled.div`
|
|
71
|
+
margin: 5px 0;
|
|
72
|
+
display: flex;
|
|
73
|
+
input {
|
|
74
|
+
margin-right: 10px;
|
|
75
|
+
cursor: pointer;
|
|
76
|
+
}
|
|
77
|
+
label {
|
|
78
|
+
font-size: 14px;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
}
|
|
81
|
+
`;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import styled from 'styled-components';
|
|
3
|
+
|
|
4
|
+
import type { SentimentProps, ReasonsProps } from '@theme/Feedback';
|
|
5
|
+
import { Comment, Reasons } from '@theme/Feedback';
|
|
6
|
+
|
|
7
|
+
import { ThumbUp, ThumbDown } from './Thumbs';
|
|
8
|
+
|
|
9
|
+
export const Sentiment = ({ settings, onSubmit }: SentimentProps): JSX.Element => {
|
|
10
|
+
const { label, submitText, comment: commentSettings, reasons: reasonsSettings } = settings || {};
|
|
11
|
+
const [score, setScore] = React.useState(0);
|
|
12
|
+
const [comment, setComment] = React.useState('');
|
|
13
|
+
const [reasons, setReasons] = React.useState([] as ReasonsProps['settings']['items']);
|
|
14
|
+
|
|
15
|
+
if (score && reasonsSettings?.enable && !reasons.length) {
|
|
16
|
+
const { label: reasonsLabel, items, multi } = reasonsSettings;
|
|
17
|
+
const buttonText = commentSettings?.enable ? 'Next' : 'Send';
|
|
18
|
+
return (
|
|
19
|
+
<Reasons
|
|
20
|
+
onSubmit={({ reasons }) => setReasons(reasons)}
|
|
21
|
+
settings={{ label: reasonsLabel, items, multi, buttonText }}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (score && commentSettings?.enable && !comment) {
|
|
27
|
+
const commentLabel =
|
|
28
|
+
score === 1
|
|
29
|
+
? commentSettings.likeLabel || 'What was most helpful?'
|
|
30
|
+
: commentSettings.dislikeLabel || 'What can we improve?';
|
|
31
|
+
return (
|
|
32
|
+
<Comment onSubmit={({ comment }) => setComment(comment)} settings={{ label: commentLabel }} />
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (score) {
|
|
37
|
+
onSubmit({
|
|
38
|
+
score,
|
|
39
|
+
comment,
|
|
40
|
+
reasons,
|
|
41
|
+
});
|
|
42
|
+
return (
|
|
43
|
+
<Wrapper>
|
|
44
|
+
<Label>{submitText || 'Thank you for helping improve our documentation!'}</Label>
|
|
45
|
+
</Wrapper>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<Wrapper data-component-name="Feedback/Sentiment">
|
|
51
|
+
<Label>{label || 'Was this page helpful?'}</Label>
|
|
52
|
+
<Vote onClick={() => setScore(1)}>
|
|
53
|
+
<ThumbUp text="Yes" />
|
|
54
|
+
</Vote>
|
|
55
|
+
<Vote onClick={() => setScore(-1)}>
|
|
56
|
+
<ThumbDown />
|
|
57
|
+
</Vote>
|
|
58
|
+
</Wrapper>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const Wrapper = styled.div`
|
|
63
|
+
font-family: var(--font-family-base);
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const Label = styled.h3`
|
|
69
|
+
margin-right: 15px;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
const Vote = styled.div`
|
|
73
|
+
cursor: pointer;
|
|
74
|
+
margin: 0 10px;
|
|
75
|
+
`;
|