@redocly/theme 0.47.0 → 0.47.1

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.
Files changed (188) hide show
  1. package/lib/components/Buttons/CopyButton.d.ts +8 -3
  2. package/lib/components/Buttons/CopyButton.js +4 -3
  3. package/lib/components/StatusCode/StatusCode.js +11 -14
  4. package/lib/core/constants/code-walkthrough.d.ts +1 -0
  5. package/lib/core/constants/code-walkthrough.js +5 -0
  6. package/lib/core/constants/index.d.ts +1 -0
  7. package/lib/core/constants/index.js +1 -0
  8. package/lib/core/contexts/CodeWalkthrough/CodeWalkthroughControlsContext.d.ts +2 -0
  9. package/lib/core/contexts/CodeWalkthrough/CodeWalkthroughControlsContext.js +18 -0
  10. package/lib/core/contexts/CodeWalkthrough/CodeWalkthroughStepsContext.d.ts +2 -0
  11. package/lib/core/contexts/CodeWalkthrough/CodeWalkthroughStepsContext.js +11 -0
  12. package/lib/core/contexts/index.d.ts +2 -0
  13. package/lib/core/contexts/index.js +2 -0
  14. package/lib/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.d.ts +10 -0
  15. package/lib/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.js +55 -0
  16. package/lib/core/hooks/code-walkthrough/use-code-panel.d.ts +6 -0
  17. package/lib/core/hooks/code-walkthrough/use-code-panel.js +93 -0
  18. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.d.ts +22 -0
  19. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-controls.js +183 -0
  20. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.d.ts +16 -0
  21. package/lib/core/hooks/code-walkthrough/use-code-walkthrough-steps.js +117 -0
  22. package/lib/core/hooks/code-walkthrough/use-code-walkthrough.d.ts +14 -0
  23. package/lib/core/hooks/code-walkthrough/use-code-walkthrough.js +22 -0
  24. package/lib/core/hooks/index.d.ts +4 -0
  25. package/lib/core/hooks/index.js +4 -0
  26. package/lib/core/styles/global.js +2 -0
  27. package/lib/core/templates/Markdown.d.ts +8 -2
  28. package/lib/core/templates/Markdown.js +5 -2
  29. package/lib/core/types/hooks.d.ts +2 -0
  30. package/lib/core/types/l10n.d.ts +1 -1
  31. package/lib/core/utils/download-code-walkthrough.d.ts +4 -0
  32. package/lib/core/utils/download-code-walkthrough.js +32 -0
  33. package/lib/core/utils/get-code-walkthrough-file-text.d.ts +4 -0
  34. package/lib/core/utils/get-code-walkthrough-file-text.js +22 -0
  35. package/lib/core/utils/get-file-icon.d.ts +2 -0
  36. package/lib/core/utils/get-file-icon.js +31 -0
  37. package/lib/core/utils/index.d.ts +5 -0
  38. package/lib/core/utils/index.js +5 -0
  39. package/lib/core/utils/js-utils.d.ts +30 -0
  40. package/lib/core/utils/js-utils.js +41 -0
  41. package/lib/core/utils/match-code-walkthrough-conditions.d.ts +4 -0
  42. package/lib/core/utils/match-code-walkthrough-conditions.js +23 -0
  43. package/lib/core/utils/replace-inputs-with-value.d.ts +3 -0
  44. package/lib/core/utils/replace-inputs-with-value.js +16 -0
  45. package/lib/icons/DocumentCssIcon/DocumentCssIcon.d.ts +9 -0
  46. package/lib/icons/DocumentCssIcon/DocumentCssIcon.js +23 -0
  47. package/lib/icons/DocumentCssIcon/index.d.ts +1 -0
  48. package/lib/icons/DocumentCssIcon/index.js +6 -0
  49. package/lib/icons/DocumentGraphqlIcon/DocumentGraphqlIcon.d.ts +9 -0
  50. package/lib/icons/DocumentGraphqlIcon/DocumentGraphqlIcon.js +31 -0
  51. package/lib/icons/DocumentGraphqlIcon/index.d.ts +1 -0
  52. package/lib/icons/DocumentGraphqlIcon/index.js +6 -0
  53. package/lib/icons/DocumentHtmlIcon/DocumentHtmlIcon.d.ts +9 -0
  54. package/lib/icons/DocumentHtmlIcon/DocumentHtmlIcon.js +23 -0
  55. package/lib/icons/DocumentHtmlIcon/index.d.ts +1 -0
  56. package/lib/icons/DocumentHtmlIcon/index.js +6 -0
  57. package/lib/icons/DocumentJsIcon/DocumentJsIcon.d.ts +9 -0
  58. package/lib/icons/DocumentJsIcon/DocumentJsIcon.js +23 -0
  59. package/lib/icons/DocumentJsIcon/index.d.ts +1 -0
  60. package/lib/icons/DocumentJsIcon/index.js +6 -0
  61. package/lib/icons/DocumentJsonIcon/DocumentJsonIcon.d.ts +9 -0
  62. package/lib/icons/DocumentJsonIcon/DocumentJsonIcon.js +23 -0
  63. package/lib/icons/DocumentJsonIcon/index.d.ts +1 -0
  64. package/lib/icons/DocumentJsonIcon/index.js +6 -0
  65. package/lib/icons/DocumentMarkdownIcon/DocumentMarkdownIcon.d.ts +9 -0
  66. package/lib/icons/DocumentMarkdownIcon/DocumentMarkdownIcon.js +23 -0
  67. package/lib/icons/DocumentMarkdownIcon/index.d.ts +1 -0
  68. package/lib/icons/DocumentMarkdownIcon/index.js +6 -0
  69. package/lib/icons/DocumentReactIcon/DocumentReactIcon.d.ts +9 -0
  70. package/lib/icons/DocumentReactIcon/DocumentReactIcon.js +23 -0
  71. package/lib/icons/DocumentReactIcon/index.d.ts +1 -0
  72. package/lib/icons/DocumentReactIcon/index.js +6 -0
  73. package/lib/icons/DocumentTsIcon/DocumentTsIcon.d.ts +9 -0
  74. package/lib/icons/DocumentTsIcon/DocumentTsIcon.js +23 -0
  75. package/lib/icons/DocumentTsIcon/index.d.ts +1 -0
  76. package/lib/icons/DocumentTsIcon/index.js +6 -0
  77. package/lib/icons/DocumentYamlIcon/DocumentYamlIcon.d.ts +9 -0
  78. package/lib/icons/DocumentYamlIcon/DocumentYamlIcon.js +23 -0
  79. package/lib/icons/DocumentYamlIcon/index.d.ts +1 -0
  80. package/lib/icons/DocumentYamlIcon/index.js +6 -0
  81. package/lib/index.d.ts +1 -0
  82. package/lib/index.js +1 -0
  83. package/lib/layouts/CodeWalkthroughLayout.d.ts +5 -0
  84. package/lib/layouts/CodeWalkthroughLayout.js +72 -0
  85. package/lib/markdoc/attributes/code-walkthrough-filesets.d.ts +5 -0
  86. package/lib/markdoc/attributes/code-walkthrough-filesets.js +16 -0
  87. package/lib/markdoc/attributes/code-walkthrough-filters.d.ts +5 -0
  88. package/lib/markdoc/attributes/code-walkthrough-filters.js +16 -0
  89. package/lib/markdoc/components/CodeWalkthrough/CodeContainer.d.ts +5 -0
  90. package/lib/markdoc/components/CodeWalkthrough/CodeContainer.js +81 -0
  91. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.d.ts +12 -0
  92. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +58 -0
  93. package/lib/markdoc/components/CodeWalkthrough/CodePanel.d.ts +8 -0
  94. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +64 -0
  95. package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.d.ts +8 -0
  96. package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.js +155 -0
  97. package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.d.ts +2 -0
  98. package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.js +73 -0
  99. package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.d.ts +5 -0
  100. package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.js +47 -0
  101. package/lib/markdoc/components/CodeWalkthrough/CodeStep.d.ts +12 -0
  102. package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +128 -0
  103. package/lib/markdoc/components/CodeWalkthrough/CodeToggle.d.ts +9 -0
  104. package/lib/markdoc/components/CodeWalkthrough/CodeToggle.js +69 -0
  105. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.d.ts +4 -0
  106. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +121 -0
  107. package/lib/markdoc/components/CodeWalkthrough/Input.d.ts +8 -0
  108. package/lib/markdoc/components/CodeWalkthrough/Input.js +99 -0
  109. package/lib/markdoc/components/CodeWalkthrough/variables.d.ts +1 -0
  110. package/lib/markdoc/components/CodeWalkthrough/variables.js +19 -0
  111. package/lib/markdoc/components/default.d.ts +5 -0
  112. package/lib/markdoc/components/default.js +5 -0
  113. package/lib/markdoc/default.js +8 -0
  114. package/lib/markdoc/tags/code-step.d.ts +2 -0
  115. package/lib/markdoc/tags/code-step.js +28 -0
  116. package/lib/markdoc/tags/code-toggle.d.ts +2 -0
  117. package/lib/markdoc/tags/code-toggle.js +40 -0
  118. package/lib/markdoc/tags/code-walkthrough.d.ts +8 -0
  119. package/lib/markdoc/tags/code-walkthrough.js +242 -0
  120. package/lib/markdoc/tags/input.d.ts +2 -0
  121. package/lib/markdoc/tags/input.js +37 -0
  122. package/lib/plugin.d.ts +2 -1
  123. package/lib/plugin.js +2 -4
  124. package/package.json +9 -2
  125. package/src/components/Buttons/CopyButton.tsx +24 -6
  126. package/src/components/StatusCode/StatusCode.ts +11 -10
  127. package/src/core/constants/code-walkthrough.ts +1 -0
  128. package/src/core/constants/index.ts +1 -0
  129. package/src/core/contexts/CodeWalkthrough/CodeWalkthroughControlsContext.tsx +21 -0
  130. package/src/core/contexts/CodeWalkthrough/CodeWalkthroughStepsContext.tsx +10 -0
  131. package/src/core/contexts/index.ts +2 -0
  132. package/src/core/hooks/code-walkthrough/__mocks__/MockIntersectionObserver.ts +22 -0
  133. package/src/core/hooks/code-walkthrough/use-code-panel.ts +164 -0
  134. package/src/core/hooks/code-walkthrough/use-code-walkthrough-controls.ts +302 -0
  135. package/src/core/hooks/code-walkthrough/use-code-walkthrough-steps.ts +165 -0
  136. package/src/core/hooks/code-walkthrough/use-code-walkthrough.ts +51 -0
  137. package/src/core/hooks/index.ts +4 -0
  138. package/src/core/styles/global.ts +2 -0
  139. package/src/core/templates/Markdown.tsx +16 -5
  140. package/src/core/types/hooks.ts +2 -0
  141. package/src/core/types/l10n.ts +3 -1
  142. package/src/core/utils/download-code-walkthrough.ts +25 -0
  143. package/src/core/utils/get-code-walkthrough-file-text.ts +32 -0
  144. package/src/core/utils/get-file-icon.ts +35 -0
  145. package/src/core/utils/index.ts +5 -0
  146. package/src/core/utils/js-utils.ts +48 -0
  147. package/src/core/utils/match-code-walkthrough-conditions.ts +29 -0
  148. package/src/core/utils/replace-inputs-with-value.ts +11 -0
  149. package/src/icons/DocumentCssIcon/DocumentCssIcon.tsx +36 -0
  150. package/src/icons/DocumentCssIcon/index.ts +1 -0
  151. package/src/icons/DocumentGraphqlIcon/DocumentGraphqlIcon.tsx +64 -0
  152. package/src/icons/DocumentGraphqlIcon/index.ts +1 -0
  153. package/src/icons/DocumentHtmlIcon/DocumentHtmlIcon.tsx +36 -0
  154. package/src/icons/DocumentHtmlIcon/index.ts +1 -0
  155. package/src/icons/DocumentJsIcon/DocumentJsIcon.tsx +36 -0
  156. package/src/icons/DocumentJsIcon/index.ts +1 -0
  157. package/src/icons/DocumentJsonIcon/DocumentJsonIcon.tsx +36 -0
  158. package/src/icons/DocumentJsonIcon/index.ts +1 -0
  159. package/src/icons/DocumentMarkdownIcon/DocumentMarkdownIcon.tsx +36 -0
  160. package/src/icons/DocumentMarkdownIcon/index.ts +1 -0
  161. package/src/icons/DocumentReactIcon/DocumentReactIcon.tsx +36 -0
  162. package/src/icons/DocumentReactIcon/index.ts +1 -0
  163. package/src/icons/DocumentTsIcon/DocumentTsIcon.tsx +38 -0
  164. package/src/icons/DocumentTsIcon/index.ts +1 -0
  165. package/src/icons/DocumentYamlIcon/DocumentYamlIcon.tsx +36 -0
  166. package/src/icons/DocumentYamlIcon/index.ts +1 -0
  167. package/src/index.ts +1 -0
  168. package/src/layouts/CodeWalkthroughLayout.tsx +78 -0
  169. package/src/markdoc/attributes/code-walkthrough-filesets.ts +9 -0
  170. package/src/markdoc/attributes/code-walkthrough-filters.ts +9 -0
  171. package/src/markdoc/components/CodeWalkthrough/CodeContainer.tsx +76 -0
  172. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +87 -0
  173. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +68 -0
  174. package/src/markdoc/components/CodeWalkthrough/CodePanelHeader.tsx +192 -0
  175. package/src/markdoc/components/CodeWalkthrough/CodePanelPreview.tsx +53 -0
  176. package/src/markdoc/components/CodeWalkthrough/CodePanelToolbar.tsx +31 -0
  177. package/src/markdoc/components/CodeWalkthrough/CodeStep.tsx +149 -0
  178. package/src/markdoc/components/CodeWalkthrough/CodeToggle.tsx +63 -0
  179. package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +111 -0
  180. package/src/markdoc/components/CodeWalkthrough/Input.tsx +101 -0
  181. package/src/markdoc/components/CodeWalkthrough/variables.ts +16 -0
  182. package/src/markdoc/components/default.ts +5 -0
  183. package/src/markdoc/default.ts +8 -0
  184. package/src/markdoc/tags/code-step.ts +27 -0
  185. package/src/markdoc/tags/code-toggle.ts +37 -0
  186. package/src/markdoc/tags/code-walkthrough.ts +315 -0
  187. package/src/markdoc/tags/input.ts +35 -0
  188. package/src/plugin.js +2 -2
@@ -0,0 +1 @@
1
+ export { DocumentTsIcon } from '@redocly/theme/icons/DocumentTsIcon/DocumentTsIcon';
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { IconProps } from '@redocly/theme/icons/types';
5
+
6
+ import { getCssColorVariable } from '@redocly/theme/core/utils';
7
+
8
+ const Icon = (props: IconProps) => (
9
+ <svg
10
+ width="16"
11
+ height="16"
12
+ viewBox="0 0 16 16"
13
+ fill="none"
14
+ xmlns="http://www.w3.org/2000/svg"
15
+ {...props}
16
+ >
17
+ <g id="iconYaml">
18
+ <path
19
+ id="Vector"
20
+ d="M8.66675 5.99967H12.3334L8.66675 2.33301V5.99967ZM4.00008 1.33301H9.33342L13.3334 5.33301V13.333C13.3334 14.0663 12.7334 14.6663 12.0001 14.6663H4.00008C3.26675 14.6663 2.66675 14.0663 2.66675 13.333V2.66634C2.66675 1.93301 3.26675 1.33301 4.00008 1.33301ZM12.0001 11.9997V10.6663H6.00008V11.9997H12.0001ZM9.33342 9.33301V7.99967H4.00008V9.33301H9.33342Z"
21
+ fill="#3B3C45"
22
+ />
23
+ </g>
24
+ </svg>
25
+ );
26
+
27
+ export const DocumentYamlIcon = styled(Icon).attrs(() => ({
28
+ 'data-component-name': 'icons/DocumentYamlIcon/DocumentYamlIcon',
29
+ }))<IconProps>`
30
+ path {
31
+ fill: ${({ color }) => getCssColorVariable(color)};
32
+ }
33
+
34
+ height: ${({ size }) => size || '16px'};
35
+ width: ${({ size }) => size || '16px'};
36
+ `;
@@ -0,0 +1 @@
1
+ export { DocumentYamlIcon } from '@redocly/theme/icons/DocumentYamlIcon/DocumentYamlIcon';
package/src/index.ts CHANGED
@@ -242,6 +242,7 @@ export * from '@redocly/theme/layouts/NotFound';
242
242
  export * from '@redocly/theme/layouts/Forbidden';
243
243
  export * from '@redocly/theme/layouts/OIDCForbidden';
244
244
  export * from '@redocly/theme/layouts/ThreePanelLayout';
245
+ export * from '@redocly/theme/layouts/CodeWalkthroughLayout';
245
246
  /* Markdoc */
246
247
  export * as markdoc from '@redocly/theme/markdoc/default';
247
248
  /* DatePicker */
@@ -0,0 +1,78 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ export type CodeWalkthroughLayoutProps = React.PropsWithChildren<{
5
+ className?: string;
6
+ }>;
7
+
8
+ export function CodeWalkthroughLayout({
9
+ className,
10
+ children,
11
+ }: CodeWalkthroughLayoutProps): JSX.Element {
12
+ return (
13
+ <LayoutWrapper data-component-name="Layout/CodeWalkthroughLayout" className={className}>
14
+ <ContentWrapper>{children}</ContentWrapper>
15
+ </LayoutWrapper>
16
+ );
17
+ }
18
+
19
+ const LayoutWrapper = styled.div.attrs(({ className }) => ({
20
+ className,
21
+ }))`
22
+ display: flex;
23
+ flex: 1;
24
+ width: 100%;
25
+ `;
26
+
27
+ const ContentWrapper = styled.section`
28
+ width: 100%;
29
+ --md-content-font-size: var(--font-size-lg);
30
+ --md-content-line-height: var(--line-height-lg);
31
+ --md-table-font-size: var(--md-content-font-size);
32
+ --md-table-line-height: var(--md-content-line-height);
33
+ --md-tabs-content-font-size: var(--md-content-font-size);
34
+ --md-tabs-content-line-height: var(--md-content-line-height);
35
+
36
+ article {
37
+ padding: var(--spacing-xl) 0;
38
+
39
+ /* Spacing for elements preceding a code walkthrough */
40
+ > :not(.code-walkthrough):has(+ .code-walkthrough) {
41
+ margin-bottom: var(--spacing-xl);
42
+ }
43
+
44
+ /* Spacing for code walkthroughs not at the end */
45
+ > .code-walkthrough:not(:last-child) {
46
+ margin-bottom: var(--spacing-xl);
47
+ }
48
+
49
+ /* Layout constraints for direct children except .code-walkthrough */
50
+ > :not(.code-walkthrough) {
51
+ max-width: var(--md-content-max-width);
52
+ padding-left: 0;
53
+ padding-right: 0;
54
+ margin-left: auto !important;
55
+ margin-right: auto !important;
56
+ }
57
+
58
+ /* Adjust padding for edge cases with .code-walkthrough */
59
+ &:has(.code-walkthrough:first-child) {
60
+ padding-top: 0;
61
+ }
62
+
63
+ &:has(.code-walkthrough:last-child) {
64
+ padding-bottom: 0;
65
+ }
66
+
67
+ /* Full-width styling for all .code-walkthroughs */
68
+ .code-walkthrough {
69
+ max-width: none;
70
+ width: 100%;
71
+ }
72
+
73
+ &:first-child > h1:first-child {
74
+ // disable margin top for h1 on the title heading
75
+ margin-top: 0;
76
+ }
77
+ }
78
+ `;
@@ -0,0 +1,9 @@
1
+ import type { CustomAttributeTypeInterface, ValidationError } from '@markdoc/markdoc';
2
+
3
+ export class CodeWalkthroughFilesets implements CustomAttributeTypeInterface {
4
+ validate(_value: string): ValidationError[] {
5
+ return [];
6
+ }
7
+
8
+ static resolver = 'codeWalkthroughFilesets';
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { CustomAttributeTypeInterface, ValidationError } from '@markdoc/markdoc';
2
+
3
+ export class CodeWalkthroughFilters implements CustomAttributeTypeInterface {
4
+ validate(_value: string): ValidationError[] {
5
+ return [];
6
+ }
7
+
8
+ static resolver = 'codeWalkthroughFilters';
9
+ }
@@ -0,0 +1,76 @@
1
+ import React, { useContext, useRef, useEffect, useState } from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import { CodeWalkthroughStepsContext } from '@redocly/theme/core/contexts';
5
+ import { CodeBlockContainer } from '@redocly/theme/components/CodeBlock/CodeBlockContainer';
6
+
7
+ export type CodeContainerProps = {
8
+ highlightedCode: string;
9
+ toolbar: JSX.Element;
10
+ };
11
+
12
+ export function CodeContainer({
13
+ highlightedCode,
14
+ toolbar,
15
+ }: CodeContainerProps): JSX.Element | null {
16
+ const { activeStep } = useContext(CodeWalkthroughStepsContext);
17
+ const [isHovered, setIsHovered] = useState(false);
18
+ const compRef = useRef<HTMLDivElement | null>(null);
19
+
20
+ useEffect(() => {
21
+ // useEffect executed before DOM is updated due to re-render called before "painting" phase.
22
+ setTimeout(() => {
23
+ if (compRef.current) {
24
+ const element = compRef.current.querySelector('span.line.highlighted');
25
+ if (element) {
26
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' });
27
+ }
28
+ }
29
+ }, 200);
30
+ }, [activeStep]);
31
+
32
+ return (
33
+ <CodeContainerWrapper
34
+ ref={compRef}
35
+ hideCodeColors={!isHovered}
36
+ onMouseEnter={() => setIsHovered(true)}
37
+ onMouseLeave={() => setIsHovered(false)}
38
+ >
39
+ <CodeBlockContainer dangerouslySetInnerHTML={{ __html: highlightedCode }} />
40
+ {toolbar}
41
+ </CodeContainerWrapper>
42
+ );
43
+ }
44
+
45
+ const CodeContainerWrapper = styled.div<{ hideCodeColors?: boolean }>`
46
+ position: relative;
47
+
48
+ display: flex;
49
+ flex-direction: column;
50
+ flex-grow: 1;
51
+ min-height: 0;
52
+
53
+ pre {
54
+ display: grid;
55
+ grid-auto-rows: min-content;
56
+ min-height: 0;
57
+ overflow: scroll;
58
+ margin: 0 !important;
59
+ height: 100%;
60
+ padding-left: 0 !important;
61
+
62
+ span.line::before {
63
+ color: var(--code-panel-line-numbering-color);
64
+ }
65
+ ${({ hideCodeColors }) =>
66
+ hideCodeColors &&
67
+ css`
68
+ .line.greyed-out {
69
+ color: var(--text-color-helper) !important;
70
+ * {
71
+ color: var(--text-color-helper) !important;
72
+ }
73
+ }
74
+ `}
75
+ }
76
+ `;
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { CodeWalkthroughFilter } from '@redocly/config';
5
+
6
+ import { Tag } from '@redocly/theme/components/Tag/Tag';
7
+
8
+ export type CodeFilterProps = {
9
+ filters: CodeWalkthroughFilter[];
10
+ getFilterState: (groupId: string) => { value: string; render: boolean } | null;
11
+ handleFilterSelect: (groupId: string, id: string) => void;
12
+ filtersElementRef?: React.RefObject<HTMLDivElement>;
13
+ };
14
+
15
+ export function CodeFilters({
16
+ filters,
17
+ getFilterState,
18
+ handleFilterSelect,
19
+ filtersElementRef,
20
+ }: CodeFilterProps) {
21
+ if (filters.length === 0) {
22
+ return null;
23
+ }
24
+
25
+ return (
26
+ <FilterWrapper ref={filtersElementRef}>
27
+ {filters.map(({ label, items, id }) => {
28
+ return (
29
+ <Filter key={id}>
30
+ {label && <FilterName>{label}:</FilterName>}
31
+ <ButtonsWrapper>
32
+ {items?.map((item) => (
33
+ <TagButton
34
+ size="large"
35
+ borderless
36
+ active={getFilterState(id)?.value === item.value}
37
+ key={item.value}
38
+ onClick={() => handleFilterSelect(id, item.value)}
39
+ >
40
+ {item.value}
41
+ </TagButton>
42
+ ))}
43
+ </ButtonsWrapper>
44
+ </Filter>
45
+ );
46
+ })}
47
+ </FilterWrapper>
48
+ );
49
+ }
50
+
51
+ const Filter = styled.div`
52
+ display: flex;
53
+ align-items: center;
54
+ gap: var(--spacing-xs);
55
+ `;
56
+
57
+ const FilterName = styled.div`
58
+ color: var(--color-text-primary);
59
+ font-size: var(--font-size-base);
60
+ `;
61
+
62
+ const FilterWrapper = styled.div`
63
+ --tag-text-transform: none;
64
+ display: flex;
65
+ flex-direction: row;
66
+ gap: var(--spacing-sm);
67
+ flex-wrap: wrap;
68
+ position: sticky;
69
+
70
+ padding-top: calc(var(--spacing-xs) + var(--spacing-xl));
71
+ padding-right: var(--spacing-xl);
72
+ padding-left: var(--spacing-xl);
73
+ padding-bottom: var(--spacing-xs);
74
+ top: calc(var(--navbar-height));
75
+ background-color: var(--bg-color);
76
+ z-index: 1;
77
+ `;
78
+
79
+ const ButtonsWrapper = styled.div`
80
+ display: flex;
81
+ `;
82
+
83
+ const TagButton = styled(Tag)`
84
+ cursor: pointer;
85
+ padding: 0px var(--spacing-xs);
86
+ margin-right: var(--spacing-xs);
87
+ `;
@@ -0,0 +1,68 @@
1
+ import React, { useContext } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { CodeWalkthroughFile } from '@redocly/config';
5
+
6
+ import { useCodePanel } from '@redocly/theme/core/hooks';
7
+ import { CodeWalkthroughControlsStateContext } from '@redocly/theme/core/contexts';
8
+ import { CodePanelHeader } from '@redocly/theme/markdoc/components/CodeWalkthrough/CodePanelHeader';
9
+ import { CodePanelPreview } from '@redocly/theme/markdoc/components/CodeWalkthrough/CodePanelPreview';
10
+ import { CodeContainer } from '@redocly/theme/markdoc/components/CodeWalkthrough/CodeContainer';
11
+ import { CodePanelToolbar } from '@redocly/theme/markdoc/components/CodeWalkthrough/CodePanelToolbar';
12
+
13
+ export type CodePanelProps = {
14
+ files: CodeWalkthroughFile[];
15
+ downloadAssociatedFiles: CodeWalkthroughFile[];
16
+ preview: React.ReactNode[];
17
+ };
18
+
19
+ export function CodePanel({
20
+ files,
21
+ downloadAssociatedFiles,
22
+ preview,
23
+ }: CodePanelProps): JSX.Element | null {
24
+ const { activeFile, handleTabSwitch, highlightedCode } = useCodePanel(files);
25
+ const { handleDownloadCode } = useContext(CodeWalkthroughControlsStateContext);
26
+
27
+ return (
28
+ <CodePanelWrapper>
29
+ {preview ? (
30
+ <CodePanelPreview>
31
+ {preview.map((element, idx) => (
32
+ <React.Fragment key={idx}>{element}</React.Fragment>
33
+ ))}
34
+ </CodePanelPreview>
35
+ ) : null}
36
+ <CodePanelHeader
37
+ files={files}
38
+ activeTabName={activeFile?.path || ''}
39
+ handleTabSwitch={handleTabSwitch}
40
+ onDownloadCode={() => handleDownloadCode([...files, ...downloadAssociatedFiles])}
41
+ />
42
+ <CodeContainer
43
+ key={activeFile?.path || ''}
44
+ highlightedCode={highlightedCode}
45
+ toolbar={<CodePanelToolbar file={activeFile} />}
46
+ />
47
+ </CodePanelWrapper>
48
+ );
49
+ }
50
+
51
+ const CodePanelWrapper = styled.div`
52
+ display: flex;
53
+ flex-direction: column;
54
+ align-self: flex-start;
55
+
56
+ min-height: 144px;
57
+ min-width: 0;
58
+ height: 100%;
59
+ word-wrap: break-word;
60
+
61
+ background-color: var(--code-panel-bg-color);
62
+ border: 1px solid var(--code-panel-border-color);
63
+ border-radius: var(--code-panel-border-radius);
64
+ --code-block-max-height: calc(100vh - var(--navbar-height) - 2 * var(--spacing-xl));
65
+ height: calc(100vh - var(--navbar-height) - 2 * var(--spacing-xl));
66
+ position: sticky;
67
+ top: calc(var(--navbar-height) + var(--spacing-xl));
68
+ `;
@@ -0,0 +1,192 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import styled, { css } from 'styled-components';
3
+
4
+ import type { CodeWalkthroughFile } from '@redocly/config';
5
+
6
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
7
+ import { getFileIconByExt } from '@redocly/theme/core/utils';
8
+ import { OverflowMenuVerticalIcon } from '@redocly/theme/icons/OverflowMenuVerticalIcon/OverflowMenuVerticalIcon';
9
+ import { Dropdown } from '@redocly/theme/components/Dropdown/Dropdown';
10
+ import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu';
11
+ import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem';
12
+ import { DownloadIcon } from '@redocly/theme/icons/DownloadIcon/DownloadIcon';
13
+ import { Button } from '@redocly/theme/components/Button/Button';
14
+
15
+ export type CodePanelHeaderProps = {
16
+ files: CodeWalkthroughFile[];
17
+ handleTabSwitch: (name: string) => void;
18
+ activeTabName: string;
19
+ onDownloadCode: () => void;
20
+ };
21
+
22
+ export function CodePanelHeader({
23
+ files,
24
+ handleTabSwitch,
25
+ activeTabName,
26
+ onDownloadCode,
27
+ }: CodePanelHeaderProps): JSX.Element {
28
+ const { useTranslate } = useThemeHooks();
29
+ const { translate } = useTranslate();
30
+ const tabRefs = useRef<HTMLButtonElement[]>([]);
31
+ const tabsWrapperRef = useRef<HTMLDivElement>(null);
32
+ const [hiddenFiles, setHiddenFiles] = useState<CodeWalkthroughFile[]>([]);
33
+
34
+ useEffect(() => {
35
+ const activeTab = tabRefs.current.find((tab) => tab?.dataset.name === activeTabName);
36
+ if (activeTab) {
37
+ activeTab.scrollIntoView({ block: 'nearest', inline: 'center' });
38
+ }
39
+ }, [activeTabName]);
40
+
41
+ useEffect(() => {
42
+ const calculateHiddenFiles = () => {
43
+ if (!tabsWrapperRef.current) return;
44
+ const { left: wrapperLeft, right: wrapperRight } =
45
+ tabsWrapperRef.current.getBoundingClientRect();
46
+
47
+ const hidden = files.filter((_, i) => {
48
+ const tab = tabRefs.current[i];
49
+ if (!tab) return false;
50
+ const { left: tabLeft, right: tabRight } = tab.getBoundingClientRect();
51
+
52
+ return tabLeft < wrapperLeft || tabRight > wrapperRight;
53
+ });
54
+
55
+ setHiddenFiles(hidden);
56
+ };
57
+
58
+ calculateHiddenFiles();
59
+ window.addEventListener('resize', calculateHiddenFiles);
60
+ return () => window.removeEventListener('resize', calculateHiddenFiles);
61
+ }, [files]);
62
+
63
+ const getFileTypeIcon = useCallback((basename: string) => {
64
+ const extension = basename.split('.').pop()?.toLowerCase() || '';
65
+ return getFileIconByExt(extension);
66
+ }, []);
67
+
68
+ return (
69
+ <CodePanelHeaderWrapper data-component-name="Markdoc/CodeWalkthrough/CodePanelHeader">
70
+ <TabsWrapper ref={tabsWrapperRef}>
71
+ <Tabs>
72
+ {files.map(({ path, basename }, i) => {
73
+ const FileIcon = getFileTypeIcon(basename);
74
+ return (
75
+ <Tab
76
+ ref={(el: HTMLButtonElement) => (tabRefs.current[i] = el)}
77
+ data-name={path}
78
+ active={path === activeTabName}
79
+ key={i}
80
+ onClick={() => handleTabSwitch(path)}
81
+ >
82
+ <FileIcon />
83
+ {basename}
84
+ </Tab>
85
+ );
86
+ })}
87
+ </Tabs>
88
+ <Gradient />
89
+ </TabsWrapper>
90
+
91
+ <ActionBar>
92
+ {hiddenFiles.length ? (
93
+ <Dropdown trigger={<StyledOverflowMenuVerticalIcon size="14px" />} alignment="end">
94
+ <StyledDropdownMenu>
95
+ {hiddenFiles.map(({ path, basename }, i) => {
96
+ const FileIcon = getFileTypeIcon(basename);
97
+ return (
98
+ <DropdownMenuItem
99
+ active={path === activeTabName}
100
+ key={i}
101
+ onAction={() => handleTabSwitch(path)}
102
+ prefix={<FileIcon />}
103
+ content={basename}
104
+ />
105
+ );
106
+ })}
107
+ </StyledDropdownMenu>
108
+ </Dropdown>
109
+ ) : null}
110
+
111
+ <Button variant="text" icon={<DownloadIcon />} onClick={onDownloadCode} size="small">
112
+ {translate('codeWalkthrough.download', 'Download')}
113
+ </Button>
114
+ </ActionBar>
115
+ </CodePanelHeaderWrapper>
116
+ );
117
+ }
118
+
119
+ const CodePanelHeaderWrapper = styled.div`
120
+ display: flex;
121
+ align-items: center;
122
+ justify-content: space-between;
123
+
124
+ padding: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) var(--spacing-sm);
125
+ max-width: 100%;
126
+ `;
127
+
128
+ const TabsWrapper = styled.div`
129
+ display: flex;
130
+ position: relative;
131
+ min-width: 0;
132
+ `;
133
+
134
+ const Gradient = styled.div`
135
+ position: absolute;
136
+ right: 0;
137
+ width: var(--spacing-base);
138
+ height: var(--code-panel-header-height);
139
+ background: var(--bg-raised-gradient);
140
+ `;
141
+
142
+ const Tabs = styled.div`
143
+ display: flex;
144
+ overflow-x: auto;
145
+ padding-right: var(--spacing-base);
146
+
147
+ &::-webkit-scrollbar {
148
+ display: none;
149
+ }
150
+ `;
151
+
152
+ const ActionBar = styled.div`
153
+ display: flex;
154
+ `;
155
+
156
+ const Tab = styled.button<{ active: boolean }>`
157
+ display: inline-flex;
158
+ align-items: center;
159
+ padding: 0 var(--spacing-sm);
160
+ background-color: transparent;
161
+ height: var(--code-panel-header-height);
162
+ border-radius: var(--border-radius);
163
+ cursor: pointer;
164
+ gap: var(--spacing-xs);
165
+ color: var(--text-color-secondary);
166
+ white-space: nowrap;
167
+
168
+ ${({ active }) =>
169
+ active
170
+ ? css`
171
+ color: var(--text-color-primary);
172
+ background-color: var(--tab-bg-color-filled);
173
+ `
174
+ : css`
175
+ &:hover {
176
+ color: var(--text-color-primary);
177
+ }
178
+ `}
179
+ `;
180
+
181
+ // code-walk-todo: figure it our why we could not do it differently
182
+ const StyledDropdownMenu = styled(DropdownMenu)`
183
+ --md-list-left-padding: var(--dropdown-menu-padding);
184
+ `;
185
+
186
+ const StyledOverflowMenuVerticalIcon = styled(OverflowMenuVerticalIcon)`
187
+ && {
188
+ outline: none;
189
+ box-sizing: content-box;
190
+ padding: 5px;
191
+ }
192
+ `;
@@ -0,0 +1,53 @@
1
+ import React, { PropsWithChildren, useState } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
5
+ import { ChevronUpIcon } from '@redocly/theme/icons/ChevronUpIcon/ChevronUpIcon';
6
+ import { ChevronDownIcon } from '@redocly/theme/icons/ChevronDownIcon/ChevronDownIcon';
7
+
8
+ export function CodePanelPreview({ children }: PropsWithChildren): JSX.Element {
9
+ const [isOpen, setIsOpen] = useState(false);
10
+ const { useTranslate } = useThemeHooks();
11
+ const { translate } = useTranslate();
12
+
13
+ return (
14
+ <CodePanelPreviewWrapper>
15
+ <PreviewDropdown onClick={() => setIsOpen(!isOpen)}>
16
+ {translate('codeWalkthrough.preview', 'Preview')}
17
+ {isOpen ? <ChevronUpIcon /> : <ChevronDownIcon />}
18
+ </PreviewDropdown>
19
+ <PreviewContentWrapper isOpen={isOpen}>{children}</PreviewContentWrapper>
20
+ </CodePanelPreviewWrapper>
21
+ );
22
+ }
23
+
24
+ const CodePanelPreviewWrapper = styled.div`
25
+ width: 100%;
26
+ padding: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) var(--spacing-sm);
27
+ border-bottom: 1px solid var(--border-color-secondary);
28
+ `;
29
+
30
+ const PreviewDropdown = styled.div`
31
+ display: flex;
32
+ align-items: center;
33
+
34
+ gap: (--spacing-xxs);
35
+
36
+ user-select: none;
37
+
38
+ font-size: var(--font-size-base);
39
+ cursor: pointer;
40
+ `;
41
+
42
+ const PreviewContentWrapper = styled.div<{ isOpen: boolean }>`
43
+ display: ${({ isOpen }) => (isOpen ? 'grid' : 'none')};
44
+ place-items: center;
45
+
46
+ margin: auto 0;
47
+
48
+ max-height: 50vh;
49
+ width: 100%;
50
+ max-width: 100%;
51
+
52
+ overflow: auto;
53
+ `;
@@ -0,0 +1,31 @@
1
+ import React, { useContext } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { CodeWalkthroughFile } from '@redocly/config';
5
+
6
+ import { CodeWalkthroughControlsStateContext } from '@redocly/theme/core/contexts';
7
+ import { CopyButton } from '@redocly/theme/components/Buttons/CopyButton';
8
+
9
+ export type CodeToolbarProps = {
10
+ file: CodeWalkthroughFile;
11
+ };
12
+
13
+ export function CodePanelToolbar({ file }: CodeToolbarProps): JSX.Element {
14
+ const { getFileText } = useContext(CodeWalkthroughControlsStateContext);
15
+
16
+ const fileContent = getFileText(file);
17
+
18
+ return (
19
+ <CodeToolbarWrapper>
20
+ <CopyButton data={fileContent} type="compound" variant="secondary" size="medium" />
21
+ </CodeToolbarWrapper>
22
+ );
23
+ }
24
+
25
+ const CodeToolbarWrapper = styled.div`
26
+ display: flex;
27
+ position: absolute;
28
+ bottom: var(--spacing-sm);
29
+ right: var(--spacing-sm);
30
+ gap: var(--spacing-xs);
31
+ `;