@redocly/theme 0.7.2 → 0.7.4

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.
@@ -31,7 +31,7 @@ const React = __importStar(require("react"));
31
31
  const styled_components_1 = __importDefault(require("styled-components"));
32
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,6 +72,10 @@ const TextArea = styled_components_1.default.textarea `
70
72
  margin: 0 0 10px 0;
71
73
  padding: 10px;
72
74
  `;
75
+ const ButtonsContainer = styled_components_1.default.div `
76
+ display: flex;
77
+ justify-content: start;
78
+ `;
73
79
  const SendButton = (0, styled_components_1.default)(Button_1.Button).attrs(() => ({
74
80
  color: 'primary',
75
81
  })) `
@@ -77,4 +83,11 @@ const SendButton = (0, styled_components_1.default)(Button_1.Button).attrs(() =>
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
@@ -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 { codeSnippet: { copy = {}, report = { hide: true } } = {} } = (0, useThemeConfig_1.useThemeConfig)(); // TODO: report temporary disabled
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), copy.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
+ !copy.hide && (react_1.default.createElement(react_1.default.Fragment, null,
48
+ !isCopied && (react_1.default.createElement(Button, { onClick: () => copyCode(rawContent), title: copy.tooltipText || 'Copy to clipboard' }, copy.buttonText || 'Copy')),
49
+ isCopied && react_1.default.createElement(DoneIndicator, null, copy.toasterText || 'Copied!'))),
50
+ !report.hide && (react_1.default.createElement(Button, { onClick: () => showDialog(), title: report.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: report.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
@@ -312,6 +312,68 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
312
312
  text?: string | undefined;
313
313
  } | undefined;
314
314
  }>>>;
315
+ codeSnippet: z.ZodOptional<z.ZodDefault<z.ZodObject<{
316
+ copy: z.ZodDefault<z.ZodOptional<z.ZodObject<z.extendShape<{
317
+ buttonText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
318
+ tooltipText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
319
+ toasterText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
320
+ toasterDuration: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
321
+ }, {
322
+ hide: z.ZodOptional<z.ZodBoolean>;
323
+ }>, "strip", z.ZodTypeAny, {
324
+ hide?: boolean | undefined;
325
+ buttonText?: string | undefined;
326
+ tooltipText?: string | undefined;
327
+ toasterText?: string | undefined;
328
+ toasterDuration?: number | undefined;
329
+ }, {
330
+ hide?: boolean | undefined;
331
+ buttonText?: string | undefined;
332
+ tooltipText?: string | undefined;
333
+ toasterText?: string | undefined;
334
+ toasterDuration?: number | undefined;
335
+ }>>>;
336
+ report: z.ZodDefault<z.ZodOptional<z.ZodObject<z.extendShape<{
337
+ tooltipText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
338
+ label: z.ZodOptional<z.ZodString>;
339
+ }, {
340
+ hide: z.ZodOptional<z.ZodBoolean>;
341
+ }>, "strip", z.ZodTypeAny, {
342
+ hide?: boolean | undefined;
343
+ tooltipText?: string | undefined;
344
+ label?: string | undefined;
345
+ }, {
346
+ hide?: boolean | undefined;
347
+ tooltipText?: string | undefined;
348
+ label?: string | undefined;
349
+ }>>>;
350
+ }, "strict", z.ZodTypeAny, {
351
+ copy: {
352
+ hide?: boolean | undefined;
353
+ buttonText?: string | undefined;
354
+ tooltipText?: string | undefined;
355
+ toasterText?: string | undefined;
356
+ toasterDuration?: number | undefined;
357
+ };
358
+ report: {
359
+ hide?: boolean | undefined;
360
+ tooltipText?: string | undefined;
361
+ label?: string | undefined;
362
+ };
363
+ }, {
364
+ copy?: {
365
+ hide?: boolean | undefined;
366
+ buttonText?: string | undefined;
367
+ tooltipText?: string | undefined;
368
+ toasterText?: string | undefined;
369
+ toasterDuration?: number | undefined;
370
+ } | undefined;
371
+ report?: {
372
+ hide?: boolean | undefined;
373
+ tooltipText?: string | undefined;
374
+ label?: string | undefined;
375
+ } | undefined;
376
+ }>>>;
315
377
  markdown: z.ZodOptional<z.ZodDefault<z.ZodObject<{
316
378
  frontMatterKeysToResolve: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString, "many">>>;
317
379
  lastUpdatedBlock: z.ZodOptional<z.ZodDefault<z.ZodObject<z.extendShape<{
@@ -359,26 +421,6 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
359
421
  baseUrl?: string | undefined;
360
422
  icon?: string | undefined;
361
423
  }>>>;
362
- copyCodeSnippet: z.ZodDefault<z.ZodOptional<z.ZodObject<z.extendShape<{
363
- buttonText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
364
- tooltipText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
365
- toasterText: z.ZodOptional<z.ZodDefault<z.ZodString>>;
366
- toasterDuration: z.ZodOptional<z.ZodDefault<z.ZodNumber>>;
367
- }, {
368
- hide: z.ZodOptional<z.ZodBoolean>;
369
- }>, "strip", z.ZodTypeAny, {
370
- hide?: boolean | undefined;
371
- buttonText?: string | undefined;
372
- tooltipText?: string | undefined;
373
- toasterText?: string | undefined;
374
- toasterDuration?: number | undefined;
375
- }, {
376
- hide?: boolean | undefined;
377
- buttonText?: string | undefined;
378
- tooltipText?: string | undefined;
379
- toasterText?: string | undefined;
380
- toasterDuration?: number | undefined;
381
- }>>>;
382
424
  }, "strict", z.ZodTypeAny, {
383
425
  frontMatterKeysToResolve?: string[] | undefined;
384
426
  lastUpdatedBlock?: {
@@ -397,13 +439,6 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
397
439
  header?: string | undefined;
398
440
  depth?: number | undefined;
399
441
  };
400
- copyCodeSnippet: {
401
- hide?: boolean | undefined;
402
- buttonText?: string | undefined;
403
- tooltipText?: string | undefined;
404
- toasterText?: string | undefined;
405
- toasterDuration?: number | undefined;
406
- };
407
442
  }, {
408
443
  frontMatterKeysToResolve?: string[] | undefined;
409
444
  lastUpdatedBlock?: {
@@ -422,13 +457,6 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
422
457
  baseUrl?: string | undefined;
423
458
  icon?: string | undefined;
424
459
  } | undefined;
425
- copyCodeSnippet?: {
426
- hide?: boolean | undefined;
427
- buttonText?: string | undefined;
428
- tooltipText?: string | undefined;
429
- toasterText?: string | undefined;
430
- toasterDuration?: number | undefined;
431
- } | undefined;
432
460
  }>>>;
433
461
  openapi: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
434
462
  graphql: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, {}, {}>>;
@@ -525,6 +553,20 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
525
553
  placement?: string | undefined;
526
554
  shortcuts?: string[] | undefined;
527
555
  } | undefined;
556
+ codeSnippet?: {
557
+ copy: {
558
+ hide?: boolean | undefined;
559
+ buttonText?: string | undefined;
560
+ tooltipText?: string | undefined;
561
+ toasterText?: string | undefined;
562
+ toasterDuration?: number | undefined;
563
+ };
564
+ report: {
565
+ hide?: boolean | undefined;
566
+ tooltipText?: string | undefined;
567
+ label?: string | undefined;
568
+ };
569
+ } | undefined;
528
570
  markdown?: {
529
571
  frontMatterKeysToResolve?: string[] | undefined;
530
572
  lastUpdatedBlock?: {
@@ -543,13 +585,6 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
543
585
  header?: string | undefined;
544
586
  depth?: number | undefined;
545
587
  };
546
- copyCodeSnippet: {
547
- hide?: boolean | undefined;
548
- buttonText?: string | undefined;
549
- tooltipText?: string | undefined;
550
- toasterText?: string | undefined;
551
- toasterDuration?: number | undefined;
552
- };
553
588
  } | undefined;
554
589
  openapi?: {} | undefined;
555
590
  graphql?: {} | undefined;
@@ -665,6 +700,20 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
665
700
  text?: string | undefined;
666
701
  } | undefined;
667
702
  } | undefined;
703
+ codeSnippet?: {
704
+ copy?: {
705
+ hide?: boolean | undefined;
706
+ buttonText?: string | undefined;
707
+ tooltipText?: string | undefined;
708
+ toasterText?: string | undefined;
709
+ toasterDuration?: number | undefined;
710
+ } | undefined;
711
+ report?: {
712
+ hide?: boolean | undefined;
713
+ tooltipText?: string | undefined;
714
+ label?: string | undefined;
715
+ } | undefined;
716
+ } | undefined;
668
717
  markdown?: {
669
718
  frontMatterKeysToResolve?: string[] | undefined;
670
719
  lastUpdatedBlock?: {
@@ -683,13 +732,6 @@ export declare const ThemeConfig: z.ZodDefault<z.ZodObject<{
683
732
  baseUrl?: string | undefined;
684
733
  icon?: string | undefined;
685
734
  } | undefined;
686
- copyCodeSnippet?: {
687
- hide?: boolean | undefined;
688
- buttonText?: string | undefined;
689
- tooltipText?: string | undefined;
690
- toasterText?: string | undefined;
691
- toasterDuration?: number | undefined;
692
- } | undefined;
693
735
  } | undefined;
694
736
  openapi?: {} | undefined;
695
737
  graphql?: {} | undefined;
package/lib/config.js CHANGED
@@ -117,6 +117,30 @@ exports.ThemeConfig = zod_1.z
117
117
  .strict()
118
118
  .optional()
119
119
  .default({}),
120
+ codeSnippet: zod_1.z
121
+ .object({
122
+ copy: zod_1.z
123
+ .object({
124
+ buttonText: zod_1.z.string().default('Copy').optional(),
125
+ tooltipText: zod_1.z.string().default('Copy to clipboard').optional(),
126
+ toasterText: zod_1.z.string().default('Copied').optional(),
127
+ toasterDuration: zod_1.z.number().default(1500).optional(),
128
+ })
129
+ .extend(HideConfig.shape)
130
+ .optional()
131
+ .default({}),
132
+ report: zod_1.z
133
+ .object({
134
+ tooltipText: zod_1.z.string().default('Report a problem').optional(),
135
+ label: zod_1.z.string().optional(),
136
+ })
137
+ .extend(HideConfig.shape)
138
+ .optional()
139
+ .default({}),
140
+ })
141
+ .strict()
142
+ .default({})
143
+ .optional(),
120
144
  markdown: zod_1.z
121
145
  .object({
122
146
  frontMatterKeysToResolve: zod_1.z.array(zod_1.z.string()).default(['image', 'links']).optional(),
@@ -145,16 +169,6 @@ exports.ThemeConfig = zod_1.z
145
169
  .extend(HideConfig.shape)
146
170
  .default({})
147
171
  .optional(),
148
- copyCodeSnippet: zod_1.z
149
- .object({
150
- buttonText: zod_1.z.string().default('Copy').optional(),
151
- tooltipText: zod_1.z.string().default('Copy to clipboard').optional(),
152
- toasterText: zod_1.z.string().default('Copied').optional(),
153
- toasterDuration: zod_1.z.number().default(1500).optional(),
154
- })
155
- .extend(HideConfig.shape)
156
- .optional()
157
- .default({}),
158
172
  })
159
173
  .strict()
160
174
  .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
@@ -8,16 +8,22 @@ function useThemeConfig() {
8
8
  placement: 'navbar',
9
9
  shortcuts: ['ctrl+f', 'cmd+k', '/'],
10
10
  },
11
- markdown: {
12
- toc: { depth: 3, header: 'Table of contents', hide: false },
13
- lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
14
- copyCodeSnippet: {
11
+ codeSnippet: {
12
+ copy: {
15
13
  hide: false,
16
14
  buttonText: 'Copy',
17
15
  tooltipText: 'Copy to clipboard',
18
16
  toasterText: 'Copied',
19
17
  toasterDuration: 1500,
20
18
  },
19
+ report: {
20
+ hide: false,
21
+ tooltipText: 'Report a problem',
22
+ },
23
+ },
24
+ markdown: {
25
+ toc: { depth: 3, header: 'Table of contents', hide: false },
26
+ lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
21
27
  editPage: {
22
28
  baseUrl: '',
23
29
  text: 'Edit this page',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/theme",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Shared UI components lib",
5
5
  "author": "team@redocly.com",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -5,7 +5,7 @@ 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
+ `;
@@ -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,58 @@ 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 { codeSnippet: { copy = {}, report = { hide: true } } = {} } = useThemeConfig(); // TODO: report temporary disabled
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), copy.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
+ {!copy.hide && (
34
+ <>
35
+ {!isCopied && (
36
+ <Button
37
+ onClick={() => copyCode(rawContent)}
38
+ title={copy.tooltipText || 'Copy to clipboard'}
39
+ >
40
+ {copy.buttonText || 'Copy'}
41
+ </Button>
42
+ )}
43
+ {isCopied && <DoneIndicator>{copy.toasterText || 'Copied!'}</DoneIndicator>}
44
+ </>
45
+ )}
46
+
47
+ {!report.hide && (
48
+ <Button onClick={() => showDialog()} title={report.tooltipText || 'Report a problem'}>
49
+ Report
50
+ </Button>
51
+ )}
52
+
53
+ {isDialogShown && (
54
+ <ReportDialog id="modal">
55
+ <Comment
56
+ settings={{
57
+ label: report.label || 'What is wrong with a code?',
58
+ onCancel: () => {
59
+ hideDialog();
60
+ },
61
+ }}
62
+ onSubmit={(value) => {
63
+ submitFeedback('problem', { ...value, location: rawContent });
64
+ hideDialog();
65
+ }}
66
+ />
67
+ </ReportDialog>
68
+ )}
69
+ </CodeSampleButtonContainer>
37
70
  <pre className={langClassName}>
38
71
  <code className={langClassName} dangerouslySetInnerHTML={{ __html: highlighted }} />
39
72
  </pre>
@@ -42,12 +75,13 @@ export function CodeSample({ rawContent, highlighted, language }: CodeSampleProp
42
75
  }
43
76
 
44
77
  const CodeSampleButtonContainer = styled.div`
78
+ display: flex;
45
79
  position: absolute;
46
80
  top: 12px;
47
81
  right: 5px;
48
82
  `;
49
83
 
50
- const CopyCodeButton = styled.div`
84
+ const Button = styled.div`
51
85
  padding: var(--code-block-controls-padding);
52
86
  border-radius: var(--code-block-controls-border-radius);
53
87
  font-size: var(--code-block-controls-font-size);
@@ -124,13 +158,13 @@ const Wrapper = styled.div`
124
158
  border-radius: 4px;
125
159
  position: relative;
126
160
 
127
- ${CopyCodeButton},
161
+ ${Button},
128
162
  ${DoneIndicator} {
129
163
  color: var(--code-block-controls-text-color);
130
164
  background-color: var(--code-block-controls-background-color);
131
165
  opacity: var(--code-block-controls-opacity);
132
166
  }
133
- ${CopyCodeButton}:hover {
167
+ ${Button}:hover {
134
168
  color: var(--code-block-controls-hover-text-color);
135
169
  background-color: var(--code-block-controls-hover-background-color);
136
170
  opacity: var(--code-block-controls-active-opacity);
@@ -208,3 +242,25 @@ const Wrapper = styled.div`
208
242
  ${darkStyleTokens};
209
243
  }
210
244
  `;
245
+
246
+ const ReportDialog = styled.div`
247
+ position: fixed;
248
+ top: 0;
249
+ left: 0;
250
+ width: 100vw;
251
+ height: 100vh;
252
+ background: var(--modal-overlay-background-color);
253
+ z-index: 10000;
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+
258
+ & > * {
259
+ background: var(--modal-background-color);
260
+ box-shadow: var(--modal-box-shadow);
261
+ padding: 15px;
262
+ margin: 15px;
263
+ max-width: 500px;
264
+ max-height: 300px;
265
+ }
266
+ `;
package/src/config.ts CHANGED
@@ -126,6 +126,30 @@ export const ThemeConfig = z
126
126
  .strict()
127
127
  .optional()
128
128
  .default({}),
129
+ codeSnippet: z
130
+ .object({
131
+ copy: z
132
+ .object({
133
+ buttonText: z.string().default('Copy').optional(),
134
+ tooltipText: z.string().default('Copy to clipboard').optional(),
135
+ toasterText: z.string().default('Copied').optional(),
136
+ toasterDuration: z.number().default(1500).optional(),
137
+ })
138
+ .extend(HideConfig.shape)
139
+ .optional()
140
+ .default({}),
141
+ report: z
142
+ .object({
143
+ tooltipText: z.string().default('Report a problem').optional(),
144
+ label: z.string().optional(),
145
+ })
146
+ .extend(HideConfig.shape)
147
+ .optional()
148
+ .default({}),
149
+ })
150
+ .strict()
151
+ .default({})
152
+ .optional(),
129
153
  markdown: z
130
154
  .object({
131
155
  frontMatterKeysToResolve: z.array(z.string()).default(['image', 'links']).optional(),
@@ -154,16 +178,6 @@ export const ThemeConfig = z
154
178
  .extend(HideConfig.shape)
155
179
  .default({})
156
180
  .optional(),
157
- copyCodeSnippet: z
158
- .object({
159
- buttonText: z.string().default('Copy').optional(),
160
- tooltipText: z.string().default('Copy to clipboard').optional(),
161
- toasterText: z.string().default('Copied').optional(),
162
- toasterDuration: z.number().default(1500).optional(),
163
- })
164
- .extend(HideConfig.shape)
165
- .optional()
166
- .default({}),
167
181
  })
168
182
  .strict()
169
183
  .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
+ }
@@ -13,16 +13,22 @@ export function useThemeConfig<T extends Record<string, unknown>>(): T & ThemeUI
13
13
  placement: 'navbar',
14
14
  shortcuts: ['ctrl+f', 'cmd+k', '/'],
15
15
  },
16
- markdown: {
17
- toc: { depth: 3, header: 'Table of contents', hide: false },
18
- lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
19
- copyCodeSnippet: {
16
+ codeSnippet: {
17
+ copy: {
20
18
  hide: false,
21
19
  buttonText: 'Copy',
22
20
  tooltipText: 'Copy to clipboard',
23
21
  toasterText: 'Copied',
24
22
  toasterDuration: 1500,
25
23
  },
24
+ report: {
25
+ hide: false,
26
+ tooltipText: 'Report a problem',
27
+ },
28
+ },
29
+ markdown: {
30
+ toc: { depth: 3, header: 'Table of contents', hide: false },
31
+ lastUpdatedBlock: { hide: false, format: 'timeago', locale: 'en-US' },
26
32
  editPage: {
27
33
  baseUrl: '',
28
34
  text: 'Edit this page',