mintlify 1.1.1 → 1.1.2

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 (193) hide show
  1. package/bin/index.js +2 -3
  2. package/bin/index.js.map +1 -1
  3. package/bin/local-preview/helper-commands/clearCommand.js +4 -4
  4. package/bin/local-preview/helper-commands/clearCommand.js.map +1 -1
  5. package/bin/local-preview/index.js +43 -4
  6. package/bin/local-preview/index.js.map +1 -1
  7. package/bin/local-preview/injectNav.js +94 -0
  8. package/bin/local-preview/injectNav.js.map +1 -0
  9. package/bin/local-preview/utils/listener.js +1 -1
  10. package/bin/local-preview/utils/listener.js.map +1 -1
  11. package/bin/mint/client/.babel-plugin-macrosrc.json +5 -0
  12. package/bin/mint/client/.babelrc +4 -0
  13. package/bin/mint/client/.editorconfig +12 -0
  14. package/bin/mint/client/.eslintrc.json +7 -0
  15. package/bin/mint/client/.prettierignore +4 -0
  16. package/bin/mint/client/.prettierrc +14 -0
  17. package/bin/mint/client/.vscode/launch.json +28 -0
  18. package/bin/mint/client/README.md +44 -0
  19. package/bin/mint/client/jest.config.ts +195 -0
  20. package/bin/mint/client/next-env.d.ts +4 -0
  21. package/bin/mint/client/next.config.js +152 -0
  22. package/bin/mint/client/package.json +139 -0
  23. package/bin/mint/client/postcss.config.cjs +9 -0
  24. package/bin/mint/client/prebuild/faviconConfig.js +35 -0
  25. package/bin/mint/client/prebuild/getOpenApiContext.js +53 -0
  26. package/bin/mint/client/prebuild/index.js +117 -0
  27. package/bin/mint/client/prebuild/injectNav.js +115 -0
  28. package/bin/mint/client/prebuild/slugToTitle.js +7 -0
  29. package/bin/mint/client/rehype/withApiComponents.js +60 -0
  30. package/bin/mint/client/rehype/withCodeBlocks.js +54 -0
  31. package/bin/mint/client/rehype/withLayouts.js +113 -0
  32. package/bin/mint/client/rehype/withLinkRoles.js +13 -0
  33. package/bin/mint/client/rehype/withRawComponents.js +13 -0
  34. package/bin/mint/client/rehype/withStaticProps.js +25 -0
  35. package/bin/mint/client/rehype/withSyntaxHighlighting.js +60 -0
  36. package/bin/mint/client/remark/utils.js +369 -0
  37. package/bin/mint/client/remark/withFrames.js +55 -0
  38. package/bin/mint/client/remark/withImportsInjected.js +36 -0
  39. package/bin/mint/client/remark/withNextLinks.js +37 -0
  40. package/bin/mint/client/remark/withTableOfContents.js +71 -0
  41. package/bin/mint/client/scripts/local.js +177 -0
  42. package/bin/mint/client/sentry.client.config.js +15 -0
  43. package/bin/mint/client/sentry.properties +4 -0
  44. package/bin/mint/client/sentry.server.config.js +15 -0
  45. package/bin/mint/client/src/analytics/AbstractAnalyticsImplementation.ts +50 -0
  46. package/bin/mint/client/src/analytics/AnalyticsContext.ts +5 -0
  47. package/bin/mint/client/src/analytics/AnalyticsMediator.ts +101 -0
  48. package/bin/mint/client/src/analytics/FakeAnalyticsMediator.ts +9 -0
  49. package/bin/mint/client/src/analytics/GA4Script.tsx +33 -0
  50. package/bin/mint/client/src/analytics/implementations/amplitude.ts +26 -0
  51. package/bin/mint/client/src/analytics/implementations/fathom.ts +38 -0
  52. package/bin/mint/client/src/analytics/implementations/ga4.ts +33 -0
  53. package/bin/mint/client/src/analytics/implementations/hotjar.ts +53 -0
  54. package/bin/mint/client/src/analytics/implementations/mixpanel-browser.d.ts +1 -0
  55. package/bin/mint/client/src/analytics/implementations/mixpanel.ts +52 -0
  56. package/bin/mint/client/src/analytics/implementations/posthog.ts +37 -0
  57. package/bin/mint/client/src/components/Accordion/Accordion.tsx +43 -0
  58. package/bin/mint/client/src/components/Accordion/index.ts +4 -0
  59. package/bin/mint/client/src/components/ApiExample.tsx +9 -0
  60. package/bin/mint/client/src/components/Card.tsx +51 -0
  61. package/bin/mint/client/src/components/CodeGroup.tsx +132 -0
  62. package/bin/mint/client/src/components/Editor.tsx +12 -0
  63. package/bin/mint/client/src/components/Expandable.tsx +40 -0
  64. package/bin/mint/client/src/components/Heading.tsx +84 -0
  65. package/bin/mint/client/src/components/Param.tsx +56 -0
  66. package/bin/mint/client/src/components/Request.tsx +19 -0
  67. package/bin/mint/client/src/components/ResponseField.tsx +33 -0
  68. package/bin/mint/client/src/components/TabBar.tsx +61 -0
  69. package/bin/mint/client/src/config.ts +115 -0
  70. package/bin/mint/client/src/css/bar-of-progress.css +10 -0
  71. package/bin/mint/client/src/css/base.css +29 -0
  72. package/bin/mint/client/src/css/font-awesome.css +7 -0
  73. package/bin/mint/client/src/css/fonts.css +44 -0
  74. package/bin/mint/client/src/css/main.css +11 -0
  75. package/bin/mint/client/src/css/prism.css +270 -0
  76. package/bin/mint/client/src/css/utilities.css +43 -0
  77. package/bin/mint/client/src/enums/components.ts +8 -0
  78. package/bin/mint/client/src/fonts/FiraCode-VF.woff +0 -0
  79. package/bin/mint/client/src/fonts/FiraCode-VF.woff2 +0 -0
  80. package/bin/mint/client/src/fonts/IBMPlexMono-Regular.ttf +0 -0
  81. package/bin/mint/client/src/fonts/IBMPlexMono-SemiBold.ttf +0 -0
  82. package/bin/mint/client/src/fonts/Inter-italic-latin.var.woff2 +0 -0
  83. package/bin/mint/client/src/fonts/Inter-roman-latin.var.woff2 +0 -0
  84. package/bin/mint/client/src/fonts/Pally-Variable.ttf +0 -0
  85. package/bin/mint/client/src/fonts/SourceSansPro-Regular.otf +0 -0
  86. package/bin/mint/client/src/fonts/SourceSerifPro-Regular.ttf +0 -0
  87. package/bin/mint/client/src/fonts/Synonym-Variable.ttf +0 -0
  88. package/bin/mint/client/src/fonts/Ubuntu-Mono-bold.woff2 +0 -0
  89. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.woff2 +0 -0
  90. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.zopfli.woff +0 -0
  91. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular.module.css +11 -0
  92. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.woff2 +0 -0
  93. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.zopfli.woff +0 -0
  94. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold.module.css +11 -0
  95. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.woff2 +0 -0
  96. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.zopfli.woff +0 -0
  97. package/bin/mint/client/src/fonts/generated/Pally-Variable.module.css +11 -0
  98. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.woff2 +0 -0
  99. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.zopfli.woff +0 -0
  100. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular.module.css +11 -0
  101. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.woff2 +0 -0
  102. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.zopfli.woff +0 -0
  103. package/bin/mint/client/src/fonts/generated/Synonym-Variable.module.css +11 -0
  104. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.woff2 +0 -0
  105. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.zopfli.woff +0 -0
  106. package/bin/mint/client/src/fonts/generated/TenorSans-Regular.module.css +11 -0
  107. package/bin/mint/client/src/hooks/useActionKey.ts +20 -0
  108. package/bin/mint/client/src/hooks/useIsomorphicLayoutEffect.ts +3 -0
  109. package/bin/mint/client/src/hooks/useMedia.ts +27 -0
  110. package/bin/mint/client/src/hooks/usePrevNext.ts +34 -0
  111. package/bin/mint/client/src/hooks/useTop.ts +15 -0
  112. package/bin/mint/client/src/icons/CopyToClipboard.tsx +33 -0
  113. package/bin/mint/client/src/index.d.ts +1 -0
  114. package/bin/mint/client/src/layouts/ApiSupplemental.tsx +173 -0
  115. package/bin/mint/client/src/layouts/ContentsLayout.tsx +256 -0
  116. package/bin/mint/client/src/layouts/DocumentationLayout.tsx +44 -0
  117. package/bin/mint/client/src/layouts/OpenApiContent.tsx +301 -0
  118. package/bin/mint/client/src/layouts/SidebarLayout.tsx +412 -0
  119. package/bin/mint/client/src/layouts/UserFeedback.tsx +73 -0
  120. package/bin/mint/client/src/layouts/getGroupsInDivision.ts +25 -0
  121. package/bin/mint/client/src/layouts/isPathInGroupPages.ts +10 -0
  122. package/bin/mint/client/src/metadata.ts +58 -0
  123. package/bin/mint/client/src/nav.json +219 -0
  124. package/bin/mint/client/src/openapi.ts +3 -0
  125. package/bin/mint/client/src/pages/404.tsx +73 -0
  126. package/bin/mint/client/src/pages/_app.tsx +138 -0
  127. package/bin/mint/client/src/pages/_document.tsx +57 -0
  128. package/bin/mint/client/src/pages/api/issue.ts +10 -0
  129. package/bin/mint/client/src/pages/api/name.ts +8 -0
  130. package/bin/mint/client/src/pages/api/request.ts +31 -0
  131. package/bin/mint/client/src/pages/api/suggest.ts +10 -0
  132. package/bin/mint/client/src/pages/api/syntax-highlighted-json.ts +13 -0
  133. package/bin/mint/client/src/pages/api/utils.ts +6 -0
  134. package/bin/mint/client/src/pages/index.tsx +31 -0
  135. package/bin/mint/client/src/ui/Api.tsx +359 -0
  136. package/bin/mint/client/src/ui/Footer.tsx +124 -0
  137. package/bin/mint/client/src/ui/Header.tsx +370 -0
  138. package/bin/mint/client/src/ui/Logo.tsx +55 -0
  139. package/bin/mint/client/src/ui/PageHeader.tsx +51 -0
  140. package/bin/mint/client/src/ui/Search.tsx +386 -0
  141. package/bin/mint/client/src/ui/ThemeToggle.tsx +285 -0
  142. package/bin/mint/client/src/ui/Title.tsx +22 -0
  143. package/bin/mint/client/src/ui/TopLevelLink.tsx +122 -0
  144. package/bin/mint/client/src/utils/api.ts +252 -0
  145. package/bin/mint/client/src/utils/brands.ts +217 -0
  146. package/bin/mint/client/src/utils/castArray.ts +3 -0
  147. package/bin/mint/client/src/utils/childrenArray.ts +3 -0
  148. package/bin/mint/client/src/utils/fit.ts +27 -0
  149. package/bin/mint/client/src/utils/fontAwesome.ts +577 -0
  150. package/bin/mint/client/src/utils/getAnalyticsConfig.ts +14 -0
  151. package/bin/mint/client/src/utils/getLogoHref.ts +9 -0
  152. package/bin/mint/client/src/utils/getOpenApiContext.ts +26 -0
  153. package/bin/mint/client/src/utils/importAll.ts +6 -0
  154. package/bin/mint/client/src/utils/isObject.ts +3 -0
  155. package/bin/mint/client/src/utils/kebabToTitleCase.ts +3 -0
  156. package/bin/mint/client/src/utils/loadImage.ts +8 -0
  157. package/bin/mint/client/src/utils/slugToTitle.ts +7 -0
  158. package/bin/mint/client/src/utils/wait.ts +5 -0
  159. package/bin/mint/client/tailwind.config.cjs +323 -0
  160. package/bin/mint/client/test/test.test.ts +5 -0
  161. package/bin/mint/client/tsconfig.json +36 -0
  162. package/bin/mint/client/yarn.lock +9702 -0
  163. package/bin/scraping/downloadAllImages.js +4 -0
  164. package/bin/scraping/downloadAllImages.js.map +1 -1
  165. package/bin/scraping/scrapeSectionCommands.js +18 -46
  166. package/bin/scraping/scrapeSectionCommands.js.map +1 -1
  167. package/bin/scraping/site-scrapers/alternateGroupTitle.js +9 -0
  168. package/bin/scraping/site-scrapers/alternateGroupTitle.js.map +1 -0
  169. package/bin/scraping/site-scrapers/getLinksRecursively.js +7 -2
  170. package/bin/scraping/site-scrapers/getLinksRecursively.js.map +1 -1
  171. package/bin/scraping/site-scrapers/openNestedDocusaurusMenus.js +30 -0
  172. package/bin/scraping/site-scrapers/openNestedDocusaurusMenus.js.map +1 -0
  173. package/bin/scraping/site-scrapers/openNestedGitbookMenus.js +37 -0
  174. package/bin/scraping/site-scrapers/openNestedGitbookMenus.js.map +1 -0
  175. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js +20 -21
  176. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js.map +1 -1
  177. package/bin/scraping/site-scrapers/scrapeGitBookSection.js +2 -9
  178. package/bin/scraping/site-scrapers/scrapeGitBookSection.js.map +1 -1
  179. package/package.json +1 -1
  180. package/src/index.ts +2 -2
  181. package/src/local-preview/helper-commands/clearCommand.ts +6 -4
  182. package/src/local-preview/index.ts +48 -3
  183. package/src/local-preview/utils/listener.ts +1 -1
  184. package/src/scraping/downloadAllImages.ts +5 -0
  185. package/src/scraping/scrapeSectionCommands.ts +34 -60
  186. package/src/scraping/site-scrapers/alternateGroupTitle.ts +8 -0
  187. package/src/scraping/site-scrapers/getLinksRecursively.ts +7 -2
  188. package/src/scraping/site-scrapers/openNestedDocusaurusMenus.ts +42 -0
  189. package/src/scraping/site-scrapers/openNestedGitbookMenus.ts +49 -0
  190. package/src/scraping/site-scrapers/scrapeDocusaurusSection.ts +23 -21
  191. package/src/scraping/site-scrapers/scrapeGitBookSection.ts +2 -10
  192. package/bin/local-preview/helper-commands/cleanCommand.js +0 -8
  193. package/bin/local-preview/helper-commands/cleanCommand.js.map +0 -1
@@ -0,0 +1,33 @@
1
+ export const CopyToClipboard = () => (
2
+ <span className="copy-to-clipboard z-10 flex absolute right-5">
3
+ <svg
4
+ className="top-5 h-5 fill-slate-500 hover:fill-slate-300 cursor-pointer"
5
+ viewBox="0 0 20 20"
6
+ >
7
+ <path d="M8 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" />
8
+ <path d="M6 3a2 2 0 00-2 2v11a2 2 0 002 2h8a2 2 0 002-2V5a2 2 0 00-2-2 3 3 0 01-3 3H9a3 3 0 01-3-3z" />
9
+ </svg>
10
+ <div className="tooltip hidden absolute bottom-full left-1/2 mb-3.5 pb-1 -translate-x-1/2">
11
+ <div
12
+ className="relative bg-primary-dark text-white text-xs leading-6 font-medium px-1.5 rounded-lg"
13
+ data-reach-alert="true"
14
+ >
15
+ Copied
16
+ <svg
17
+ aria-hidden="true"
18
+ width="16"
19
+ height="6"
20
+ viewBox="0 0 16 6"
21
+ className="text-primary-dark absolute top-full left-1/2 -mt-px -ml-2"
22
+ >
23
+ <path
24
+ fillRule="evenodd"
25
+ clipRule="evenodd"
26
+ d="M15 0H1V1.00366V1.00366V1.00371H1.01672C2.72058 1.0147 4.24225 2.74704 5.42685 4.72928C6.42941 6.40691 9.57154 6.4069 10.5741 4.72926C11.7587 2.74703 13.2803 1.0147 14.9841 1.00371H15V0Z"
27
+ fill="currentColor"
28
+ ></path>
29
+ </svg>
30
+ </div>
31
+ </div>
32
+ </span>
33
+ );
@@ -0,0 +1 @@
1
+ declare module '*.jpg';
@@ -0,0 +1,173 @@
1
+ import axios from 'axios';
2
+ import parse from 'html-react-parser';
3
+ import React from 'react';
4
+ import { useState, useEffect } from 'react';
5
+
6
+ import { RequestExample, ResponseExample } from '@/components/ApiExample';
7
+ import { Editor } from '@/components/Editor';
8
+ import { Component } from '@/enums/components';
9
+ import { CopyToClipboard } from '@/icons/CopyToClipboard';
10
+ import { getOpenApiOperationMethodAndEndpoint } from '@/utils/getOpenApiContext';
11
+
12
+ const responseHasExample = (response: any) => {
13
+ return (
14
+ response?.content &&
15
+ response?.content.hasOwnProperty('application/json') &&
16
+ response?.content['application/json']?.examples &&
17
+ response?.content['application/json']?.examples.hasOwnProperty(['example-1']) &&
18
+ response?.content['application/json']?.examples['example-1']?.value
19
+ );
20
+ };
21
+
22
+ type ApiComponent = {
23
+ type: string;
24
+ children: { filename: string; html: string }[];
25
+ };
26
+
27
+ export function ApiSupplemental({
28
+ apiComponents,
29
+ openapi,
30
+ }: {
31
+ apiComponents: ApiComponent[];
32
+ openapi?: string;
33
+ }) {
34
+ // Response and Request Examples from MDX
35
+ const [mdxRequestExample, setMdxRequestExample] = useState<JSX.Element | undefined>(undefined);
36
+ const [mdxResponseExample, setMdxResponseExample] = useState<JSX.Element | undefined>(undefined);
37
+ useEffect(() => {
38
+ const requestComponentSkeleton = apiComponents.find((apiComponent) => {
39
+ return apiComponent.type === Component.RequestExample;
40
+ });
41
+
42
+ const responseComponentSkeleton = apiComponents.find((apiComponent) => {
43
+ return apiComponent.type === Component.ResponseExample;
44
+ });
45
+
46
+ const htmlToReactComponent = (html: string) => {
47
+ // Convert newlines to breaks to be properly parsed
48
+ // return parse(html.replaceAll('\n', '<br />'));
49
+ return parse(html);
50
+ };
51
+
52
+ const request: JSX.Element | undefined = requestComponentSkeleton && (
53
+ <RequestExample
54
+ children={requestComponentSkeleton.children.map((child) => {
55
+ return <Editor filename={child.filename}>{htmlToReactComponent(child.html)}</Editor>;
56
+ })}
57
+ />
58
+ );
59
+
60
+ setMdxRequestExample(request);
61
+
62
+ const response: JSX.Element | undefined = responseComponentSkeleton && (
63
+ <ResponseExample
64
+ children={responseComponentSkeleton.children.map((child) => {
65
+ return <Editor filename={child.filename}>{htmlToReactComponent(child.html)}</Editor>;
66
+ })}
67
+ />
68
+ );
69
+
70
+ setMdxResponseExample(response);
71
+ }, [apiComponents]);
72
+ // Open API generated response examples
73
+ const [openApiResponseExamples, setOpenApiResponseExamples] = useState<string[]>([]);
74
+ const [highlightedExamples, setHighlightedExamples] = useState<string[]>([]);
75
+
76
+ useEffect(() => {
77
+ if (openapi == null) {
78
+ return;
79
+ }
80
+ const { operation } = getOpenApiOperationMethodAndEndpoint(openapi);
81
+ if (operation?.responses != null) {
82
+ const responseExamplesOpenApi = Object.values(operation?.responses)
83
+ .map((resp: any) => {
84
+ if (responseHasExample(resp)) {
85
+ return resp?.content['application/json']?.examples['example-1']?.value;
86
+ }
87
+ return '';
88
+ })
89
+ .filter((example) => example !== '');
90
+ if (responseExamplesOpenApi != null) {
91
+ setOpenApiResponseExamples(responseExamplesOpenApi);
92
+ }
93
+ }
94
+ }, [openapi]);
95
+
96
+ useEffect(() => {
97
+ if (openApiResponseExamples.length > 0) {
98
+ const highlightPromises = openApiResponseExamples.map((example) => {
99
+ return axios.post('/api/syntax-highlighted-json', {
100
+ json: example,
101
+ });
102
+ });
103
+ Promise.all(highlightPromises).then((responses) => {
104
+ const highlightedExamples = responses.map((response) => response.data.highlightedJson);
105
+ setHighlightedExamples(highlightedExamples);
106
+ });
107
+ }
108
+ }, [openApiResponseExamples]);
109
+
110
+ useEffect(() => {
111
+ // Hacky approach to wait 1ms until document loads
112
+ setTimeout(() => {
113
+ document.querySelectorAll('.copy-to-clipboard').forEach((item) => {
114
+ item.addEventListener(
115
+ 'click',
116
+ () => {
117
+ const codeElement = item.nextSibling;
118
+ if (!codeElement || !window.getSelection) {
119
+ return;
120
+ }
121
+ const selection = window.getSelection();
122
+ const range = document.createRange();
123
+ range.selectNodeContents(codeElement);
124
+ selection?.removeAllRanges();
125
+ selection?.addRange(range);
126
+
127
+ navigator.clipboard.writeText(selection?.toString() || '');
128
+
129
+ const tooltip = item.getElementsByClassName('tooltip')[0];
130
+ tooltip.classList.remove('hidden');
131
+ setTimeout(() => {
132
+ tooltip.classList.add('hidden');
133
+ }, 2000);
134
+ },
135
+ true
136
+ );
137
+ });
138
+ }, 50);
139
+ }, []);
140
+
141
+ const ResponseExampleChild = ({ code }: { code: any }) => (
142
+ <pre className="language-json">
143
+ <CopyToClipboard />
144
+ <code
145
+ className="language-json"
146
+ dangerouslySetInnerHTML={{
147
+ __html: code,
148
+ }}
149
+ />
150
+ </pre>
151
+ );
152
+
153
+ return (
154
+ <div className="space-y-6 pb-6">
155
+ {mdxRequestExample}
156
+ {/* TODO - Make it so that you can see both the openapi and response example in 1 view if they're both defined */}
157
+ {highlightedExamples.length === 0 && mdxResponseExample}
158
+ {highlightedExamples.length > 0 && (
159
+ <ResponseExample
160
+ children={{
161
+ props: {
162
+ filename: 'Response Example',
163
+ children: highlightedExamples.map((code, i) => {
164
+ if (code === '') return null;
165
+ return <ResponseExampleChild code={code} key={`example-${i}`} />;
166
+ }),
167
+ },
168
+ }}
169
+ />
170
+ )}
171
+ </div>
172
+ );
173
+ }
@@ -0,0 +1,256 @@
1
+ import { MDXProvider } from '@mdx-js/react';
2
+ import clsx from 'clsx';
3
+ import { useState, useEffect, createContext, Fragment, useCallback, useContext } from 'react';
4
+
5
+ import { Heading } from '@/components/Heading';
6
+ import { usePrevNext } from '@/hooks/usePrevNext';
7
+ import { SidebarContext } from '@/layouts/SidebarLayout';
8
+ import { Footer } from '@/ui/Footer';
9
+ import { PageHeader } from '@/ui/PageHeader';
10
+
11
+ import { ApiSupplemental } from './ApiSupplemental';
12
+ import { OpenApiContent } from './OpenApiContent';
13
+
14
+ type Section = {
15
+ title: string;
16
+ slug: string;
17
+ depth: number;
18
+ children: any;
19
+ };
20
+
21
+ export const ContentsContext = createContext(undefined);
22
+
23
+ function TableOfContents({ tableOfContents, currentSection }: any) {
24
+ let sidebarContext = useContext(SidebarContext);
25
+ let isMainNav = Boolean(sidebarContext);
26
+
27
+ function closeNav() {
28
+ if (isMainNav && sidebarContext) {
29
+ sidebarContext.setNavIsOpen(false);
30
+ }
31
+ }
32
+
33
+ function isActive(section: Section) {
34
+ if (section.slug === currentSection) {
35
+ return true;
36
+ }
37
+ if (!section.children) {
38
+ return false;
39
+ }
40
+ return section.children.findIndex(isActive) > -1;
41
+ }
42
+
43
+ let pageHasSubsections = tableOfContents.some((section: Section) => section.children.length > 0);
44
+
45
+ return (
46
+ <>
47
+ <ul className="text-slate-700 text-sm leading-6">
48
+ {tableOfContents.map((section: Section) => {
49
+ let prevDepth = section.depth;
50
+ let prevMargin = 0;
51
+ return (
52
+ <Fragment key={section.slug}>
53
+ <li>
54
+ <a
55
+ href={`#${section.slug}`}
56
+ onClick={closeNav}
57
+ className={clsx(
58
+ 'block py-1',
59
+ pageHasSubsections ? 'font-medium' : '',
60
+ isActive(section)
61
+ ? 'font-medium text-primary dark:text-primary-light'
62
+ : 'hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-300'
63
+ )}
64
+ >
65
+ {section.title}
66
+ </a>
67
+ </li>
68
+ {section.children.map((subsection: Section) => {
69
+ if (subsection.depth - prevDepth >= 1) {
70
+ prevMargin += 4;
71
+ }
72
+ prevDepth = subsection.depth;
73
+ return (
74
+ <li className={`ml-${prevMargin}`} key={subsection.slug}>
75
+ <a
76
+ href={`#${subsection.slug}`}
77
+ onClick={closeNav}
78
+ className={clsx(
79
+ 'group flex items-start py-1 whitespace-pre-wrap',
80
+ isActive(subsection)
81
+ ? 'text-primary dark:text-primary-light'
82
+ : 'text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-300'
83
+ )}
84
+ >
85
+ {subsection.title}
86
+ </a>
87
+ </li>
88
+ );
89
+ })}
90
+ </Fragment>
91
+ );
92
+ })}
93
+ </ul>
94
+ </>
95
+ );
96
+ }
97
+
98
+ function useTableOfContents(tableOfContents: Section[]) {
99
+ let [currentSection, setCurrentSection] = useState(tableOfContents[0]?.slug);
100
+ let [headings, setHeadings] = useState<any[]>([]);
101
+
102
+ const registerHeading = useCallback((id: string, top: string) => {
103
+ setHeadings((headings: any) => [
104
+ ...headings.filter((h: { id: string }) => id !== h.id),
105
+ { id, top },
106
+ ]);
107
+ }, []);
108
+
109
+ const unregisterHeading = useCallback((id: string) => {
110
+ setHeadings((headings) => headings.filter((h) => id !== h.id));
111
+ }, []);
112
+
113
+ useEffect(() => {
114
+ if (tableOfContents.length === 0 || headings.length === 0) return;
115
+ function onScroll() {
116
+ let style = window.getComputedStyle(document.documentElement);
117
+ let scrollMt = parseFloat(style.getPropertyValue('--scroll-mt').match(/[\d.]+/)?.[0] ?? '0');
118
+ let fontSize = parseFloat(style.fontSize.match(/[\d.]+/)?.[0] ?? '16');
119
+ scrollMt = scrollMt * fontSize;
120
+
121
+ let sortedHeadings = headings.concat([]).sort((a, b) => a.top - b.top);
122
+ let top = window.pageYOffset + scrollMt + 1;
123
+ let current = sortedHeadings[0].id;
124
+ for (let i = 0; i < sortedHeadings.length; i++) {
125
+ if (top >= sortedHeadings[i].top) {
126
+ current = sortedHeadings[i].id;
127
+ }
128
+ }
129
+ setCurrentSection(current);
130
+ }
131
+ window.addEventListener('scroll', onScroll, {
132
+ capture: true,
133
+ passive: true,
134
+ });
135
+ onScroll();
136
+ return () => {
137
+ window.removeEventListener('scroll', onScroll, {
138
+ capture: true,
139
+ passive: true,
140
+ } as any);
141
+ };
142
+ }, [headings, tableOfContents]);
143
+
144
+ useEffect(() => {
145
+ document.querySelectorAll('.copy-to-clipboard').forEach((item) => {
146
+ item.addEventListener('click', () => {
147
+ const codeElement = item.nextSibling;
148
+ if (!codeElement || !window.getSelection) {
149
+ return;
150
+ }
151
+ const selection = window.getSelection();
152
+ const range = document.createRange();
153
+ range.selectNodeContents(codeElement);
154
+ selection?.removeAllRanges();
155
+ selection?.addRange(range);
156
+
157
+ navigator.clipboard.writeText(selection?.toString() || '');
158
+
159
+ const tooltip = item.getElementsByClassName('tooltip')[0];
160
+ tooltip.classList.remove('hidden');
161
+ setTimeout(() => {
162
+ tooltip.classList.add('hidden');
163
+ }, 2000);
164
+ });
165
+ });
166
+ }, []);
167
+
168
+ return { currentSection, registerHeading, unregisterHeading };
169
+ }
170
+
171
+ export type Meta = {
172
+ title?: string;
173
+ description?: string;
174
+ sidebarTitle?: string;
175
+ auth?: string;
176
+ api?: string;
177
+ openapi?: string;
178
+ size?: 'wide';
179
+ };
180
+
181
+ type ContentsLayoutProps = {
182
+ children: any;
183
+ meta: Meta;
184
+ tableOfContents: any;
185
+ section: string;
186
+ apiComponents: any;
187
+ };
188
+
189
+ export function ContentsLayout({
190
+ children,
191
+ meta,
192
+ tableOfContents,
193
+ section,
194
+ apiComponents,
195
+ }: ContentsLayoutProps) {
196
+ const toc = [...tableOfContents];
197
+
198
+ const { currentSection, registerHeading, unregisterHeading } = useTableOfContents(toc);
199
+ let { prev, next } = usePrevNext();
200
+
201
+ const hasApiSupplementalComponents = apiComponents.some(
202
+ (component: any) => component.type === 'ResponseExample' || component.type === 'RequestExample'
203
+ );
204
+
205
+ const isWideSize = meta.size === 'wide';
206
+
207
+ return (
208
+ <div
209
+ className={clsx(
210
+ 'relative max-w-3xl mx-auto pt-10 xl:max-w-none xl:ml-0',
211
+ hasApiSupplementalComponents
212
+ ? 'xl:pr-12 xl:mr-[28rem]'
213
+ : isWideSize
214
+ ? 'xl:pr-20 xl:mr-[12rem]'
215
+ : 'xl:pr-20 xl:mr-[18rem]'
216
+ )}
217
+ >
218
+ <PageHeader
219
+ title={meta.title}
220
+ description={meta.description}
221
+ api={meta.api}
222
+ openapi={meta.openapi}
223
+ auth={meta.auth}
224
+ section={section}
225
+ children={children}
226
+ apiComponents={apiComponents}
227
+ />
228
+ <ContentsContext.Provider value={{ registerHeading, unregisterHeading } as any}>
229
+ <div id="content-wrapper" className="relative z-20 prose prose-slate mt-8 dark:prose-dark">
230
+ <MDXProvider components={{ Heading }}>{children}</MDXProvider>
231
+ </div>
232
+ </ContentsContext.Provider>
233
+
234
+ {meta.openapi && <OpenApiContent openapi={meta.openapi} auth={meta.auth} />}
235
+
236
+ <Footer previous={prev} next={next} hasBottomPadding={!hasApiSupplementalComponents} />
237
+ <div
238
+ className={clsx(
239
+ 'z-10 hidden xl:block pr-8',
240
+ hasApiSupplementalComponents
241
+ ? 'w-[30rem] absolute top-[7.6rem] left-full h-full'
242
+ : 'fixed pl-8 w-[21rem] top-[3.8rem] bottom-0 right-[max(0px,calc(50%-45rem))] py-10 overflow-auto'
243
+ )}
244
+ >
245
+ {!hasApiSupplementalComponents && toc.length > 0 && !isWideSize && (
246
+ <TableOfContents tableOfContents={toc} currentSection={currentSection} meta={meta} />
247
+ )}
248
+ {hasApiSupplementalComponents && (
249
+ <div className="sticky top-[6rem] left-0">
250
+ <ApiSupplemental openapi={meta.openapi} apiComponents={apiComponents} />
251
+ </div>
252
+ )}
253
+ </div>
254
+ </div>
255
+ );
256
+ }
@@ -0,0 +1,44 @@
1
+ import { useRouter } from 'next/router';
2
+ import { ReactNode } from 'react';
3
+
4
+ import { config } from '@/config';
5
+ import { SidebarLayout } from '@/layouts/SidebarLayout';
6
+ import { documentationNav } from '@/metadata';
7
+ import { Title } from '@/ui/Title';
8
+ import { slugToTitle } from '@/utils/slugToTitle';
9
+
10
+ import { Meta } from './ContentsLayout';
11
+
12
+ export function DocumentationLayout({
13
+ isMdx,
14
+ navIsOpen,
15
+ setNavIsOpen,
16
+ meta,
17
+ children,
18
+ }: {
19
+ isMdx: boolean;
20
+ navIsOpen: boolean;
21
+ setNavIsOpen: any;
22
+ meta: Meta;
23
+ slug?: string;
24
+ children: ReactNode;
25
+ }) {
26
+ const router = useRouter();
27
+
28
+ if (!isMdx) {
29
+ return <>{children}</>;
30
+ }
31
+
32
+ const defaultTitle = slugToTitle(router.pathname);
33
+
34
+ return (
35
+ <>
36
+ <Title suffix={router.pathname === '/' ? '' : config.name}>
37
+ {meta.sidebarTitle || meta.title || defaultTitle}
38
+ </Title>
39
+ <SidebarLayout nav={documentationNav} navIsOpen={navIsOpen} setNavIsOpen={setNavIsOpen}>
40
+ {children}
41
+ </SidebarLayout>
42
+ </>
43
+ );
44
+ }