@redocly/theme 0.1.26 → 0.1.29

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 (135) hide show
  1. package/Button/Button.js +3 -3
  2. package/CodeBlock/CodeBlock.js +1 -1
  3. package/CopyButton/CopyButton.js +17 -1
  4. package/CopyButton/CopyButtonWrapper.js +1 -1
  5. package/Footer/Footer.js +2 -1
  6. package/Footer/FooterColumn.js +1 -1
  7. package/Footer/FooterColumns.d.ts +2 -2
  8. package/Footer/FooterColumns.js +1 -1
  9. package/JsonViewer/JsonViewer.d.ts +2 -0
  10. package/JsonViewer/JsonViewer.js +53 -22
  11. package/Markdown/Admonition.js +1 -1
  12. package/Markdown/CodeSample/CodeSample.js +17 -1
  13. package/Markdown/Heading.js +11 -2
  14. package/Markdown/MarkdownWrapper.js +2 -2
  15. package/Markdown/Mermaid.js +1 -1
  16. package/Markdown/Sup.d.ts +2 -0
  17. package/Markdown/Sup.js +19 -0
  18. package/Markdown/Tabs/Tabs.js +17 -1
  19. package/Markdown/index.d.ts +4 -3
  20. package/Markdown/index.js +4 -3
  21. package/Navbar/MobileNavbarDropdown.d.ts +8 -0
  22. package/Navbar/MobileNavbarDropdown.js +21 -0
  23. package/Navbar/MobileNavbarItem.d.ts +15 -0
  24. package/Navbar/MobileNavbarItem.js +102 -0
  25. package/Navbar/MobileNavbarMenu.d.ts +6 -0
  26. package/Navbar/MobileNavbarMenu.js +32 -0
  27. package/Navbar/MobileNavbarMenuButton.d.ts +4 -0
  28. package/Navbar/MobileNavbarMenuButton.js +19 -0
  29. package/Navbar/Navbar.js +26 -4
  30. package/Navbar/NavbarDropdown.js +1 -1
  31. package/Navbar/NavbarItem.d.ts +9 -3
  32. package/Navbar/NavbarItem.js +9 -9
  33. package/Navbar/NavbarMenu.js +3 -2
  34. package/PageNavigation/NextPageLink.js +4 -4
  35. package/PageNavigation/PreviousPageLink.js +4 -4
  36. package/Panel/PanelComponent.js +18 -2
  37. package/Profile/Profile.d.ts +8 -0
  38. package/Profile/Profile.js +60 -0
  39. package/Profile/index.d.ts +2 -0
  40. package/Profile/index.js +5 -0
  41. package/Search/Autocomplete.js +18 -2
  42. package/Search/utils.js +17 -1
  43. package/Sidebar/SidebarLayout.js +17 -1
  44. package/SourceCode/SourceCode.d.ts +10 -3
  45. package/SourceCode/SourceCode.js +10 -5
  46. package/TableOfContent/TableOfContent.js +4 -4
  47. package/Tooltip/Tooltip.d.ts +5 -4
  48. package/Tooltip/Tooltip.js +43 -21
  49. package/globalStyle.js +2 -2
  50. package/hooks/useActiveHeading.js +17 -1
  51. package/hooks/useActiveSectionId.d.ts +1 -1
  52. package/hooks/useActiveSectionId.js +17 -1
  53. package/hooks/useControl.js +17 -1
  54. package/hooks/useMobileMenu.js +17 -1
  55. package/hooks/useNavbarHeight.js +17 -1
  56. package/index.d.ts +1 -0
  57. package/index.js +1 -0
  58. package/package.json +1 -1
  59. package/src/Button/Button.tsx +5 -1
  60. package/src/CodeBlock/CodeBlock.ts +12 -0
  61. package/src/CopyButton/CopyButtonWrapper.tsx +1 -1
  62. package/src/Footer/Footer.tsx +4 -3
  63. package/src/Footer/FooterColumn.tsx +3 -1
  64. package/src/Footer/FooterColumns.tsx +3 -3
  65. package/src/JsonViewer/JsonViewer.tsx +55 -40
  66. package/src/Markdown/Admonition.tsx +1 -1
  67. package/src/Markdown/Heading.tsx +13 -2
  68. package/src/Markdown/MarkdownWrapper.tsx +58 -58
  69. package/src/Markdown/Mermaid.tsx +1 -1
  70. package/src/Markdown/Sup.tsx +8 -0
  71. package/src/Markdown/index.ts +4 -3
  72. package/src/Navbar/MobileNavbarDropdown.tsx +37 -0
  73. package/src/Navbar/MobileNavbarItem.tsx +116 -0
  74. package/src/Navbar/MobileNavbarMenu.tsx +106 -0
  75. package/src/Navbar/MobileNavbarMenuButton.tsx +13 -0
  76. package/src/Navbar/Navbar.tsx +11 -3
  77. package/src/Navbar/NavbarDropdown.tsx +1 -1
  78. package/src/Navbar/NavbarItem.tsx +9 -8
  79. package/src/Navbar/NavbarMenu.tsx +9 -4
  80. package/src/PageNavigation/NextPageLink.tsx +3 -3
  81. package/src/PageNavigation/PreviousPageLink.tsx +3 -3
  82. package/src/Profile/Profile.tsx +91 -0
  83. package/src/Profile/index.ts +2 -0
  84. package/src/SourceCode/SourceCode.tsx +32 -5
  85. package/src/TableOfContent/TableOfContent.tsx +3 -3
  86. package/src/Tooltip/Tooltip.tsx +87 -63
  87. package/src/globalStyle.ts +2 -0
  88. package/src/hooks/useActiveSectionId.ts +1 -1
  89. package/src/index.ts +1 -0
  90. package/src/types/portal/src/client/app/Sidebar/types.d.ts +2 -1
  91. package/src/types/portal/src/server/constants.d.ts +2 -0
  92. package/src/types/portal/src/server/dev-server/types.d.ts +22 -0
  93. package/src/types/portal/src/server/plugins/markdown/types.d.ts +15 -5
  94. package/src/types/portal/src/server/plugins/portal-config/get-frontmatter-keys-to-resolve.d.ts +2 -0
  95. package/src/types/portal/src/server/plugins/portal-config/types.d.ts +6 -2
  96. package/src/types/portal/src/server/plugins/reference-docs/utils.d.ts +26 -0
  97. package/src/types/portal/src/server/plugins/types.d.ts +29 -12
  98. package/src/types/portal/src/server/store.d.ts +16 -16
  99. package/src/types/portal/src/server/utils/fs.d.ts +2 -1
  100. package/src/types/portal/src/server/utils/index.d.ts +1 -0
  101. package/src/types/portal/src/server/utils/paths.d.ts +4 -0
  102. package/src/types/portal/src/server/utils/rbac.d.ts +15 -0
  103. package/src/types/portal/src/shared/constants.d.ts +7 -0
  104. package/src/types/portal/src/shared/models/config.d.ts +24 -12
  105. package/src/types/portal/src/shared/types.d.ts +17 -4
  106. package/src/types/portal/src/shared/urls.d.ts +1 -1
  107. package/src/types/portal/src/shared/utils.d.ts +2 -0
  108. package/src/ui/Burger.tsx +36 -0
  109. package/src/ui/Flex.tsx +1 -0
  110. package/src/utils/args-typecheck.ts +9 -0
  111. package/src/utils/class-names.ts +8 -0
  112. package/src/utils/color.ts +9 -0
  113. package/src/utils/highlight.ts +11 -0
  114. package/src/utils/index.ts +3 -0
  115. package/src/utils/jsonToHtml.ts +171 -59
  116. package/src/utils/theme-helpers.ts +3 -1
  117. package/ui/Burger.d.ts +8 -0
  118. package/ui/Burger.js +23 -0
  119. package/ui/Dropdown.js +17 -1
  120. package/ui/Flex.js +1 -1
  121. package/ui/UniversalLink.js +17 -1
  122. package/utils/args-typecheck.d.ts +2 -0
  123. package/utils/args-typecheck.js +13 -0
  124. package/utils/class-names.d.ts +1 -0
  125. package/utils/class-names.js +15 -0
  126. package/utils/color.d.ts +2 -0
  127. package/utils/color.js +12 -0
  128. package/utils/highlight.d.ts +1 -0
  129. package/utils/highlight.js +12 -1
  130. package/utils/index.d.ts +3 -0
  131. package/utils/index.js +3 -0
  132. package/utils/jsonToHtml.d.ts +4 -1
  133. package/utils/jsonToHtml.js +287 -83
  134. package/utils/media-css.js +40 -3
  135. package/utils/theme-helpers.js +59 -10
@@ -11,9 +11,17 @@ export interface JsonProps {
11
11
  data: any;
12
12
  className?: string;
13
13
  jsonSampleExpandLevel: number;
14
+ withLineNumbers?: boolean;
15
+ startLineNumber?: number;
14
16
  }
15
17
 
16
- function JsonComponent({ data, jsonSampleExpandLevel, className }: JsonProps): JSX.Element {
18
+ function JsonComponent({
19
+ data,
20
+ jsonSampleExpandLevel,
21
+ className,
22
+ withLineNumbers,
23
+ startLineNumber,
24
+ }: JsonProps): JSX.Element {
17
25
  const node = useRef<HTMLDivElement | null>(null);
18
26
 
19
27
  useMount(() => {
@@ -84,10 +92,10 @@ function JsonComponent({ data, jsonSampleExpandLevel, className }: JsonProps): J
84
92
  )}
85
93
  </SampleControls>
86
94
  <StyledCodeBlock
87
- className={className}
95
+ className={withLineNumbers ? `${className} line-numbers` : className}
88
96
  ref={node}
89
97
  dangerouslySetInnerHTML={{
90
- __html: jsonToHTML(data, jsonSampleExpandLevel),
98
+ __html: jsonToHTML(data, jsonSampleExpandLevel, startLineNumber),
91
99
  }}
92
100
  />
93
101
  </JsonViewerWrap>
@@ -111,15 +119,11 @@ export const JsonViewer = styled(Json).attrs(() => ({
111
119
  color: var(--color-content-inverse);
112
120
  padding: inherit;
113
121
  border: none;
114
-
115
- & > .collapser {
116
- display: none;
117
- pointer-events: none;
118
- }
119
122
  }
120
123
 
121
124
  contain: content;
122
125
  overflow-x: auto;
126
+ position: relative;
123
127
  padding: 10px;
124
128
  border-radius: var(--global-border-radius);
125
129
  background-color: var(--samples-panel-controls-background-color);
@@ -128,13 +132,26 @@ export const JsonViewer = styled(Json).attrs(() => ({
128
132
  font-family: var(--code-font-family);
129
133
  white-space: var(--code-wrap, pre);
130
134
 
131
- .callback-function {
132
- color: gray;
135
+ &.line-numbers {
136
+ padding: 20px 20px 20px 3em;
137
+
138
+ *[data-line]:not(.collapsed *[data-line]) {
139
+ &:before {
140
+ content: attr(data-line);
141
+ position: absolute;
142
+ left: 0;
143
+ min-width: 2em;
144
+ text-align: right;
145
+ pointer-events: none;
146
+ user-select: none;
147
+ padding: 0 0.5em;
148
+ font-size: 13px;
149
+ }
150
+ }
133
151
  }
134
152
 
135
- .collapser:after {
136
- content: '-';
137
- cursor: pointer;
153
+ .callback-function {
154
+ color: gray;
138
155
  }
139
156
 
140
157
  .collapsed > .collapser:after {
@@ -147,11 +164,17 @@ export const JsonViewer = styled(Json).attrs(() => ({
147
164
  }
148
165
 
149
166
  .collapsible {
150
- margin-left: 2ch;
167
+ padding-left: 2ch;
168
+ display: inline-block;
151
169
  }
152
170
 
153
171
  .hoverable {
154
172
  padding: 1px 2px;
173
+ display: inline-block;
174
+ }
175
+
176
+ .collapsed {
177
+ display: inline-flex;
155
178
  }
156
179
 
157
180
  .hovered {
@@ -161,39 +184,31 @@ export const JsonViewer = styled(Json).attrs(() => ({
161
184
  .collapser {
162
185
  background-color: transparent;
163
186
  border: 0;
187
+ padding: 0;
164
188
  color: #fff;
165
- display: flex;
166
- align-items: center;
167
- justify-content: center;
168
- width: 15px;
189
+ width: 0;
169
190
  height: 15px;
170
- position: absolute;
171
- top: 4px;
172
- left: -1.5em;
173
191
  cursor: default;
174
192
  user-select: none;
175
193
  -webkit-user-select: none;
176
- padding: 2px;
177
194
  font-family: var(--code-font-family);
178
195
  font-size: var(--code-font-size);
179
- &:focus {
180
- outline: #fff dotted 1px;
181
- }
182
- }
183
-
184
- ul {
185
- list-style-type: none;
186
- padding: 0;
187
- margin: 0 0 0 26px;
188
- }
189
196
 
190
- li {
191
- position: relative;
192
- display: block;
193
- }
194
-
195
- .hoverable {
196
- display: inline-block;
197
+ &:after {
198
+ content: '-';
199
+ cursor: pointer;
200
+ display: flex;
201
+ align-items: center;
202
+ justify-content: center;
203
+ width: 15px;
204
+ height: 100%;
205
+ padding: 2px 5px 2px 2px;
206
+ transform: translateX(-100%);
207
+
208
+ &:focus {
209
+ outline: #fff dotted 1px;
210
+ }
211
+ }
197
212
  }
198
213
 
199
214
  .selected {
@@ -210,7 +225,7 @@ export const JsonViewer = styled(Json).attrs(() => ({
210
225
  }
211
226
 
212
227
  .collapsed > .ellipsis {
213
- display: inherit;
228
+ display: inline;
214
229
  }
215
230
  `;
216
231
 
@@ -17,7 +17,7 @@ export function Admonition({
17
17
  children,
18
18
  }: React.PropsWithChildren<AdmonitionProps>): JSX.Element {
19
19
  return (
20
- <Wrapper type={type} data-component-name="Markdown/Admonition/Admonition">
20
+ <Wrapper type={type} data-component-name="Markdown/Admonition">
21
21
  <AlertIcon type={type} />
22
22
  {name ? <Heading type={type}>{name}</Heading> : null}
23
23
  <Content>{children}</Content>
@@ -1,5 +1,12 @@
1
1
  import React, { createElement, PropsWithChildren } from 'react';
2
2
 
3
+ import { concatClassNames } from '@theme/utils';
4
+
5
+ /**
6
+ * Class name for all MD tags
7
+ */
8
+ const mdClassName = 'md';
9
+
3
10
  const SvgIcon = (
4
11
  <svg
5
12
  aria-hidden="true"
@@ -22,14 +29,18 @@ export function Heading({
22
29
  children,
23
30
  }: PropsWithChildren<{ level: number; id: string }>): JSX.Element {
24
31
  const linkEl = (
25
- <a href={`#${id}`} className="anchor before">
32
+ <a href={`#${id}`} className={concatClassNames('anchor', 'before')}>
26
33
  {SvgIcon}
27
34
  </a>
28
35
  );
29
36
 
30
37
  return createElement(
31
38
  `h${level}`,
32
- { id, className: 'heading-anchor', 'data-component-name': 'Markdown/Heading/Heading' },
39
+ {
40
+ id,
41
+ className: concatClassNames('heading-anchor', mdClassName),
42
+ 'data-component-name': 'Markdown/Heading',
43
+ },
33
44
  <>
34
45
  {linkEl}
35
46
  {children}
@@ -3,7 +3,7 @@ import styled, { css, FlattenSimpleInterpolation } from 'styled-components';
3
3
  import { typography } from '@theme/utils';
4
4
 
5
5
  export const baseTable = css`
6
- table {
6
+ table.md {
7
7
  display: block;
8
8
  width: 100%;
9
9
  overflow: auto;
@@ -13,58 +13,58 @@ export const baseTable = css`
13
13
  margin-top: 20px;
14
14
  margin-bottom: 20px;
15
15
  font-size: 14px;
16
- }
17
16
 
18
- table th,
19
- table td {
20
- padding: 12px;
21
- border-bottom: 1px solid var(--global-border-color);
22
- }
17
+ th,
18
+ td {
19
+ padding: 12px;
20
+ border-bottom: 1px solid var(--global-border-color);
21
+ }
23
22
 
24
- table th {
25
- text-align: left;
26
- font-weight: bold;
27
- background-color: var(--color-secondary-300);
28
- }
23
+ th {
24
+ text-align: left;
25
+ font-weight: bold;
26
+ background-color: var(--color-secondary-300);
27
+ }
29
28
 
30
- table tr th:first-child,
31
- table tr td:first-child {
32
- border-left: 1px solid var(--global-border-color);
33
- }
29
+ tr th:first-child,
30
+ tr td:first-child {
31
+ border-left: 1px solid var(--global-border-color);
32
+ }
34
33
 
35
- table tr td:last-child,
36
- table tr th:last-child {
37
- border-right: 1px solid var(--global-border-color);
38
- }
34
+ tr td:last-child,
35
+ tr th:last-child {
36
+ border-right: 1px solid var(--global-border-color);
37
+ }
39
38
 
40
- table thead td,
41
- table thead th {
42
- border-top: 1px solid var(--global-border-color);
43
- }
39
+ thead td,
40
+ thead th {
41
+ border-top: 1px solid var(--global-border-color);
42
+ }
44
43
 
45
- /* top-left border */
44
+ /* top-left border */
46
45
 
47
- table thead tr:first-child th:first-child {
48
- border-top-left-radius: var(--panels-border-radius);
49
- }
46
+ thead tr:first-child th:first-child {
47
+ border-top-left-radius: var(--panels-border-radius);
48
+ }
50
49
 
51
- /* top-right border */
50
+ /* top-right border */
52
51
 
53
- table thead tr:first-child th:last-child {
54
- border-top-right-radius: var(--panels-border-radius);
55
- border-top: 1px solid var(--global-border-color);
56
- }
52
+ thead tr:first-child th:last-child {
53
+ border-top-right-radius: var(--panels-border-radius);
54
+ border-top: 1px solid var(--global-border-color);
55
+ }
57
56
 
58
- /* bottom-left border */
57
+ /* bottom-left border */
59
58
 
60
- table tbody tr:last-child td:first-child {
61
- border-bottom-left-radius: var(--panels-border-radius);
62
- }
59
+ tbody tr:last-child td:first-child {
60
+ border-bottom-left-radius: var(--panels-border-radius);
61
+ }
63
62
 
64
- /* bottom-right border */
63
+ /* bottom-right border */
65
64
 
66
- table tbody tr:last-child td:last-child {
67
- border-bottom-right-radius: var(--panels-border-radius);
65
+ tbody tr:last-child td:last-child {
66
+ border-bottom-right-radius: var(--panels-border-radius);
67
+ }
68
68
  }
69
69
  `;
70
70
 
@@ -123,12 +123,12 @@ export const MarkdownWrapper = styled.main.attrs(() => ({
123
123
  max-width: 100%;
124
124
  }
125
125
 
126
- h1,
127
- h2,
128
- h3,
129
- h4,
130
- h5,
131
- h6 {
126
+ h1.md,
127
+ h2.md,
128
+ h3.md,
129
+ h4.md,
130
+ h5.md,
131
+ h6.md {
132
132
  font-weight: var(--h-font-weight);
133
133
  font-family: var(--h-font-family);
134
134
  position: relative;
@@ -206,9 +206,9 @@ export const MarkdownWrapper = styled.main.attrs(() => ({
206
206
  }
207
207
  }
208
208
 
209
- h1 {
209
+ h1.md {
210
210
  ${typography('h1', 'h')};
211
- margin: var(--h1-margin-top) var(--h1-margin-bottom);
211
+ margin: var(--h1-margin-top) 0 var(--h1-margin-bottom) 0;
212
212
  ${headingAnchor()};
213
213
 
214
214
  &:first-child {
@@ -216,33 +216,33 @@ export const MarkdownWrapper = styled.main.attrs(() => ({
216
216
  }
217
217
  }
218
218
 
219
- h2 {
219
+ h2.md {
220
220
  ${typography('h2', 'h')};
221
- margin: var(--h2-margin-top) var(--h2-margin-bottom);
221
+ margin: var(--h2-margin-top) 0 var(--h2-margin-bottom) 0;
222
222
  ${headingAnchor()};
223
223
  }
224
224
 
225
- h3 {
225
+ h3.md {
226
226
  ${typography('h3', 'h')};
227
- margin: var(--h3-margin-top) var(--h3-margin-bottom);
227
+ margin: var(--h3-margin-top) 0 var(--h3-margin-bottom) 0;
228
228
  ${headingAnchor()};
229
229
  }
230
230
 
231
- h4 {
231
+ h4.md {
232
232
  ${typography('h4', 'h')};
233
- margin: var(--h4-margin-top) var(--h4-margin-bottom);
233
+ margin: var(--h4-margin-top) 0 var(--h4-margin-bottom) 0;
234
234
  ${headingAnchor()};
235
235
  }
236
236
 
237
- h5 {
237
+ h5.md {
238
238
  ${typography('h5', 'h')};
239
- margin: var(--h5-margin-top) var(--h5-margin-bottom);
239
+ margin: var(--h5-margin-top) 0 var(--h5-margin-bottom) 0;
240
240
  ${headingAnchor()};
241
241
  }
242
242
 
243
- h6 {
243
+ h6.md {
244
244
  ${typography('h6', 'h')};
245
- margin: var(--h6-margin-top) var(--h6-margin-bottom);
245
+ margin: var(--h6-margin-top) 0 var(--h6-margin-bottom) 0;
246
246
  ${headingAnchor()};
247
247
  }
248
248
 
@@ -10,7 +10,7 @@ export function Mermaid({ diagramHtml }: MermaidProps): JSX.Element {
10
10
  <Wrapper
11
11
  className="mermaid-wrapper"
12
12
  dangerouslySetInnerHTML={{ __html: diagramHtml }}
13
- data-component-name="Markdown/Mermaid/Mermaid"
13
+ data-component-name="Markdown/Mermaid"
14
14
  />
15
15
  );
16
16
  }
@@ -0,0 +1,8 @@
1
+ import React, { PropsWithChildren } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ export function Sup({ children }: PropsWithChildren<unknown>): JSX.Element {
5
+ return <Wrapper data-component-name="Markdown/Sup">{children}</Wrapper>;
6
+ }
7
+
8
+ const Wrapper = styled.sup``;
@@ -1,9 +1,10 @@
1
- export * from '@theme/Markdown/CodeSample';
2
- export * from '@theme/Markdown/Tabs';
3
1
  export * from '@theme/Markdown/Admonition';
2
+ export * from '@theme/Markdown/CodeSample';
4
3
  export * from '@theme/Markdown/ContentWrapper';
5
4
  export * from '@theme/Markdown/Heading';
6
5
  export * from '@theme/Markdown/MarkdownLayout';
6
+ export * from '@theme/Markdown/MarkdownWrapper';
7
7
  export * from '@theme/Markdown/Mermaid';
8
8
  export * from '@theme/Markdown/PageWrapper';
9
- export * from '@theme/Markdown/MarkdownWrapper';
9
+ export * from '@theme/Markdown/Sup';
10
+ export * from '@theme/Markdown/Tabs';
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { ResolvedNavLinkItem } from '@theme/types/portal';
5
+ import { Link } from '@portal/Link';
6
+
7
+ interface NavbarDropdownProps {
8
+ items: ResolvedNavLinkItem[];
9
+ }
10
+
11
+ export function MobileNavbarDropdown({ items }: NavbarDropdownProps): JSX.Element {
12
+ return (
13
+ <MobileDropdownWrapper data-component-name="Navbar/MobileNavbarDropdown">
14
+ {items.map((item, index) => (
15
+ <div key={`${item.label}_${index}`}>
16
+ <Link to={item.link}>{item.label}</Link>
17
+ </div>
18
+ ))}
19
+ </MobileDropdownWrapper>
20
+ );
21
+ }
22
+
23
+ export const MobileDropdownWrapper = styled.div`
24
+ padding: 0 15px;
25
+ width: max-content;
26
+ transition: all 0.2s ease-in-out;
27
+ overflow: hidden;
28
+ box-shadow: var(--navbar-dropdown-shadow);
29
+ & > div {
30
+ padding: 10px 0;
31
+ cursor: pointer;
32
+ a {
33
+ color: var(--navbar-text-color);
34
+ text-decoration: none;
35
+ }
36
+ }
37
+ `;
@@ -0,0 +1,116 @@
1
+ import React, { useState } from 'react';
2
+ import styled from 'styled-components';
3
+ import { useLocation } from 'react-router-dom';
4
+
5
+ import type {
6
+ ResolvedNavItem,
7
+ ResolvedNavLinkItem,
8
+ ResolvedNavGroupItem,
9
+ } from '@theme/types/portal';
10
+ import { Link } from '@portal/Link';
11
+ import { withPathPrefix } from '@portal/utils';
12
+ import { MobileDropdownWrapper, MobileNavbarDropdown } from '@theme/Navbar/MobileNavbarDropdown';
13
+
14
+ export interface NavbarItemProps {
15
+ navItem: ResolvedNavItem;
16
+ className?: string;
17
+ }
18
+
19
+ export function MobileNavbarItem({ navItem, className }: NavbarItemProps): JSX.Element | null {
20
+ const { pathname } = useLocation();
21
+ const [expandedDropdown, setExpandedDropdown] = useState(false);
22
+ const toggleDropdown = () => setExpandedDropdown(!expandedDropdown);
23
+
24
+ if ((navItem as ResolvedNavLinkItem).link) {
25
+ const item = navItem as ResolvedNavLinkItem;
26
+ const isActive = pathname === withPathPrefix(item.link);
27
+ return (
28
+ <NavMenuItem
29
+ active={isActive}
30
+ data-component-name="Navbar/MobileNavbarItem"
31
+ className={className}
32
+ >
33
+ <NavLink to={item.link} active={isActive}>
34
+ <NavLabel>{item.label}</NavLabel>
35
+ </NavLink>
36
+ </NavMenuItem>
37
+ );
38
+ }
39
+
40
+ if ((navItem as ResolvedNavGroupItem).items) {
41
+ const item = navItem as ResolvedNavGroupItem;
42
+ return (
43
+ <NavMenuItemWithDropdownWrapper expanded={expandedDropdown}>
44
+ <NavMenuItem
45
+ active={false}
46
+ onClick={toggleDropdown}
47
+ data-component-name="Navbar/MobileNavbarItem"
48
+ className={className}
49
+ >
50
+ <NavLabel>{item.label}</NavLabel>
51
+ <ExpandedArrow />
52
+ </NavMenuItem>
53
+ <MobileNavbarDropdown items={item.items as ResolvedNavLinkItem[]} />
54
+ </NavMenuItemWithDropdownWrapper>
55
+ );
56
+ }
57
+
58
+ return null;
59
+ }
60
+
61
+ const ExpandedArrow = styled.div`
62
+ width: 5px;
63
+ height: 5px;
64
+ border: 1px solid;
65
+ border-left: none;
66
+ border-top: none;
67
+ transition: all 0.3s ease-out;
68
+ `;
69
+
70
+ export const NavMenuItem = styled.li<{ active?: boolean }>`
71
+ display: flex;
72
+ justify-content: space-between;
73
+ align-items: center;
74
+ padding: calc(var(--sidebar-spacing-horizontal) * 2);
75
+ text-align: left;
76
+ line-height: 1;
77
+ font-size: var(--navbar-item-font-size);
78
+ margin-left: var(--navbar-item-margin-horizontal);
79
+ margin-right: var(--navbar-item-margin-horizontal);
80
+ font-weight: var(--navbar-item-font-weight);
81
+ background: ${({ active }) => (active ? 'var(--navbar-item-active-background-color)' : 'none')};
82
+ &:not(:last-child) {
83
+ border-bottom: 1px solid var(--navbar-item-separator-line-color, #dadada);
84
+ }
85
+ `;
86
+
87
+ export const NavMenuItemWithDropdownWrapper = styled.div<{ expanded: boolean }>`
88
+ display: inline-block;
89
+ position: relative;
90
+ border-bottom: 1px solid var(--navbar-item-separator-line-color, #dadada);
91
+
92
+ ${ExpandedArrow} {
93
+ transform: rotate(${({ expanded }) => (expanded ? '' : '-')}45deg);
94
+ }
95
+
96
+ ${MobileDropdownWrapper} {
97
+ height: ${({ expanded }) => (expanded ? '100%' : '0')};
98
+ opacity: ${({ expanded }) => (expanded ? '1' : '0')};
99
+ }
100
+
101
+ ${NavMenuItem} {
102
+ border-bottom: none;
103
+ }
104
+ `;
105
+
106
+ export const NavLink = styled(Link)`
107
+ color: ${({ active }) =>
108
+ active ? 'var(--navbar-item-active-text-color)' : 'var(--navbar-text-color)'};
109
+ text-decoration: ${({ active }) =>
110
+ active ? 'var(--navbar-item-active-text-decoration)' : 'none'};
111
+ `;
112
+
113
+ const NavLabel = styled.span`
114
+ cursor: pointer;
115
+ vertical-align: middle;
116
+ `;
@@ -0,0 +1,106 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import { NavMenuItem, NavMenuItemWithDropdownWrapper } from '@theme/Navbar/NavbarItem';
5
+ import { MobileNavbarItem } from '@theme/Navbar/MobileNavbarItem';
6
+ import { DropdownWrapper } from '@theme/Navbar/NavbarDropdown';
7
+ import type { ResolvedConfigLinks, ResolvedNavItem } from '@theme/types/portal';
8
+ import { isPrimitive, isEmptyArray } from '@theme/utils';
9
+
10
+ export function MobileNavbarMenu({
11
+ menuItems,
12
+ closeMenu,
13
+ }: {
14
+ menuItems: ResolvedConfigLinks;
15
+ closeMenu: () => void;
16
+ }): JSX.Element | null {
17
+ if (isPrimitive(menuItems) || isEmptyArray(menuItems)) {
18
+ return null;
19
+ }
20
+
21
+ return (
22
+ <NavItemsWrapper data-component-name="Navbar/MobileNavbarMenu">
23
+ <NavItemsContainer>
24
+ {(menuItems as ResolvedNavItem[]).map((navItem, index) => {
25
+ return (
26
+ <MobileNavbarItem
27
+ key={`${navItem.label}_${index}`}
28
+ data-cy={navItem.label}
29
+ navItem={navItem}
30
+ />
31
+ );
32
+ })}
33
+ </NavItemsContainer>
34
+ <NavItemsClosableArea onClick={closeMenu} />
35
+ </NavItemsWrapper>
36
+ );
37
+ }
38
+
39
+ const NavItemsWrapper = styled.div`
40
+ height: 100%;
41
+ width: 100%;
42
+ position: fixed;
43
+ z-index: 201; //more than Search
44
+ left: 0;
45
+ top: 0;
46
+ overflow-x: hidden;
47
+ transition: 0.5s;
48
+ display: flex;
49
+ ${DropdownWrapper} {
50
+ & > div {
51
+ text-align: center;
52
+ padding: 10px 0;
53
+ cursor: pointer;
54
+ a {
55
+ color: var(--navbar-text-color);
56
+ text-decoration: none;
57
+ }
58
+ :hover {
59
+ text-decoration: underline;
60
+ }
61
+ }
62
+ }
63
+ `;
64
+
65
+ const NavItemsClosableArea = styled.div`
66
+ display: flex;
67
+ flex: 1;
68
+ min-width: 50px;
69
+ height: 100%;
70
+ background-color: rgba(255, 255, 255, 0.4);
71
+ `;
72
+
73
+ const NavItemsContainer = styled.ul`
74
+ width: 70%;
75
+ list-style: none;
76
+ margin: 0;
77
+ padding: 0;
78
+ display: flex;
79
+ flex-direction: column;
80
+ background: var(--navbar-background-color);
81
+
82
+ ${NavMenuItem} {
83
+ &:not(:last-child){
84
+ border-bottom: 1px solid var(--navbar-item-separator-line-color, #dadada);
85
+ }
86
+ border-radius: 0;
87
+ padding: 1em 0;
88
+ width: 100%;
89
+ }
90
+
91
+ ${NavMenuItemWithDropdownWrapper} {
92
+ display: block;
93
+ &:not(:last-child){
94
+ border-bottom: 1px solid var(--navbar-item-separator-line-color, #dadada);
95
+ border-radius: 0;
96
+ }
97
+ ${NavMenuItem} {
98
+ border-bottom: none;
99
+ }
100
+ ${DropdownWrapper} {
101
+ background-color: var(--navbar-background-color);
102
+ width: 100%;
103
+ padding: 0;
104
+ position: relative;
105
+ }
106
+ `;
@@ -0,0 +1,13 @@
1
+ import styled from 'styled-components';
2
+
3
+ import { Burger } from '@theme/ui/Burger';
4
+
5
+ export const MobileNavbarMenuButton = styled(Burger).attrs(() => ({
6
+ 'data-component-name': 'Navbar/MobileNavbarMenuButton',
7
+ }))`
8
+ display: block;
9
+
10
+ ${({ theme }) => theme.mediaQueries.medium} {
11
+ display: none;
12
+ }
13
+ `;