mintlify 1.1.5 → 1.1.7

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 (224) hide show
  1. package/CONTRIBUTING.md +5 -0
  2. package/bin/index.js +1 -8
  3. package/bin/index.js.map +1 -1
  4. package/bin/local-preview/index.js +4 -6
  5. package/bin/local-preview/index.js.map +1 -1
  6. package/bin/local-preview/injectNav.js +94 -0
  7. package/bin/local-preview/injectNav.js.map +1 -0
  8. package/bin/local-preview/utils/categorizeFiles.js +10 -3
  9. package/bin/local-preview/utils/categorizeFiles.js.map +1 -1
  10. package/bin/local-preview/utils/getOpenApiContext.js +21 -9
  11. package/bin/local-preview/utils/getOpenApiContext.js.map +1 -1
  12. package/bin/local-preview/utils/listener.js +3 -2
  13. package/bin/local-preview/utils/listener.js.map +1 -1
  14. package/bin/local-preview/utils/metadata.js +4 -8
  15. package/bin/local-preview/utils/metadata.js.map +1 -1
  16. package/bin/local-preview/utils/openApiCheck.js +3 -4
  17. package/bin/local-preview/utils/openApiCheck.js.map +1 -1
  18. package/bin/mint/client/.babel-plugin-macrosrc.json +5 -0
  19. package/bin/mint/client/.babelrc +4 -0
  20. package/bin/mint/client/.editorconfig +12 -0
  21. package/bin/mint/client/.eslintrc.json +7 -0
  22. package/bin/mint/client/.prettierignore +4 -0
  23. package/bin/mint/client/.prettierrc +14 -0
  24. package/bin/mint/client/.vscode/launch.json +28 -0
  25. package/bin/mint/client/README.md +44 -0
  26. package/bin/mint/client/jest.config.ts +195 -0
  27. package/bin/mint/client/next-env.d.ts +4 -0
  28. package/bin/mint/client/next.config.js +152 -0
  29. package/bin/mint/client/package.json +139 -0
  30. package/bin/mint/client/postcss.config.cjs +9 -0
  31. package/bin/mint/client/prebuild/faviconConfig.js +35 -0
  32. package/bin/mint/client/prebuild/getOpenApiContext.js +53 -0
  33. package/bin/mint/client/prebuild/index.js +117 -0
  34. package/bin/mint/client/prebuild/injectNav.js +115 -0
  35. package/bin/mint/client/prebuild/slugToTitle.js +7 -0
  36. package/bin/mint/client/rehype/withApiComponents.js +60 -0
  37. package/bin/mint/client/rehype/withCodeBlocks.js +54 -0
  38. package/bin/mint/client/rehype/withLayouts.js +113 -0
  39. package/bin/mint/client/rehype/withLinkRoles.js +13 -0
  40. package/bin/mint/client/rehype/withRawComponents.js +13 -0
  41. package/bin/mint/client/rehype/withStaticProps.js +25 -0
  42. package/bin/mint/client/rehype/withSyntaxHighlighting.js +60 -0
  43. package/bin/mint/client/remark/utils.js +369 -0
  44. package/bin/mint/client/remark/withFrames.js +55 -0
  45. package/bin/mint/client/remark/withImportsInjected.js +36 -0
  46. package/bin/mint/client/remark/withNextLinks.js +37 -0
  47. package/bin/mint/client/remark/withTableOfContents.js +71 -0
  48. package/bin/mint/client/scripts/local.js +177 -0
  49. package/bin/mint/client/sentry.client.config.js +15 -0
  50. package/bin/mint/client/sentry.properties +4 -0
  51. package/bin/mint/client/sentry.server.config.js +15 -0
  52. package/bin/mint/client/src/analytics/AbstractAnalyticsImplementation.ts +50 -0
  53. package/bin/mint/client/src/analytics/AnalyticsContext.ts +5 -0
  54. package/bin/mint/client/src/analytics/AnalyticsMediator.ts +101 -0
  55. package/bin/mint/client/src/analytics/FakeAnalyticsMediator.ts +9 -0
  56. package/bin/mint/client/src/analytics/GA4Script.tsx +33 -0
  57. package/bin/mint/client/src/analytics/implementations/amplitude.ts +26 -0
  58. package/bin/mint/client/src/analytics/implementations/fathom.ts +38 -0
  59. package/bin/mint/client/src/analytics/implementations/ga4.ts +33 -0
  60. package/bin/mint/client/src/analytics/implementations/hotjar.ts +53 -0
  61. package/bin/mint/client/src/analytics/implementations/mixpanel-browser.d.ts +1 -0
  62. package/bin/mint/client/src/analytics/implementations/mixpanel.ts +52 -0
  63. package/bin/mint/client/src/analytics/implementations/posthog.ts +37 -0
  64. package/bin/mint/client/src/components/Accordion/Accordion.tsx +43 -0
  65. package/bin/mint/client/src/components/Accordion/index.ts +4 -0
  66. package/bin/mint/client/src/components/ApiExample.tsx +9 -0
  67. package/bin/mint/client/src/components/Card.tsx +51 -0
  68. package/bin/mint/client/src/components/CodeGroup.tsx +132 -0
  69. package/bin/mint/client/src/components/Editor.tsx +12 -0
  70. package/bin/mint/client/src/components/Expandable.tsx +40 -0
  71. package/bin/mint/client/src/components/Heading.tsx +84 -0
  72. package/bin/mint/client/src/components/Param.tsx +56 -0
  73. package/bin/mint/client/src/components/Request.tsx +19 -0
  74. package/bin/mint/client/src/components/ResponseField.tsx +33 -0
  75. package/bin/mint/client/src/components/TabBar.tsx +61 -0
  76. package/bin/mint/client/src/config.ts +115 -0
  77. package/bin/mint/client/src/css/bar-of-progress.css +10 -0
  78. package/bin/mint/client/src/css/base.css +29 -0
  79. package/bin/mint/client/src/css/font-awesome.css +7 -0
  80. package/bin/mint/client/src/css/fonts.css +44 -0
  81. package/bin/mint/client/src/css/main.css +11 -0
  82. package/bin/mint/client/src/css/prism.css +270 -0
  83. package/bin/mint/client/src/css/utilities.css +43 -0
  84. package/bin/mint/client/src/enums/components.ts +8 -0
  85. package/bin/mint/client/src/fonts/FiraCode-VF.woff +0 -0
  86. package/bin/mint/client/src/fonts/FiraCode-VF.woff2 +0 -0
  87. package/bin/mint/client/src/fonts/IBMPlexMono-Regular.ttf +0 -0
  88. package/bin/mint/client/src/fonts/IBMPlexMono-SemiBold.ttf +0 -0
  89. package/bin/mint/client/src/fonts/Inter-italic-latin.var.woff2 +0 -0
  90. package/bin/mint/client/src/fonts/Inter-roman-latin.var.woff2 +0 -0
  91. package/bin/mint/client/src/fonts/Pally-Variable.ttf +0 -0
  92. package/bin/mint/client/src/fonts/SourceSansPro-Regular.otf +0 -0
  93. package/bin/mint/client/src/fonts/SourceSerifPro-Regular.ttf +0 -0
  94. package/bin/mint/client/src/fonts/Synonym-Variable.ttf +0 -0
  95. package/bin/mint/client/src/fonts/Ubuntu-Mono-bold.woff2 +0 -0
  96. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.woff2 +0 -0
  97. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular-subset.zopfli.woff +0 -0
  98. package/bin/mint/client/src/fonts/generated/IBMPlexMono-Regular.module.css +11 -0
  99. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.woff2 +0 -0
  100. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold-subset.zopfli.woff +0 -0
  101. package/bin/mint/client/src/fonts/generated/IBMPlexMono-SemiBold.module.css +11 -0
  102. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.woff2 +0 -0
  103. package/bin/mint/client/src/fonts/generated/Pally-Variable-subset.zopfli.woff +0 -0
  104. package/bin/mint/client/src/fonts/generated/Pally-Variable.module.css +11 -0
  105. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.woff2 +0 -0
  106. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular-subset.zopfli.woff +0 -0
  107. package/bin/mint/client/src/fonts/generated/SourceSerifPro-Regular.module.css +11 -0
  108. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.woff2 +0 -0
  109. package/bin/mint/client/src/fonts/generated/Synonym-Variable-subset.zopfli.woff +0 -0
  110. package/bin/mint/client/src/fonts/generated/Synonym-Variable.module.css +11 -0
  111. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.woff2 +0 -0
  112. package/bin/mint/client/src/fonts/generated/TenorSans-Regular-subset.zopfli.woff +0 -0
  113. package/bin/mint/client/src/fonts/generated/TenorSans-Regular.module.css +11 -0
  114. package/bin/mint/client/src/hooks/useActionKey.ts +20 -0
  115. package/bin/mint/client/src/hooks/useIsomorphicLayoutEffect.ts +3 -0
  116. package/bin/mint/client/src/hooks/useMedia.ts +27 -0
  117. package/bin/mint/client/src/hooks/usePrevNext.ts +34 -0
  118. package/bin/mint/client/src/hooks/useTop.ts +15 -0
  119. package/bin/mint/client/src/icons/CopyToClipboard.tsx +33 -0
  120. package/bin/mint/client/src/index.d.ts +1 -0
  121. package/bin/mint/client/src/layouts/ApiSupplemental.tsx +173 -0
  122. package/bin/mint/client/src/layouts/ContentsLayout.tsx +256 -0
  123. package/bin/mint/client/src/layouts/DocumentationLayout.tsx +44 -0
  124. package/bin/mint/client/src/layouts/OpenApiContent.tsx +301 -0
  125. package/bin/mint/client/src/layouts/SidebarLayout.tsx +412 -0
  126. package/bin/mint/client/src/layouts/UserFeedback.tsx +73 -0
  127. package/bin/mint/client/src/layouts/getGroupsInDivision.ts +25 -0
  128. package/bin/mint/client/src/layouts/isPathInGroupPages.ts +10 -0
  129. package/bin/mint/client/src/metadata.ts +58 -0
  130. package/bin/mint/client/src/nav.json +219 -0
  131. package/bin/mint/client/src/openapi.ts +3 -0
  132. package/bin/mint/client/src/pages/404.tsx +73 -0
  133. package/bin/mint/client/src/pages/_app.tsx +138 -0
  134. package/bin/mint/client/src/pages/_document.tsx +57 -0
  135. package/bin/mint/client/src/pages/api/issue.ts +10 -0
  136. package/bin/mint/client/src/pages/api/name.ts +8 -0
  137. package/bin/mint/client/src/pages/api/request.ts +31 -0
  138. package/bin/mint/client/src/pages/api/suggest.ts +10 -0
  139. package/bin/mint/client/src/pages/api/syntax-highlighted-json.ts +13 -0
  140. package/bin/mint/client/src/pages/api/utils.ts +6 -0
  141. package/bin/mint/client/src/pages/index.tsx +31 -0
  142. package/bin/mint/client/src/ui/Api.tsx +359 -0
  143. package/bin/mint/client/src/ui/Footer.tsx +124 -0
  144. package/bin/mint/client/src/ui/Header.tsx +370 -0
  145. package/bin/mint/client/src/ui/Logo.tsx +55 -0
  146. package/bin/mint/client/src/ui/PageHeader.tsx +51 -0
  147. package/bin/mint/client/src/ui/Search.tsx +386 -0
  148. package/bin/mint/client/src/ui/ThemeToggle.tsx +285 -0
  149. package/bin/mint/client/src/ui/Title.tsx +22 -0
  150. package/bin/mint/client/src/ui/TopLevelLink.tsx +122 -0
  151. package/bin/mint/client/src/utils/api.ts +252 -0
  152. package/bin/mint/client/src/utils/brands.ts +217 -0
  153. package/bin/mint/client/src/utils/castArray.ts +3 -0
  154. package/bin/mint/client/src/utils/childrenArray.ts +3 -0
  155. package/bin/mint/client/src/utils/fit.ts +27 -0
  156. package/bin/mint/client/src/utils/fontAwesome.ts +577 -0
  157. package/bin/mint/client/src/utils/getAnalyticsConfig.ts +14 -0
  158. package/bin/mint/client/src/utils/getLogoHref.ts +9 -0
  159. package/bin/mint/client/src/utils/getOpenApiContext.ts +26 -0
  160. package/bin/mint/client/src/utils/importAll.ts +6 -0
  161. package/bin/mint/client/src/utils/isObject.ts +3 -0
  162. package/bin/mint/client/src/utils/kebabToTitleCase.ts +3 -0
  163. package/bin/mint/client/src/utils/loadImage.ts +8 -0
  164. package/bin/mint/client/src/utils/slugToTitle.ts +7 -0
  165. package/bin/mint/client/src/utils/wait.ts +5 -0
  166. package/bin/mint/client/tailwind.config.cjs +323 -0
  167. package/bin/mint/client/test/test.test.ts +5 -0
  168. package/bin/mint/client/tsconfig.json +36 -0
  169. package/bin/mint/client/yarn.lock +9702 -0
  170. package/bin/scraping/detectFramework.js +12 -3
  171. package/bin/scraping/detectFramework.js.map +1 -1
  172. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js +2 -2
  173. package/bin/scraping/scrapeFileGettingFileNameFromUrl.js.map +1 -1
  174. package/bin/scraping/scrapeGettingFileNameFromUrl.js +3 -3
  175. package/bin/scraping/scrapeGettingFileNameFromUrl.js.map +1 -1
  176. package/bin/scraping/scrapePage.js +2 -2
  177. package/bin/scraping/scrapePage.js.map +1 -1
  178. package/bin/scraping/scrapePageCommands.js +6 -6
  179. package/bin/scraping/scrapePageCommands.js.map +1 -1
  180. package/bin/scraping/scrapeSection.js +2 -2
  181. package/bin/scraping/scrapeSection.js.map +1 -1
  182. package/bin/scraping/scrapeSectionCommands.js +8 -7
  183. package/bin/scraping/scrapeSectionCommands.js.map +1 -1
  184. package/bin/scraping/site-scrapers/links-per-group/getDocusaurusLinksPerGroup.js +36 -0
  185. package/bin/scraping/site-scrapers/links-per-group/getDocusaurusLinksPerGroup.js.map +1 -0
  186. package/bin/scraping/site-scrapers/links-per-group/getLinksRecursively.js +38 -0
  187. package/bin/scraping/site-scrapers/links-per-group/getLinksRecursively.js.map +1 -0
  188. package/bin/scraping/site-scrapers/scrapeDocusaurusPage.js +14 -8
  189. package/bin/scraping/site-scrapers/scrapeDocusaurusPage.js.map +1 -1
  190. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js +4 -29
  191. package/bin/scraping/site-scrapers/scrapeDocusaurusSection.js.map +1 -1
  192. package/bin/scraping/site-scrapers/scrapeGitBookPage.js +2 -1
  193. package/bin/scraping/site-scrapers/scrapeGitBookPage.js.map +1 -1
  194. package/bin/scraping/site-scrapers/scrapeGitBookSection.js +3 -3
  195. package/bin/scraping/site-scrapers/scrapeGitBookSection.js.map +1 -1
  196. package/bin/scraping/site-scrapers/scrapeReadMePage.js +2 -1
  197. package/bin/scraping/site-scrapers/scrapeReadMePage.js.map +1 -1
  198. package/bin/scraping/site-scrapers/scrapeReadMeSection.js +3 -3
  199. package/bin/scraping/site-scrapers/scrapeReadMeSection.js.map +1 -1
  200. package/package.json +1 -1
  201. package/src/index.ts +0 -16
  202. package/src/local-preview/index.ts +4 -6
  203. package/src/local-preview/utils/categorizeFiles.ts +12 -4
  204. package/src/local-preview/utils/getOpenApiContext.ts +27 -11
  205. package/src/local-preview/utils/listener.ts +9 -4
  206. package/src/local-preview/utils/metadata.ts +4 -8
  207. package/src/local-preview/utils/openApiCheck.ts +4 -5
  208. package/src/scraping/detectFramework.ts +13 -3
  209. package/src/scraping/scrapeFileGettingFileNameFromUrl.ts +5 -2
  210. package/src/scraping/scrapeGettingFileNameFromUrl.ts +5 -1
  211. package/src/scraping/scrapePage.ts +6 -3
  212. package/src/scraping/scrapePageCommands.ts +10 -6
  213. package/src/scraping/scrapeSection.ts +9 -2
  214. package/src/scraping/scrapeSectionCommands.ts +24 -7
  215. package/src/scraping/site-scrapers/links-per-group/getDocusaurusLinksPerGroup.ts +46 -0
  216. package/src/scraping/site-scrapers/{getLinksRecursively.ts → links-per-group/getLinksRecursively.ts} +0 -0
  217. package/src/scraping/site-scrapers/scrapeDocusaurusPage.ts +20 -8
  218. package/src/scraping/site-scrapers/scrapeDocusaurusSection.ts +9 -33
  219. package/src/scraping/site-scrapers/scrapeGitBookPage.ts +2 -1
  220. package/src/scraping/site-scrapers/scrapeGitBookSection.ts +5 -3
  221. package/src/scraping/site-scrapers/scrapeReadMePage.ts +2 -1
  222. package/src/scraping/site-scrapers/scrapeReadMeSection.ts +4 -2
  223. package/bin/local-preview/helper-commands/cleanCommand.js +0 -8
  224. package/bin/local-preview/helper-commands/cleanCommand.js.map +0 -1
@@ -0,0 +1,386 @@
1
+ import { Combobox, Dialog, Transition } from '@headlessui/react';
2
+ import { ChevronRightIcon, FolderIcon, SearchIcon } from '@heroicons/react/outline';
3
+ import algoliasearch from 'algoliasearch';
4
+ import axios from 'axios';
5
+ import clsx from 'clsx';
6
+ import { useRouter } from 'next/router';
7
+ import {
8
+ Fragment,
9
+ useState,
10
+ useCallback,
11
+ useRef,
12
+ createContext,
13
+ useContext,
14
+ useEffect,
15
+ } from 'react';
16
+ import { useHotkeys } from 'react-hotkeys-hook';
17
+
18
+ import { config } from '@/config';
19
+ import { useActionKey } from '@/hooks/useActionKey';
20
+
21
+ const client = algoliasearch('M6VUKXZ4U5', '60f283c4bc8c9feb5c44da3df3c21ce3');
22
+ const index = client.initIndex('docs');
23
+
24
+ // @ts-ignore
25
+ const SearchContext = createContext();
26
+
27
+ type HighlightedResult = { value: string; matchLevel: 'none' | 'full' };
28
+
29
+ type Hit = {
30
+ objectID: string;
31
+ title: string;
32
+ heading?: string;
33
+ subheading?: string;
34
+ content: string;
35
+ slug: string;
36
+ _highlightResult: {
37
+ title: HighlightedResult;
38
+ heading?: HighlightedResult;
39
+ subheading?: HighlightedResult;
40
+ content?: HighlightedResult;
41
+ };
42
+ _snippetResult: {
43
+ heading: HighlightedResult;
44
+ content: HighlightedResult;
45
+ };
46
+ };
47
+
48
+ // TODO: Simplify the repeated components
49
+ function SearchHit({ active, hit }: { active: boolean; hit: Hit }) {
50
+ if (hit._highlightResult.heading?.matchLevel === 'full') {
51
+ return (
52
+ <>
53
+ <div
54
+ className={clsx(
55
+ 'rounded-md ring-1 ring-slate-900/5 shadow-sm group-hover:shadow group-hover:ring-slate-900/10 dark:ring-0 dark:shadow-none dark:group-hover:shadow-none dark:group-hover:highlight-white/10',
56
+ active ? 'bg-white dark:bg-primary' : 'dark:bg-slate-800'
57
+ )}
58
+ >
59
+ <svg
60
+ className="h-6 w-6 p-1.5"
61
+ xmlns="http://www.w3.org/2000/svg"
62
+ viewBox="0 0 12 12"
63
+ fill="none"
64
+ >
65
+ <path
66
+ className={clsx(
67
+ 'stroke-primary group-hover:stroke-primary-dark dark:stroke-primary-ultralight dark:group-hover:stroke-white',
68
+ active && 'stroke-primary-dark dark:stroke-white'
69
+ )}
70
+ d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10"
71
+ strokeWidth="1.5"
72
+ stroke-linecap="round"
73
+ ></path>
74
+ </svg>
75
+ </div>
76
+ <div className="ml-3 flex-auto">
77
+ {hit._highlightResult.title?.value && (
78
+ <div>
79
+ <span
80
+ className={clsx(
81
+ 'rounded-full py-px px-2 text-xs',
82
+ active
83
+ ? 'bg-primary text-white'
84
+ : 'bg-slate-200 dark:bg-slate-700 text-slate-600 dark:text-slate-400'
85
+ )}
86
+ dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }}
87
+ ></span>
88
+ </div>
89
+ )}
90
+ <div
91
+ className="mt-1 truncate"
92
+ dangerouslySetInnerHTML={{ __html: hit._highlightResult.heading?.value }}
93
+ ></div>
94
+ </div>
95
+ {active && <ChevronRightIcon className="h-4 w-4 ml-3 flex-none" />}
96
+ </>
97
+ );
98
+ }
99
+
100
+ if (hit._highlightResult.subheading?.matchLevel === 'full') {
101
+ return (
102
+ <>
103
+ <div
104
+ className={clsx(
105
+ 'rounded-md ring-1 ring-slate-900/5 shadow-sm group-hover:shadow group-hover:ring-slate-900/10 dark:ring-0 dark:shadow-none dark:group-hover:shadow-none dark:group-hover:highlight-white/10',
106
+ active ? 'bg-white dark:bg-primary' : 'dark:bg-slate-800'
107
+ )}
108
+ >
109
+ <svg
110
+ className="h-6 w-6 p-1.5"
111
+ xmlns="http://www.w3.org/2000/svg"
112
+ viewBox="0 0 12 12"
113
+ fill="none"
114
+ >
115
+ <path
116
+ className={clsx(
117
+ 'stroke-primary group-hover:stroke-primary-dark dark:stroke-primary-ultralight dark:group-hover:stroke-white',
118
+ active && 'stroke-primary-dark dark:stroke-white'
119
+ )}
120
+ d="M3.75 1v10M8.25 1v10M1 3.75h10M1 8.25h10"
121
+ strokeWidth="1.5"
122
+ stroke-linecap="round"
123
+ ></path>
124
+ </svg>
125
+ </div>
126
+ <div className="ml-3 flex-auto">
127
+ {hit._highlightResult.title?.value && (
128
+ <div>
129
+ <span
130
+ className={clsx(
131
+ 'rounded-full py-px px-2 text-xs',
132
+ active
133
+ ? 'bg-primary text-white'
134
+ : 'bg-slate-200 dark:bg-slate-700 text-slate-600 dark:text-slate-400'
135
+ )}
136
+ dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }}
137
+ ></span>
138
+ </div>
139
+ )}
140
+ <div
141
+ className="mt-1 truncate"
142
+ dangerouslySetInnerHTML={{ __html: hit._highlightResult.subheading?.value }}
143
+ ></div>
144
+ </div>
145
+ {active && <ChevronRightIcon className="h-4 w-4 ml-3 flex-none" />}
146
+ </>
147
+ );
148
+ }
149
+
150
+ return (
151
+ <>
152
+ <div
153
+ className={clsx(
154
+ 'rounded-md ring-1 ring-slate-900/5 shadow-sm group-hover:shadow group-hover:ring-slate-900/10 dark:ring-0 dark:shadow-none dark:group-hover:shadow-none dark:group-hover:highlight-white/10',
155
+ active ? 'bg-white dark:bg-primary' : 'dark:bg-slate-800'
156
+ )}
157
+ >
158
+ <svg
159
+ className="h-6 w-6 p-1"
160
+ xmlns="http://www.w3.org/2000/svg"
161
+ viewBox="0 0 20 20"
162
+ fill="none"
163
+ >
164
+ <path
165
+ className={clsx(
166
+ 'fill-primary group-hover:fill-primary-dark dark:fill-primary-ultralight dark:group-hover:fill-white',
167
+ active && 'fill-primary-dark dark:fill-white'
168
+ )}
169
+ d="M9 4.804A7.968 7.968 0 005.5 4c-1.255 0-2.443.29-3.5.804v10A7.969 7.969 0 015.5 14c1.669 0 3.218.51 4.5 1.385A7.962 7.962 0 0114.5 14c1.255 0 2.443.29 3.5.804v-10A7.968 7.968 0 0014.5 4c-1.255 0-2.443.29-3.5.804V12a1 1 0 11-2 0V4.804z"
170
+ ></path>
171
+ </svg>
172
+ </div>
173
+ <div className="ml-3 flex-auto">
174
+ <div
175
+ className="truncate"
176
+ dangerouslySetInnerHTML={{ __html: hit._highlightResult.title.value }}
177
+ ></div>
178
+ {hit._highlightResult.content?.matchLevel === 'full' &&
179
+ hit._snippetResult.content?.value && (
180
+ <div dangerouslySetInnerHTML={{ __html: hit._snippetResult.content.value }}></div>
181
+ )}
182
+ </div>
183
+ {active && <ChevronRightIcon className="h-4 w-4 ml-3 flex-none" />}
184
+ </>
185
+ );
186
+ }
187
+
188
+ export function SearchProvider({ children }: any) {
189
+ const router = useRouter();
190
+ const [searchId, setSearchId] = useState('');
191
+ const [isOpen, setIsOpen] = useState(false);
192
+ const [query, setQuery] = useState<string>('');
193
+ const [hits, setHits] = useState<Hit[]>([]);
194
+
195
+ useEffect(() => {
196
+ axios.get(`${config.basePath ?? ''}/api/name`).then(({ data }) => {
197
+ setSearchId(data);
198
+ });
199
+ }, []);
200
+
201
+ useHotkeys('cmd+k', (e) => {
202
+ e.preventDefault();
203
+ setIsOpen(true);
204
+ });
205
+
206
+ const onOpen = useCallback(() => {
207
+ setIsOpen(true);
208
+ }, [setIsOpen]);
209
+
210
+ const onClose = useCallback(() => {
211
+ setIsOpen(false);
212
+ }, [setIsOpen]);
213
+
214
+ const onInput = useCallback(
215
+ (e: any) => {
216
+ setIsOpen(true);
217
+ setQuery(e.key);
218
+ },
219
+ [setIsOpen, setQuery]
220
+ );
221
+
222
+ const onSearch = async (query: string) => {
223
+ if (!query) {
224
+ setHits([]);
225
+ return;
226
+ }
227
+ const { hits } = await index.search(query, {
228
+ filters: `orgID:${searchId}`,
229
+ });
230
+
231
+ setHits(hits as Hit[]);
232
+ };
233
+
234
+ const onSelectOption = (hit: any) => {
235
+ onClose();
236
+
237
+ const section =
238
+ hit._highlightResult.subheading?.matchLevel === 'full'
239
+ ? `#${hit.subheading}`
240
+ : hit._highlightResult.heading?.matchLevel === 'full'
241
+ ? `#${hit.heading}`
242
+ : '';
243
+ const sectionSlug = section
244
+ .toLowerCase()
245
+ .replaceAll(' ', '-')
246
+ .replaceAll(/[^a-zA-Z0-9-_#]/g, '');
247
+ router.push(`/${hit.slug}${sectionSlug}`);
248
+ setHits([]);
249
+ };
250
+
251
+ return (
252
+ <>
253
+ <SearchContext.Provider
254
+ value={{
255
+ isOpen,
256
+ onOpen,
257
+ onClose,
258
+ onInput,
259
+ }}
260
+ >
261
+ {children}
262
+ </SearchContext.Provider>
263
+ {isOpen && (
264
+ <Transition.Root
265
+ show={isOpen}
266
+ as={Fragment}
267
+ afterLeave={() => {
268
+ setQuery('');
269
+ setHits([]);
270
+ }}
271
+ appear
272
+ >
273
+ <Dialog as="div" className="relative z-50" onClose={setIsOpen}>
274
+ <Transition.Child
275
+ as={Fragment}
276
+ enter="ease-out duration-300"
277
+ enterFrom="opacity-0"
278
+ enterTo="opacity-100"
279
+ leave="ease-in duration-200"
280
+ leaveFrom="opacity-100"
281
+ leaveTo="opacity-0"
282
+ >
283
+ <div className="fixed inset-0 bg-gray-500 bg-opacity-25 transition-opacity backdrop-blur-sm" />
284
+ </Transition.Child>
285
+
286
+ <div className="fixed inset-0 z-10 overflow-y-auto p-4 sm:p-6 md:p-20">
287
+ <Transition.Child
288
+ as={Fragment}
289
+ enter="ease-out duration-300"
290
+ enterFrom="opacity-0 scale-95"
291
+ enterTo="opacity-100 scale-100"
292
+ leave="ease-in duration-200"
293
+ leaveFrom="opacity-100 scale-100"
294
+ leaveTo="opacity-0 scale-95"
295
+ >
296
+ <Dialog.Panel className="mx-auto max-w-3xl transform divide-y divide-gray-500 divide-opacity-10 overflow-hidden rounded-md bg-white dark:bg-slate-900 bg-opacity-80 shadow-2xl backdrop-blur backdrop-filter transition-all">
297
+ <Combobox onChange={(option) => onSelectOption(option)} value={query}>
298
+ <div className="relative flex items-center">
299
+ <SearchIcon
300
+ className="pointer-events-none absolute left-4 h-5 w-5 text-slate-700 dark:text-slate-400"
301
+ aria-hidden="true"
302
+ />
303
+ <Combobox.Input
304
+ className="h-14 w-full border-0 bg-transparent pl-11 pr-6 text-gray-900 dark:text-slate-100 placeholder-slate-400 focus:ring-0 sm:text-sm focus:outline-none"
305
+ placeholder="Find anything..."
306
+ onChange={(event) => onSearch(event.target.value)}
307
+ />
308
+ </div>
309
+
310
+ {(query === '' || hits.length > 0) && (
311
+ <Combobox.Options
312
+ static
313
+ className="max-h-80 scroll-py-2 divide-y divide-slate-500 divide-opacity-10 overflow-y-auto"
314
+ >
315
+ {hits.length > 0 && (
316
+ <li className="p-2">
317
+ <ul className="text-sm text-slate-700">
318
+ {hits.map((hit: Hit) => (
319
+ <Combobox.Option
320
+ key={hit.objectID}
321
+ value={hit}
322
+ className={({ active }) =>
323
+ clsx(
324
+ 'flex cursor-pointer select-none items-center px-3 py-2 rounded-md',
325
+ active
326
+ ? 'bg-primary-dark text-white dark:text-white'
327
+ : 'dark:text-slate-500'
328
+ )
329
+ }
330
+ >
331
+ {({ active }) => <SearchHit active={active} hit={hit} />}
332
+ </Combobox.Option>
333
+ ))}
334
+ </ul>
335
+ </li>
336
+ )}
337
+ </Combobox.Options>
338
+ )}
339
+
340
+ {query !== '' && hits.length === 0 && (
341
+ <div className="py-14 px-6 text-center sm:px-14">
342
+ <FolderIcon
343
+ className="mx-auto h-6 w-6 text-slate-900 dark:text-slate-400 text-opacity-40"
344
+ aria-hidden="true"
345
+ />
346
+ <p className="mt-4 text-sm text-slate-900 dark:text-slate-400">
347
+ We couldn't find any projects with that term. Please try again.
348
+ </p>
349
+ </div>
350
+ )}
351
+ </Combobox>
352
+ </Dialog.Panel>
353
+ </Transition.Child>
354
+ </div>
355
+ </Dialog>
356
+ </Transition.Root>
357
+ )}
358
+ </>
359
+ );
360
+ }
361
+
362
+ export function SearchButton({ children, ...props }: any) {
363
+ let searchButtonRef = useRef();
364
+ let actionKey = useActionKey();
365
+ let { onOpen, onInput } = useContext(SearchContext) as any;
366
+
367
+ useEffect(() => {
368
+ function onKeyDown(event: any) {
369
+ if (searchButtonRef && searchButtonRef.current === document.activeElement && onInput) {
370
+ if (/[a-zA-Z0-9]/.test(String.fromCharCode(event.keyCode))) {
371
+ onInput(event);
372
+ }
373
+ }
374
+ }
375
+ window.addEventListener('keydown', onKeyDown);
376
+ return () => {
377
+ window.removeEventListener('keydown', onKeyDown);
378
+ };
379
+ }, [onInput, searchButtonRef]);
380
+
381
+ return (
382
+ <button type="button" ref={searchButtonRef} onClick={onOpen} {...props}>
383
+ {typeof children === 'function' ? children({ actionKey }) : children}
384
+ </button>
385
+ );
386
+ }
@@ -0,0 +1,285 @@
1
+ import { Listbox } from '@headlessui/react';
2
+ import clsx from 'clsx';
3
+ import { Fragment, useEffect, useRef } from 'react';
4
+ import create from 'zustand';
5
+
6
+ import { useIsomorphicLayoutEffect } from '@/hooks/useIsomorphicLayoutEffect';
7
+
8
+ const useSetting = create((set: any) => ({
9
+ setting: 'system',
10
+ setSetting: (setting: string) => set({ setting }),
11
+ })) as any;
12
+
13
+ function update() {
14
+ if (
15
+ localStorage.theme === 'dark' ||
16
+ (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
17
+ ) {
18
+ document.documentElement.classList.add('dark', 'changing-theme');
19
+ } else {
20
+ document.documentElement.classList.remove('dark', 'changing-theme');
21
+ }
22
+ window.setTimeout(() => {
23
+ document.documentElement.classList.remove('changing-theme');
24
+ });
25
+ }
26
+
27
+ let settings = [
28
+ {
29
+ value: 'light',
30
+ label: 'Light',
31
+ icon: SunIcon,
32
+ },
33
+ {
34
+ value: 'dark',
35
+ label: 'Dark',
36
+ icon: MoonIcon,
37
+ },
38
+ {
39
+ value: 'system',
40
+ label: 'System',
41
+ icon: PcIcon,
42
+ },
43
+ ];
44
+
45
+ function SunIcon({ selected, ...props }: { selected?: boolean; className: string }) {
46
+ return (
47
+ <svg
48
+ viewBox="0 0 24 24"
49
+ fill="none"
50
+ strokeWidth="2"
51
+ strokeLinecap="round"
52
+ strokeLinejoin="round"
53
+ {...props}
54
+ >
55
+ <path
56
+ d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
57
+ className={selected ? 'stroke-yellow-500' : 'stroke-slate-400 dark:stroke-slate-500'}
58
+ />
59
+ <path
60
+ d="M12 4v1M17.66 6.344l-.828.828M20.005 12.004h-1M17.66 17.664l-.828-.828M12 20.01V19M6.34 17.664l.835-.836M3.995 12.004h1.01M6 6l.835.836"
61
+ className={selected ? 'stroke-yellow-500' : 'stroke-slate-400 dark:stroke-slate-500'}
62
+ />
63
+ </svg>
64
+ );
65
+ }
66
+
67
+ function MoonIcon({ selected, ...props }: { selected: boolean; className: string }) {
68
+ return (
69
+ <svg viewBox="0 0 24 24" fill="none" {...props}>
70
+ <path
71
+ fillRule="evenodd"
72
+ clipRule="evenodd"
73
+ d="M17.715 15.15A6.5 6.5 0 0 1 9 6.035C6.106 6.922 4 9.645 4 12.867c0 3.94 3.153 7.136 7.042 7.136 3.101 0 5.734-2.032 6.673-4.853Z"
74
+ className={selected ? 'fill-primary-light/20' : 'fill-transparent'}
75
+ />
76
+ <path
77
+ d="m17.715 15.15.95.316a1 1 0 0 0-1.445-1.185l.495.869ZM9 6.035l.846.534a1 1 0 0 0-1.14-1.49L9 6.035Zm8.221 8.246a5.47 5.47 0 0 1-2.72.718v2a7.47 7.47 0 0 0 3.71-.98l-.99-1.738Zm-2.72.718A5.5 5.5 0 0 1 9 9.5H7a7.5 7.5 0 0 0 7.5 7.5v-2ZM9 9.5c0-1.079.31-2.082.845-2.93L8.153 5.5A7.47 7.47 0 0 0 7 9.5h2Zm-4 3.368C5 10.089 6.815 7.75 9.292 6.99L8.706 5.08C5.397 6.094 3 9.201 3 12.867h2Zm6.042 6.136C7.718 19.003 5 16.268 5 12.867H3c0 4.48 3.588 8.136 8.042 8.136v-2Zm5.725-4.17c-.81 2.433-3.074 4.17-5.725 4.17v2c3.552 0 6.553-2.327 7.622-5.537l-1.897-.632Z"
78
+ className={
79
+ selected ? 'fill-primary dark:fill-primary-light' : 'fill-slate-400 dark:fill-slate-500'
80
+ }
81
+ />
82
+ <path
83
+ fillRule="evenodd"
84
+ clipRule="evenodd"
85
+ d="M17 3a1 1 0 0 1 1 1 2 2 0 0 0 2 2 1 1 0 1 1 0 2 2 2 0 0 0-2 2 1 1 0 1 1-2 0 2 2 0 0 0-2-2 1 1 0 1 1 0-2 2 2 0 0 0 2-2 1 1 0 0 1 1-1Z"
86
+ className={
87
+ selected ? 'fill-primary dark:fill-primary-light' : 'fill-slate-400 dark:fill-slate-500'
88
+ }
89
+ />
90
+ </svg>
91
+ );
92
+ }
93
+
94
+ function PcIcon({ selected, ...props }: { selected: boolean; className: string }) {
95
+ return (
96
+ <svg viewBox="0 0 24 24" fill="none" {...props}>
97
+ <path
98
+ d="M4 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6Z"
99
+ strokeWidth="2"
100
+ strokeLinejoin="round"
101
+ className={
102
+ selected
103
+ ? 'stroke-primary dark:stroke-primary-light fill-primary-light/20'
104
+ : 'stroke-slate-400 dark:stroke-slate-500'
105
+ }
106
+ />
107
+ <path
108
+ d="M14 15c0 3 2 5 2 5H8s2-2 2-5"
109
+ strokeWidth="2"
110
+ strokeLinecap="round"
111
+ strokeLinejoin="round"
112
+ className={
113
+ selected
114
+ ? 'stroke-primary dark:stroke-primary-light'
115
+ : 'stroke-slate-400 dark:stroke-slate-500'
116
+ }
117
+ />
118
+ </svg>
119
+ );
120
+ }
121
+
122
+ function useTheme() {
123
+ let { setting, setSetting } = useSetting();
124
+ let initial = useRef(true);
125
+
126
+ useIsomorphicLayoutEffect(() => {
127
+ let theme = localStorage.theme;
128
+ if (theme === 'light' || theme === 'dark') {
129
+ setSetting(theme);
130
+ }
131
+ }, []);
132
+
133
+ useIsomorphicLayoutEffect(() => {
134
+ if (setting === 'system') {
135
+ localStorage.removeItem('theme');
136
+ } else if (setting === 'light' || setting === 'dark') {
137
+ localStorage.theme = setting;
138
+ }
139
+ if (initial.current) {
140
+ initial.current = false;
141
+ } else {
142
+ update();
143
+ }
144
+ }, [setting]);
145
+
146
+ useEffect(() => {
147
+ let mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
148
+
149
+ if (mediaQuery?.addEventListener) {
150
+ mediaQuery.addEventListener('change', update);
151
+ } else {
152
+ mediaQuery.addListener(update);
153
+ }
154
+
155
+ function onStorage() {
156
+ update();
157
+ let theme = localStorage.theme;
158
+ if (theme === 'light' || theme === 'dark') {
159
+ setSetting(theme);
160
+ } else {
161
+ setSetting('system');
162
+ }
163
+ }
164
+ window.addEventListener('storage', onStorage);
165
+
166
+ return () => {
167
+ if (mediaQuery?.removeEventListener) {
168
+ mediaQuery.removeEventListener('change', update);
169
+ } else {
170
+ mediaQuery.removeListener(update);
171
+ }
172
+
173
+ window.removeEventListener('storage', onStorage);
174
+ };
175
+ }, [setSetting]);
176
+
177
+ return [setting, setSetting];
178
+ }
179
+
180
+ export function ThemeToggle({ panelClassName = 'mt-4' }) {
181
+ let [setting, setSetting] = useTheme();
182
+
183
+ return (
184
+ <Listbox value={setting} onChange={setSetting}>
185
+ <Listbox.Label className="sr-only">Theme</Listbox.Label>
186
+ <Listbox.Button type="button">
187
+ <span className="dark:hidden">
188
+ <SunIcon className="w-6 h-6" selected={setting !== 'system'} />
189
+ </span>
190
+ <span className="hidden dark:inline">
191
+ <MoonIcon className="w-6 h-6" selected={setting !== 'system'} />
192
+ </span>
193
+ </Listbox.Button>
194
+ <Listbox.Options
195
+ className={clsx(
196
+ 'absolute z-50 top-full right-0 bg-white rounded-lg ring-1 ring-slate-900/10 shadow-lg overflow-hidden w-36 py-1 text-sm text-slate-700 font-medium dark:bg-slate-800 dark:ring-0 dark:highlight-white/5 dark:text-slate-300',
197
+ panelClassName
198
+ )}
199
+ >
200
+ {settings.map(({ value, label, icon: Icon }) => (
201
+ <Listbox.Option key={value} value={value} as={Fragment}>
202
+ {({ active, selected }) => (
203
+ <li
204
+ className={clsx(
205
+ 'py-1 px-2 flex items-center cursor-pointer',
206
+ selected
207
+ ? value === 'light'
208
+ ? 'text-yellow-500'
209
+ : 'text-primary dark:text-primary-light'
210
+ : '',
211
+ active && 'bg-slate-50 dark:bg-slate-600/30'
212
+ )}
213
+ >
214
+ <Icon selected={selected} className="w-6 h-6 mr-2" />
215
+ {label}
216
+ </li>
217
+ )}
218
+ </Listbox.Option>
219
+ ))}
220
+ </Listbox.Options>
221
+ </Listbox>
222
+ );
223
+ }
224
+
225
+ export function ThemeSelect() {
226
+ let [setting, setSetting] = useTheme();
227
+
228
+ const foundSetting = settings.find((x) => x.value === setting);
229
+ if (foundSetting == null) {
230
+ return null;
231
+ }
232
+
233
+ const { label } = foundSetting;
234
+
235
+ return (
236
+ <div className="flex items-center justify-between">
237
+ <label htmlFor="theme" className="text-slate-700 font-normal dark:text-slate-400">
238
+ Switch theme
239
+ </label>
240
+ <div className="relative flex items-center ring-1 ring-slate-900/10 rounded-lg shadow-sm p-2 text-slate-700 font-semibold dark:bg-slate-600 dark:ring-0 dark:highlight-white/5 dark:text-slate-200">
241
+ <SunIcon className="w-6 h-6 mr-2 dark:hidden" />
242
+ <svg viewBox="0 0 24 24" fill="none" className="w-6 h-6 mr-2 hidden dark:block">
243
+ <path
244
+ fillRule="evenodd"
245
+ clipRule="evenodd"
246
+ d="M17.715 15.15A6.5 6.5 0 0 1 9 6.035C6.106 6.922 4 9.645 4 12.867c0 3.94 3.153 7.136 7.042 7.136 3.101 0 5.734-2.032 6.673-4.853Z"
247
+ className="fill-transparent"
248
+ />
249
+ <path
250
+ d="m17.715 15.15.95.316a1 1 0 0 0-1.445-1.185l.495.869ZM9 6.035l.846.534a1 1 0 0 0-1.14-1.49L9 6.035Zm8.221 8.246a5.47 5.47 0 0 1-2.72.718v2a7.47 7.47 0 0 0 3.71-.98l-.99-1.738Zm-2.72.718A5.5 5.5 0 0 1 9 9.5H7a7.5 7.5 0 0 0 7.5 7.5v-2ZM9 9.5c0-1.079.31-2.082.845-2.93L8.153 5.5A7.47 7.47 0 0 0 7 9.5h2Zm-4 3.368C5 10.089 6.815 7.75 9.292 6.99L8.706 5.08C5.397 6.094 3 9.201 3 12.867h2Zm6.042 6.136C7.718 19.003 5 16.268 5 12.867H3c0 4.48 3.588 8.136 8.042 8.136v-2Zm5.725-4.17c-.81 2.433-3.074 4.17-5.725 4.17v2c3.552 0 6.553-2.327 7.622-5.537l-1.897-.632Z"
251
+ className="fill-slate-400"
252
+ />
253
+ <path
254
+ fillRule="evenodd"
255
+ clipRule="evenodd"
256
+ d="M17 3a1 1 0 0 1 1 1 2 2 0 0 0 2 2 1 1 0 1 1 0 2 2 2 0 0 0-2 2 1 1 0 1 1-2 0 2 2 0 0 0-2-2 1 1 0 1 1 0-2 2 2 0 0 0 2-2 1 1 0 0 1 1-1Z"
257
+ className="fill-slate-400"
258
+ />
259
+ </svg>
260
+ {label}
261
+ <svg className="w-6 h-6 ml-2 text-slate-400" fill="none">
262
+ <path
263
+ d="m15 11-3 3-3-3"
264
+ stroke="currentColor"
265
+ strokeWidth="2"
266
+ strokeLinecap="round"
267
+ strokeLinejoin="round"
268
+ />
269
+ </svg>
270
+ <select
271
+ id="theme"
272
+ value={setting}
273
+ onChange={(e) => setSetting(e.target.value)}
274
+ className="absolute appearance-none inset-0 w-full h-full opacity-0"
275
+ >
276
+ {settings.map(({ value, label }) => (
277
+ <option key={value} value={value}>
278
+ {label}
279
+ </option>
280
+ ))}
281
+ </select>
282
+ </div>
283
+ </div>
284
+ );
285
+ }
@@ -0,0 +1,22 @@
1
+ import Head from 'next/head'
2
+ import { ReactNode } from 'react'
3
+
4
+ export function Title({ suffix, children }: { suffix: string, children: ReactNode }) {
5
+ let title = '';
6
+ if (suffix != null) {
7
+ title = suffix;
8
+ if (children != null) {
9
+ title = children + ` - ${title}`
10
+ }
11
+ } else if (children != null) {
12
+ title = children.toString();
13
+ }
14
+
15
+ return (
16
+ <Head>
17
+ <title key="title">{title}</title>
18
+ <meta key="twitter:title" name="twitter:title" content={title} />
19
+ <meta key="og:title" property="og:title" content={title} />
20
+ </Head>
21
+ )
22
+ }