@brainfish-ai/devdoc 0.1.21

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 (268) hide show
  1. package/LICENSE +33 -0
  2. package/README.md +415 -0
  3. package/bin/devdoc.js +13 -0
  4. package/dist/cli/commands/build.d.ts +5 -0
  5. package/dist/cli/commands/build.js +87 -0
  6. package/dist/cli/commands/check.d.ts +1 -0
  7. package/dist/cli/commands/check.js +143 -0
  8. package/dist/cli/commands/create.d.ts +24 -0
  9. package/dist/cli/commands/create.js +387 -0
  10. package/dist/cli/commands/deploy.d.ts +9 -0
  11. package/dist/cli/commands/deploy.js +433 -0
  12. package/dist/cli/commands/dev.d.ts +6 -0
  13. package/dist/cli/commands/dev.js +139 -0
  14. package/dist/cli/commands/init.d.ts +11 -0
  15. package/dist/cli/commands/init.js +238 -0
  16. package/dist/cli/commands/keys.d.ts +12 -0
  17. package/dist/cli/commands/keys.js +165 -0
  18. package/dist/cli/commands/start.d.ts +5 -0
  19. package/dist/cli/commands/start.js +56 -0
  20. package/dist/cli/commands/upload.d.ts +13 -0
  21. package/dist/cli/commands/upload.js +238 -0
  22. package/dist/cli/commands/whoami.d.ts +8 -0
  23. package/dist/cli/commands/whoami.js +91 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +106 -0
  26. package/dist/config/index.d.ts +80 -0
  27. package/dist/config/index.js +133 -0
  28. package/dist/constants.d.ts +9 -0
  29. package/dist/constants.js +13 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.js +12 -0
  32. package/dist/utils/logger.d.ts +16 -0
  33. package/dist/utils/logger.js +61 -0
  34. package/dist/utils/paths.d.ts +16 -0
  35. package/dist/utils/paths.js +50 -0
  36. package/package.json +51 -0
  37. package/renderer/app/api/assets/[...path]/route.ts +123 -0
  38. package/renderer/app/api/assets/route.ts +124 -0
  39. package/renderer/app/api/assets/upload/route.ts +177 -0
  40. package/renderer/app/api/auth-schemes/route.ts +77 -0
  41. package/renderer/app/api/chat/route.ts +858 -0
  42. package/renderer/app/api/codegen/route.ts +72 -0
  43. package/renderer/app/api/collections/route.ts +1016 -0
  44. package/renderer/app/api/debug/route.ts +53 -0
  45. package/renderer/app/api/deploy/route.ts +234 -0
  46. package/renderer/app/api/device/route.ts +42 -0
  47. package/renderer/app/api/docs/route.ts +187 -0
  48. package/renderer/app/api/keys/regenerate/route.ts +80 -0
  49. package/renderer/app/api/openapi-spec/route.ts +151 -0
  50. package/renderer/app/api/projects/[slug]/route.ts +153 -0
  51. package/renderer/app/api/projects/[slug]/stats/route.ts +96 -0
  52. package/renderer/app/api/projects/register/route.ts +152 -0
  53. package/renderer/app/api/proxy/route.ts +149 -0
  54. package/renderer/app/api/proxy-stream/route.ts +168 -0
  55. package/renderer/app/api/redirects/route.ts +47 -0
  56. package/renderer/app/api/schema/route.ts +65 -0
  57. package/renderer/app/api/subdomains/check/route.ts +172 -0
  58. package/renderer/app/api/suggestions/route.ts +144 -0
  59. package/renderer/app/favicon.ico +0 -0
  60. package/renderer/app/globals.css +1103 -0
  61. package/renderer/app/layout.tsx +47 -0
  62. package/renderer/app/llms-full.txt/route.ts +346 -0
  63. package/renderer/app/llms.txt/route.ts +279 -0
  64. package/renderer/app/page.tsx +14 -0
  65. package/renderer/app/robots.txt/route.ts +84 -0
  66. package/renderer/app/sitemap.xml/route.ts +199 -0
  67. package/renderer/components/docs/index.ts +12 -0
  68. package/renderer/components/docs/mdx/accordion.tsx +169 -0
  69. package/renderer/components/docs/mdx/badge.tsx +132 -0
  70. package/renderer/components/docs/mdx/callouts.tsx +154 -0
  71. package/renderer/components/docs/mdx/cards.tsx +213 -0
  72. package/renderer/components/docs/mdx/changelog.tsx +120 -0
  73. package/renderer/components/docs/mdx/code-block.tsx +186 -0
  74. package/renderer/components/docs/mdx/code-group.tsx +421 -0
  75. package/renderer/components/docs/mdx/file-embeds.tsx +105 -0
  76. package/renderer/components/docs/mdx/frame.tsx +112 -0
  77. package/renderer/components/docs/mdx/highlight.tsx +151 -0
  78. package/renderer/components/docs/mdx/iframe.tsx +134 -0
  79. package/renderer/components/docs/mdx/image.tsx +235 -0
  80. package/renderer/components/docs/mdx/index.ts +204 -0
  81. package/renderer/components/docs/mdx/mermaid.tsx +240 -0
  82. package/renderer/components/docs/mdx/param-field.tsx +200 -0
  83. package/renderer/components/docs/mdx/steps.tsx +113 -0
  84. package/renderer/components/docs/mdx/tabs.tsx +86 -0
  85. package/renderer/components/docs/mdx-renderer.tsx +100 -0
  86. package/renderer/components/docs/navigation/breadcrumbs.tsx +76 -0
  87. package/renderer/components/docs/navigation/index.ts +8 -0
  88. package/renderer/components/docs/navigation/page-nav.tsx +64 -0
  89. package/renderer/components/docs/navigation/sidebar.tsx +515 -0
  90. package/renderer/components/docs/navigation/toc.tsx +113 -0
  91. package/renderer/components/docs/notice.tsx +105 -0
  92. package/renderer/components/docs-header.tsx +274 -0
  93. package/renderer/components/docs-viewer/agent/agent-chat.tsx +2076 -0
  94. package/renderer/components/docs-viewer/agent/cards/debug-context-card.tsx +90 -0
  95. package/renderer/components/docs-viewer/agent/cards/endpoint-context-card.tsx +49 -0
  96. package/renderer/components/docs-viewer/agent/cards/index.tsx +50 -0
  97. package/renderer/components/docs-viewer/agent/cards/response-options-card.tsx +212 -0
  98. package/renderer/components/docs-viewer/agent/cards/types.ts +84 -0
  99. package/renderer/components/docs-viewer/agent/chat-message.tsx +17 -0
  100. package/renderer/components/docs-viewer/agent/index.tsx +6 -0
  101. package/renderer/components/docs-viewer/agent/messages/assistant-message.tsx +119 -0
  102. package/renderer/components/docs-viewer/agent/messages/chat-message.tsx +46 -0
  103. package/renderer/components/docs-viewer/agent/messages/index.ts +17 -0
  104. package/renderer/components/docs-viewer/agent/messages/tool-call-display.tsx +721 -0
  105. package/renderer/components/docs-viewer/agent/messages/types.ts +61 -0
  106. package/renderer/components/docs-viewer/agent/messages/typing-indicator.tsx +24 -0
  107. package/renderer/components/docs-viewer/agent/messages/user-message.tsx +51 -0
  108. package/renderer/components/docs-viewer/code-editor/index.tsx +2 -0
  109. package/renderer/components/docs-viewer/code-editor/notes-mode.tsx +1283 -0
  110. package/renderer/components/docs-viewer/content/changelog-page.tsx +331 -0
  111. package/renderer/components/docs-viewer/content/doc-page.tsx +285 -0
  112. package/renderer/components/docs-viewer/content/documentation-viewer.tsx +17 -0
  113. package/renderer/components/docs-viewer/content/index.tsx +29 -0
  114. package/renderer/components/docs-viewer/content/introduction.tsx +21 -0
  115. package/renderer/components/docs-viewer/content/request-details.tsx +330 -0
  116. package/renderer/components/docs-viewer/content/sections/auth.tsx +69 -0
  117. package/renderer/components/docs-viewer/content/sections/body.tsx +66 -0
  118. package/renderer/components/docs-viewer/content/sections/headers.tsx +43 -0
  119. package/renderer/components/docs-viewer/content/sections/overview.tsx +40 -0
  120. package/renderer/components/docs-viewer/content/sections/parameters.tsx +43 -0
  121. package/renderer/components/docs-viewer/content/sections/responses.tsx +87 -0
  122. package/renderer/components/docs-viewer/global-auth-modal.tsx +352 -0
  123. package/renderer/components/docs-viewer/index.tsx +1466 -0
  124. package/renderer/components/docs-viewer/playground/auth-editor.tsx +280 -0
  125. package/renderer/components/docs-viewer/playground/body-editor.tsx +221 -0
  126. package/renderer/components/docs-viewer/playground/code-editor.tsx +224 -0
  127. package/renderer/components/docs-viewer/playground/code-snippet.tsx +387 -0
  128. package/renderer/components/docs-viewer/playground/graphql-playground.tsx +745 -0
  129. package/renderer/components/docs-viewer/playground/index.tsx +671 -0
  130. package/renderer/components/docs-viewer/playground/key-value-editor.tsx +261 -0
  131. package/renderer/components/docs-viewer/playground/method-selector.tsx +60 -0
  132. package/renderer/components/docs-viewer/playground/request-builder.tsx +179 -0
  133. package/renderer/components/docs-viewer/playground/request-tabs.tsx +237 -0
  134. package/renderer/components/docs-viewer/playground/response-cards/idle-card.tsx +21 -0
  135. package/renderer/components/docs-viewer/playground/response-cards/index.tsx +93 -0
  136. package/renderer/components/docs-viewer/playground/response-cards/loading-card.tsx +16 -0
  137. package/renderer/components/docs-viewer/playground/response-cards/network-error-card.tsx +23 -0
  138. package/renderer/components/docs-viewer/playground/response-cards/response-body-card.tsx +268 -0
  139. package/renderer/components/docs-viewer/playground/response-cards/types.ts +82 -0
  140. package/renderer/components/docs-viewer/playground/response-viewer.tsx +43 -0
  141. package/renderer/components/docs-viewer/search/index.ts +2 -0
  142. package/renderer/components/docs-viewer/search/search-dialog.tsx +331 -0
  143. package/renderer/components/docs-viewer/search/use-search.ts +117 -0
  144. package/renderer/components/docs-viewer/shared/markdown-renderer.tsx +431 -0
  145. package/renderer/components/docs-viewer/shared/method-badge.tsx +41 -0
  146. package/renderer/components/docs-viewer/shared/schema-viewer.tsx +349 -0
  147. package/renderer/components/docs-viewer/sidebar/collection-tree.tsx +239 -0
  148. package/renderer/components/docs-viewer/sidebar/endpoint-options.tsx +316 -0
  149. package/renderer/components/docs-viewer/sidebar/index.tsx +343 -0
  150. package/renderer/components/docs-viewer/sidebar/right-sidebar.tsx +202 -0
  151. package/renderer/components/docs-viewer/sidebar/sidebar-group.tsx +118 -0
  152. package/renderer/components/docs-viewer/sidebar/sidebar-item.tsx +226 -0
  153. package/renderer/components/docs-viewer/sidebar/sidebar-section.tsx +52 -0
  154. package/renderer/components/theme-provider.tsx +11 -0
  155. package/renderer/components/theme-toggle.tsx +76 -0
  156. package/renderer/components/ui/badge.tsx +46 -0
  157. package/renderer/components/ui/button.tsx +59 -0
  158. package/renderer/components/ui/dialog.tsx +118 -0
  159. package/renderer/components/ui/dropdown-menu.tsx +257 -0
  160. package/renderer/components/ui/input.tsx +21 -0
  161. package/renderer/components/ui/label.tsx +24 -0
  162. package/renderer/components/ui/navigation-menu.tsx +168 -0
  163. package/renderer/components/ui/select.tsx +190 -0
  164. package/renderer/components/ui/spinner.tsx +114 -0
  165. package/renderer/components/ui/tabs.tsx +66 -0
  166. package/renderer/components/ui/tooltip.tsx +61 -0
  167. package/renderer/hooks/use-code-copy.ts +88 -0
  168. package/renderer/hooks/use-openapi-title.ts +44 -0
  169. package/renderer/lib/api-docs/agent/index.ts +6 -0
  170. package/renderer/lib/api-docs/agent/indexer.ts +323 -0
  171. package/renderer/lib/api-docs/agent/spec-summary.ts +335 -0
  172. package/renderer/lib/api-docs/agent/types.ts +116 -0
  173. package/renderer/lib/api-docs/auth/auth-context.tsx +225 -0
  174. package/renderer/lib/api-docs/auth/auth-storage.ts +87 -0
  175. package/renderer/lib/api-docs/auth/crypto.ts +89 -0
  176. package/renderer/lib/api-docs/auth/index.ts +4 -0
  177. package/renderer/lib/api-docs/code-editor/db.ts +164 -0
  178. package/renderer/lib/api-docs/code-editor/hooks.ts +266 -0
  179. package/renderer/lib/api-docs/code-editor/index.ts +6 -0
  180. package/renderer/lib/api-docs/code-editor/mode-context.tsx +207 -0
  181. package/renderer/lib/api-docs/code-editor/types.ts +105 -0
  182. package/renderer/lib/api-docs/codegen/definitions.ts +297 -0
  183. package/renderer/lib/api-docs/codegen/har.ts +251 -0
  184. package/renderer/lib/api-docs/codegen/index.ts +159 -0
  185. package/renderer/lib/api-docs/factories.ts +151 -0
  186. package/renderer/lib/api-docs/index.ts +17 -0
  187. package/renderer/lib/api-docs/mobile-context.tsx +112 -0
  188. package/renderer/lib/api-docs/navigation-context.tsx +88 -0
  189. package/renderer/lib/api-docs/parsers/graphql/README.md +129 -0
  190. package/renderer/lib/api-docs/parsers/graphql/index.ts +91 -0
  191. package/renderer/lib/api-docs/parsers/graphql/parser.ts +491 -0
  192. package/renderer/lib/api-docs/parsers/graphql/transformer.ts +246 -0
  193. package/renderer/lib/api-docs/parsers/graphql/types.ts +283 -0
  194. package/renderer/lib/api-docs/parsers/openapi/README.md +32 -0
  195. package/renderer/lib/api-docs/parsers/openapi/dereferencer.ts +60 -0
  196. package/renderer/lib/api-docs/parsers/openapi/extractors/auth.ts +574 -0
  197. package/renderer/lib/api-docs/parsers/openapi/extractors/body.ts +403 -0
  198. package/renderer/lib/api-docs/parsers/openapi/extractors/index.ts +232 -0
  199. package/renderer/lib/api-docs/parsers/openapi/index.ts +171 -0
  200. package/renderer/lib/api-docs/parsers/openapi/transformer.ts +277 -0
  201. package/renderer/lib/api-docs/parsers/openapi/validator.ts +31 -0
  202. package/renderer/lib/api-docs/playground/context.tsx +107 -0
  203. package/renderer/lib/api-docs/playground/navigation-context.tsx +124 -0
  204. package/renderer/lib/api-docs/playground/request-builder.ts +223 -0
  205. package/renderer/lib/api-docs/playground/request-runner.ts +282 -0
  206. package/renderer/lib/api-docs/playground/types.ts +35 -0
  207. package/renderer/lib/api-docs/types.ts +269 -0
  208. package/renderer/lib/api-docs/utils.ts +311 -0
  209. package/renderer/lib/cache.ts +193 -0
  210. package/renderer/lib/docs/config/index.ts +29 -0
  211. package/renderer/lib/docs/config/loader.ts +142 -0
  212. package/renderer/lib/docs/config/schema.ts +298 -0
  213. package/renderer/lib/docs/index.ts +12 -0
  214. package/renderer/lib/docs/mdx/compiler.ts +176 -0
  215. package/renderer/lib/docs/mdx/frontmatter.ts +80 -0
  216. package/renderer/lib/docs/mdx/index.ts +26 -0
  217. package/renderer/lib/docs/navigation/generator.ts +348 -0
  218. package/renderer/lib/docs/navigation/index.ts +12 -0
  219. package/renderer/lib/docs/navigation/types.ts +123 -0
  220. package/renderer/lib/docs-navigation-context.tsx +80 -0
  221. package/renderer/lib/multi-tenant/context.ts +105 -0
  222. package/renderer/lib/storage/blob.ts +845 -0
  223. package/renderer/lib/utils.ts +6 -0
  224. package/renderer/next.config.ts +76 -0
  225. package/renderer/package.json +66 -0
  226. package/renderer/postcss.config.mjs +5 -0
  227. package/renderer/public/assets/images/screenshot.png +0 -0
  228. package/renderer/public/assets/logo/dark.svg +9 -0
  229. package/renderer/public/assets/logo/light.svg +9 -0
  230. package/renderer/public/assets/logo.svg +9 -0
  231. package/renderer/public/file.svg +1 -0
  232. package/renderer/public/globe.svg +1 -0
  233. package/renderer/public/icon.png +0 -0
  234. package/renderer/public/logo.svg +9 -0
  235. package/renderer/public/window.svg +1 -0
  236. package/renderer/tsconfig.json +28 -0
  237. package/templates/basic/README.md +139 -0
  238. package/templates/basic/assets/favicon.svg +4 -0
  239. package/templates/basic/assets/logo.svg +9 -0
  240. package/templates/basic/docs.json +47 -0
  241. package/templates/basic/guides/configuration.mdx +149 -0
  242. package/templates/basic/guides/overview.mdx +96 -0
  243. package/templates/basic/index.mdx +39 -0
  244. package/templates/basic/package.json +14 -0
  245. package/templates/basic/quickstart.mdx +92 -0
  246. package/templates/basic/vercel.json +6 -0
  247. package/templates/graphql/README.md +139 -0
  248. package/templates/graphql/api-reference/schema.graphql +305 -0
  249. package/templates/graphql/assets/favicon.svg +4 -0
  250. package/templates/graphql/assets/logo.svg +9 -0
  251. package/templates/graphql/docs.json +54 -0
  252. package/templates/graphql/guides/configuration.mdx +149 -0
  253. package/templates/graphql/guides/overview.mdx +96 -0
  254. package/templates/graphql/index.mdx +39 -0
  255. package/templates/graphql/package.json +14 -0
  256. package/templates/graphql/quickstart.mdx +92 -0
  257. package/templates/graphql/vercel.json +6 -0
  258. package/templates/openapi/README.md +139 -0
  259. package/templates/openapi/api-reference/openapi.json +419 -0
  260. package/templates/openapi/assets/favicon.svg +4 -0
  261. package/templates/openapi/assets/logo.svg +9 -0
  262. package/templates/openapi/docs.json +61 -0
  263. package/templates/openapi/guides/configuration.mdx +149 -0
  264. package/templates/openapi/guides/overview.mdx +96 -0
  265. package/templates/openapi/index.mdx +39 -0
  266. package/templates/openapi/package.json +14 -0
  267. package/templates/openapi/quickstart.mdx +92 -0
  268. package/templates/openapi/vercel.json +6 -0
@@ -0,0 +1,240 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useRef, useState, useCallback } from 'react'
4
+ import { createPortal } from 'react-dom'
5
+ import { cn } from '@/lib/utils'
6
+ import { ArrowsOut, X } from '@phosphor-icons/react'
7
+
8
+ interface MermaidProps {
9
+ children: string
10
+ className?: string
11
+ }
12
+
13
+ // Helper to detect dark mode
14
+ function useIsDarkMode() {
15
+ const [isDark, setIsDark] = useState(false)
16
+
17
+ useEffect(() => {
18
+ const checkDarkMode = () => {
19
+ setIsDark(document.documentElement.classList.contains('dark'))
20
+ }
21
+
22
+ checkDarkMode()
23
+
24
+ // Watch for theme changes
25
+ const observer = new MutationObserver(checkDarkMode)
26
+ observer.observe(document.documentElement, {
27
+ attributes: true,
28
+ attributeFilter: ['class']
29
+ })
30
+
31
+ return () => observer.disconnect()
32
+ }, [])
33
+
34
+ return isDark
35
+ }
36
+
37
+ export function Mermaid({ children, className }: MermaidProps) {
38
+ const contentRef = useRef<HTMLDivElement>(null)
39
+ const [isLoaded, setIsLoaded] = useState(false)
40
+ const [error, setError] = useState<string | null>(null)
41
+ const [isModalOpen, setIsModalOpen] = useState(false)
42
+ const [mounted, setMounted] = useState(false)
43
+ const [modalSvg, setModalSvg] = useState<string>('')
44
+ const [modalLoading, setModalLoading] = useState(false)
45
+ const isDarkMode = useIsDarkMode()
46
+
47
+ const code = typeof children === 'string' ? children.trim() : ''
48
+
49
+ // Track if component is mounted (for portal)
50
+ useEffect(() => {
51
+ setMounted(true)
52
+ }, [])
53
+
54
+ // Render inline diagram
55
+ useEffect(() => {
56
+ if (!code || !contentRef.current) return
57
+
58
+ const renderDiagram = async () => {
59
+ try {
60
+ const mermaid = (await import('mermaid')).default
61
+
62
+ mermaid.initialize({
63
+ startOnLoad: false,
64
+ theme: isDarkMode ? 'dark' : 'default',
65
+ securityLevel: 'loose',
66
+ fontFamily: 'inherit',
67
+ })
68
+
69
+ const id = `mermaid-inline-${Math.random().toString(36).substr(2, 9)}`
70
+ const { svg } = await mermaid.render(id, code)
71
+
72
+ if (contentRef.current) {
73
+ contentRef.current.innerHTML = svg
74
+ setIsLoaded(true)
75
+ setError(null)
76
+ }
77
+ } catch (err) {
78
+ console.error('Mermaid rendering error:', err)
79
+ setError(err instanceof Error ? err.message : 'Failed to render diagram')
80
+ setIsLoaded(true)
81
+ }
82
+ }
83
+
84
+ renderDiagram()
85
+ }, [code, isDarkMode])
86
+
87
+ // Render modal diagram when modal opens
88
+ useEffect(() => {
89
+ if (!isModalOpen || !code) return
90
+
91
+ setModalLoading(true)
92
+ setModalSvg('')
93
+
94
+ const renderModalDiagram = async () => {
95
+ try {
96
+ const mermaid = (await import('mermaid')).default
97
+
98
+ mermaid.initialize({
99
+ startOnLoad: false,
100
+ theme: isDarkMode ? 'dark' : 'default',
101
+ securityLevel: 'loose',
102
+ fontFamily: 'inherit',
103
+ })
104
+
105
+ const id = `mermaid-modal-${Math.random().toString(36).substr(2, 9)}`
106
+ const { svg } = await mermaid.render(id, code)
107
+
108
+ setModalSvg(svg)
109
+ setModalLoading(false)
110
+ } catch (err) {
111
+ console.error('Mermaid modal rendering error:', err)
112
+ setModalSvg(`<div class="p-4 text-red-500">Failed to render diagram</div>`)
113
+ setModalLoading(false)
114
+ }
115
+ }
116
+
117
+ renderModalDiagram()
118
+ }, [isModalOpen, code, isDarkMode])
119
+
120
+ // Close modal on escape key
121
+ useEffect(() => {
122
+ const handleEscape = (e: KeyboardEvent) => {
123
+ if (e.key === 'Escape' && isModalOpen) {
124
+ setIsModalOpen(false)
125
+ }
126
+ }
127
+
128
+ document.addEventListener('keydown', handleEscape)
129
+ return () => document.removeEventListener('keydown', handleEscape)
130
+ }, [isModalOpen])
131
+
132
+ // Prevent body scroll when modal is open
133
+ useEffect(() => {
134
+ if (isModalOpen) {
135
+ document.body.style.overflow = 'hidden'
136
+ } else {
137
+ document.body.style.overflow = ''
138
+ }
139
+ return () => {
140
+ document.body.style.overflow = ''
141
+ }
142
+ }, [isModalOpen])
143
+
144
+ const openModal = useCallback(() => {
145
+ setIsModalOpen(true)
146
+ }, [])
147
+
148
+ const closeModal = useCallback(() => {
149
+ setIsModalOpen(false)
150
+ }, [])
151
+
152
+ if (error) {
153
+ return (
154
+ <div className={cn(
155
+ 'my-4 p-4 rounded-lg border border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-950',
156
+ className
157
+ )}>
158
+ <p className="text-sm text-red-600 dark:text-red-400 font-medium">
159
+ Failed to render Mermaid diagram
160
+ </p>
161
+ <pre className="mt-2 text-xs text-red-500 dark:text-red-400 overflow-auto">
162
+ {error}
163
+ </pre>
164
+ </div>
165
+ )
166
+ }
167
+
168
+ return (
169
+ <>
170
+ <div
171
+ className={cn(
172
+ 'my-4 relative rounded-lg border border-border bg-muted/30 overflow-hidden group',
173
+ className
174
+ )}
175
+ >
176
+ {/* Inline diagram */}
177
+ <div className="overflow-hidden min-h-[200px] relative">
178
+ <div
179
+ ref={contentRef}
180
+ className={cn(
181
+ 'flex items-center justify-center p-4',
182
+ !isLoaded && 'opacity-0'
183
+ )}
184
+ />
185
+ {!isLoaded && (
186
+ <div className="absolute inset-0 flex items-center justify-center">
187
+ <div className="text-sm text-muted-foreground">Loading diagram...</div>
188
+ </div>
189
+ )}
190
+ </div>
191
+
192
+ {/* Fullscreen button */}
193
+ {isLoaded && (
194
+ <button
195
+ onClick={openModal}
196
+ className="absolute bottom-3 right-3 p-2 bg-background/90 backdrop-blur-sm rounded-lg border border-border shadow-sm hover:bg-muted transition-colors opacity-0 group-hover:opacity-100"
197
+ title="View fullscreen"
198
+ >
199
+ <ArrowsOut className="h-4 w-4" weight="bold" />
200
+ </button>
201
+ )}
202
+ </div>
203
+
204
+ {/* Modal via Portal */}
205
+ {mounted && isModalOpen && createPortal(
206
+ <div
207
+ className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/80 backdrop-blur-sm"
208
+ onClick={closeModal}
209
+ >
210
+ <div
211
+ className="relative bg-background rounded-lg border border-border shadow-2xl w-[95vw] h-[95vh] overflow-auto flex items-center justify-center"
212
+ onClick={(e) => e.stopPropagation()}
213
+ >
214
+ {/* Close button */}
215
+ <button
216
+ onClick={closeModal}
217
+ className="absolute top-4 right-4 p-2 bg-muted/80 hover:bg-muted rounded-lg transition-colors z-10"
218
+ title="Close (Esc)"
219
+ >
220
+ <X className="h-5 w-5" weight="bold" />
221
+ </button>
222
+
223
+ {/* Modal diagram */}
224
+ {modalLoading ? (
225
+ <div className="text-sm text-muted-foreground">Loading diagram...</div>
226
+ ) : modalSvg ? (
227
+ <div
228
+ className="p-8 flex items-center justify-center [&_svg]:w-auto [&_svg]:h-auto [&_svg]:min-w-[60vw] [&_svg]:min-h-[60vh] [&_svg]:max-w-[90vw] [&_svg]:max-h-[90vh]"
229
+ dangerouslySetInnerHTML={{ __html: modalSvg }}
230
+ />
231
+ ) : (
232
+ <div className="text-sm text-muted-foreground">No diagram content (modalSvg is empty)</div>
233
+ )}
234
+ </div>
235
+ </div>,
236
+ document.body
237
+ )}
238
+ </>
239
+ )
240
+ }
@@ -0,0 +1,200 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ /**
7
+ * ParamField and ResponseField Components for MDX Documentation
8
+ *
9
+ * Mintlify-compatible components for documenting API parameters and responses.
10
+ */
11
+
12
+ interface ParamFieldProps {
13
+ /** Parameter path/name (e.g., "body.user.name" or "query.limit") */
14
+ path?: string
15
+ /** Parameter name (alternative to path) */
16
+ name?: string
17
+ /** Parameter type (e.g., "string", "number", "object") */
18
+ type?: string
19
+ /** Whether the parameter is required */
20
+ required?: boolean
21
+ /** Whether the parameter is deprecated */
22
+ deprecated?: boolean
23
+ /** Default value */
24
+ default?: string
25
+ /** Placeholder text */
26
+ placeholder?: string
27
+ /** Additional description as children */
28
+ children?: React.ReactNode
29
+ className?: string
30
+ }
31
+
32
+ export function ParamField({
33
+ path,
34
+ name,
35
+ type,
36
+ required = false,
37
+ deprecated = false,
38
+ default: defaultValue,
39
+ placeholder,
40
+ children,
41
+ className,
42
+ }: ParamFieldProps) {
43
+ const paramName = name || path?.split('.').pop() || 'param'
44
+ const paramPath = path || name
45
+
46
+ return (
47
+ <div
48
+ className={cn(
49
+ 'py-4 border-b border-border last:border-0',
50
+ deprecated && 'opacity-60',
51
+ className
52
+ )}
53
+ >
54
+ <div className="flex flex-wrap items-baseline gap-2 mb-1">
55
+ {/* Parameter name */}
56
+ <code className="text-sm font-semibold text-foreground">
57
+ {paramName}
58
+ </code>
59
+
60
+ {/* Type badge */}
61
+ {type && (
62
+ <span className="text-xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-mono">
63
+ {type}
64
+ </span>
65
+ )}
66
+
67
+ {/* Required badge */}
68
+ {required && (
69
+ <span className="text-xs px-1.5 py-0.5 rounded bg-red-500/10 text-red-600 dark:text-red-400 font-medium">
70
+ required
71
+ </span>
72
+ )}
73
+
74
+ {/* Deprecated badge */}
75
+ {deprecated && (
76
+ <span className="text-xs px-1.5 py-0.5 rounded bg-amber-500/10 text-amber-600 dark:text-amber-400 font-medium">
77
+ deprecated
78
+ </span>
79
+ )}
80
+ </div>
81
+
82
+ {/* Full path if different from name */}
83
+ {paramPath && paramPath !== paramName && (
84
+ <div className="text-xs text-muted-foreground mb-2 font-mono">
85
+ {paramPath}
86
+ </div>
87
+ )}
88
+
89
+ {/* Default value */}
90
+ {defaultValue && (
91
+ <div className="text-xs text-muted-foreground mb-2">
92
+ Default: <code className="bg-muted px-1 py-0.5 rounded">{defaultValue}</code>
93
+ </div>
94
+ )}
95
+
96
+ {/* Placeholder */}
97
+ {placeholder && (
98
+ <div className="text-xs text-muted-foreground mb-2">
99
+ Example: <code className="bg-muted px-1 py-0.5 rounded">{placeholder}</code>
100
+ </div>
101
+ )}
102
+
103
+ {/* Description */}
104
+ {children && (
105
+ <div className="text-sm text-foreground/90 [&>p]:mb-2 [&>p:last-child]:mb-0">
106
+ {children}
107
+ </div>
108
+ )}
109
+ </div>
110
+ )
111
+ }
112
+
113
+ interface ResponseFieldProps {
114
+ /** Field name */
115
+ name: string
116
+ /** Field type */
117
+ type?: string
118
+ /** Whether the field is always present */
119
+ required?: boolean
120
+ /** Additional description */
121
+ children?: React.ReactNode
122
+ className?: string
123
+ }
124
+
125
+ export function ResponseField({
126
+ name,
127
+ type,
128
+ required = false,
129
+ children,
130
+ className,
131
+ }: ResponseFieldProps) {
132
+ return (
133
+ <div className={cn('py-4 border-b border-border last:border-0', className)}>
134
+ <div className="flex flex-wrap items-baseline gap-2 mb-1">
135
+ {/* Field name */}
136
+ <code className="text-sm font-semibold text-foreground">
137
+ {name}
138
+ </code>
139
+
140
+ {/* Type badge */}
141
+ {type && (
142
+ <span className="text-xs px-1.5 py-0.5 rounded bg-muted text-muted-foreground font-mono">
143
+ {type}
144
+ </span>
145
+ )}
146
+
147
+ {/* Required/always present badge */}
148
+ {required && (
149
+ <span className="text-xs px-1.5 py-0.5 rounded bg-green-500/10 text-green-600 dark:text-green-400 font-medium">
150
+ always present
151
+ </span>
152
+ )}
153
+ </div>
154
+
155
+ {/* Description */}
156
+ {children && (
157
+ <div className="text-sm text-foreground/90 [&>p]:mb-2 [&>p:last-child]:mb-0">
158
+ {children}
159
+ </div>
160
+ )}
161
+ </div>
162
+ )
163
+ }
164
+
165
+ /**
166
+ * Expandable component for nested objects
167
+ */
168
+ interface ExpandableProps {
169
+ title?: string
170
+ defaultOpen?: boolean
171
+ children: React.ReactNode
172
+ className?: string
173
+ }
174
+
175
+ export function Expandable({
176
+ title = 'Show child attributes',
177
+ defaultOpen = false,
178
+ children,
179
+ className,
180
+ }: ExpandableProps) {
181
+ const [isOpen, setIsOpen] = React.useState(defaultOpen)
182
+
183
+ return (
184
+ <div className={cn('mt-2 ml-4 border-l-2 border-border', className)}>
185
+ <button
186
+ type="button"
187
+ onClick={() => setIsOpen(!isOpen)}
188
+ className="text-xs text-primary hover:text-primary/80 transition-colors pl-3 py-1"
189
+ >
190
+ {isOpen ? 'Hide' : 'Show'} {title.replace('Show ', '').replace('Hide ', '')}
191
+ </button>
192
+
193
+ {isOpen && (
194
+ <div className="pl-4 pt-2">
195
+ {children}
196
+ </div>
197
+ )}
198
+ </div>
199
+ )
200
+ }
@@ -0,0 +1,113 @@
1
+ 'use client'
2
+
3
+ import React from 'react'
4
+ import { cn } from '@/lib/utils'
5
+ import * as PhosphorIcons from '@phosphor-icons/react'
6
+
7
+ /**
8
+ * Steps Components for MDX Documentation
9
+ *
10
+ * Mintlify-compatible step-by-step guide components.
11
+ */
12
+
13
+ // Dynamic icon resolver
14
+ function getIcon(iconName: string): React.ComponentType<{ className?: string; weight?: string }> | null {
15
+ if (!iconName) return null
16
+
17
+ const pascalCase = iconName
18
+ .split(/[-_]/)
19
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
20
+ .join('')
21
+
22
+ const Icon = (PhosphorIcons as Record<string, unknown>)[pascalCase] as React.ComponentType<{ className?: string; weight?: string }> | undefined
23
+ return Icon || null
24
+ }
25
+
26
+ interface StepProps {
27
+ title: string
28
+ children: React.ReactNode
29
+ icon?: string
30
+ iconType?: string
31
+ stepNumber?: number
32
+ titleSize?: 'p' | 'h2' | 'h3' | 'h4'
33
+ className?: string
34
+ }
35
+
36
+ interface StepsContextValue {
37
+ titleSize: 'p' | 'h2' | 'h3' | 'h4'
38
+ }
39
+
40
+ const StepsContext = React.createContext<StepsContextValue>({ titleSize: 'p' })
41
+
42
+ export function Step({
43
+ title,
44
+ children,
45
+ icon,
46
+ stepNumber,
47
+ titleSize: localTitleSize,
48
+ className,
49
+ }: StepProps) {
50
+ const { titleSize: contextTitleSize } = React.useContext(StepsContext)
51
+ const titleSize = localTitleSize ?? contextTitleSize
52
+
53
+ const Icon = icon ? getIcon(icon) : null
54
+
55
+ const TitleTag = titleSize === 'p' ? 'div' : titleSize
56
+ const titleClass = cn(
57
+ 'font-semibold text-foreground',
58
+ titleSize === 'h2' && 'text-xl',
59
+ titleSize === 'h3' && 'text-lg',
60
+ titleSize === 'h4' && 'text-base',
61
+ titleSize === 'p' && 'text-base'
62
+ )
63
+
64
+ return (
65
+ <div className={cn('relative pl-8 pb-8 last:pb-0', className)}>
66
+ {/* Vertical line */}
67
+ <div className="absolute left-[11px] top-8 bottom-0 w-px bg-border last:hidden" />
68
+
69
+ {/* Step indicator */}
70
+ <div className="absolute left-0 top-0 flex h-6 w-6 items-center justify-center rounded-full bg-primary text-primary-foreground text-xs font-semibold">
71
+ {Icon ? (
72
+ <Icon className="h-3.5 w-3.5" weight="bold" />
73
+ ) : (
74
+ stepNumber
75
+ )}
76
+ </div>
77
+
78
+ {/* Content */}
79
+ <div className="pt-0.5">
80
+ <TitleTag className={titleClass}>{title}</TitleTag>
81
+ <div className="mt-2 text-sm text-foreground/90 [&>p]:mb-2 [&>p:last-child]:mb-0 [&>pre]:my-3 [&>ul]:mt-2 [&>ol]:mt-2">
82
+ {children}
83
+ </div>
84
+ </div>
85
+ </div>
86
+ )
87
+ }
88
+
89
+ interface StepsProps {
90
+ children: React.ReactNode
91
+ titleSize?: 'p' | 'h2' | 'h3' | 'h4'
92
+ className?: string
93
+ }
94
+
95
+ export function Steps({ children, titleSize = 'p', className }: StepsProps) {
96
+ // Auto-number steps
97
+ const numberedChildren = React.Children.map(children, (child, index) => {
98
+ if (React.isValidElement<StepProps>(child) && child.type === Step) {
99
+ return React.cloneElement(child, {
100
+ stepNumber: child.props.stepNumber ?? index + 1,
101
+ })
102
+ }
103
+ return child
104
+ })
105
+
106
+ return (
107
+ <StepsContext.Provider value={{ titleSize }}>
108
+ <div className={cn('my-6', className)}>
109
+ {numberedChildren}
110
+ </div>
111
+ </StepsContext.Provider>
112
+ )
113
+ }
@@ -0,0 +1,86 @@
1
+ 'use client'
2
+
3
+ import React, { useState } from 'react'
4
+ import { cn } from '@/lib/utils'
5
+
6
+ /**
7
+ * Tabs Components for MDX Documentation
8
+ *
9
+ * Mintlify-compatible tab components for organizing content.
10
+ */
11
+
12
+ interface TabProps {
13
+ title: string
14
+ children: React.ReactNode
15
+ className?: string
16
+ }
17
+
18
+ interface TabsProps {
19
+ children: React.ReactNode
20
+ defaultValue?: string
21
+ className?: string
22
+ }
23
+
24
+ // Context for sharing tab state
25
+ interface TabsContextValue {
26
+ activeTab: string
27
+ setActiveTab: (tab: string) => void
28
+ }
29
+
30
+ const TabsContext = React.createContext<TabsContextValue | null>(null)
31
+
32
+ export function Tab({ children, className }: TabProps) {
33
+ // Tab content is rendered by Tabs parent
34
+ return <div className={className}>{children}</div>
35
+ }
36
+
37
+ export function Tabs({ children, defaultValue, className }: TabsProps) {
38
+ // Extract tab titles and content from children
39
+ const tabs: { title: string; content: React.ReactNode }[] = []
40
+
41
+ React.Children.forEach(children, (child) => {
42
+ if (React.isValidElement<TabProps>(child) && child.type === Tab) {
43
+ tabs.push({
44
+ title: child.props.title,
45
+ content: child.props.children,
46
+ })
47
+ }
48
+ })
49
+
50
+ const [activeTab, setActiveTab] = useState(defaultValue || tabs[0]?.title || '')
51
+
52
+ const activeContent = tabs.find(tab => tab.title === activeTab)?.content
53
+
54
+ return (
55
+ <TabsContext.Provider value={{ activeTab, setActiveTab }}>
56
+ <div className={cn('my-4', className)}>
57
+ {/* Tab headers */}
58
+ <div className="flex border-b border-border overflow-x-auto">
59
+ {tabs.map((tab) => (
60
+ <button
61
+ key={tab.title}
62
+ type="button"
63
+ onClick={() => setActiveTab(tab.title)}
64
+ className={cn(
65
+ 'px-4 py-2 text-sm font-medium whitespace-nowrap transition-colors',
66
+ 'hover:text-foreground',
67
+ 'focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/50',
68
+ 'border-b-2 -mb-px',
69
+ activeTab === tab.title
70
+ ? 'border-primary text-foreground'
71
+ : 'border-transparent text-muted-foreground'
72
+ )}
73
+ >
74
+ {tab.title}
75
+ </button>
76
+ ))}
77
+ </div>
78
+
79
+ {/* Tab content */}
80
+ <div className="pt-4">
81
+ {activeContent}
82
+ </div>
83
+ </div>
84
+ </TabsContext.Provider>
85
+ )
86
+ }