@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,202 @@
1
+ 'use client'
2
+
3
+ import { useEffect, useState, useCallback } from 'react'
4
+ import Image from 'next/image'
5
+ import { X, ArrowClockwise } from '@phosphor-icons/react'
6
+ import type { BrainfishCollection, BrainfishRESTRequest } from '@/lib/api-docs/types'
7
+ import type { PrefillData } from '@/lib/api-docs/agent/types'
8
+ import type { DebugContext } from '../playground/response-viewer'
9
+ import { AgentChat } from '../agent'
10
+ import { Button } from '@/components/ui/button'
11
+ import { useMobile } from '@/lib/api-docs/mobile-context'
12
+ import { cn } from '@/lib/utils'
13
+ import {
14
+ Tooltip,
15
+ TooltipContent,
16
+ TooltipTrigger,
17
+ } from '@/components/ui/tooltip'
18
+
19
+ interface RightSidebarProps {
20
+ /** Current endpoint - when null, only agent mode is available */
21
+ request: BrainfishRESTRequest | null
22
+ /** Full collection for agent context */
23
+ collection: BrainfishCollection
24
+ /** Pre-generated API summary (cached server-side) */
25
+ apiSummary?: string | null
26
+ /** Callback when agent navigates to an endpoint */
27
+ onNavigateToEndpoint: (endpointId: string) => void
28
+ /** Callback when agent prefills parameters */
29
+ onPrefillParameters: (data: PrefillData) => void
30
+ /** Debug context from playground response - triggers agent debug */
31
+ debugContext?: DebugContext | null
32
+ /** Callback to clear debug context after processing */
33
+ onClearDebugContext?: () => void
34
+ /** Explain context from playground response - triggers agent explanation */
35
+ explainContext?: DebugContext | null
36
+ /** Callback to clear explain context after processing */
37
+ onClearExplainContext?: () => void
38
+ /** Callback to open global auth dialog */
39
+ onOpenGlobalAuth?: () => void
40
+ /** Callback to navigate to authorization tab in playground */
41
+ onNavigateToAuthTab?: () => void
42
+ /** Callback to navigate to parameters tab in playground */
43
+ onNavigateToParamsTab?: () => void
44
+ /** Callback to navigate to body tab in playground */
45
+ onNavigateToBodyTab?: () => void
46
+ /** Callback to navigate to headers tab in playground */
47
+ onNavigateToHeadersTab?: () => void
48
+ /** Callback to navigate to a documentation section */
49
+ onNavigateToDocSection?: (sectionId: string) => void
50
+ /** Callback to navigate to a documentation page */
51
+ onNavigateToDocPage?: (slug: string) => void
52
+ }
53
+
54
+ export function RightSidebar({
55
+ request,
56
+ collection,
57
+ apiSummary,
58
+ onNavigateToEndpoint,
59
+ onPrefillParameters,
60
+ debugContext,
61
+ onClearDebugContext,
62
+ explainContext,
63
+ onClearExplainContext,
64
+ onOpenGlobalAuth,
65
+ onNavigateToAuthTab,
66
+ onNavigateToParamsTab,
67
+ onNavigateToBodyTab,
68
+ onNavigateToHeadersTab,
69
+ onNavigateToDocSection,
70
+ onNavigateToDocPage,
71
+ }: RightSidebarProps) {
72
+ // Mobile context
73
+ const { isMobile, isRightSidebarOpen, closeRightSidebar } = useMobile()
74
+
75
+ // Debug context to send to agent (full context for card display)
76
+ const [pendingDebugContext, setPendingDebugContext] = useState<DebugContext | null>(null)
77
+
78
+ // Handle debug context
79
+ useEffect(() => {
80
+ if (debugContext) {
81
+ // Pass full context to agent
82
+ setPendingDebugContext(debugContext)
83
+
84
+ // Clear the debug context from parent
85
+ onClearDebugContext?.()
86
+ }
87
+ }, [debugContext, onClearDebugContext])
88
+
89
+ // Clear debug context after it's been used
90
+ const handleDebugContextConsumed = () => {
91
+ setPendingDebugContext(null)
92
+ }
93
+
94
+ // Key for resetting chat
95
+ const [chatKey, setChatKey] = useState(0)
96
+
97
+ // Track if there are messages
98
+ const [hasMessages, setHasMessages] = useState(false)
99
+
100
+ // Handle reset conversation
101
+ const handleResetConversation = useCallback(() => {
102
+ // Clear chat storage before remounting
103
+ localStorage.removeItem('brainfish-agent-chat')
104
+ setChatKey(prev => prev + 1)
105
+ setHasMessages(false)
106
+ }, [])
107
+
108
+ return (
109
+ <>
110
+ {/* Mobile overlay backdrop */}
111
+ {isMobile && isRightSidebarOpen && (
112
+ <div
113
+ className="docs-agent-overlay fixed inset-0 bg-black/50 z-40 lg:hidden"
114
+ onClick={closeRightSidebar}
115
+ />
116
+ )}
117
+
118
+ <div
119
+ className={cn(
120
+ "docs-agent-panel border-l border-border bg-background flex flex-col overflow-hidden",
121
+ // Desktop: always visible, fixed width
122
+ "lg:relative lg:w-96 lg:h-full",
123
+ // Mobile: drawer behavior from right
124
+ "fixed inset-y-0 right-0 z-50 w-[320px] sm:w-[360px] h-full",
125
+ "transform transition-transform duration-300 ease-in-out",
126
+ "lg:transform-none lg:translate-x-0",
127
+ isMobile && !isRightSidebarOpen && "translate-x-full",
128
+ isMobile && isRightSidebarOpen && "translate-x-0"
129
+ )}
130
+ >
131
+ {/* Header */}
132
+ <div className="docs-agent-header shrink-0 px-3 sm:px-4 h-[41px] flex items-center border-b border-border bg-muted/30">
133
+ <div className="flex items-center justify-between gap-2 w-full">
134
+ {/* Left: Assistant */}
135
+ <div className="docs-agent-title flex items-center gap-2.5">
136
+ <div className="docs-agent-avatar size-7 rounded-full overflow-hidden bg-muted flex items-center justify-center shrink-0">
137
+ <Image src="/icon.png" alt="Assistant" width={28} height={28} className="size-7 object-cover" />
138
+ </div>
139
+ <span className="text-sm font-medium">Assistant</span>
140
+ </div>
141
+
142
+ {/* Right: Actions */}
143
+ <div className="flex items-center gap-1 shrink-0">
144
+ {/* Reset conversation button - only show when there are messages */}
145
+ {hasMessages && (
146
+ <Tooltip>
147
+ <TooltipTrigger asChild>
148
+ <Button
149
+ variant="ghost"
150
+ size="icon"
151
+ onClick={handleResetConversation}
152
+ className="h-7 w-7 text-muted-foreground hover:text-foreground"
153
+ >
154
+ <ArrowClockwise className="h-4 w-4" weight="bold" />
155
+ </Button>
156
+ </TooltipTrigger>
157
+ <TooltipContent side="bottom">New conversation</TooltipContent>
158
+ </Tooltip>
159
+ )}
160
+
161
+ {/* Mobile close button */}
162
+ {isMobile && (
163
+ <Button
164
+ variant="ghost"
165
+ size="icon"
166
+ onClick={closeRightSidebar}
167
+ className="h-7 w-7 lg:hidden"
168
+ >
169
+ <X className="h-4 w-4" weight="bold" />
170
+ </Button>
171
+ )}
172
+ </div>
173
+ </div>
174
+ </div>
175
+
176
+ {/* Content */}
177
+ <div className="docs-agent-content flex-1 overflow-hidden">
178
+ <AgentChat
179
+ key={chatKey}
180
+ collection={collection}
181
+ currentEndpoint={request}
182
+ apiSummary={apiSummary}
183
+ onNavigate={onNavigateToEndpoint}
184
+ onPrefill={onPrefillParameters}
185
+ debugContext={pendingDebugContext}
186
+ onDebugContextConsumed={handleDebugContextConsumed}
187
+ explainContext={explainContext}
188
+ onExplainContextConsumed={onClearExplainContext}
189
+ onOpenGlobalAuth={onOpenGlobalAuth}
190
+ onNavigateToAuthTab={onNavigateToAuthTab}
191
+ onNavigateToParamsTab={onNavigateToParamsTab}
192
+ onNavigateToBodyTab={onNavigateToBodyTab}
193
+ onNavigateToHeadersTab={onNavigateToHeadersTab}
194
+ onNavigateToDocSection={onNavigateToDocSection}
195
+ onNavigateToDocPage={onNavigateToDocPage}
196
+ onHasMessagesChange={setHasMessages}
197
+ />
198
+ </div>
199
+ </div>
200
+ </>
201
+ )
202
+ }
@@ -0,0 +1,118 @@
1
+ 'use client'
2
+
3
+ import { ReactNode, useState, useRef, useEffect } from 'react'
4
+ import { CaretRight } from '@phosphor-icons/react'
5
+ import { cn } from '@/lib/utils'
6
+
7
+ interface SidebarGroupProps {
8
+ title: ReactNode
9
+ children: ReactNode
10
+ defaultOpen?: boolean
11
+ selected?: boolean
12
+ indent?: number
13
+ onClick?: () => void
14
+ asideContent?: ReactNode
15
+ /** Selected child slug - when this changes and a child is selected, auto-expand */
16
+ selectedChildSlug?: string | null
17
+ }
18
+
19
+ /**
20
+ * Sidebar Group component - collapsible group with toggle
21
+ * Arrow on right side with smooth rotation and expand animations
22
+ */
23
+ export function SidebarGroup({
24
+ title,
25
+ children,
26
+ defaultOpen = false,
27
+ selected = false,
28
+ indent = 0,
29
+ onClick,
30
+ asideContent,
31
+ selectedChildSlug,
32
+ }: SidebarGroupProps) {
33
+ const [isOpen, setIsOpen] = useState(defaultOpen)
34
+ const contentRef = useRef<HTMLUListElement>(null)
35
+ const [contentHeight, setContentHeight] = useState<number | undefined>(
36
+ defaultOpen ? undefined : 0
37
+ )
38
+
39
+ // Auto-expand when a child is selected (e.g., via agent navigation)
40
+ // Triggers on defaultOpen change OR when selectedChildSlug changes (even if defaultOpen stays true)
41
+ useEffect(() => {
42
+ if (defaultOpen) {
43
+ setIsOpen(true)
44
+ }
45
+ }, [defaultOpen, selectedChildSlug])
46
+
47
+ // Update height when open state changes
48
+ useEffect(() => {
49
+ if (isOpen) {
50
+ const height = contentRef.current?.scrollHeight
51
+ setContentHeight(height)
52
+ // After animation, set to auto for dynamic content
53
+ const timer = setTimeout(() => setContentHeight(undefined), 200)
54
+ return () => clearTimeout(timer)
55
+ } else {
56
+ // First set the current height, then animate to 0
57
+ const height = contentRef.current?.scrollHeight
58
+ setContentHeight(height)
59
+ requestAnimationFrame(() => {
60
+ setContentHeight(0)
61
+ })
62
+ }
63
+ }, [isOpen])
64
+
65
+ const handleToggle = () => {
66
+ setIsOpen(!isOpen)
67
+ onClick?.()
68
+ }
69
+
70
+ return (
71
+ <li className="docs-sidebar-group flex flex-col">
72
+ <button
73
+ type="button"
74
+ aria-expanded={isOpen}
75
+ onClick={handleToggle}
76
+ className={cn(
77
+ // Base styles
78
+ 'docs-sidebar-group-toggle group/button flex items-center rounded-lg px-3 py-2 w-full text-left',
79
+ 'text-sm leading-5 transition-colors duration-150',
80
+ // State variants
81
+ selected
82
+ ? 'docs-sidebar-group-active bg-sidebar-primary text-sidebar-primary-foreground font-medium'
83
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent/30 hover:text-sidebar-foreground'
84
+ )}
85
+ style={{ paddingLeft: indent > 0 ? `${indent * 12 + 12}px` : undefined }}
86
+ >
87
+ <span className="flex-1 truncate font-medium">{title}</span>
88
+ {asideContent && (
89
+ <span className="ml-2 shrink-0">{asideContent}</span>
90
+ )}
91
+ {/* Toggle icon - right side with rotation animation */}
92
+ <span className="docs-sidebar-group-icon ml-2 text-sidebar-foreground/50 group-hover/button:text-sidebar-foreground/70">
93
+ <CaretRight
94
+ weight="bold"
95
+ className={cn(
96
+ "h-3.5 w-3.5 transition-transform duration-200 ease-out",
97
+ isOpen && "rotate-90"
98
+ )}
99
+ />
100
+ </span>
101
+ </button>
102
+ {/* Child items with expand animation */}
103
+ <ul
104
+ ref={contentRef}
105
+ className={cn(
106
+ "docs-sidebar-group-items flex flex-col overflow-hidden transition-all duration-200 ease-out",
107
+ !isOpen && "opacity-0",
108
+ isOpen && "opacity-100"
109
+ )}
110
+ style={{
111
+ height: contentHeight !== undefined ? `${contentHeight}px` : 'auto',
112
+ }}
113
+ >
114
+ {children}
115
+ </ul>
116
+ </li>
117
+ )
118
+ }
@@ -0,0 +1,226 @@
1
+ 'use client'
2
+
3
+ import { ReactNode, useRef, useEffect, useLayoutEffect, useState, createContext, useContext } from 'react'
4
+ import { cn } from '@/lib/utils'
5
+ import * as PhosphorIcons from '@phosphor-icons/react'
6
+
7
+ // Helper to get Phosphor icon component from name
8
+ function getIcon(iconName?: string): React.ComponentType<{ className?: string; weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone" }> | null {
9
+ if (!iconName) return null
10
+
11
+ // Convert kebab-case to PascalCase for Phosphor icons
12
+ const pascalCase = iconName
13
+ .split('-')
14
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
15
+ .join('')
16
+
17
+ const IconComponent = (PhosphorIcons as Record<string, unknown>)[pascalCase] as React.ComponentType<{ className?: string; weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone" }> | undefined
18
+ return IconComponent || null
19
+ }
20
+
21
+ // Context for the sliding indicator
22
+ interface SlidingIndicatorContextType {
23
+ registerItem: (id: string, element: HTMLElement | null) => void
24
+ selectedId: string | null
25
+ setSelectedId: (id: string) => void
26
+ }
27
+
28
+ const SlidingIndicatorContext = createContext<SlidingIndicatorContextType | null>(null)
29
+
30
+ /**
31
+ * Wrapper component that provides sliding indicator animation
32
+ */
33
+ interface SlidingIndicatorProviderProps {
34
+ children: ReactNode
35
+ className?: string
36
+ }
37
+
38
+ export function SlidingIndicatorProvider({ children, className }: SlidingIndicatorProviderProps) {
39
+ const containerRef = useRef<HTMLDivElement>(null)
40
+ const itemsRef = useRef<Map<string, HTMLElement>>(new Map())
41
+ const [selectedId, setSelectedId] = useState<string | null>(null)
42
+ const [indicatorStyle, setIndicatorStyle] = useState<React.CSSProperties>({
43
+ opacity: 0,
44
+ top: 0,
45
+ height: 0,
46
+ })
47
+
48
+ const registerItem = (id: string, element: HTMLElement | null) => {
49
+ if (element) {
50
+ itemsRef.current.set(id, element)
51
+ } else {
52
+ itemsRef.current.delete(id)
53
+ }
54
+ }
55
+
56
+ // Update indicator position when selection changes
57
+ useLayoutEffect(() => {
58
+ if (!selectedId || !containerRef.current) {
59
+ setIndicatorStyle(prev => ({ ...prev, opacity: 0 }))
60
+ return
61
+ }
62
+
63
+ const selectedElement = itemsRef.current.get(selectedId)
64
+ if (!selectedElement) {
65
+ setIndicatorStyle(prev => ({ ...prev, opacity: 0 }))
66
+ return
67
+ }
68
+
69
+ const containerRect = containerRef.current.getBoundingClientRect()
70
+ const itemRect = selectedElement.getBoundingClientRect()
71
+
72
+ setIndicatorStyle({
73
+ opacity: 1,
74
+ top: itemRect.top - containerRect.top + containerRef.current.scrollTop,
75
+ height: itemRect.height,
76
+ left: 8,
77
+ right: 8,
78
+ })
79
+ }, [selectedId])
80
+
81
+ // Also update on scroll to keep indicator in sync
82
+ useEffect(() => {
83
+ const container = containerRef.current
84
+ if (!container) return
85
+
86
+ const handleScroll = () => {
87
+ if (!selectedId) return
88
+ const selectedElement = itemsRef.current.get(selectedId)
89
+ if (!selectedElement) return
90
+
91
+ const containerRect = container.getBoundingClientRect()
92
+ const itemRect = selectedElement.getBoundingClientRect()
93
+
94
+ setIndicatorStyle(prev => ({
95
+ ...prev,
96
+ top: itemRect.top - containerRect.top + container.scrollTop,
97
+ }))
98
+ }
99
+
100
+ container.addEventListener('scroll', handleScroll, { passive: true })
101
+ return () => container.removeEventListener('scroll', handleScroll)
102
+ }, [selectedId])
103
+
104
+ return (
105
+ <SlidingIndicatorContext.Provider value={{ registerItem, selectedId, setSelectedId }}>
106
+ <div ref={containerRef} className={cn('relative', className)}>
107
+ {/* Sliding indicator background */}
108
+ <div
109
+ className="docs-sidebar-indicator absolute rounded-lg bg-background dark:bg-stone-800/50 pointer-events-none z-0"
110
+ style={{
111
+ ...indicatorStyle,
112
+ transition: 'top 350ms cubic-bezier(0.4, 0, 0.2, 1), height 250ms cubic-bezier(0.4, 0, 0.2, 1), opacity 200ms ease-out',
113
+ }}
114
+ />
115
+ {children}
116
+ </div>
117
+ </SlidingIndicatorContext.Provider>
118
+ )
119
+ }
120
+
121
+ interface SidebarItemProps {
122
+ children: ReactNode
123
+ selected?: boolean
124
+ active?: boolean
125
+ disabled?: boolean
126
+ indent?: number
127
+ onClick?: () => void
128
+ className?: string
129
+ asideContent?: ReactNode
130
+ /** Unique ID for sliding animation */
131
+ itemId?: string
132
+ /** Phosphor icon name */
133
+ icon?: string
134
+ }
135
+
136
+ /**
137
+ * Sidebar Item component - individual clickable item in the sidebar
138
+ * Uses subtle sage/mint style when selected with smooth sliding animation
139
+ */
140
+ export function SidebarItem({
141
+ children,
142
+ selected = false,
143
+ active = false,
144
+ disabled = false,
145
+ indent = 0,
146
+ onClick,
147
+ className,
148
+ asideContent,
149
+ itemId,
150
+ icon,
151
+ }: SidebarItemProps) {
152
+ const buttonRef = useRef<HTMLButtonElement>(null)
153
+ const context = useContext(SlidingIndicatorContext)
154
+ const id = itemId || String(children)
155
+ const IconComponent = getIcon(icon)
156
+
157
+ // Register this item with the sliding indicator provider
158
+ useEffect(() => {
159
+ if (context && buttonRef.current) {
160
+ context.registerItem(id, buttonRef.current)
161
+ return () => context.registerItem(id, null)
162
+ }
163
+ }, [context, id])
164
+
165
+ // Update selected state in context
166
+ useEffect(() => {
167
+ if (context && selected) {
168
+ context.setSelectedId(id)
169
+ }
170
+ }, [context, selected, id])
171
+
172
+ // Auto-scroll into view when selected (e.g., via agent navigation)
173
+ useEffect(() => {
174
+ if (selected && buttonRef.current) {
175
+ // Small delay to allow folder expansion animation to complete
176
+ setTimeout(() => {
177
+ buttonRef.current?.scrollIntoView({
178
+ behavior: 'smooth',
179
+ block: 'center',
180
+ })
181
+ }, 100)
182
+ }
183
+ }, [selected])
184
+
185
+ // Check if we're inside a sliding indicator provider
186
+ const hasSliding = context !== null
187
+
188
+ return (
189
+ <li className="docs-sidebar-item-wrapper flex flex-col">
190
+ <button
191
+ ref={buttonRef}
192
+ type="button"
193
+ disabled={disabled}
194
+ aria-selected={selected}
195
+ onClick={onClick}
196
+ className={cn(
197
+ // Base styles
198
+ 'docs-sidebar-item group/button flex items-center rounded-lg px-3 py-2 w-full text-left relative z-10',
199
+ 'text-sm leading-5 transition-colors duration-150',
200
+ // Indentation
201
+ indent > 0 && `ml-${indent * 3}`,
202
+ // State variants
203
+ selected
204
+ ? hasSliding
205
+ ? 'docs-sidebar-item-active text-green-700 font-semibold dark:text-green-400' // No bg when sliding
206
+ : 'docs-sidebar-item-active bg-background text-green-700 font-semibold dark:bg-stone-800/50 dark:text-green-400'
207
+ : active
208
+ ? 'text-sidebar-foreground font-medium hover:bg-sidebar-accent/50'
209
+ : disabled
210
+ ? 'text-sidebar-foreground/50 cursor-default'
211
+ : 'text-sidebar-foreground/80 hover:bg-sidebar-accent/30 hover:text-sidebar-foreground',
212
+ className
213
+ )}
214
+ style={{ paddingLeft: indent > 0 ? `${indent * 12 + 12}px` : undefined }}
215
+ >
216
+ {IconComponent && (
217
+ <IconComponent className="h-4 w-4 mr-2 shrink-0 opacity-60" weight="regular" />
218
+ )}
219
+ <span className="flex-1 truncate">{children}</span>
220
+ {asideContent && (
221
+ <span className="ml-2 shrink-0">{asideContent}</span>
222
+ )}
223
+ </button>
224
+ </li>
225
+ )
226
+ }
@@ -0,0 +1,52 @@
1
+ 'use client'
2
+
3
+ import { ReactNode } from 'react'
4
+ import { cn } from '@/lib/utils'
5
+ import * as PhosphorIcons from '@phosphor-icons/react'
6
+
7
+ interface SidebarSectionProps {
8
+ title: string
9
+ children: ReactNode
10
+ className?: string
11
+ /** Phosphor icon name (e.g., "rocket", "book-open", "sliders") */
12
+ icon?: string
13
+ }
14
+
15
+ // Map of common icon names to Phosphor components
16
+ function getIcon(iconName?: string): React.ComponentType<{ className?: string; weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone" }> | null {
17
+ if (!iconName) return null
18
+
19
+ // Convert kebab-case to PascalCase for Phosphor icons
20
+ const pascalCase = iconName
21
+ .split('-')
22
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
23
+ .join('')
24
+
25
+ const IconComponent = (PhosphorIcons as Record<string, unknown>)[pascalCase] as React.ComponentType<{ className?: string; weight?: "thin" | "light" | "regular" | "bold" | "fill" | "duotone" }> | undefined
26
+ return IconComponent || null
27
+ }
28
+
29
+ /**
30
+ * Sidebar Section component - groups items under a title with optional icon
31
+ */
32
+ export function SidebarSection({ title, children, className = '', icon }: SidebarSectionProps) {
33
+ const IconComponent = getIcon(icon)
34
+
35
+ return (
36
+ <div className={cn('docs-sidebar-section flex flex-col', className)}>
37
+ {/* Section title with optional icon */}
38
+ <div className="docs-sidebar-section-header flex items-center gap-2 px-4 py-3">
39
+ {IconComponent && (
40
+ <IconComponent className="docs-sidebar-section-icon h-4 w-4 text-sidebar-foreground/70" weight="regular" />
41
+ )}
42
+ <span className="docs-sidebar-section-title text-sm font-semibold text-sidebar-foreground">
43
+ {title}
44
+ </span>
45
+ </div>
46
+ {/* Section items */}
47
+ <ul className="docs-sidebar-section-items flex flex-col gap-0.5 px-2 pb-4">
48
+ {children}
49
+ </ul>
50
+ </div>
51
+ )
52
+ }
@@ -0,0 +1,11 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ThemeProvider as NextThemesProvider } from "next-themes"
5
+
6
+ export function ThemeProvider({
7
+ children,
8
+ ...props
9
+ }: React.ComponentProps<typeof NextThemesProvider>) {
10
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
11
+ }
@@ -0,0 +1,76 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Moon, Sun, Desktop, Check } from "@phosphor-icons/react"
5
+ import { useTheme } from "next-themes"
6
+ import { Button } from "@/components/ui/button"
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuTrigger,
12
+ } from "@/components/ui/dropdown-menu"
13
+ import { cn } from "@/lib/utils"
14
+
15
+ export function ThemeToggle() {
16
+ const { theme, setTheme } = useTheme()
17
+ const [mounted, setMounted] = React.useState(false)
18
+
19
+ // Avoid hydration mismatch
20
+ React.useEffect(() => {
21
+ setMounted(true)
22
+ }, [])
23
+
24
+ return (
25
+ <DropdownMenu>
26
+ <DropdownMenuTrigger asChild>
27
+ <Button variant="ghost" size="icon" className="h-9 w-9">
28
+ <Sun className="h-4 w-4 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
29
+ <Moon className="absolute h-4 w-4 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
30
+ <span className="sr-only">Toggle theme</span>
31
+ </Button>
32
+ </DropdownMenuTrigger>
33
+ <DropdownMenuContent align="end" className="min-w-[140px]">
34
+ <DropdownMenuItem
35
+ onClick={() => setTheme("light")}
36
+ className={cn(
37
+ "flex items-center justify-between gap-2",
38
+ mounted && theme === "light" && "bg-accent"
39
+ )}
40
+ >
41
+ <div className="flex items-center gap-2">
42
+ <Sun className="h-4 w-4" />
43
+ <span>Light</span>
44
+ </div>
45
+ {mounted && theme === "light" && <Check className="h-4 w-4" />}
46
+ </DropdownMenuItem>
47
+ <DropdownMenuItem
48
+ onClick={() => setTheme("dark")}
49
+ className={cn(
50
+ "flex items-center justify-between gap-2",
51
+ mounted && theme === "dark" && "bg-accent"
52
+ )}
53
+ >
54
+ <div className="flex items-center gap-2">
55
+ <Moon className="h-4 w-4" />
56
+ <span>Dark</span>
57
+ </div>
58
+ {mounted && theme === "dark" && <Check className="h-4 w-4" />}
59
+ </DropdownMenuItem>
60
+ <DropdownMenuItem
61
+ onClick={() => setTheme("system")}
62
+ className={cn(
63
+ "flex items-center justify-between gap-2",
64
+ mounted && theme === "system" && "bg-accent"
65
+ )}
66
+ >
67
+ <div className="flex items-center gap-2">
68
+ <Desktop className="h-4 w-4" />
69
+ <span>System</span>
70
+ </div>
71
+ {mounted && theme === "system" && <Check className="h-4 w-4" />}
72
+ </DropdownMenuItem>
73
+ </DropdownMenuContent>
74
+ </DropdownMenu>
75
+ )
76
+ }