@redocly/theme 0.7.1 → 0.7.3

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.
@@ -29,9 +29,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.Comment = void 0;
30
30
  const React = __importStar(require("react"));
31
31
  const styled_components_1 = __importDefault(require("styled-components"));
32
- const _theme_1 = require("../index.js");
32
+ const Button_1 = require("../Button/Button");
33
33
  const Comment = ({ settings, onSubmit }) => {
34
- const { label, submitText } = settings || {};
34
+ const { label, submitText, onCancel } = settings || {};
35
35
  const [text, setText] = React.useState('');
36
36
  const [submitValue, setSubmitValue] = React.useState('');
37
37
  const send = () => {
@@ -48,9 +48,11 @@ const Comment = ({ settings, onSubmit }) => {
48
48
  React.createElement(Label, null, submitText || 'Thank you for helping improve our documentation!')));
49
49
  }
50
50
  return (React.createElement(Wrapper, { "data-component-name": "Feedback/Comment" },
51
- React.createElement(Label, null, label || 'Please share your feedback with us:'),
51
+ React.createElement(Label, null, label || 'Please share your feedback with us.'),
52
52
  React.createElement(TextArea, { rows: 3, onChange: handleTextAreaChange }),
53
- React.createElement(SendButton, { onClick: send }, "Send")));
53
+ React.createElement(ButtonsContainer, null,
54
+ React.createElement(SendButton, { onClick: send }, "Send"),
55
+ onCancel && React.createElement(CancelButton, { onClick: onCancel }, "Cancel"))));
54
56
  };
55
57
  exports.Comment = Comment;
56
58
  const Wrapper = styled_components_1.default.div `
@@ -70,11 +72,22 @@ const TextArea = styled_components_1.default.textarea `
70
72
  margin: 0 0 10px 0;
71
73
  padding: 10px;
72
74
  `;
73
- const SendButton = (0, styled_components_1.default)(_theme_1.Button).attrs(() => ({
75
+ const ButtonsContainer = styled_components_1.default.div `
76
+ display: flex;
77
+ justify-content: start;
78
+ `;
79
+ const SendButton = (0, styled_components_1.default)(Button_1.Button).attrs(() => ({
74
80
  color: 'primary',
75
81
  })) `
76
82
  width: 100px;
77
83
  margin-left: 0;
78
84
  margin-right: 0;
79
85
  `;
86
+ const CancelButton = (0, styled_components_1.default)(Button_1.Button).attrs(() => ({
87
+ color: 'secondary',
88
+ })) `
89
+ width: 100px;
90
+ margin-left: 0;
91
+ margin-right: 0;
92
+ `;
80
93
  //# sourceMappingURL=Comment.js.map
@@ -29,7 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.Reasons = void 0;
30
30
  const React = __importStar(require("react"));
31
31
  const styled_components_1 = __importDefault(require("styled-components"));
32
- const _theme_1 = require("../index.js");
32
+ const Button_1 = require("../Button/Button");
33
33
  const Reasons = ({ settings, onSubmit }) => {
34
34
  const { label, multi, buttonText, items = [] } = settings;
35
35
  const [checkedState, setCheckedState] = React.useState(new Array(items.length).fill(false));
@@ -62,7 +62,7 @@ const Wrapper = styled_components_1.default.div `
62
62
  const Label = styled_components_1.default.h3 `
63
63
  margin-right: 15px;
64
64
  `;
65
- const SendButton = (0, styled_components_1.default)(_theme_1.Button).attrs(() => ({
65
+ const SendButton = (0, styled_components_1.default)(Button_1.Button).attrs(() => ({
66
66
  color: 'primary',
67
67
  })) `
68
68
  width: 100px;
@@ -30,7 +30,7 @@ exports.Sentiment = void 0;
30
30
  const React = __importStar(require("react"));
31
31
  const styled_components_1 = __importDefault(require("styled-components"));
32
32
  const Feedback_1 = require("../Feedback");
33
- const Thumbs_1 = require("./Thumbs");
33
+ const Thumbs_1 = require("../Feedback/Thumbs");
34
34
  const Sentiment = ({ settings, onSubmit }) => {
35
35
  const { label, submitText, comment: commentSettings, reasons: reasonsSettings } = settings || {};
36
36
  const [score, setScore] = React.useState(0);
@@ -49,6 +49,7 @@ export type CommentProps = {
49
49
  settings?: {
50
50
  label?: string;
51
51
  submitText?: string;
52
+ onCancel?: () => unknown;
52
53
  };
53
54
  };
54
55
  export type ReasonsProps = {
@@ -28,29 +28,47 @@ const react_1 = __importStar(require("react"));
28
28
  const styled_components_1 = __importStar(require("styled-components"));
29
29
  const ClipboardService_1 = require("../../utils/ClipboardService");
30
30
  const useThemeConfig_1 = require("../../hooks/useThemeConfig");
31
+ const Feedback_1 = require("../../Feedback");
32
+ const useSubmitFeedback_1 = require("../../mocks/Feedback/useSubmitFeedback");
33
+ const useReportDialog_1 = require("../../hooks/useReportDialog");
31
34
  function CodeSample({ rawContent, highlighted, language }) {
32
35
  const langClassName = language ? `language-${language}` : '';
33
- const { markdown: { copyCodeSnippet = {} } = {} } = (0, useThemeConfig_1.useThemeConfig)();
36
+ const { markdown: { copyCodeSnippet = {}, reportCodeSnippet = {} } = {} } = (0, useThemeConfig_1.useThemeConfig)();
37
+ const { submitFeedback } = (0, useSubmitFeedback_1.useSubmitFeedback)();
34
38
  const [isCopied, setIsCopied] = (0, react_1.useState)(false);
39
+ const [isDialogShown, showDialog, hideDialog] = (0, useReportDialog_1.useReportDialog)(false);
35
40
  const copyCode = (code) => {
36
41
  ClipboardService_1.ClipboardService.copyCustom(code);
37
42
  setIsCopied(true);
38
- setTimeout(() => setIsCopied(false), copyCodeSnippet.toasterDuration);
43
+ setTimeout(() => setIsCopied(false), copyCodeSnippet.toasterDuration || 1000);
39
44
  };
40
45
  return (react_1.default.createElement(Wrapper, { className: "code-sample", "data-component-name": "Markdown/CodeSample/CodeSample" },
41
- !copyCodeSnippet.hide && (react_1.default.createElement(CodeSampleButtonContainer, { onClick: () => copyCode(rawContent) },
42
- !isCopied && (react_1.default.createElement(CopyCodeButton, { title: copyCodeSnippet.tooltipText || 'Copy to clipboard' }, copyCodeSnippet.buttonText)),
43
- isCopied && react_1.default.createElement(DoneIndicator, null, copyCodeSnippet.toasterText))),
46
+ react_1.default.createElement(CodeSampleButtonContainer, null,
47
+ !copyCodeSnippet.hide && (react_1.default.createElement(react_1.default.Fragment, null,
48
+ !isCopied && (react_1.default.createElement(Button, { onClick: () => copyCode(rawContent), title: copyCodeSnippet.tooltipText || 'Copy to clipboard' }, copyCodeSnippet.buttonText || 'Copy')),
49
+ isCopied && react_1.default.createElement(DoneIndicator, null, copyCodeSnippet.toasterText || 'Copied!'))),
50
+ !reportCodeSnippet.hide && (react_1.default.createElement(Button, { onClick: () => showDialog(), title: reportCodeSnippet.tooltipText || 'Report a problem' }, "Report")),
51
+ isDialogShown && (react_1.default.createElement(ReportDialog, { id: "modal" },
52
+ react_1.default.createElement(Feedback_1.Comment, { settings: {
53
+ label: reportCodeSnippet.label || 'What is wrong with a code?',
54
+ onCancel: () => {
55
+ hideDialog();
56
+ },
57
+ }, onSubmit: (value) => {
58
+ submitFeedback('problem', Object.assign(Object.assign({}, value), { location: rawContent }));
59
+ hideDialog();
60
+ } })))),
44
61
  react_1.default.createElement("pre", { className: langClassName },
45
62
  react_1.default.createElement("code", { className: langClassName, dangerouslySetInnerHTML: { __html: highlighted } }))));
46
63
  }
47
64
  exports.CodeSample = CodeSample;
48
65
  const CodeSampleButtonContainer = styled_components_1.default.div `
66
+ display: flex;
49
67
  position: absolute;
50
68
  top: 12px;
51
69
  right: 5px;
52
70
  `;
53
- const CopyCodeButton = styled_components_1.default.div `
71
+ const Button = styled_components_1.default.div `
54
72
  padding: var(--code-block-controls-padding);
55
73
  border-radius: var(--code-block-controls-border-radius);
56
74
  font-size: var(--code-block-controls-font-size);
@@ -124,13 +142,13 @@ const Wrapper = styled_components_1.default.div `
124
142
  border-radius: 4px;
125
143
  position: relative;
126
144
 
127
- ${CopyCodeButton},
145
+ ${Button},
128
146
  ${DoneIndicator} {
129
147
  color: var(--code-block-controls-text-color);
130
148
  background-color: var(--code-block-controls-background-color);
131
149
  opacity: var(--code-block-controls-opacity);
132
150
  }
133
- ${CopyCodeButton}:hover {
151
+ ${Button}:hover {
134
152
  color: var(--code-block-controls-hover-text-color);
135
153
  background-color: var(--code-block-controls-hover-background-color);
136
154
  opacity: var(--code-block-controls-active-opacity);
@@ -208,4 +226,25 @@ const Wrapper = styled_components_1.default.div `
208
226
  ${darkStyleTokens};
209
227
  }
210
228
  `;
229
+ const ReportDialog = styled_components_1.default.div `
230
+ position: fixed;
231
+ top: 0;
232
+ left: 0;
233
+ width: 100vw;
234
+ height: 100vh;
235
+ background: var(--modal-overlay-background-color);
236
+ z-index: 10000;
237
+ display: flex;
238
+ align-items: center;
239
+ justify-content: center;
240
+
241
+ & > * {
242
+ background: var(--modal-background-color);
243
+ box-shadow: var(--modal-box-shadow);
244
+ padding: 15px;
245
+ margin: 15px;
246
+ max-width: 500px;
247
+ max-height: 300px;
248
+ }
249
+ `;
211
250
  //# sourceMappingURL=CodeSample.js.map
package/lib/config.d.ts CHANGED
@@ -379,6 +379,20 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
379
379
  toasterText?: string | undefined;
380
380
  toasterDuration?: number | undefined;
381
381
  }>>>;
382
+ reportCodeSnippet: z.ZodDefault<z.ZodOptional<z.ZodObject<z.extendShape<{
383
+ tooltipText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
384
+ label: z.ZodOptional<z.ZodString>;
385
+ }, {
386
+ hide: z.ZodOptional<z.ZodBoolean>;
387
+ }>, "strip", z.ZodTypeAny, {
388
+ hide?: boolean | undefined;
389
+ tooltipText?: string | undefined;
390
+ label?: string | undefined;
391
+ }, {
392
+ hide?: boolean | undefined;
393
+ tooltipText?: string | undefined;
394
+ label?: string | undefined;
395
+ }>>>;
382
396
  }, "strict", z.ZodTypeAny, {
383
397
  frontMatterKeysToResolve?: string[] | undefined;
384
398
  lastUpdatedBlock?: {
@@ -404,6 +418,11 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
404
418
  toasterText?: string | undefined;
405
419
  toasterDuration?: number | undefined;
406
420
  };
421
+ reportCodeSnippet: {
422
+ hide?: boolean | undefined;
423
+ tooltipText?: string | undefined;
424
+ label?: string | undefined;
425
+ };
407
426
  }, {
408
427
  frontMatterKeysToResolve?: string[] | undefined;
409
428
  lastUpdatedBlock?: {
@@ -429,6 +448,11 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
429
448
  toasterText?: string | undefined;
430
449
  toasterDuration?: number | undefined;
431
450
  } | undefined;
451
+ reportCodeSnippet?: {
452
+ hide?: boolean | undefined;
453
+ tooltipText?: string | undefined;
454
+ label?: string | undefined;
455
+ } | undefined;
432
456
  }>>>;
433
457
  openapi: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
434
458
  graphql: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
@@ -550,6 +574,11 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
550
574
  toasterText?: string | undefined;
551
575
  toasterDuration?: number | undefined;
552
576
  };
577
+ reportCodeSnippet: {
578
+ hide?: boolean | undefined;
579
+ tooltipText?: string | undefined;
580
+ label?: string | undefined;
581
+ };
553
582
  } | undefined;
554
583
  openapi?: {} | undefined;
555
584
  graphql?: {} | undefined;
@@ -690,6 +719,11 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
690
719
  toasterText?: string | undefined;
691
720
  toasterDuration?: number | undefined;
692
721
  } | undefined;
722
+ reportCodeSnippet?: {
723
+ hide?: boolean | undefined;
724
+ tooltipText?: string | undefined;
725
+ label?: string | undefined;
726
+ } | undefined;
693
727
  } | undefined;
694
728
  openapi?: {} | undefined;
695
729
  graphql?: {} | undefined;
package/lib/config.js CHANGED
@@ -155,6 +155,14 @@ exports.ThemeConfig = zod_1.z
155
155
  .extend(HideConfig.shape)
156
156
  .optional()
157
157
  .default({}),
158
+ reportCodeSnippet: zod_1.z
159
+ .object({
160
+ tooltipText: zod_1.z.string().default('Report a problem').optional(),
161
+ label: zod_1.z.string().optional(),
162
+ })
163
+ .extend(HideConfig.shape)
164
+ .optional()
165
+ .default({ hide: true }), // TODO: temporary disabled
158
166
  })
159
167
  .strict()
160
168
  .default({})
@@ -1938,6 +1938,15 @@ const pages = (0, styled_components_1.css) `
1938
1938
 
1939
1939
  // @tokens End
1940
1940
  `;
1941
+ const modal = (0, styled_components_1.css) `
1942
+ body:has([id='modal']) {
1943
+ overflow: hidden;
1944
+ }
1945
+
1946
+ --modal-box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.6);
1947
+ --modal-overlay-background-color: rgba(206, 206, 206, 0.49);
1948
+ --modal-background-color: var(--background-color);
1949
+ `;
1941
1950
  exports.styles = (0, styled_components_1.css) `
1942
1951
  :root {
1943
1952
  ${baseColors}
@@ -1968,6 +1977,7 @@ exports.styles = (0, styled_components_1.css) `
1968
1977
  ${loadProgressBar}
1969
1978
  ${apiLogsTable}
1970
1979
  ${pages}
1980
+ ${modal}
1971
1981
  }
1972
1982
 
1973
1983
  :root.dark {
@@ -0,0 +1 @@
1
+ export declare function useReportDialog(initialState?: boolean): [boolean, () => void, () => void];
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useReportDialog = void 0;
4
+ const react_1 = require("react");
5
+ function useReportDialog(initialState = false) {
6
+ const [isDialogShown, setIsShown] = (0, react_1.useState)(initialState);
7
+ const showDialog = () => {
8
+ setIsShown(true);
9
+ };
10
+ const hideDialog = () => {
11
+ setIsShown(false);
12
+ };
13
+ return [isDialogShown, showDialog, hideDialog];
14
+ }
15
+ exports.useReportDialog = useReportDialog;
16
+ //# sourceMappingURL=useReportDialog.js.map
@@ -0,0 +1 @@
1
+ export declare function useSubmitFeedback(): any;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.useSubmitFeedback = void 0;
13
+ function useSubmitFeedback() {
14
+ const submitFeedback = () => __awaiter(this, void 0, void 0, function* () { });
15
+ return { submitFeedback };
16
+ }
17
+ exports.useSubmitFeedback = useSubmitFeedback;
18
+ //# sourceMappingURL=useSubmitFeedback.js.map
@@ -18,6 +18,10 @@ function useThemeConfig() {
18
18
  toasterText: 'Copied',
19
19
  toasterDuration: 1500,
20
20
  },
21
+ reportCodeSnippet: {
22
+ hide: false,
23
+ tooltipText: 'Report a problem',
24
+ },
21
25
  editPage: {
22
26
  baseUrl: '',
23
27
  text: 'Edit this page',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Shared UI components lib",
5
5
  "author": "team@redocly.com",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -1,11 +1,11 @@
1
1
  import * as React from 'react';
2
2
  import styled from 'styled-components';
3
- import { Button } from '@theme';
4
3
 
4
+ import { Button } from '@theme/Button/Button';
5
5
  import type { CommentProps } from '@theme/Feedback';
6
6
 
7
7
  export const Comment = ({ settings, onSubmit }: CommentProps): JSX.Element => {
8
- const { label, submitText } = settings || {};
8
+ const { label, submitText, onCancel } = settings || {};
9
9
  const [text, setText] = React.useState('');
10
10
  const [submitValue, setSubmitValue] = React.useState('');
11
11
 
@@ -28,9 +28,12 @@ export const Comment = ({ settings, onSubmit }: CommentProps): JSX.Element => {
28
28
 
29
29
  return (
30
30
  <Wrapper data-component-name="Feedback/Comment">
31
- <Label>{label || 'Please share your feedback with us:'}</Label>
31
+ <Label>{label || 'Please share your feedback with us.'}</Label>
32
32
  <TextArea rows={3} onChange={handleTextAreaChange} />
33
- <SendButton onClick={send}>Send</SendButton>
33
+ <ButtonsContainer>
34
+ <SendButton onClick={send}>Send</SendButton>
35
+ {onCancel && <CancelButton onClick={onCancel}>Cancel</CancelButton>}
36
+ </ButtonsContainer>
34
37
  </Wrapper>
35
38
  );
36
39
  };
@@ -55,6 +58,11 @@ const TextArea = styled.textarea`
55
58
  padding: 10px;
56
59
  `;
57
60
 
61
+ const ButtonsContainer = styled.div`
62
+ display: flex;
63
+ justify-content: start;
64
+ `;
65
+
58
66
  const SendButton = styled(Button).attrs(() => ({
59
67
  color: 'primary',
60
68
  }))`
@@ -62,3 +70,11 @@ const SendButton = styled(Button).attrs(() => ({
62
70
  margin-left: 0;
63
71
  margin-right: 0;
64
72
  `;
73
+
74
+ const CancelButton = styled(Button).attrs(() => ({
75
+ color: 'secondary',
76
+ }))`
77
+ width: 100px;
78
+ margin-left: 0;
79
+ margin-right: 0;
80
+ `;
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import styled from 'styled-components';
3
- import { Button } from '@theme';
4
3
 
4
+ import { Button } from '@theme/Button/Button';
5
5
  import type { ReasonsProps } from '@theme/Feedback';
6
6
 
7
7
  export const Reasons = ({ settings, onSubmit }: ReasonsProps): JSX.Element => {
@@ -3,8 +3,7 @@ import styled from 'styled-components';
3
3
 
4
4
  import type { SentimentProps, ReasonsProps } from '@theme/Feedback';
5
5
  import { Comment, Reasons } from '@theme/Feedback';
6
-
7
- import { ThumbUp, ThumbDown } from './Thumbs';
6
+ import { ThumbUp, ThumbDown } from '@theme/Feedback/Thumbs';
8
7
 
9
8
  export const Sentiment = ({ settings, onSubmit }: SentimentProps): JSX.Element => {
10
9
  const { label, submitText, comment: commentSettings, reasons: reasonsSettings } = settings || {};
@@ -41,6 +41,7 @@ export type CommentProps = {
41
41
  settings?: {
42
42
  label?: string;
43
43
  submitText?: string;
44
+ onCancel?: () => unknown;
44
45
  };
45
46
  };
46
47
 
@@ -3,6 +3,9 @@ import styled, { css } from 'styled-components';
3
3
 
4
4
  import { ClipboardService } from '@theme/utils/ClipboardService';
5
5
  import { useThemeConfig } from '@theme/hooks/useThemeConfig';
6
+ import { Comment } from '@theme/Feedback';
7
+ import { useSubmitFeedback } from '@portal/Feedback/useSubmitFeedback';
8
+ import { useReportDialog } from '@theme/hooks/useReportDialog';
6
9
 
7
10
  export type CodeSampleProps = {
8
11
  language: string;
@@ -12,28 +15,61 @@ export type CodeSampleProps = {
12
15
 
13
16
  export function CodeSample({ rawContent, highlighted, language }: CodeSampleProps): JSX.Element {
14
17
  const langClassName = language ? `language-${language}` : '';
15
- const { markdown: { copyCodeSnippet = {} } = {} } = useThemeConfig();
18
+ const { markdown: { copyCodeSnippet = {}, reportCodeSnippet = {} } = {} } = useThemeConfig();
19
+ const { submitFeedback } = useSubmitFeedback();
16
20
 
17
21
  const [isCopied, setIsCopied] = useState(false);
22
+ const [isDialogShown, showDialog, hideDialog] = useReportDialog(false);
18
23
 
19
24
  const copyCode = (code: string) => {
20
25
  ClipboardService.copyCustom(code);
21
26
  setIsCopied(true);
22
- setTimeout(() => setIsCopied(false), copyCodeSnippet.toasterDuration);
27
+ setTimeout(() => setIsCopied(false), copyCodeSnippet.toasterDuration || 1000);
23
28
  };
24
29
 
25
30
  return (
26
31
  <Wrapper className="code-sample" data-component-name="Markdown/CodeSample/CodeSample">
27
- {!copyCodeSnippet.hide && (
28
- <CodeSampleButtonContainer onClick={() => copyCode(rawContent)}>
29
- {!isCopied && (
30
- <CopyCodeButton title={copyCodeSnippet.tooltipText || 'Copy to clipboard'}>
31
- {copyCodeSnippet.buttonText}
32
- </CopyCodeButton>
33
- )}
34
- {isCopied && <DoneIndicator>{copyCodeSnippet.toasterText}</DoneIndicator>}
35
- </CodeSampleButtonContainer>
36
- )}
32
+ <CodeSampleButtonContainer>
33
+ {!copyCodeSnippet.hide && (
34
+ <>
35
+ {!isCopied && (
36
+ <Button
37
+ onClick={() => copyCode(rawContent)}
38
+ title={copyCodeSnippet.tooltipText || 'Copy to clipboard'}
39
+ >
40
+ {copyCodeSnippet.buttonText || 'Copy'}
41
+ </Button>
42
+ )}
43
+ {isCopied && <DoneIndicator>{copyCodeSnippet.toasterText || 'Copied!'}</DoneIndicator>}
44
+ </>
45
+ )}
46
+
47
+ {!reportCodeSnippet.hide && (
48
+ <Button
49
+ onClick={() => showDialog()}
50
+ title={reportCodeSnippet.tooltipText || 'Report a problem'}
51
+ >
52
+ Report
53
+ </Button>
54
+ )}
55
+
56
+ {isDialogShown && (
57
+ <ReportDialog id="modal">
58
+ <Comment
59
+ settings={{
60
+ label: reportCodeSnippet.label || 'What is wrong with a code?',
61
+ onCancel: () => {
62
+ hideDialog();
63
+ },
64
+ }}
65
+ onSubmit={(value) => {
66
+ submitFeedback('problem', { ...value, location: rawContent });
67
+ hideDialog();
68
+ }}
69
+ />
70
+ </ReportDialog>
71
+ )}
72
+ </CodeSampleButtonContainer>
37
73
  <pre className={langClassName}>
38
74
  <code className={langClassName} dangerouslySetInnerHTML={{ __html: highlighted }} />
39
75
  </pre>
@@ -42,12 +78,13 @@ export function CodeSample({ rawContent, highlighted, language }: CodeSampleProp
42
78
  }
43
79
 
44
80
  const CodeSampleButtonContainer = styled.div`
81
+ display: flex;
45
82
  position: absolute;
46
83
  top: 12px;
47
84
  right: 5px;
48
85
  `;
49
86
 
50
- const CopyCodeButton = styled.div`
87
+ const Button = styled.div`
51
88
  padding: var(--code-block-controls-padding);
52
89
  border-radius: var(--code-block-controls-border-radius);
53
90
  font-size: var(--code-block-controls-font-size);
@@ -124,13 +161,13 @@ const Wrapper = styled.div`
124
161
  border-radius: 4px;
125
162
  position: relative;
126
163
 
127
- ${CopyCodeButton},
164
+ ${Button},
128
165
  ${DoneIndicator} {
129
166
  color: var(--code-block-controls-text-color);
130
167
  background-color: var(--code-block-controls-background-color);
131
168
  opacity: var(--code-block-controls-opacity);
132
169
  }
133
- ${CopyCodeButton}:hover {
170
+ ${Button}:hover {
134
171
  color: var(--code-block-controls-hover-text-color);
135
172
  background-color: var(--code-block-controls-hover-background-color);
136
173
  opacity: var(--code-block-controls-active-opacity);
@@ -208,3 +245,25 @@ const Wrapper = styled.div`
208
245
  ${darkStyleTokens};
209
246
  }
210
247
  `;
248
+
249
+ const ReportDialog = styled.div`
250
+ position: fixed;
251
+ top: 0;
252
+ left: 0;
253
+ width: 100vw;
254
+ height: 100vh;
255
+ background: var(--modal-overlay-background-color);
256
+ z-index: 10000;
257
+ display: flex;
258
+ align-items: center;
259
+ justify-content: center;
260
+
261
+ & > * {
262
+ background: var(--modal-background-color);
263
+ box-shadow: var(--modal-box-shadow);
264
+ padding: 15px;
265
+ margin: 15px;
266
+ max-width: 500px;
267
+ max-height: 300px;
268
+ }
269
+ `;
package/src/config.ts CHANGED
@@ -164,6 +164,14 @@ export const ThemeConfig = z
164
164
  .extend(HideConfig.shape)
165
165
  .optional()
166
166
  .default({}),
167
+ reportCodeSnippet: z
168
+ .object({
169
+ tooltipText: z.string().default('Report a problem').optional(),
170
+ label: z.string().optional(),
171
+ })
172
+ .extend(HideConfig.shape)
173
+ .optional()
174
+ .default({ hide: true }), // TODO: temporary disabled
167
175
  })
168
176
  .strict()
169
177
  .default({})
@@ -1965,6 +1965,16 @@ const pages = css`
1965
1965
  // @tokens End
1966
1966
  `
1967
1967
 
1968
+ const modal = css`
1969
+ body:has([id='modal']) {
1970
+ overflow: hidden;
1971
+ }
1972
+
1973
+ --modal-box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.6);
1974
+ --modal-overlay-background-color: rgba(206, 206, 206, 0.49);
1975
+ --modal-background-color: var(--background-color);
1976
+ `
1977
+
1968
1978
  export const styles = css`
1969
1979
  :root {
1970
1980
  ${baseColors}
@@ -1995,6 +2005,7 @@ export const styles = css`
1995
2005
  ${loadProgressBar}
1996
2006
  ${apiLogsTable}
1997
2007
  ${pages}
2008
+ ${modal}
1998
2009
  }
1999
2010
 
2000
2011
  :root.dark {
@@ -0,0 +1,14 @@
1
+ import { useState } from 'react';
2
+
3
+ export function useReportDialog(initialState = false): [boolean, () => void, () => void] {
4
+ const [isDialogShown, setIsShown] = useState(initialState);
5
+
6
+ const showDialog = () => {
7
+ setIsShown(true);
8
+ };
9
+ const hideDialog = () => {
10
+ setIsShown(false);
11
+ };
12
+
13
+ return [isDialogShown, showDialog, hideDialog];
14
+ }
@@ -0,0 +1,4 @@
1
+ export function useSubmitFeedback(): any {
2
+ const submitFeedback = async () => {};
3
+ return { submitFeedback };
4
+ }
@@ -23,6 +23,10 @@ export function useThemeConfig<T extends Record<string, unknown>>(): T & ThemeUI
23
23
  toasterText: 'Copied',
24
24
  toasterDuration: 1500,
25
25
  },
26
+ reportCodeSnippet: {
27
+ hide: false,
28
+ tooltipText: 'Report a problem',
29
+ },
26
30
  editPage: {
27
31
  baseUrl: '',
28
32
  text: 'Edit this page',